OSDN Git Service

fix #36659
[jnethack/source.git] / src / mthrowu.c
1 /* NetHack 3.6  mthrowu.c       $NHDT-Date: 1446887531 2015/11/07 09:12:11 $  $NHDT-Branch: master $:$NHDT-Revision: 1.63 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 /* JNetHack Copyright */
6 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000  */
7 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2016            */
8 /* JNetHack may be freely redistributed.  See license for details. */
9
10 #include "hack.h"
11
12 STATIC_DCL int FDECL(drop_throw, (struct obj *, BOOLEAN_P, int, int));
13
14 #define URETREATING(x, y) \
15     (distmin(u.ux, u.uy, x, y) > distmin(u.ux0, u.uy0, x, y))
16
17 #define POLE_LIM 5 /* How far monsters can use pole-weapons */
18
19 /*
20  * Keep consistent with breath weapons in zap.c, and AD_* in monattk.h.
21  */
22 STATIC_OVL NEARDATA const char *breathwep[] = {
23 #if 0 /*JP*/
24     "fragments", "fire", "frost", "sleep gas", "a disintegration blast",
25     "lightning", "poison gas", "acid", "strange breath #8",
26     "strange breath #9"
27 #else
28     "\94j\95Ð", "\89\8a", "\97â\8bC", "\90\87\96°\83K\83X", "\95ª\89ð\82Ì\91§",
29     "\88î\8dÈ", "\93Å\82Ì\91§", "\8e_", "strange breath #8",
30     "strange breath #9"
31 #endif
32 };
33
34 extern boolean notonhead; /* for long worms */
35
36 /* hero is hit by something other than a monster */
37 int
38 thitu(tlev, dam, obj, name)
39 int tlev, dam;
40 struct obj *obj;
41 const char *name; /* if null, then format `obj' */
42 {
43     const char *onm, *knm;
44     boolean is_acid;
45     int kprefix = KILLED_BY_AN;
46     char onmbuf[BUFSZ], knmbuf[BUFSZ];
47
48     if (!name) {
49         if (!obj)
50             panic("thitu: name & obj both null?");
51         name =
52             strcpy(onmbuf, (obj->quan > 1L) ? doname(obj) : mshot_xname(obj));
53         knm = strcpy(knmbuf, killer_xname(obj));
54         kprefix = KILLED_BY; /* killer_name supplies "an" if warranted */
55     } else {
56 #if 0 /*JP*/
57         knm = name;
58         /* [perhaps ought to check for plural here to] */
59         if (!strncmpi(name, "the ", 4) || !strncmpi(name, "an ", 3)
60             || !strncmpi(name, "a ", 2))
61             kprefix = KILLED_BY;
62 #else
63         knm = strcpy(knmbuf, name);
64 #endif
65     }
66 #if 1 /*JP*/
67     strcat(knmbuf, "\82É\93\96\82½\82Á\82Ä");
68 #endif
69     onm = (obj && obj_is_pname(obj)) ? the(name) : (obj && obj->quan > 1L)
70                                                        ? name
71                                                        : an(name);
72     is_acid = (obj && obj->otyp == ACID_VENOM);
73
74     if (u.uac + tlev <= rnd(20)) {
75         if (Blind || !flags.verbose)
76 /*JP
77             pline("It misses.");
78 */
79             pline("\82»\82ê\82Í\82Í\82¸\82ê\82½\81D");
80         else
81 /*JP
82             You("are almost hit by %s.", onm);
83 */
84             pline("\82à\82¤\8f­\82µ\82Å%s\82É\96½\92\86\82·\82é\82Æ\82±\82ë\82¾\82Á\82½\81I",onm);
85         return 0;
86     } else {
87         if (Blind || !flags.verbose)
88 /*JP
89             You("are hit%s", exclam(dam));
90 */
91             pline("\89½\82©\82ª\82 \82È\82½\82É\96½\92\86\82µ\82½\81I");
92         else
93 /*JP
94             You("are hit by %s%s", onm, exclam(dam));
95 */
96             pline("%s\82ª\82 \82È\82½\82É\96½\92\86\82µ\82½\81I", onm);
97
98         if (obj && objects[obj->otyp].oc_material == SILVER && Hate_silver) {
99             /* extra damage already applied by dmgval() */
100 /*JP
101             pline_The("silver sears your flesh!");
102 */
103             pline("\82 \82È\82½\82Ì\91Ì\82Í\8bâ\82Å\8fÄ\82©\82ê\82½\81I");
104             exercise(A_CON, FALSE);
105         }
106         if (is_acid && Acid_resistance)
107 /*JP
108             pline("It doesn't seem to hurt you.");
109 */
110             pline("\82 \82È\82½\82Í\8f\9d\82Â\82©\82È\82©\82Á\82½\81D");
111         else {
112             if (is_acid)
113 /*JP
114                 pline("It burns!");
115 */
116                 pline("\8e_\82Å\8fÄ\82©\82ê\82½\81I");
117             losehp(dam, knm, kprefix); /* acid damage */
118             exercise(A_STR, FALSE);
119         }
120         return 1;
121     }
122 }
123
124 /* Be sure this corresponds with what happens to player-thrown objects in
125  * dothrow.c (for consistency). --KAA
126  * Returns 0 if object still exists (not destroyed).
127  */
128 STATIC_OVL int
129 drop_throw(obj, ohit, x, y)
130 register struct obj *obj;
131 boolean ohit;
132 int x, y;
133 {
134     int retvalu = 1;
135     int create;
136     struct monst *mtmp;
137     struct trap *t;
138
139     if (obj->otyp == CREAM_PIE || obj->oclass == VENOM_CLASS
140         || (ohit && obj->otyp == EGG))
141         create = 0;
142     else if (ohit && (is_multigen(obj) || obj->otyp == ROCK))
143         create = !rn2(3);
144     else
145         create = 1;
146
147     if (create
148         && !((mtmp = m_at(x, y)) && (mtmp->mtrapped) && (t = t_at(x, y))
149              && ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT)))) {
150         int objgone = 0;
151
152         if (down_gate(x, y) != -1)
153             objgone = ship_object(obj, x, y, FALSE);
154         if (!objgone) {
155 #if 0 /*JP*/
156             if (!flooreffects(obj, x, y,
157                               "fall")) { /* don't double-dip on damage */
158 #else
159             if (!flooreffects(obj, x, y,
160                               "\97\8e\82¿\82é")) { /* don't double-dip on damage */
161 #endif
162                 place_object(obj, x, y);
163                 if (!mtmp && x == u.ux && y == u.uy)
164                     mtmp = &youmonst;
165                 if (mtmp && ohit)
166                     passive_obj(mtmp, obj, (struct attack *) 0);
167                 stackobj(obj);
168                 retvalu = 0;
169             }
170         }
171     } else
172         obfree(obj, (struct obj *) 0);
173     return retvalu;
174 }
175
176 /* an object launched by someone/thing other than player attacks a monster;
177    return 1 if the object has stopped moving (hit or its range used up) */
178 int
179 ohitmon(mtmp, otmp, range, verbose)
180 struct monst *mtmp; /* accidental target, located at <bhitpos.x,.y> */
181 struct obj *otmp;   /* missile; might be destroyed by drop_throw */
182 int range;          /* how much farther will object travel if it misses;
183                        use -1 to signify to keep going even after hit,
184                        unless it's gone (used for rolling_boulder_traps) */
185 boolean verbose;    /* give message(s) even when you can't see what happened */
186 {
187     int damage, tmp;
188     boolean vis, ismimic;
189     int objgone = 1;
190
191     notonhead = (bhitpos.x != mtmp->mx || bhitpos.y != mtmp->my);
192     ismimic = mtmp->m_ap_type && mtmp->m_ap_type != M_AP_MONSTER;
193     vis = cansee(bhitpos.x, bhitpos.y);
194
195     tmp = 5 + find_mac(mtmp) + omon_adj(mtmp, otmp, FALSE);
196     if (tmp < rnd(20)) {
197         if (!ismimic) {
198             if (vis)
199                 miss(distant_name(otmp, mshot_xname), mtmp);
200             else if (verbose)
201 /*JP
202                 pline("It is missed.");
203 */
204                 pline("\89½\82©\82ª\82©\82·\82ß\82½\81D");
205         }
206         if (!range) { /* Last position; object drops */
207             (void) drop_throw(otmp, 0, mtmp->mx, mtmp->my);
208             return 1;
209         }
210     } else if (otmp->oclass == POTION_CLASS) {
211         if (ismimic)
212             seemimic(mtmp);
213         mtmp->msleeping = 0;
214         if (vis)
215             otmp->dknown = 1;
216         potionhit(mtmp, otmp, FALSE);
217         return 1;
218     } else {
219         damage = dmgval(otmp, mtmp);
220         if (otmp->otyp == ACID_VENOM && resists_acid(mtmp))
221             damage = 0;
222         if (ismimic)
223             seemimic(mtmp);
224         mtmp->msleeping = 0;
225         if (vis)
226             hit(distant_name(otmp, mshot_xname), mtmp, exclam(damage));
227         else if (verbose)
228 /*JP
229             pline("%s is hit%s", Monnam(mtmp), exclam(damage));
230 */
231             pline("%s\82É\96½\92\86\82µ\82½%s", Monnam(mtmp), exclam(damage));
232
233         if (otmp->opoisoned && is_poisonable(otmp)) {
234             if (resists_poison(mtmp)) {
235                 if (vis)
236 /*JP
237                     pline_The("poison doesn't seem to affect %s.",
238 */
239                     pline("%s\82Í\93Å\82Ì\89e\8b¿\82ð\8eó\82¯\82È\82¢\82æ\82¤\82¾\81D",
240                               mon_nam(mtmp));
241             } else {
242                 if (rn2(30)) {
243                     damage += rnd(6);
244                 } else {
245                     if (vis)
246 /*JP
247                         pline_The("poison was deadly...");
248 */
249                         pline("\93Å\82Í\92v\8e\80\97Ê\82¾\82Á\82½\81D\81D\81D");
250                     damage = mtmp->mhp;
251                 }
252             }
253         }
254         if (objects[otmp->otyp].oc_material == SILVER
255             && mon_hates_silver(mtmp)) {
256             if (vis)
257 /*JP
258                 pline_The("silver sears %s flesh!", s_suffix(mon_nam(mtmp)));
259 */
260                 pline("%s\82Ì\91Ì\82Í\8bâ\82Å\8fÄ\82©\82ê\82½\81I", s_suffix(mon_nam(mtmp)));
261             else if (verbose)
262 /*JP
263                 pline("Its flesh is seared!");
264 */
265                 pline("\89½\8eÒ\82©\82Ì\91Ì\82Í\8fÄ\82©\82ê\82½\81I");
266         }
267         if (otmp->otyp == ACID_VENOM && cansee(mtmp->mx, mtmp->my)) {
268             if (resists_acid(mtmp)) {
269                 if (vis || verbose)
270 /*JP
271                     pline("%s is unaffected.", Monnam(mtmp));
272 */
273                     pline("%s\82Í\89e\8b¿\82ð\8eó\82¯\82È\82¢\81D", Monnam(mtmp));
274                 damage = 0;
275             } else {
276                 if (vis)
277 /*JP
278                     pline_The("acid burns %s!", mon_nam(mtmp));
279 */
280                     pline("%s\82Í\8e_\82Å\8fÄ\82©\82ê\82½\81I", mon_nam(mtmp));
281                 else if (verbose)
282 /*JP
283                     pline("It is burned!");
284 */
285                     pline("\89½\82©\82Í\8fÄ\82©\82ê\82½\81I");
286             }
287         }
288         mtmp->mhp -= damage;
289         if (mtmp->mhp < 1) {
290             if (vis || verbose)
291 #if 0 /*JP*/
292                 pline("%s is %s!", Monnam(mtmp),
293                       (nonliving(mtmp->data) || is_vampshifter(mtmp)
294                        || !canspotmon(mtmp))
295                           ? "destroyed"
296                           : "killed");
297 #else
298                 pline("%s\82Í%s\81I", Monnam(mtmp),
299                       (nonliving(mtmp->data) || is_vampshifter(mtmp)
300                        || !canspotmon(mtmp))
301                           ? "\93|\82³\82ê\82½"
302                           : "\8e\80\82ñ\82¾");
303 #endif
304             /* don't blame hero for unknown rolling boulder trap */
305             if (!context.mon_moving
306                 && (otmp->otyp != BOULDER || range >= 0 || otmp->otrapped))
307                 xkilled(mtmp, 0);
308             else
309                 mondied(mtmp);
310         }
311
312         if (can_blnd((struct monst *) 0, mtmp,
313                      (uchar) (otmp->otyp == BLINDING_VENOM ? AT_SPIT
314                                                            : AT_WEAP),
315                      otmp)) {
316             if (vis && mtmp->mcansee)
317 /*JP
318                 pline("%s is blinded by %s.", Monnam(mtmp), the(xname(otmp)));
319 */
320                 pline("%s\82Í%s\82É\82æ\82Á\82Ä\96Ú\82ª\8c©\82¦\82È\82­\82È\82Á\82½\81D", Monnam(mtmp), the(xname(otmp)));
321             mtmp->mcansee = 0;
322             tmp = (int) mtmp->mblinded + rnd(25) + 20;
323             if (tmp > 127)
324                 tmp = 127;
325             mtmp->mblinded = tmp;
326         }
327
328         objgone = drop_throw(otmp, 1, bhitpos.x, bhitpos.y);
329         if (!objgone && range == -1) { /* special case */
330             obj_extract_self(otmp);    /* free it for motion again */
331             return 0;
332         }
333         return 1;
334     }
335     return 0;
336 }
337
338 void
339 m_throw(mon, x, y, dx, dy, range, obj)
340 struct monst *mon;       /* launching monster */
341 int x, y, dx, dy, range; /* launch point, direction, and range */
342 struct obj *obj;         /* missile (or stack providing it) */
343 {
344     struct monst *mtmp;
345     struct obj *singleobj;
346     char sym = obj->oclass;
347     int hitu, oldumort, blindinc = 0;
348
349     bhitpos.x = x;
350     bhitpos.y = y;
351     notonhead = FALSE; /* reset potentially stale value */
352
353     if (obj->quan == 1L) {
354         /*
355          * Remove object from minvent.  This cannot be done later on;
356          * what if the player dies before then, leaving the monster
357          * with 0 daggers?  (This caused the infamous 2^32-1 orcish
358          * dagger bug).
359          *
360          * VENOM is not in minvent - it should already be OBJ_FREE.
361          * The extract below does nothing.
362          */
363
364         /* not possibly_unwield, which checks the object's */
365         /* location, not its existence */
366         if (MON_WEP(mon) == obj)
367             setmnotwielded(mon, obj);
368         obj_extract_self(obj);
369         singleobj = obj;
370         obj = (struct obj *) 0;
371     } else {
372         singleobj = splitobj(obj, 1L);
373         obj_extract_self(singleobj);
374     }
375
376     singleobj->owornmask = 0; /* threw one of multiple weapons in hand? */
377
378     if ((singleobj->cursed || singleobj->greased) && (dx || dy) && !rn2(7)) {
379         if (canseemon(mon) && flags.verbose) {
380             if (is_ammo(singleobj))
381 /*JP
382                 pline("%s misfires!", Monnam(mon));
383 */
384                 pline("%s\82Í\82Í\82¸\82µ\82½\81I", Monnam(mon));
385             else
386 #if 0 /*JP*/
387                 pline("%s as %s throws it!", Tobjnam(singleobj, "slip"),
388                       mon_nam(mon));
389 #else
390                 pline("%s\82ª\93\8a\82°\82æ\82¤\82Æ\82µ\82½\82Æ\82½\82ñ%s\82ª\8a\8a\82Á\82½\81I",
391                           mon_nam(mon), xname(singleobj));
392 #endif
393         }
394         dx = rn2(3) - 1;
395         dy = rn2(3) - 1;
396         /* check validity of new direction */
397         if (!dx && !dy) {
398             (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
399             return;
400         }
401     }
402
403     /* pre-check for doors, walls and boundaries.
404        Also need to pre-check for bars regardless of direction;
405        the random chance for small objects hitting bars is
406        skipped when reaching them at point blank range */
407     if (!isok(bhitpos.x + dx, bhitpos.y + dy)
408         || IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ)
409         || closed_door(bhitpos.x + dx, bhitpos.y + dy)
410         || (levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS
411             && hits_bars(&singleobj, bhitpos.x, bhitpos.y, 0, 0))) {
412         (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
413         return;
414     }
415
416     /* Note: drop_throw may destroy singleobj.  Since obj must be destroyed
417      * early to avoid the dagger bug, anyone who modifies this code should
418      * be careful not to use either one after it's been freed.
419      */
420     if (sym)
421         tmp_at(DISP_FLASH, obj_to_glyph(singleobj));
422     while (range-- > 0) { /* Actually the loop is always exited by break */
423         bhitpos.x += dx;
424         bhitpos.y += dy;
425         if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
426             if (ohitmon(mtmp, singleobj, range, TRUE))
427                 break;
428         } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) {
429             if (multi)
430                 nomul(0);
431
432             if (singleobj->oclass == GEM_CLASS
433                 && singleobj->otyp <= LAST_GEM + 9 /* 9 glass colors */
434                 && is_unicorn(youmonst.data)) {
435                 if (singleobj->otyp > LAST_GEM) {
436 /*JP
437                     You("catch the %s.", xname(singleobj));
438 */
439                     You("%s\82ð\82Â\82©\82Ü\82¦\82½\81D", xname(singleobj));
440 /*JP
441                     You("are not interested in %s junk.",
442 */
443                     You("%s\82Ì\83K\83\89\83N\83^\82É\8b»\96¡\82Í\82È\82¢\81D",
444                         s_suffix(mon_nam(mon)));
445                     makeknown(singleobj->otyp);
446                     dropy(singleobj);
447                 } else {
448                     You(
449 /*JP
450                      "accept %s gift in the spirit in which it was intended.",
451 */
452                      "\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",
453                         s_suffix(mon_nam(mon)));
454 #if 0 /*JP*/
455                     (void) hold_another_object(
456                         singleobj, "You catch, but drop, %s.",
457                         xname(singleobj), "You catch:");
458 #else
459                     (void) hold_another_object(
460                         singleobj, "\82 \82È\82½\82Í%s\82ð\82Â\82©\82Ü\82¦\82½\82ª\81C\97\8e\82µ\82½\81D",
461                         xname(singleobj), "\82ð\82Â\82©\82Ü\82¦\82½\81D");
462 #endif
463                 }
464                 break;
465             }
466             if (singleobj->oclass == POTION_CLASS) {
467                 if (!Blind)
468                     singleobj->dknown = 1;
469                 potionhit(&youmonst, singleobj, FALSE);
470                 break;
471             }
472             oldumort = u.umortality;
473             switch (singleobj->otyp) {
474                 int dam, hitv;
475             case EGG:
476                 if (!touch_petrifies(&mons[singleobj->corpsenm])) {
477                     impossible("monster throwing egg type %d",
478                                singleobj->corpsenm);
479                     hitu = 0;
480                     break;
481                 }
482             /* fall through */
483             case CREAM_PIE:
484             case BLINDING_VENOM:
485                 hitu = thitu(8, 0, singleobj, (char *) 0);
486                 break;
487             default:
488                 dam = dmgval(singleobj, &youmonst);
489                 hitv = 3 - distmin(u.ux, u.uy, mon->mx, mon->my);
490                 if (hitv < -4)
491                     hitv = -4;
492                 if (is_elf(mon->data)
493                     && objects[singleobj->otyp].oc_skill == P_BOW) {
494                     hitv++;
495                     if (MON_WEP(mon) && MON_WEP(mon)->otyp == ELVEN_BOW)
496                         hitv++;
497                     if (singleobj->otyp == ELVEN_ARROW)
498                         dam++;
499                 }
500                 if (bigmonst(youmonst.data))
501                     hitv++;
502                 hitv += 8 + singleobj->spe;
503                 if (dam < 1)
504                     dam = 1;
505                 hitu = thitu(hitv, dam, singleobj, (char *) 0);
506             }
507             if (hitu && singleobj->opoisoned && is_poisonable(singleobj)) {
508                 char onmbuf[BUFSZ], knmbuf[BUFSZ];
509
510                 Strcpy(onmbuf, xname(singleobj));
511                 Strcpy(knmbuf, killer_xname(singleobj));
512                 poisoned(onmbuf, A_STR, knmbuf,
513                          /* if damage triggered life-saving,
514                             poison is limited to attrib loss */
515                          (u.umortality > oldumort) ? 0 : 10, TRUE);
516             }
517             if (hitu && can_blnd((struct monst *) 0, &youmonst,
518                                  (uchar) (singleobj->otyp == BLINDING_VENOM
519                                              ? AT_SPIT
520                                              : AT_WEAP),
521                                  singleobj)) {
522                 blindinc = rnd(25);
523                 if (singleobj->otyp == CREAM_PIE) {
524                     if (!Blind)
525 /*JP
526                         pline("Yecch!  You've been creamed.");
527 */
528                         pline("\83E\83F\81[\81D\83N\83\8a\81[\83\80\82ð\82©\82Ô\82Á\82½\81D");
529                     else
530 #if 0 /*JP*/
531                         pline("There's %s sticky all over your %s.",
532                               something, body_part(FACE));
533 #else
534                         pline("\82 \82È\82½\82Í%s\82É\82×\82Æ\82Â\82­\82à\82Ì\82ð\8a´\82\82½\81D",
535                               body_part(FACE));
536 #endif
537                 } else if (singleobj->otyp == BLINDING_VENOM) {
538 #if 0 /*JP*/
539                     const char *eyes = body_part(EYE);
540
541                     if (eyecount(youmonst.data) != 1)
542                         eyes = makeplural(eyes);
543                     /* venom in the eyes */
544                     if (!Blind)
545                         pline_The("venom blinds you.");
546                     else
547                         Your("%s %s.", eyes, vtense(eyes, "sting"));
548 #else
549                     if(!Blind)
550                         pline("\93Å\82Å\96Ú\82ª\8c©\82¦\82È\82­\82È\82Á\82½\81D");
551                     else
552                         Your("%s\82Í\82¿\82­\82¿\82­\82µ\82½\81D", body_part(EYE));
553 #endif
554                 }
555             }
556             if (hitu && singleobj->otyp == EGG) {
557                 if (!Stoned && !Stone_resistance
558                     && !(poly_when_stoned(youmonst.data)
559                          && polymon(PM_STONE_GOLEM))) {
560                     make_stoned(5L, (char *) 0, KILLED_BY, "");
561                 }
562             }
563             stop_occupation();
564             if (hitu || !range) {
565                 (void) drop_throw(singleobj, hitu, u.ux, u.uy);
566                 break;
567             }
568         }
569         if (!range /* reached end of path */
570             /* missile hits edge of screen */
571             || !isok(bhitpos.x + dx, bhitpos.y + dy)
572             /* missile hits the wall */
573             || IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ)
574             /* missile hit closed door */
575             || closed_door(bhitpos.x + dx, bhitpos.y + dy)
576             /* missile might hit iron bars */
577             || (levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS
578                 && hits_bars(&singleobj, bhitpos.x, bhitpos.y, !rn2(5), 0))
579             /* Thrown objects "sink" */
580             || IS_SINK(levl[bhitpos.x][bhitpos.y].typ)) {
581             if (singleobj) /* hits_bars might have destroyed it */
582                 (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
583             break;
584         }
585         tmp_at(bhitpos.x, bhitpos.y);
586         delay_output();
587     }
588     tmp_at(bhitpos.x, bhitpos.y);
589     delay_output();
590     tmp_at(DISP_END, 0);
591
592     if (blindinc) {
593         u.ucreamed += blindinc;
594         make_blinded(Blinded + (long) blindinc, FALSE);
595         if (!Blind)
596             Your1(vision_clears);
597     }
598 }
599
600 /* remove an entire item from a monster's inventory; destroy that item */
601 void
602 m_useupall(mon, obj)
603 struct monst *mon;
604 struct obj *obj;
605 {
606     obj_extract_self(obj);
607     if (obj->owornmask) {
608         if (obj == MON_WEP(mon))
609             mwepgone(mon);
610         mon->misc_worn_check &= ~obj->owornmask;
611         update_mon_intrinsics(mon, obj, FALSE, FALSE);
612         obj->owornmask = 0L;
613     }
614     obfree(obj, (struct obj *) 0);
615 }
616
617 /* remove one instance of an item from a monster's inventory */
618 void
619 m_useup(mon, obj)
620 struct monst *mon;
621 struct obj *obj;
622 {
623     if (obj->quan > 1L) {
624         obj->quan--;
625         obj->owt = weight(obj);
626     } else {
627         m_useupall(mon, obj);
628     }
629 }
630
631 /* monster attempts ranged weapon attack against player */
632 void
633 thrwmu(mtmp)
634 struct monst *mtmp;
635 {
636     struct obj *otmp, *mwep;
637     xchar x, y;
638     int multishot;
639     const char *onm;
640
641     /* Rearranged beginning so monsters can use polearms not in a line */
642     if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) {
643         mtmp->weapon_check = NEED_RANGED_WEAPON;
644         /* mon_wield_item resets weapon_check as appropriate */
645         if (mon_wield_item(mtmp) != 0)
646             return;
647     }
648
649     /* Pick a weapon */
650     otmp = select_rwep(mtmp);
651     if (!otmp)
652         return;
653
654     if (is_pole(otmp)) {
655         int dam, hitv;
656
657         if (otmp != MON_WEP(mtmp))
658             return; /* polearm must be wielded */
659         if (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) > POLE_LIM
660             || !couldsee(mtmp->mx, mtmp->my))
661             return; /* Out of range, or intervening wall */
662
663         if (canseemon(mtmp)) {
664             onm = xname(otmp);
665 #if 0 /*JP*/
666             pline("%s thrusts %s.", Monnam(mtmp),
667                   obj_is_pname(otmp) ? the(onm) : an(onm));
668 #else
669             pline("%s\82Í%s\82ð\93Ë\82«\8eh\82µ\82½\81D", Monnam(mtmp), onm);
670 #endif
671         }
672
673         dam = dmgval(otmp, &youmonst);
674         hitv = 3 - distmin(u.ux, u.uy, mtmp->mx, mtmp->my);
675         if (hitv < -4)
676             hitv = -4;
677         if (bigmonst(youmonst.data))
678             hitv++;
679         hitv += 8 + otmp->spe;
680         if (dam < 1)
681             dam = 1;
682
683         (void) thitu(hitv, dam, otmp, (char *) 0);
684         stop_occupation();
685         return;
686     }
687
688     x = mtmp->mx;
689     y = mtmp->my;
690     /* If you are coming toward the monster, the monster
691      * should try to soften you up with missiles.  If you are
692      * going away, you are probably hurt or running.  Give
693      * chase, but if you are getting too far away, throw.
694      */
695     if (!lined_up(mtmp)
696         || (URETREATING(x, y)
697             && rn2(BOLT_LIM - distmin(x, y, mtmp->mux, mtmp->muy))))
698         return;
699
700     mwep = MON_WEP(mtmp); /* wielded weapon */
701
702     /* Multishot calculations */
703     multishot = 1;
704     if (otmp->quan > 1L /* no point checking if there's only 1 */
705         /* ammo requires corresponding launcher be wielded */
706         && (is_ammo(otmp)
707                ? matching_launcher(otmp, mwep)
708                /* otherwise any stackable (non-ammo) weapon */
709                : otmp->oclass == WEAPON_CLASS)
710         && !mtmp->mconf) {
711         int skill = (int) objects[otmp->otyp].oc_skill;
712
713         /* Assumes lords are skilled, princes are expert */
714         if (is_prince(mtmp->data))
715             multishot += 2;
716         else if (is_lord(mtmp->data))
717             multishot++;
718         /* fake players treated as skilled (regardless of role limits) */
719         else if (is_mplayer(mtmp->data))
720             multishot++;
721
722         /* class bonus */
723         switch (monsndx(mtmp->data)) {
724         case PM_MONK:
725             if (skill == -P_SHURIKEN)
726                 multishot++;
727             break;
728         case PM_RANGER:
729             multishot++;
730             break;
731         case PM_ROGUE:
732             if (skill == P_DAGGER)
733                 multishot++;
734             break;
735         case PM_NINJA:
736             if (skill == -P_SHURIKEN || skill == -P_DART)
737                 multishot++;
738             /*FALLTHRU*/
739         case PM_SAMURAI:
740             if (otmp->otyp == YA && mwep && mwep->otyp == YUMI)
741                 multishot++;
742             break;
743         default:
744             break;
745         }
746         /* racial bonus */
747         if ((is_elf(mtmp->data) && otmp->otyp == ELVEN_ARROW && mwep
748              && mwep->otyp == ELVEN_BOW)
749             || (is_orc(mtmp->data) && otmp->otyp == ORCISH_ARROW && mwep
750                 && mwep->otyp == ORCISH_BOW))
751             multishot++;
752
753         multishot = rnd(multishot);
754         if ((long) multishot > otmp->quan)
755             multishot = (int) otmp->quan;
756     }
757
758     if (canseemon(mtmp)) {
759         char onmbuf[BUFSZ];
760
761         if (multishot > 1) {
762             /* "N arrows"; multishot > 1 implies otmp->quan > 1, so
763                xname()'s result will already be pluralized */
764 /*JP
765             Sprintf(onmbuf, "%d %s", multishot, xname(otmp));
766 */
767             Sprintf(onmbuf, "%d%s\82Ì%s", multishot, numeral(otmp), xname(otmp));
768             onm = onmbuf;
769         } else {
770             /* "an arrow" */
771             onm = singular(otmp, xname);
772             onm = obj_is_pname(otmp) ? the(onm) : an(onm);
773         }
774         m_shot.s = ammo_and_launcher(otmp, mwep) ? TRUE : FALSE;
775 /*JP
776         pline("%s %s %s!", Monnam(mtmp), m_shot.s ? "shoots" : "throws", onm);
777 */
778         pline("%s\82Í%s\82ð%s!", Monnam(mtmp), onm, m_shot.s ? "\8c\82\82Á\82½" : "\93\8a\82°\82½");
779         m_shot.o = otmp->otyp;
780     } else {
781         m_shot.o = STRANGE_OBJECT; /* don't give multishot feedback */
782     }
783
784     m_shot.n = multishot;
785     for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) {
786         m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
787                 distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy), otmp);
788         /* conceptually all N missiles are in flight at once, but
789            if mtmp gets killed (shot kills adjacent gas spore and
790            triggers explosion, perhaps), inventory will be dropped
791            and otmp might go away via merging into another stack */
792         if (mtmp->mhp <= 0 && m_shot.i < m_shot.n) {
793             /* cancel pending shots (ought to give a message here since
794                we gave one above about throwing/shooting N missiles) */
795             break; /* endmultishot(FALSE); */
796         }
797     }
798     m_shot.n = m_shot.i = 0;
799     m_shot.o = STRANGE_OBJECT;
800     m_shot.s = FALSE;
801
802     nomul(0);
803 }
804
805 /* monster spits substance at you */
806 int
807 spitmu(mtmp, mattk)
808 struct monst *mtmp;
809 struct attack *mattk;
810 {
811     struct obj *otmp;
812
813     if (mtmp->mcan) {
814         if (!Deaf)
815 /*JP
816             pline("A dry rattle comes from %s throat.",
817 */
818             pline("%s\82Ì\8dA\82ª\83K\83\89\83K\83\89\82Æ\96Â\82Á\82½\81D",
819                   s_suffix(mon_nam(mtmp)));
820         return 0;
821     }
822     if (lined_up(mtmp)) {
823         switch (mattk->adtyp) {
824         case AD_BLND:
825         case AD_DRST:
826             otmp = mksobj(BLINDING_VENOM, TRUE, FALSE);
827             break;
828         default:
829             impossible("bad attack type in spitmu");
830         /* fall through */
831         case AD_ACID:
832             otmp = mksobj(ACID_VENOM, TRUE, FALSE);
833             break;
834         }
835         if (!rn2(BOLT_LIM
836                  - distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy))) {
837             if (canseemon(mtmp))
838 /*JP
839                 pline("%s spits venom!", Monnam(mtmp));
840 */
841                 pline("%s\82Í\93Å\82ð\93f\82¢\82½\81I", Monnam(mtmp));
842             m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
843                     distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy), otmp);
844             nomul(0);
845             return 0;
846         } else {
847             obj_extract_self(otmp);
848             obfree(otmp, (struct obj *) 0);
849         }
850     }
851     return 0;
852 }
853
854 /* monster breathes at you (ranged) */
855 int
856 breamu(mtmp, mattk)
857 struct monst *mtmp;
858 struct attack *mattk;
859 {
860     /* if new breath types are added, change AD_ACID to max type */
861     int typ = (mattk->adtyp == AD_RBRE) ? rnd(AD_ACID) : mattk->adtyp;
862
863     if (lined_up(mtmp)) {
864         if (mtmp->mcan) {
865             if (!Deaf) {
866                 if (canseemon(mtmp))
867 /*JP
868                     pline("%s coughs.", Monnam(mtmp));
869 */
870                     pline("%s\82Í\82¹\82«\82ð\82µ\82½\81D", Monnam(mtmp));
871                 else
872 /*JP
873                     You_hear("a cough.");
874 */
875                     You_hear("\82¹\82«\82Ì\89¹\82ð\95·\82¢\82½\81D");
876             }
877             return 0;
878         }
879         if (!mtmp->mspec_used && rn2(3)) {
880             if ((typ >= AD_MAGM) && (typ <= AD_ACID)) {
881                 if (canseemon(mtmp))
882 #if 0 /*JP*/
883                     pline("%s breathes %s!", Monnam(mtmp),
884                           breathwep[typ - 1]);
885 #else
886                     pline("%s\82Í%s\82ð\93f\82¢\82½\81I", Monnam(mtmp),
887                           breathwep[typ - 1]);
888 #endif
889                 buzz((int) (-20 - (typ - 1)), (int) mattk->damn, mtmp->mx,
890                      mtmp->my, sgn(tbx), sgn(tby));
891                 nomul(0);
892                 /* breath runs out sometimes. Also, give monster some
893                  * cunning; don't breath if the player fell asleep.
894                  */
895                 if (!rn2(3))
896                     mtmp->mspec_used = 10 + rn2(20);
897                 if (typ == AD_SLEE && !Sleep_resistance)
898                     mtmp->mspec_used += rnd(20);
899             } else
900                 impossible("Breath weapon %d used", typ - 1);
901         }
902     }
903     return 1;
904 }
905
906 boolean
907 linedup(ax, ay, bx, by, boulderhandling)
908 register xchar ax, ay, bx, by;
909 int boulderhandling; /* 0=block, 1=ignore, 2=conditionally block */
910 {
911     int dx, dy, boulderspots;
912
913     /* These two values are set for use after successful return. */
914     tbx = ax - bx;
915     tby = ay - by;
916
917     /* sometimes displacement makes a monster think that you're at its
918        own location; prevent it from throwing and zapping in that case */
919     if (!tbx && !tby)
920         return FALSE;
921
922     if ((!tbx || !tby || abs(tbx) == abs(tby)) /* straight line or diagonal */
923         && distmin(tbx, tby, 0, 0) < BOLT_LIM) {
924         if ((ax == u.ux && ay == u.uy) ? (boolean) couldsee(bx, by)
925                                        : clear_path(ax, ay, bx, by))
926             return TRUE;
927         /* don't have line of sight, but might still be lined up
928            if that lack of sight is due solely to boulders */
929         if (boulderhandling == 0)
930             return FALSE;
931         dx = sgn(ax - bx), dy = sgn(ay - by);
932         boulderspots = 0;
933         do {
934             /* <bx,by> is guaranteed to eventually converge with <ax,ay> */
935             bx += dx, by += dy;
936             if (IS_ROCK(levl[bx][by].typ) || closed_door(bx, by))
937                 return FALSE;
938             if (sobj_at(BOULDER, bx, by))
939                 ++boulderspots;
940         } while (bx != ax || by != ay);
941         /* reached target position without encountering obstacle */
942         if (boulderhandling == 1 || rn2(2 + boulderspots) < 2)
943             return TRUE;
944     }
945     return FALSE;
946 }
947
948 /* is mtmp in position to use ranged attack? */
949 boolean
950 lined_up(mtmp)
951 register struct monst *mtmp;
952 {
953     boolean ignore_boulders;
954
955     /* hero concealment usually trumps monst awareness of being lined up */
956     if (Upolyd && rn2(25)
957         && (u.uundetected || (youmonst.m_ap_type != M_AP_NOTHING
958                               && youmonst.m_ap_type != M_AP_MONSTER)))
959         return FALSE;
960
961     ignore_boulders = (throws_rocks(mtmp->data)
962                        || m_carrying(mtmp, WAN_STRIKING));
963     return linedup(mtmp->mux, mtmp->muy, mtmp->mx, mtmp->my,
964                    ignore_boulders ? 1 : 2);
965 }
966
967 /* check if a monster is carrying a particular item */
968 struct obj *
969 m_carrying(mtmp, type)
970 struct monst *mtmp;
971 int type;
972 {
973     register struct obj *otmp;
974
975     for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
976         if (otmp->otyp == type)
977             return otmp;
978     return (struct obj *) 0;
979 }
980
981 /* TRUE iff thrown/kicked/rolled object doesn't pass through iron bars */
982 boolean
983 hits_bars(obj_p, x, y, always_hit, whodidit)
984 struct obj **obj_p; /* *obj_p will be set to NULL if object breaks */
985 int x, y;
986 int always_hit; /* caller can force a hit for items which would fit through */
987 int whodidit;   /* 1==hero, 0=other, -1==just check whether it'll pass thru */
988 {
989     struct obj *otmp = *obj_p;
990     int obj_type = otmp->otyp;
991     boolean hits = always_hit;
992
993     if (!hits)
994         switch (otmp->oclass) {
995         case WEAPON_CLASS: {
996             int oskill = objects[obj_type].oc_skill;
997
998             hits = (oskill != -P_BOW && oskill != -P_CROSSBOW
999                     && oskill != -P_DART && oskill != -P_SHURIKEN
1000                     && oskill != P_SPEAR
1001                     && oskill != P_KNIFE); /* but not dagger */
1002             break;
1003         }
1004         case ARMOR_CLASS:
1005             hits = (objects[obj_type].oc_armcat != ARM_GLOVES);
1006             break;
1007         case TOOL_CLASS:
1008             hits = (obj_type != SKELETON_KEY && obj_type != LOCK_PICK
1009                     && obj_type != CREDIT_CARD && obj_type != TALLOW_CANDLE
1010                     && obj_type != WAX_CANDLE && obj_type != LENSES
1011                     && obj_type != TIN_WHISTLE && obj_type != MAGIC_WHISTLE);
1012             break;
1013         case ROCK_CLASS: /* includes boulder */
1014             if (obj_type != STATUE || mons[otmp->corpsenm].msize > MZ_TINY)
1015                 hits = TRUE;
1016             break;
1017         case FOOD_CLASS:
1018             if (obj_type == CORPSE && mons[otmp->corpsenm].msize > MZ_TINY)
1019                 hits = TRUE;
1020             else
1021                 hits = (obj_type == MEAT_STICK
1022                         || obj_type == HUGE_CHUNK_OF_MEAT);
1023             break;
1024         case SPBOOK_CLASS:
1025         case WAND_CLASS:
1026         case BALL_CLASS:
1027         case CHAIN_CLASS:
1028             hits = TRUE;
1029             break;
1030         default:
1031             break;
1032         }
1033
1034     if (hits && whodidit != -1) {
1035         if (whodidit ? hero_breaks(otmp, x, y, FALSE) : breaks(otmp, x, y))
1036             *obj_p = otmp = 0; /* object is now gone */
1037         /* breakage makes its own noises */
1038         else if (obj_type == BOULDER || obj_type == HEAVY_IRON_BALL)
1039 /*JP
1040             pline("Whang!");
1041 */
1042             pline("\82®\82í\81[\82ñ\81I");
1043         else if (otmp->oclass == COIN_CLASS
1044                  || objects[obj_type].oc_material == GOLD
1045                  || objects[obj_type].oc_material == SILVER)
1046 /*JP
1047             pline("Clink!");
1048 */
1049             pline("\83`\83\83\83\8a\83\93\81I");
1050         else
1051 /*JP
1052             pline("Clonk!");
1053 */
1054             pline("\83S\83c\83\93\81I");
1055     }
1056
1057     return hits;
1058 }
1059
1060 /*mthrowu.c*/