OSDN Git Service

7ee40256b19a27850e64680c411ed938cf7ba739
[jnethack/source.git] / src / mthrowu.c
1 /* NetHack 3.6  mthrowu.c       $NHDT-Date: 1542765360 2018/11/21 01:56:00 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.78 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Pasi Kallinen, 2016. */
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-2019            */
9 /* JNetHack may be freely redistributed.  See license for details. */
10
11 #include "hack.h"
12
13 STATIC_DCL int FDECL(monmulti, (struct monst *, struct obj *, struct obj *));
14 STATIC_DCL void FDECL(monshoot, (struct monst *, struct obj *, struct obj *));
15 STATIC_DCL int FDECL(drop_throw, (struct obj *, BOOLEAN_P, int, int));
16 STATIC_DCL boolean FDECL(m_lined_up, (struct monst *, struct monst *));
17
18 #define URETREATING(x, y) \
19     (distmin(u.ux, u.uy, x, y) > distmin(u.ux0, u.uy0, x, y))
20
21 #define POLE_LIM 5 /* How far monsters can use pole-weapons */
22
23 #define PET_MISSILE_RANGE2 36 /* Square of distance within which pets shoot */
24
25 /*
26  * Keep consistent with breath weapons in zap.c, and AD_* in monattk.h.
27  */
28 STATIC_OVL NEARDATA const char *breathwep[] = {
29 #if 0 /*JP*/
30     "fragments", "fire", "frost", "sleep gas", "a disintegration blast",
31     "lightning", "poison gas", "acid", "strange breath #8",
32     "strange breath #9"
33 #else
34     "\94j\95Ð", "\89\8a", "\97â\8bC", "\90\87\96°\83K\83X", "\95ª\89ð\82Ì\91§",
35     "\88î\8dÈ", "\93Å\82Ì\91§", "\8e_", "strange breath #8",
36     "strange breath #9"
37 #endif
38 };
39
40 extern boolean notonhead; /* for long worms */
41 STATIC_VAR int mesg_given; /* for m_throw()/thitu() 'miss' message */
42
43 /* hero is hit by something other than a monster */
44 int
45 thitu(tlev, dam, objp, name)
46 int tlev, dam;
47 struct obj **objp;
48 const char *name; /* if null, then format `*objp' */
49 {
50     struct obj *obj = objp ? *objp : 0;
51     const char *onm, *knm;
52     boolean is_acid;
53     int kprefix = KILLED_BY_AN, dieroll;
54     char onmbuf[BUFSZ], knmbuf[BUFSZ];
55
56     if (!name) {
57         if (!obj)
58             panic("thitu: name & obj both null?");
59         name = strcpy(onmbuf,
60                       (obj->quan > 1L) ? doname(obj) : mshot_xname(obj));
61         knm = strcpy(knmbuf, killer_xname(obj));
62         kprefix = KILLED_BY; /* killer_name supplies "an" if warranted */
63     } else {
64         knm = name;
65 #if 0 /*JP*/
66         /* [perhaps ought to check for plural here to] */
67         if (!strncmpi(name, "the ", 4) || !strncmpi(name, "an ", 3)
68             || !strncmpi(name, "a ", 2))
69             kprefix = KILLED_BY;
70 #else /* \93ú\96{\8cê\82Å\82Í\82»\82Ì\82Ü\82Ü */
71         knm = strcpy(knmbuf, name);
72 #endif
73     }
74 #if 1 /*JP*/
75     strcat(knmbuf, "\82É\93\96\82½\82Á\82Ä");
76 #endif
77     onm = (obj && obj_is_pname(obj)) ? the(name)
78           : (obj && obj->quan > 1L) ? name
79             : an(name);
80     is_acid = (obj && obj->otyp == ACID_VENOM);
81
82     if (u.uac + tlev <= (dieroll = rnd(20))) {
83         ++mesg_given;
84         if (Blind || !flags.verbose) {
85 /*JP
86             pline("It misses.");
87 */
88             pline("\82»\82ê\82Í\82Í\82¸\82ê\82½\81D");
89         } else if (u.uac + tlev <= dieroll - 2) {
90             if (onm != onmbuf)
91                 Strcpy(onmbuf, onm); /* [modifiable buffer for upstart()] */
92 /*JP
93             pline("%s %s you.", upstart(onmbuf), vtense(onmbuf, "miss"));
94 */
95             pline("%s\82Í\8dU\8c\82\82ð\82Í\82¸\82µ\82½\81D", upstart(onmbuf));
96         } else
97 /*JP
98             You("are almost hit by %s.", onm);
99 */
100             pline("\82à\82¤\8f­\82µ\82Å%s\82É\96½\92\86\82·\82é\82Æ\82±\82ë\82¾\82Á\82½\81I",onm);
101         return 0;
102     } else {
103         if (Blind || !flags.verbose)
104 /*JP
105             You("are hit%s", exclam(dam));
106 */
107             pline("\89½\82©\82ª\82 \82È\82½\82É\96½\92\86\82µ\82½\81I");
108         else
109 /*JP
110             You("are hit by %s%s", onm, exclam(dam));
111 */
112             pline("%s\82ª\82 \82È\82½\82É\96½\92\86\82µ\82½\81I", onm);
113
114         if (is_acid && Acid_resistance) {
115 /*JP
116             pline("It doesn't seem to hurt you.");
117 */
118             pline("\82 \82È\82½\82Í\8f\9d\82Â\82©\82È\82©\82Á\82½\81D");
119         } else if (obj && obj->oclass == POTION_CLASS) {
120             /* an explosion which scatters objects might hit hero with one
121                (potions deliberately thrown at hero are handled by m_throw) */
122             potionhit(&youmonst, obj, POTHIT_OTHER_THROW);
123             *objp = obj = 0; /* potionhit() uses up the potion */
124         } else {
125             if (obj && objects[obj->otyp].oc_material == SILVER
126                 && Hate_silver) {
127                 /* extra damage already applied by dmgval() */
128 /*JP
129             pline_The("silver sears your flesh!");
130 */
131             pline("\82 \82È\82½\82Ì\91Ì\82Í\8bâ\82Å\8fÄ\82©\82ê\82½\81I");
132                 exercise(A_CON, FALSE);
133             }
134             if (is_acid)
135 /*JP
136                 pline("It burns!");
137 */
138                 pline("\8e_\82Å\8fÄ\82©\82ê\82½\81I");
139             losehp(dam, knm, kprefix); /* acid damage */
140             exercise(A_STR, FALSE);
141         }
142         return 1;
143     }
144 }
145
146 /* Be sure this corresponds with what happens to player-thrown objects in
147  * dothrow.c (for consistency). --KAA
148  * Returns 0 if object still exists (not destroyed).
149  */
150 STATIC_OVL int
151 drop_throw(obj, ohit, x, y)
152 register struct obj *obj;
153 boolean ohit;
154 int x, y;
155 {
156     int retvalu = 1;
157     int create;
158     struct monst *mtmp;
159     struct trap *t;
160
161     if (obj->otyp == CREAM_PIE || obj->oclass == VENOM_CLASS
162         || (ohit && obj->otyp == EGG))
163         create = 0;
164     else if (ohit && (is_multigen(obj) || obj->otyp == ROCK))
165         create = !rn2(3);
166     else
167         create = 1;
168
169     if (create && !((mtmp = m_at(x, y)) != 0 && mtmp->mtrapped
170                     && (t = t_at(x, y)) != 0
171                     && is_pit(t->ttyp))) {
172         int objgone = 0;
173
174         if (down_gate(x, y) != -1)
175             objgone = ship_object(obj, x, y, FALSE);
176         if (!objgone) {
177 #if 0 /*JP:T*/
178             if (!flooreffects(obj, x, y, "fall")) {
179 #else
180             if (!flooreffects(obj, x, y, "\97\8e\82¿\82é")) {
181 #endif
182                 place_object(obj, x, y);
183                 if (!mtmp && x == u.ux && y == u.uy)
184                     mtmp = &youmonst;
185                 if (mtmp && ohit)
186                     passive_obj(mtmp, obj, (struct attack *) 0);
187                 stackobj(obj);
188                 retvalu = 0;
189             }
190         }
191     } else
192         obfree(obj, (struct obj *) 0);
193     return retvalu;
194 }
195
196 /* The monster that's being shot at when one monster shoots at another */
197 STATIC_OVL struct monst *target = 0;
198 /* The monster that's doing the shooting/throwing */
199 STATIC_OVL struct monst *archer = 0;
200
201 /* calculate multishot volley count for mtmp throwing otmp (if not ammo) or
202    shooting otmp with mwep (if otmp is ammo and mwep appropriate launcher) */
203 STATIC_OVL int
204 monmulti(mtmp, otmp, mwep)
205 struct monst *mtmp;
206 struct obj *otmp, *mwep;
207 {
208     int skill = (int) objects[otmp->otyp].oc_skill;
209     int multishot = 1;
210
211     if (otmp->quan > 1L /* no point checking if there's only 1 */
212         /* ammo requires corresponding launcher be wielded */
213         && (is_ammo(otmp)
214                ? matching_launcher(otmp, mwep)
215                /* otherwise any stackable (non-ammo) weapon */
216                : otmp->oclass == WEAPON_CLASS)
217         && !mtmp->mconf) {
218         /* Assumes lords are skilled, princes are expert */
219         if (is_prince(mtmp->data))
220             multishot += 2;
221         else if (is_lord(mtmp->data))
222             multishot++;
223         /* fake players treated as skilled (regardless of role limits) */
224         else if (is_mplayer(mtmp->data))
225             multishot++;
226
227         /* this portion is different from hero multishot; from slash'em?
228          */
229         /* Elven Craftsmanship makes for light, quick bows */
230         if (otmp->otyp == ELVEN_ARROW && !otmp->cursed)
231             multishot++;
232         if (ammo_and_launcher(otmp, uwep) && mwep->otyp == ELVEN_BOW
233             && !mwep->cursed)
234             multishot++;
235         /* 1/3 of launcher enchantment */
236         if (ammo_and_launcher(otmp, mwep) && mwep->spe > 1)
237             multishot += (long) rounddiv(mwep->spe, 3);
238         /* Some randomness */
239         multishot = (long) rnd((int) multishot);
240
241         /* class bonus */
242         switch (monsndx(mtmp->data)) {
243         case PM_CAVEMAN: /* give bonus for low-tech gear */
244             if (skill == -P_SLING || skill == P_SPEAR)
245                 multishot++;
246             break;
247         case PM_MONK: /* allow higher volley count */
248             if (skill == -P_SHURIKEN)
249                 multishot++;
250             break;
251         case PM_RANGER:
252             if (skill != P_DAGGER)
253                 multishot++;
254             break;
255         case PM_ROGUE:
256             if (skill == P_DAGGER)
257                 multishot++;
258             break;
259         case PM_NINJA:
260             if (skill == -P_SHURIKEN || skill == -P_DART)
261                 multishot++;
262             /*FALLTHRU*/
263         case PM_SAMURAI:
264             if (otmp->otyp == YA && mwep->otyp == YUMI)
265                 multishot++;
266             break;
267         default:
268             break;
269         }
270         /* racial bonus */
271         if ((is_elf(mtmp->data) && otmp->otyp == ELVEN_ARROW
272             && mwep->otyp == ELVEN_BOW)
273             || (is_orc(mtmp->data) && otmp->otyp == ORCISH_ARROW
274                 && mwep->otyp == ORCISH_BOW)
275             || (is_gnome(mtmp->data) && otmp->otyp == CROSSBOW_BOLT
276                 && mwep->otyp == CROSSBOW))
277             multishot++;
278     }
279
280     if (otmp->quan < multishot)
281         multishot = (int) otmp->quan;
282     if (multishot < 1)
283         multishot = 1;
284     return multishot;
285 }
286
287 /* mtmp throws otmp, or shoots otmp with mwep, at hero or at monster mtarg */
288 STATIC_OVL void
289 monshoot(mtmp, otmp, mwep)
290 struct monst *mtmp;
291 struct obj *otmp, *mwep;
292 {
293     struct monst *mtarg = target;
294     int dm = distmin(mtmp->mx, mtmp->my,
295                      mtarg ? mtarg->mx : mtmp->mux,
296                      mtarg ? mtarg->my : mtmp->muy),
297         multishot = monmulti(mtmp, otmp, mwep);
298         /*
299          * Caller must have called linedup() to set up tbx, tby.
300          */
301
302     if (canseemon(mtmp)) {
303         const char *onm;
304         char onmbuf[BUFSZ], trgbuf[BUFSZ];
305
306         if (multishot > 1) {
307             /* "N arrows"; multishot > 1 implies otmp->quan > 1, so
308                xname()'s result will already be pluralized */
309 /*JP
310             Sprintf(onmbuf, "%d %s", multishot, xname(otmp));
311 */
312             Sprintf(onmbuf, "%d%s\82Ì%s", multishot, numeral(otmp), xname(otmp));
313             onm = onmbuf;
314         } else {
315             /* "an arrow" */
316             onm = singular(otmp, xname);
317             onm = obj_is_pname(otmp) ? the(onm) : an(onm);
318         }
319         m_shot.s = ammo_and_launcher(otmp, mwep) ? TRUE : FALSE;
320         Strcpy(trgbuf, mtarg ? mon_nam(mtarg) : "");
321 #if 0 /*JP*//*\93ú\96{\8cê\82Å\82Ímon_nam\82Í\81u\89½\8eÒ\82©\81v\82ð\95Ô\82·\82Ì\82Å\95Ï\8dX\95s\97v*/
322         if (!strcmp(trgbuf, "it"))
323             Strcpy(trgbuf, humanoid(mtmp->data) ? "someone" : something);
324 #endif
325 #if 0 /*JP*/
326         pline("%s %s %s%s%s!", Monnam(mtmp),
327               m_shot.s ? "shoots" : "throws", onm,
328               mtarg ? " at " : "", trgbuf);
329 #else
330         pline("%s\82Í%s\82ð%s\82É%s\81I", Monnam(mtmp),
331               onm,
332               trgbuf,
333               m_shot.s ? "\8c\82\82Á\82½" : "\93\8a\82°\82½");
334 #endif
335         m_shot.o = otmp->otyp;
336     } else {
337         m_shot.o = STRANGE_OBJECT; /* don't give multishot feedback */
338     }
339     m_shot.n = multishot;
340     for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) {
341         m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), dm, otmp);
342         /* conceptually all N missiles are in flight at once, but
343            if mtmp gets killed (shot kills adjacent gas spore and
344            triggers explosion, perhaps), inventory will be dropped
345            and otmp might go away via merging into another stack */
346         if (DEADMONSTER(mtmp) && m_shot.i < m_shot.n)
347             /* cancel pending shots (perhaps ought to give a message here
348                since we gave one above about throwing/shooting N missiles) */
349             break; /* endmultishot(FALSE); */
350     }
351     /* reset 'm_shot' */
352     m_shot.n = m_shot.i = 0;
353     m_shot.o = STRANGE_OBJECT;
354     m_shot.s = FALSE;
355 }
356
357 /* an object launched by someone/thing other than player attacks a monster;
358    return 1 if the object has stopped moving (hit or its range used up) */
359 int
360 ohitmon(mtmp, otmp, range, verbose)
361 struct monst *mtmp; /* accidental target, located at <bhitpos.x,.y> */
362 struct obj *otmp;   /* missile; might be destroyed by drop_throw */
363 int range;          /* how much farther will object travel if it misses;
364                        use -1 to signify to keep going even after hit,
365                        unless it's gone (used for rolling_boulder_traps) */
366 boolean verbose;    /* give message(s) even when you can't see what happened */
367 {
368     int damage, tmp;
369     boolean vis, ismimic;
370     int objgone = 1;
371     struct obj *mon_launcher = archer ? MON_WEP(archer) : NULL;
372
373     notonhead = (bhitpos.x != mtmp->mx || bhitpos.y != mtmp->my);
374     ismimic = M_AP_TYPE(mtmp) && M_AP_TYPE(mtmp) != M_AP_MONSTER;
375     vis = cansee(bhitpos.x, bhitpos.y);
376
377     tmp = 5 + find_mac(mtmp) + omon_adj(mtmp, otmp, FALSE);
378     /* High level monsters will be more likely to hit */
379     /* This check applies only if this monster is the target
380      * the archer was aiming at. */
381     if (archer && target == mtmp) {
382         if (archer->m_lev > 5)
383             tmp += archer->m_lev - 5;
384         if (mon_launcher && mon_launcher->oartifact)
385             tmp += spec_abon(mon_launcher, mtmp);
386     }
387     if (tmp < rnd(20)) {
388         if (!ismimic) {
389             if (vis)
390                 miss(distant_name(otmp, mshot_xname), mtmp);
391             else if (verbose && !target)
392 /*JP
393                 pline("It is missed.");
394 */
395                 pline("\89½\82©\82ª\82©\82·\82ß\82½\81D");
396         }
397         if (!range) { /* Last position; object drops */
398             (void) drop_throw(otmp, 0, mtmp->mx, mtmp->my);
399             return 1;
400         }
401     } else if (otmp->oclass == POTION_CLASS) {
402         if (ismimic)
403             seemimic(mtmp);
404         mtmp->msleeping = 0;
405         if (vis)
406             otmp->dknown = 1;
407         /* probably thrown by a monster rather than 'other', but the
408            distinction only matters when hitting the hero */
409         potionhit(mtmp, otmp, POTHIT_OTHER_THROW);
410         return 1;
411     } else {
412         damage = dmgval(otmp, mtmp);
413         if (otmp->otyp == ACID_VENOM && resists_acid(mtmp))
414             damage = 0;
415         if (ismimic)
416             seemimic(mtmp);
417         mtmp->msleeping = 0;
418         if (vis) {
419             if (otmp->otyp == EGG)
420 #if 0 /*JP:T*/
421                 pline("Splat!  %s is hit with %s egg!", Monnam(mtmp),
422                       otmp->known ? an(mons[otmp->corpsenm].mname) : "an");
423 #else
424                 pline("\83r\83`\83\83\83b\81I%s\82Í%s\97\91\82É\93\96\82½\82Á\82½\81I", Monnam(mtmp),
425                       otmp->known ? s_suffix(mons[otmp->corpsenm].mname) : "");
426 #endif
427             else
428                 hit(distant_name(otmp, mshot_xname), mtmp, exclam(damage));
429         } else if (verbose && !target)
430 #if 0 /*JP:T*/
431             pline("%s%s is hit%s", (otmp->otyp == EGG) ? "Splat!  " : "",
432                   Monnam(mtmp), exclam(damage));
433 #else
434             pline("%s%s\82É\96½\92\86\82µ\82½%s", (otmp->otyp == EGG) ? "\83r\83`\83\83\83b\81I" : "",
435                   Monnam(mtmp), exclam(damage));
436 #endif
437
438         if (otmp->opoisoned && is_poisonable(otmp)) {
439             if (resists_poison(mtmp)) {
440                 if (vis)
441 /*JP
442                     pline_The("poison doesn't seem to affect %s.",
443 */
444                     pline("%s\82Í\93Å\82Ì\89e\8b¿\82ð\8eó\82¯\82È\82¢\82æ\82¤\82¾\81D",
445                               mon_nam(mtmp));
446             } else {
447                 if (rn2(30)) {
448                     damage += rnd(6);
449                 } else {
450                     if (vis)
451 /*JP
452                         pline_The("poison was deadly...");
453 */
454                         pline("\93Å\82Í\92v\8e\80\97Ê\82¾\82Á\82½\81D\81D\81D");
455                     damage = mtmp->mhp;
456                 }
457             }
458         }
459         if (objects[otmp->otyp].oc_material == SILVER
460             && mon_hates_silver(mtmp)) {
461             if (vis)
462 /*JP
463                 pline_The("silver sears %s flesh!", s_suffix(mon_nam(mtmp)));
464 */
465                 pline("%s\82Ì\91Ì\82Í\8bâ\82Å\8fÄ\82©\82ê\82½\81I", mon_nam(mtmp));
466             else if (verbose && !target)
467 /*JP
468                 pline("Its flesh is seared!");
469 */
470                 pline("\89½\8eÒ\82©\82Ì\91Ì\82Í\8fÄ\82©\82ê\82½\81I");
471         }
472         if (otmp->otyp == ACID_VENOM && cansee(mtmp->mx, mtmp->my)) {
473             if (resists_acid(mtmp)) {
474                 if (vis || (verbose && !target))
475 /*JP
476                     pline("%s is unaffected.", Monnam(mtmp));
477 */
478                     pline("%s\82Í\89e\8b¿\82ð\8eó\82¯\82È\82¢\81D", Monnam(mtmp));
479             } else {
480                 if (vis)
481 /*JP
482                     pline_The("%s burns %s!", hliquid("acid"), mon_nam(mtmp));
483 */
484                     pline_The("%s\82Í%s\82Å\8fÄ\82©\82ê\82½\81I", mon_nam(mtmp), hliquid("\8e_"));
485                 else if (verbose && !target)
486 /*JP
487                     pline("It is burned!");
488 */
489                     pline("\89½\82©\82Í\8fÄ\82©\82ê\82½\81I");
490             }
491         }
492         if (otmp->otyp == EGG && touch_petrifies(&mons[otmp->corpsenm])) {
493             if (!munstone(mtmp, TRUE))
494                 minstapetrify(mtmp, TRUE);
495             if (resists_ston(mtmp))
496                 damage = 0;
497         }
498
499         if (!DEADMONSTER(mtmp)) { /* might already be dead (if petrified) */
500             mtmp->mhp -= damage;
501             if (DEADMONSTER(mtmp)) {
502                 if (vis || (verbose && !target))
503 #if 0 /*JP:T*/
504                     pline("%s is %s!", Monnam(mtmp),
505                           (nonliving(mtmp->data) || is_vampshifter(mtmp)
506                            || !canspotmon(mtmp)) ? "destroyed" : "killed");
507 #else
508                     pline("%s\82Í%s\81I", Monnam(mtmp),
509                           (nonliving(mtmp->data) || is_vampshifter(mtmp)
510                            || !canspotmon(mtmp)) ? "\93|\82³\82ê\82½" : "\8e\80\82ñ\82¾");
511 #endif
512                 /* don't blame hero for unknown rolling boulder trap */
513                 if (!context.mon_moving && (otmp->otyp != BOULDER
514                                             || range >= 0 || otmp->otrapped))
515                     xkilled(mtmp, XKILL_NOMSG);
516                 else
517                     mondied(mtmp);
518             }
519         }
520
521         /* blinding venom and cream pie do 0 damage, but verify
522            that the target is still alive anyway */
523         if (!DEADMONSTER(mtmp)
524             && can_blnd((struct monst *) 0, mtmp,
525                         (uchar) ((otmp->otyp == BLINDING_VENOM) ? AT_SPIT
526                                                                 : AT_WEAP),
527                         otmp)) {
528             if (vis && mtmp->mcansee)
529 /*JP
530                 pline("%s is blinded by %s.", Monnam(mtmp), the(xname(otmp)));
531 */
532                 pline("%s\82Í%s\82É\82æ\82Á\82Ä\96Ú\82ª\8c©\82¦\82È\82­\82È\82Á\82½\81D", Monnam(mtmp), the(xname(otmp)));
533             mtmp->mcansee = 0;
534             tmp = (int) mtmp->mblinded + rnd(25) + 20;
535             if (tmp > 127)
536                 tmp = 127;
537             mtmp->mblinded = tmp;
538         }
539
540         objgone = drop_throw(otmp, 1, bhitpos.x, bhitpos.y);
541         if (!objgone && range == -1) { /* special case */
542             obj_extract_self(otmp);    /* free it for motion again */
543             return 0;
544         }
545         return 1;
546     }
547     return 0;
548 }
549
550 #define MT_FLIGHTCHECK(pre)                                             \
551     (/* missile hits edge of screen */                                  \
552      !isok(bhitpos.x + dx, bhitpos.y + dy)                              \
553      /* missile hits the wall */                                        \
554      || IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ)               \
555      /* missile hit closed door */                                      \
556      || closed_door(bhitpos.x + dx, bhitpos.y + dy)                     \
557      /* missile might hit iron bars */                                  \
558      /* the random chance for small objects hitting bars is */          \
559      /* skipped when reaching them at point blank range */              \
560      || (levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS           \
561          && hits_bars(&singleobj,                                       \
562                       bhitpos.x, bhitpos.y,                             \
563                       bhitpos.x + dx, bhitpos.y + dy,                   \
564                       ((pre) ? 0 : !rn2(5)), 0))                        \
565      /* Thrown objects "sink" */                                        \
566      || (!(pre) && IS_SINK(levl[bhitpos.x][bhitpos.y].typ)))
567
568 void
569 m_throw(mon, x, y, dx, dy, range, obj)
570 struct monst *mon;       /* launching monster */
571 int x, y, dx, dy, range; /* launch point, direction, and range */
572 struct obj *obj;         /* missile (or stack providing it) */
573 {
574     struct monst *mtmp;
575     struct obj *singleobj;
576     char sym = obj->oclass;
577     int hitu = 0, oldumort, blindinc = 0;
578
579     bhitpos.x = x;
580     bhitpos.y = y;
581     notonhead = FALSE; /* reset potentially stale value */
582
583     if (obj->quan == 1L) {
584         /*
585          * Remove object from minvent.  This cannot be done later on;
586          * what if the player dies before then, leaving the monster
587          * with 0 daggers?  (This caused the infamous 2^32-1 orcish
588          * dagger bug).
589          *
590          * VENOM is not in minvent - it should already be OBJ_FREE.
591          * The extract below does nothing.
592          */
593
594         /* not possibly_unwield, which checks the object's */
595         /* location, not its existence */
596         if (MON_WEP(mon) == obj)
597             setmnotwielded(mon, obj);
598         obj_extract_self(obj);
599         singleobj = obj;
600         obj = (struct obj *) 0;
601     } else {
602         singleobj = splitobj(obj, 1L);
603         obj_extract_self(singleobj);
604     }
605
606     singleobj->owornmask = 0; /* threw one of multiple weapons in hand? */
607
608     if ((singleobj->cursed || singleobj->greased) && (dx || dy) && !rn2(7)) {
609         if (canseemon(mon) && flags.verbose) {
610             if (is_ammo(singleobj))
611 /*JP
612                 pline("%s misfires!", Monnam(mon));
613 */
614                 pline("%s\82Í\82Í\82¸\82µ\82½\81I", Monnam(mon));
615             else
616 #if 0 /*JP*/
617                 pline("%s as %s throws it!", Tobjnam(singleobj, "slip"),
618                       mon_nam(mon));
619 #else
620                 pline("%s\82ª\93\8a\82°\82æ\82¤\82Æ\82µ\82½\82Æ\82½\82ñ%s\82ª\8a\8a\82Á\82½\81I",
621                           mon_nam(mon), xname(singleobj));
622 #endif
623         }
624         dx = rn2(3) - 1;
625         dy = rn2(3) - 1;
626         /* check validity of new direction */
627         if (!dx && !dy) {
628             (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
629             return;
630         }
631     }
632
633     if (MT_FLIGHTCHECK(TRUE)) {
634         (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
635         return;
636     }
637     mesg_given = 0; /* a 'missile misses' message has not yet been shown */
638
639     /* Note: drop_throw may destroy singleobj.  Since obj must be destroyed
640      * early to avoid the dagger bug, anyone who modifies this code should
641      * be careful not to use either one after it's been freed.
642      */
643     if (sym)
644         tmp_at(DISP_FLASH, obj_to_glyph(singleobj, rn2_on_display_rng));
645     while (range-- > 0) { /* Actually the loop is always exited by break */
646         bhitpos.x += dx;
647         bhitpos.y += dy;
648         if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
649             if (ohitmon(mtmp, singleobj, range, TRUE))
650                 break;
651         } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) {
652             if (multi)
653                 nomul(0);
654
655             if (singleobj->oclass == GEM_CLASS
656                 && singleobj->otyp <= LAST_GEM + 9 /* 9 glass colors */
657                 && is_unicorn(youmonst.data)) {
658                 if (singleobj->otyp > LAST_GEM) {
659 /*JP
660                     You("catch the %s.", xname(singleobj));
661 */
662                     You("%s\82ð\82Â\82©\82Ü\82¦\82½\81D", xname(singleobj));
663 #if 0 /*JP*/
664                     You("are not interested in %s junk.",
665                         s_suffix(mon_nam(mon)));
666 #else
667                     You("%s\82Ì\83K\83\89\83N\83^\82É\8b»\96¡\82Í\82È\82¢\81D",
668                         mon_nam(mon));
669 #endif
670                     makeknown(singleobj->otyp);
671                     dropy(singleobj);
672                 } else {
673                     You(
674 /*JP
675                      "accept %s gift in the spirit in which it was intended.",
676 */
677                      "\82±\82ê\82ª\97~\82µ\82©\82Á\82½\82ñ\82¾\82Æ\8ev\82¢\82È\82ª\82ç%s\82Ì\91¡\82è\95¨\82ð\8eó\82¯\82Æ\82Á\82½\81D",
678                         s_suffix(mon_nam(mon)));
679 #if 0 /*JP*/
680                     (void) hold_another_object(singleobj,
681                                                "You catch, but drop, %s.",
682                                                xname(singleobj),
683                                                "You catch:");
684 #else
685                     (void) hold_another_object(singleobj,
686                                      "\82 \82È\82½\82Í%s\82ð\82Â\82©\82Ü\82¦\82½\82ª\81C\97\8e\82µ\82½\81D",
687                                                xname(singleobj),
688                                                "\82ð\82Â\82©\82Ü\82¦\82½\81D");
689 #endif
690                 }
691                 break;
692             }
693             if (singleobj->oclass == POTION_CLASS) {
694                 if (!Blind)
695                     singleobj->dknown = 1;
696                 potionhit(&youmonst, singleobj, POTHIT_MONST_THROW);
697                 break;
698             }
699             oldumort = u.umortality;
700             switch (singleobj->otyp) {
701                 int dam, hitv;
702             case EGG:
703                 if (!touch_petrifies(&mons[singleobj->corpsenm])) {
704                     impossible("monster throwing egg type %d",
705                                singleobj->corpsenm);
706                     hitu = 0;
707                     break;
708                 }
709             /* fall through */
710             case CREAM_PIE:
711             case BLINDING_VENOM:
712                 hitu = thitu(8, 0, &singleobj, (char *) 0);
713                 break;
714             default:
715                 dam = dmgval(singleobj, &youmonst);
716                 hitv = 3 - distmin(u.ux, u.uy, mon->mx, mon->my);
717                 if (hitv < -4)
718                     hitv = -4;
719                 if (is_elf(mon->data)
720                     && objects[singleobj->otyp].oc_skill == P_BOW) {
721                     hitv++;
722                     if (MON_WEP(mon) && MON_WEP(mon)->otyp == ELVEN_BOW)
723                         hitv++;
724                     if (singleobj->otyp == ELVEN_ARROW)
725                         dam++;
726                 }
727                 if (bigmonst(youmonst.data))
728                     hitv++;
729                 hitv += 8 + singleobj->spe;
730                 if (dam < 1)
731                     dam = 1;
732                 hitu = thitu(hitv, dam, &singleobj, (char *) 0);
733             }
734             if (hitu && singleobj->opoisoned && is_poisonable(singleobj)) {
735                 char onmbuf[BUFSZ], knmbuf[BUFSZ];
736
737                 Strcpy(onmbuf, xname(singleobj));
738                 Strcpy(knmbuf, killer_xname(singleobj));
739                 poisoned(onmbuf, A_STR, knmbuf,
740                          /* if damage triggered life-saving,
741                             poison is limited to attrib loss */
742                          (u.umortality > oldumort) ? 0 : 10, TRUE);
743             }
744             if (hitu && can_blnd((struct monst *) 0, &youmonst,
745                                  (uchar) ((singleobj->otyp == BLINDING_VENOM)
746                                              ? AT_SPIT
747                                              : AT_WEAP),
748                                  singleobj)) {
749                 blindinc = rnd(25);
750                 if (singleobj->otyp == CREAM_PIE) {
751                     if (!Blind)
752 /*JP
753                         pline("Yecch!  You've been creamed.");
754 */
755                         pline("\83E\83F\81[\81D\83N\83\8a\81[\83\80\82ð\82©\82Ô\82Á\82½\81D");
756                     else
757 #if 0 /*JP*/
758                         pline("There's %s sticky all over your %s.",
759                               something, body_part(FACE));
760 #else
761                         pline("\82 \82È\82½\82Í%s\82É\82×\82Æ\82Â\82­\82à\82Ì\82ð\8a´\82\82½\81D",
762                               body_part(FACE));
763 #endif
764                 } else if (singleobj->otyp == BLINDING_VENOM) {
765 #if 0 /*JP*/
766                     const char *eyes = body_part(EYE);
767
768                     if (eyecount(youmonst.data) != 1)
769                         eyes = makeplural(eyes);
770                     /* venom in the eyes */
771                     if (!Blind)
772                         pline_The("venom blinds you.");
773                     else
774                         Your("%s %s.", eyes, vtense(eyes, "sting"));
775 #else
776                     if(!Blind)
777                         pline("\93Å\82Å\96Ú\82ª\8c©\82¦\82È\82­\82È\82Á\82½\81D");
778                     else
779                         Your("%s\82Í\82¿\82­\82¿\82­\82µ\82½\81D", body_part(EYE));
780 #endif
781                 }
782             }
783             if (hitu && singleobj->otyp == EGG) {
784                 if (!Stoned && !Stone_resistance
785                     && !(poly_when_stoned(youmonst.data)
786                          && polymon(PM_STONE_GOLEM))) {
787                     make_stoned(5L, (char *) 0, KILLED_BY, "");
788                 }
789             }
790             stop_occupation();
791             if (hitu) {
792                 (void) drop_throw(singleobj, hitu, u.ux, u.uy);
793                 break;
794             }
795         }
796         if (!range /* reached end of path */
797             || MT_FLIGHTCHECK(FALSE)) {
798             if (singleobj) { /* hits_bars might have destroyed it */
799                 if (m_shot.n > 1
800                     && (!mesg_given || bhitpos.x != u.ux || bhitpos.y != u.uy)
801                     && (cansee(bhitpos.x, bhitpos.y)
802                         || (archer && canseemon(archer))))
803 /*JP
804                     pline("%s misses.", The(mshot_xname(singleobj)));
805 */
806                     pline("%s\82Í\82Í\82¸\82ê\82½\81D", mshot_xname(singleobj));
807                 (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
808             }
809             break;
810         }
811         tmp_at(bhitpos.x, bhitpos.y);
812         delay_output();
813     }
814     tmp_at(bhitpos.x, bhitpos.y);
815     delay_output();
816     tmp_at(DISP_END, 0);
817     mesg_given = 0; /* reset */
818
819     if (blindinc) {
820         u.ucreamed += blindinc;
821         make_blinded(Blinded + (long) blindinc, FALSE);
822         if (!Blind)
823             Your1(vision_clears);
824     }
825 }
826
827 #undef MT_FLIGHTCHECK
828
829 /* Monster throws item at another monster */
830 int
831 thrwmm(mtmp, mtarg)
832 struct monst *mtmp, *mtarg;
833 {
834     struct obj *otmp, *mwep;
835     register xchar x, y;
836     boolean ispole;
837
838     /* Polearms won't be applied by monsters against other monsters */
839     if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) {
840         mtmp->weapon_check = NEED_RANGED_WEAPON;
841         /* mon_wield_item resets weapon_check as appropriate */
842         if (mon_wield_item(mtmp) != 0)
843             return 0;
844     }
845
846     /* Pick a weapon */
847     otmp = select_rwep(mtmp);
848     if (!otmp)
849         return 0;
850     ispole = is_pole(otmp);
851
852     x = mtmp->mx;
853     y = mtmp->my;
854
855     mwep = MON_WEP(mtmp); /* wielded weapon */
856
857     if (!ispole && m_lined_up(mtarg, mtmp)) {
858         int chance = max(BOLT_LIM - distmin(x, y, mtarg->mx, mtarg->my), 1);
859
860         if (!mtarg->mflee || !rn2(chance)) {
861             if (ammo_and_launcher(otmp, mwep)
862                 && dist2(mtmp->mx, mtmp->my, mtarg->mx, mtarg->my)
863                    > PET_MISSILE_RANGE2)
864                 return 0; /* Out of range */
865             /* Set target monster */
866             target = mtarg;
867             archer = mtmp;
868             monshoot(mtmp, otmp, mwep); /* multishot shooting or throwing */
869             archer = target = (struct monst *) 0;
870             nomul(0);
871             return 1;
872         }
873     }
874     return 0;
875 }
876
877 /* monster spits substance at monster */
878 int
879 spitmm(mtmp, mattk, mtarg)
880 struct monst *mtmp, *mtarg;
881 struct attack *mattk;
882 {
883     struct obj *otmp;
884
885     if (mtmp->mcan) {
886         if (!Deaf)
887 #if 0 /*JP:T*/
888             pline("A dry rattle comes from %s throat.",
889                   s_suffix(mon_nam(mtmp)));
890 #else
891             pline("%s\82Ì\8dA\82ª\83K\83\89\83K\83\89\82Æ\96Â\82Á\82½\81D",
892                   mon_nam(mtmp));
893 #endif
894         return 0;
895     }
896     if (m_lined_up(mtarg, mtmp)) {
897         switch (mattk->adtyp) {
898         case AD_BLND:
899         case AD_DRST:
900             otmp = mksobj(BLINDING_VENOM, TRUE, FALSE);
901             break;
902         default:
903             impossible("bad attack type in spitmu");
904             /* fall through */
905         case AD_ACID:
906             otmp = mksobj(ACID_VENOM, TRUE, FALSE);
907             break;
908         }
909         if (!rn2(BOLT_LIM-distmin(mtmp->mx,mtmp->my,mtarg->mx,mtarg->my))) {
910             if (canseemon(mtmp))
911 /*JP
912                 pline("%s spits venom!", Monnam(mtmp));
913 */
914                 pline("%s\82Í\93Å\82ð\93f\82¢\82½\81I", Monnam(mtmp));
915             target = mtarg;
916             m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
917                     distmin(mtmp->mx,mtmp->my,mtarg->mx,mtarg->my), otmp);
918             target = (struct monst *)0;
919             nomul(0);
920
921             /* If this is a pet, it'll get hungry. Minions and
922              * spell beings won't hunger */
923             if (mtmp->mtame && !mtmp->isminion) {
924                 struct edog *dog = EDOG(mtmp);
925
926                 /* Hunger effects will catch up next move */
927                 if (dog->hungrytime > 1)
928                     dog->hungrytime -= 5;
929             }
930
931             return 1;
932         }
933     }
934     return 0;
935 }
936
937 /* monster breathes at monster (ranged) */
938 int
939 breamm(mtmp, mattk, mtarg)
940 struct monst *mtmp, *mtarg;
941 struct attack  *mattk;
942 {
943     /* if new breath types are added, change AD_ACID to max type */
944     int typ = (mattk->adtyp == AD_RBRE) ? rnd(AD_ACID) : mattk->adtyp ;
945
946     if (m_lined_up(mtarg, mtmp)) {
947         if (mtmp->mcan) {
948             if (!Deaf) {
949                 if (canseemon(mtmp))
950 /*JP
951                     pline("%s coughs.", Monnam(mtmp));
952 */
953                     pline("%s\82Í\82¹\82«\82ð\82µ\82½\81D", Monnam(mtmp));
954                 else
955 /*JP
956                     You_hear("a cough.");
957 */
958                     You_hear("\82¹\82«\82Ì\89¹\82ð\95·\82¢\82½\81D");
959             }
960             return 0;
961         }
962         if (!mtmp->mspec_used && rn2(3)) {
963             if ((typ >= AD_MAGM) && (typ <= AD_ACID)) {
964                 if (canseemon(mtmp))
965 /*JP
966                     pline("%s breathes %s!", Monnam(mtmp), breathwep[typ - 1]);
967 */
968                     pline("%s\82Í%s\82ð\82Í\82¢\82½\81I", Monnam(mtmp), breathwep[typ - 1]);
969                 dobuzz((int) (-20 - (typ - 1)), (int) mattk->damn,
970                        mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), FALSE);
971                 nomul(0);
972                 /* breath runs out sometimes. Also, give monster some
973                  * cunning; don't breath if the target fell asleep.
974                  */
975                 mtmp->mspec_used = 6 + rn2(18);
976
977                 /* If this is a pet, it'll get hungry. Minions and
978                  * spell beings won't hunger */
979                 if (mtmp->mtame && !mtmp->isminion) {
980                     struct edog *dog = EDOG(mtmp);
981
982                     /* Hunger effects will catch up next move */
983                     if (dog->hungrytime >= 10)
984                         dog->hungrytime -= 10;
985                 }
986             } else impossible("Breath weapon %d used", typ-1);
987         } else
988             return 0;
989     }
990     return 1;
991 }
992
993
994
995 /* remove an entire item from a monster's inventory; destroy that item */
996 void
997 m_useupall(mon, obj)
998 struct monst *mon;
999 struct obj *obj;
1000 {
1001     obj_extract_self(obj);
1002     if (obj->owornmask) {
1003         if (obj == MON_WEP(mon))
1004             mwepgone(mon);
1005         mon->misc_worn_check &= ~obj->owornmask;
1006         update_mon_intrinsics(mon, obj, FALSE, FALSE);
1007         obj->owornmask = 0L;
1008     }
1009     obfree(obj, (struct obj *) 0);
1010 }
1011
1012 /* remove one instance of an item from a monster's inventory */
1013 void
1014 m_useup(mon, obj)
1015 struct monst *mon;
1016 struct obj *obj;
1017 {
1018     if (obj->quan > 1L) {
1019         obj->quan--;
1020         obj->owt = weight(obj);
1021     } else {
1022         m_useupall(mon, obj);
1023     }
1024 }
1025
1026 /* monster attempts ranged weapon attack against player */
1027 void
1028 thrwmu(mtmp)
1029 struct monst *mtmp;
1030 {
1031     struct obj *otmp, *mwep;
1032     xchar x, y;
1033     const char *onm;
1034
1035     /* Rearranged beginning so monsters can use polearms not in a line */
1036     if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) {
1037         mtmp->weapon_check = NEED_RANGED_WEAPON;
1038         /* mon_wield_item resets weapon_check as appropriate */
1039         if (mon_wield_item(mtmp) != 0)
1040             return;
1041     }
1042
1043     /* Pick a weapon */
1044     otmp = select_rwep(mtmp);
1045     if (!otmp)
1046         return;
1047
1048     if (is_pole(otmp)) {
1049         int dam, hitv;
1050
1051         if (otmp != MON_WEP(mtmp))
1052             return; /* polearm must be wielded */
1053         if (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) > POLE_LIM
1054             || !couldsee(mtmp->mx, mtmp->my))
1055             return; /* Out of range, or intervening wall */
1056
1057         if (canseemon(mtmp)) {
1058             onm = xname(otmp);
1059 #if 0 /*JP*/
1060             pline("%s thrusts %s.", Monnam(mtmp),
1061                   obj_is_pname(otmp) ? the(onm) : an(onm));
1062 #else
1063             pline("%s\82Í%s\82ð\93Ë\82«\8eh\82µ\82½\81D", Monnam(mtmp), onm);
1064 #endif
1065         }
1066
1067         dam = dmgval(otmp, &youmonst);
1068         hitv = 3 - distmin(u.ux, u.uy, mtmp->mx, mtmp->my);
1069         if (hitv < -4)
1070             hitv = -4;
1071         if (bigmonst(youmonst.data))
1072             hitv++;
1073         hitv += 8 + otmp->spe;
1074         if (dam < 1)
1075             dam = 1;
1076
1077         (void) thitu(hitv, dam, &otmp, (char *) 0);
1078         stop_occupation();
1079         return;
1080     }
1081
1082     x = mtmp->mx;
1083     y = mtmp->my;
1084     /* If you are coming toward the monster, the monster
1085      * should try to soften you up with missiles.  If you are
1086      * going away, you are probably hurt or running.  Give
1087      * chase, but if you are getting too far away, throw.
1088      */
1089     if (!lined_up(mtmp)
1090         || (URETREATING(x, y)
1091             && rn2(BOLT_LIM - distmin(x, y, mtmp->mux, mtmp->muy))))
1092         return;
1093
1094     mwep = MON_WEP(mtmp); /* wielded weapon */
1095     monshoot(mtmp, otmp, mwep); /* multishot shooting or throwing */
1096     nomul(0);
1097 }
1098
1099 /* monster spits substance at you */
1100 int
1101 spitmu(mtmp, mattk)
1102 struct monst *mtmp;
1103 struct attack *mattk;
1104 {
1105     struct obj *otmp;
1106
1107     if (mtmp->mcan) {
1108         if (!Deaf)
1109 #if 0 /*JP*/
1110             pline("A dry rattle comes from %s throat.",
1111                   s_suffix(mon_nam(mtmp)));
1112 #else
1113             pline("\8a£\82¢\82½\83K\83\89\83K\83\89\89¹\82ª%s\82Ì\82Ì\82Ç\82©\82ç\95·\82±\82¦\82Ä\82«\82½\81D",
1114                   mon_nam(mtmp));
1115 #endif
1116         return 0;
1117     }
1118     if (lined_up(mtmp)) {
1119         switch (mattk->adtyp) {
1120         case AD_BLND:
1121         case AD_DRST:
1122             otmp = mksobj(BLINDING_VENOM, TRUE, FALSE);
1123             break;
1124         default:
1125             impossible("bad attack type in spitmu");
1126         /* fall through */
1127         case AD_ACID:
1128             otmp = mksobj(ACID_VENOM, TRUE, FALSE);
1129             break;
1130         }
1131         if (!rn2(BOLT_LIM
1132                  - distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy))) {
1133             if (canseemon(mtmp))
1134 /*JP
1135                 pline("%s spits venom!", Monnam(mtmp));
1136 */
1137                 pline("%s\82Í\93Å\89t\82ð\93f\82¢\82½\81I", Monnam(mtmp));
1138             m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
1139                     distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy), otmp);
1140             nomul(0);
1141             return 0;
1142         } else {
1143             obj_extract_self(otmp);
1144             obfree(otmp, (struct obj *) 0);
1145         }
1146     }
1147     return 0;
1148 }
1149
1150 /* monster breathes at you (ranged) */
1151 int
1152 breamu(mtmp, mattk)
1153 struct monst *mtmp;
1154 struct attack *mattk;
1155 {
1156     /* if new breath types are added, change AD_ACID to max type */
1157     int typ = (mattk->adtyp == AD_RBRE) ? rnd(AD_ACID) : mattk->adtyp;
1158
1159     if (lined_up(mtmp)) {
1160         if (mtmp->mcan) {
1161             if (!Deaf) {
1162                 if (canseemon(mtmp))
1163 /*JP
1164                     pline("%s coughs.", Monnam(mtmp));
1165 */
1166                     pline("%s\82Í\82¹\82«\82ð\82µ\82½\81D", Monnam(mtmp));
1167                 else
1168 /*JP
1169                     You_hear("a cough.");
1170 */
1171                     You_hear("\82¹\82«\82Ì\89¹\82ð\95·\82¢\82½\81D");
1172             }
1173             return 0;
1174         }
1175         if (!mtmp->mspec_used && rn2(3)) {
1176             if ((typ >= AD_MAGM) && (typ <= AD_ACID)) {
1177                 if (canseemon(mtmp))
1178 #if 0 /*JP*/
1179                     pline("%s breathes %s!", Monnam(mtmp),
1180                           breathwep[typ - 1]);
1181 #else
1182                     pline("%s\82Í%s\82ð\93f\82¢\82½\81I", Monnam(mtmp),
1183                           breathwep[typ - 1]);
1184 #endif
1185                 buzz((int) (-20 - (typ - 1)), (int) mattk->damn, mtmp->mx,
1186                      mtmp->my, sgn(tbx), sgn(tby));
1187                 nomul(0);
1188                 /* breath runs out sometimes. Also, give monster some
1189                  * cunning; don't breath if the player fell asleep.
1190                  */
1191                 if (!rn2(3))
1192                     mtmp->mspec_used = 10 + rn2(20);
1193                 if (typ == AD_SLEE && !Sleep_resistance)
1194                     mtmp->mspec_used += rnd(20);
1195             } else
1196                 impossible("Breath weapon %d used", typ - 1);
1197         }
1198     }
1199     return 1;
1200 }
1201
1202 boolean
1203 linedup(ax, ay, bx, by, boulderhandling)
1204 register xchar ax, ay, bx, by;
1205 int boulderhandling; /* 0=block, 1=ignore, 2=conditionally block */
1206 {
1207     int dx, dy, boulderspots;
1208
1209     /* These two values are set for use after successful return. */
1210     tbx = ax - bx;
1211     tby = ay - by;
1212
1213     /* sometimes displacement makes a monster think that you're at its
1214        own location; prevent it from throwing and zapping in that case */
1215     if (!tbx && !tby)
1216         return FALSE;
1217
1218     if ((!tbx || !tby || abs(tbx) == abs(tby)) /* straight line or diagonal */
1219         && distmin(tbx, tby, 0, 0) < BOLT_LIM) {
1220         if ((ax == u.ux && ay == u.uy) ? (boolean) couldsee(bx, by)
1221                                        : clear_path(ax, ay, bx, by))
1222             return TRUE;
1223         /* don't have line of sight, but might still be lined up
1224            if that lack of sight is due solely to boulders */
1225         if (boulderhandling == 0)
1226             return FALSE;
1227         dx = sgn(ax - bx), dy = sgn(ay - by);
1228         boulderspots = 0;
1229         do {
1230             /* <bx,by> is guaranteed to eventually converge with <ax,ay> */
1231             bx += dx, by += dy;
1232             if (IS_ROCK(levl[bx][by].typ) || closed_door(bx, by))
1233                 return FALSE;
1234             if (sobj_at(BOULDER, bx, by))
1235                 ++boulderspots;
1236         } while (bx != ax || by != ay);
1237         /* reached target position without encountering obstacle */
1238         if (boulderhandling == 1 || rn2(2 + boulderspots) < 2)
1239             return TRUE;
1240     }
1241     return FALSE;
1242 }
1243
1244 STATIC_OVL boolean
1245 m_lined_up(mtarg, mtmp)
1246 struct monst *mtarg, *mtmp;
1247 {
1248     return (linedup(mtarg->mx, mtarg->my, mtmp->mx, mtmp->my, 0));
1249 }
1250
1251
1252 /* is mtmp in position to use ranged attack? */
1253 boolean
1254 lined_up(mtmp)
1255 register struct monst *mtmp;
1256 {
1257     boolean ignore_boulders;
1258
1259     /* hero concealment usually trumps monst awareness of being lined up */
1260     if (Upolyd && rn2(25)
1261         && (u.uundetected || (U_AP_TYPE != M_AP_NOTHING
1262                               && U_AP_TYPE != M_AP_MONSTER)))
1263         return FALSE;
1264
1265     ignore_boulders = (throws_rocks(mtmp->data)
1266                        || m_carrying(mtmp, WAN_STRIKING));
1267     return linedup(mtmp->mux, mtmp->muy, mtmp->mx, mtmp->my,
1268                    ignore_boulders ? 1 : 2);
1269 }
1270
1271 /* check if a monster is carrying a particular item */
1272 struct obj *
1273 m_carrying(mtmp, type)
1274 struct monst *mtmp;
1275 int type;
1276 {
1277     register struct obj *otmp;
1278
1279     for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
1280         if (otmp->otyp == type)
1281             return otmp;
1282     return (struct obj *) 0;
1283 }
1284
1285 void
1286 hit_bars(objp, objx, objy, barsx, barsy, your_fault, from_invent)
1287 struct obj **objp;      /* *objp will be set to NULL if object breaks */
1288 int objx, objy, barsx, barsy;
1289 boolean your_fault, from_invent;
1290 {
1291     struct obj *otmp = *objp;
1292     int obj_type = otmp->otyp;
1293     boolean unbreakable = (levl[barsx][barsy].wall_info & W_NONDIGGABLE) != 0;
1294
1295     if (your_fault
1296         ? hero_breaks(otmp, objx, objy, from_invent)
1297         : breaks(otmp, objx, objy)) {
1298         *objp = 0; /* object is now gone */
1299         /* breakage makes its own noises */
1300         if (obj_type == POT_ACID) {
1301             if (cansee(barsx, barsy) && !unbreakable)
1302 /*JP
1303                 pline_The("iron bars are dissolved!");
1304 */
1305                 pline_The("\93S\82Ì\96_\82Í\97Z\82¯\82½\81I");
1306             else
1307 /*JP
1308                 You_hear(Hallucination ? "angry snakes!" : "a hissing noise.");
1309 */
1310                 You_hear(Hallucination ? "\93{\82Á\82½\82Ö\82Ñ\82Ì\90º\82ð\95·\82¢\82½\81I" : "\83V\81[\83b\82Æ\82¢\82¤\89¹\82ð\95·\82¢\82½\81D");
1311             if (!unbreakable)
1312                 dissolve_bars(barsx, barsy);
1313         }
1314     }
1315     else if (obj_type == BOULDER || obj_type == HEAVY_IRON_BALL)
1316 /*JP
1317             pline("Whang!");
1318 */
1319             pline("\82®\82í\81[\82ñ\81I");
1320     else if (otmp->oclass == COIN_CLASS
1321              || objects[obj_type].oc_material == GOLD
1322              || objects[obj_type].oc_material == SILVER)
1323 /*JP
1324             pline("Clink!");
1325 */
1326             pline("\83`\83\83\83\8a\83\93\81I");
1327     else
1328 /*JP
1329             pline("Clonk!");
1330 */
1331             pline("\83S\83c\83\93\81I");
1332 }
1333
1334 /* TRUE iff thrown/kicked/rolled object doesn't pass through iron bars */
1335 boolean
1336 hits_bars(obj_p, x, y, barsx, barsy, always_hit, whodidit)
1337 struct obj **obj_p; /* *obj_p will be set to NULL if object breaks */
1338 int x, y, barsx, barsy;
1339 int always_hit; /* caller can force a hit for items which would fit through */
1340 int whodidit;   /* 1==hero, 0=other, -1==just check whether it'll pass thru */
1341 {
1342     struct obj *otmp = *obj_p;
1343     int obj_type = otmp->otyp;
1344     boolean hits = always_hit;
1345
1346     if (!hits)
1347         switch (otmp->oclass) {
1348         case WEAPON_CLASS: {
1349             int oskill = objects[obj_type].oc_skill;
1350
1351             hits = (oskill != -P_BOW && oskill != -P_CROSSBOW
1352                     && oskill != -P_DART && oskill != -P_SHURIKEN
1353                     && oskill != P_SPEAR
1354                     && oskill != P_KNIFE); /* but not dagger */
1355             break;
1356         }
1357         case ARMOR_CLASS:
1358             hits = (objects[obj_type].oc_armcat != ARM_GLOVES);
1359             break;
1360         case TOOL_CLASS:
1361             hits = (obj_type != SKELETON_KEY && obj_type != LOCK_PICK
1362                     && obj_type != CREDIT_CARD && obj_type != TALLOW_CANDLE
1363                     && obj_type != WAX_CANDLE && obj_type != LENSES
1364                     && obj_type != TIN_WHISTLE && obj_type != MAGIC_WHISTLE);
1365             break;
1366         case ROCK_CLASS: /* includes boulder */
1367             if (obj_type != STATUE || mons[otmp->corpsenm].msize > MZ_TINY)
1368                 hits = TRUE;
1369             break;
1370         case FOOD_CLASS:
1371             if (obj_type == CORPSE && mons[otmp->corpsenm].msize > MZ_TINY)
1372                 hits = TRUE;
1373             else
1374                 hits = (obj_type == MEAT_STICK
1375                         || obj_type == HUGE_CHUNK_OF_MEAT);
1376             break;
1377         case SPBOOK_CLASS:
1378         case WAND_CLASS:
1379         case BALL_CLASS:
1380         case CHAIN_CLASS:
1381             hits = TRUE;
1382             break;
1383         default:
1384             break;
1385         }
1386
1387     if (hits && whodidit != -1) {
1388         hit_bars(obj_p, x,y, barsx,barsy, whodidit, FALSE);
1389     }
1390
1391     return hits;
1392 }
1393
1394 /*mthrowu.c*/