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. */
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. */
12 STATIC_DCL int FDECL(drop_throw, (struct obj *, BOOLEAN_P, int, int));
14 #define URETREATING(x, y) \
15 (distmin(u.ux, u.uy, x, y) > distmin(u.ux0, u.uy0, x, y))
17 #define POLE_LIM 5 /* How far monsters can use pole-weapons */
20 * Keep consistent with breath weapons in zap.c, and AD_* in monattk.h.
22 STATIC_OVL NEARDATA const char *breathwep[] = {
24 "fragments", "fire", "frost", "sleep gas", "a disintegration blast",
25 "lightning", "poison gas", "acid", "strange breath #8",
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",
34 extern boolean notonhead; /* for long worms */
36 /* hero is hit by something other than a monster */
38 thitu(tlev, dam, obj, name)
41 const char *name; /* if null, then format `obj' */
43 const char *onm, *knm;
45 int kprefix = KILLED_BY_AN;
46 char onmbuf[BUFSZ], knmbuf[BUFSZ];
50 panic("thitu: name & obj both null?");
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 */
58 /* [perhaps ought to check for plural here to] */
59 if (!strncmpi(name, "the ", 4) || !strncmpi(name, "an ", 3)
60 || !strncmpi(name, "a ", 2))
63 knm = strcpy(knmbuf, name);
67 strcat(knmbuf, "
\82É
\93\96\82½
\82Á
\82Ä");
69 onm = (obj && obj_is_pname(obj)) ? the(name) : (obj && obj->quan > 1L)
72 is_acid = (obj && obj->otyp == ACID_VENOM);
74 if (u.uac + tlev <= rnd(20)) {
75 if (Blind || !flags.verbose)
79 pline("
\82»
\82ê
\82Í
\82Í
\82¸
\82ê
\82½
\81D");
82 You("are almost hit by %s.", onm);
84 pline("
\82à
\82¤
\8f
\82µ
\82Å%s
\82É
\96½
\92\86\82·
\82é
\82Æ
\82±
\82ë
\82¾
\82Á
\82½
\81I",onm);
87 if (Blind || !flags.verbose)
89 You("are hit%s", exclam(dam));
91 pline("
\89½
\82©
\82ª
\82 \82È
\82½
\82É
\96½
\92\86\82µ
\82½
\81I");
94 You("are hit by %s%s", onm, exclam(dam));
96 pline("%s
\82ª
\82 \82È
\82½
\82É
\96½
\92\86\82µ
\82½
\81I", onm);
98 if (obj && objects[obj->otyp].oc_material == SILVER && Hate_silver) {
99 /* extra damage already applied by dmgval() */
101 pline_The("silver sears your flesh!");
103 pline("
\82 \82È
\82½
\82Ì
\91Ì
\82Í
\8bâ
\82Å
\8fÄ
\82©
\82ê
\82½
\81I");
104 exercise(A_CON, FALSE);
106 if (is_acid && Acid_resistance)
108 pline("It doesn't seem to hurt you.");
110 pline("
\82 \82È
\82½
\82Í
\8f\9d\82Â
\82©
\82È
\82©
\82Á
\82½
\81D");
116 pline("
\8e_
\82Å
\8fÄ
\82©
\82ê
\82½
\81I");
117 losehp(dam, knm, kprefix); /* acid damage */
118 exercise(A_STR, FALSE);
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).
129 drop_throw(obj, ohit, x, y)
130 register struct obj *obj;
139 if (obj->otyp == CREAM_PIE || obj->oclass == VENOM_CLASS
140 || (ohit && obj->otyp == EGG))
142 else if (ohit && (is_multigen(obj) || obj->otyp == ROCK))
148 && !((mtmp = m_at(x, y)) && (mtmp->mtrapped) && (t = t_at(x, y))
149 && ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT)))) {
152 if (down_gate(x, y) != -1)
153 objgone = ship_object(obj, x, y, FALSE);
156 if (!flooreffects(obj, x, y,
157 "fall")) { /* don't double-dip on damage */
159 if (!flooreffects(obj, x, y,
160 "
\97\8e\82¿
\82é")) { /* don't double-dip on damage */
162 place_object(obj, x, y);
163 if (!mtmp && x == u.ux && y == u.uy)
166 passive_obj(mtmp, obj, (struct attack *) 0);
172 obfree(obj, (struct obj *) 0);
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) */
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 */
188 boolean vis, ismimic;
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);
195 tmp = 5 + find_mac(mtmp) + omon_adj(mtmp, otmp, FALSE);
199 miss(distant_name(otmp, mshot_xname), mtmp);
202 pline("It is missed.");
204 pline("
\89½
\82©
\82ª
\82©
\82·
\82ß
\82½
\81D");
206 if (!range) { /* Last position; object drops */
207 (void) drop_throw(otmp, 0, mtmp->mx, mtmp->my);
210 } else if (otmp->oclass == POTION_CLASS) {
216 potionhit(mtmp, otmp, FALSE);
219 damage = dmgval(otmp, mtmp);
220 if (otmp->otyp == ACID_VENOM && resists_acid(mtmp))
226 hit(distant_name(otmp, mshot_xname), mtmp, exclam(damage));
229 pline("%s is hit%s", Monnam(mtmp), exclam(damage));
231 pline("%s
\82É
\96½
\92\86\82µ
\82½%s", Monnam(mtmp), exclam(damage));
233 if (otmp->opoisoned && is_poisonable(otmp)) {
234 if (resists_poison(mtmp)) {
237 pline_The("poison doesn't seem to affect %s.",
239 pline("%s
\82Í
\93Å
\82Ì
\89e
\8b¿
\82ð
\8eó
\82¯
\82È
\82¢
\82æ
\82¤
\82¾
\81D",
247 pline_The("poison was deadly...");
249 pline("
\93Å
\82Í
\92v
\8e\80\97Ê
\82¾
\82Á
\82½
\81D
\81D
\81D");
254 if (objects[otmp->otyp].oc_material == SILVER
255 && mon_hates_silver(mtmp)) {
258 pline_The("silver sears %s flesh!", s_suffix(mon_nam(mtmp)));
260 pline("%s
\82Ì
\91Ì
\82Í
\8bâ
\82Å
\8fÄ
\82©
\82ê
\82½
\81I", s_suffix(mon_nam(mtmp)));
263 pline("Its flesh is seared!");
265 pline("
\89½
\8eÒ
\82©
\82Ì
\91Ì
\82Í
\8fÄ
\82©
\82ê
\82½
\81I");
267 if (otmp->otyp == ACID_VENOM && cansee(mtmp->mx, mtmp->my)) {
268 if (resists_acid(mtmp)) {
271 pline("%s is unaffected.", Monnam(mtmp));
273 pline("%s
\82Í
\89e
\8b¿
\82ð
\8eó
\82¯
\82È
\82¢
\81D", Monnam(mtmp));
278 pline_The("acid burns %s!", mon_nam(mtmp));
280 pline("%s
\82Í
\8e_
\82Å
\8fÄ
\82©
\82ê
\82½
\81I", mon_nam(mtmp));
283 pline("It is burned!");
285 pline("
\89½
\82©
\82Í
\8fÄ
\82©
\82ê
\82½
\81I");
292 pline("%s is %s!", Monnam(mtmp),
293 (nonliving(mtmp->data) || is_vampshifter(mtmp)
294 || !canspotmon(mtmp))
298 pline("%s
\82Í%s
\81I", Monnam(mtmp),
299 (nonliving(mtmp->data) || is_vampshifter(mtmp)
300 || !canspotmon(mtmp))
304 /* don't blame hero for unknown rolling boulder trap */
305 if (!context.mon_moving
306 && (otmp->otyp != BOULDER || range >= 0 || otmp->otrapped))
312 if (can_blnd((struct monst *) 0, mtmp,
313 (uchar) (otmp->otyp == BLINDING_VENOM ? AT_SPIT
316 if (vis && mtmp->mcansee)
318 pline("%s is blinded by %s.", Monnam(mtmp), the(xname(otmp)));
320 pline("%s
\82Í%s
\82É
\82æ
\82Á
\82Ä
\96Ú
\82ª
\8c©
\82¦
\82È
\82
\82È
\82Á
\82½
\81D", Monnam(mtmp), the(xname(otmp)));
322 tmp = (int) mtmp->mblinded + rnd(25) + 20;
325 mtmp->mblinded = tmp;
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 */
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) */
345 struct obj *singleobj;
346 char sym = obj->oclass;
347 int hitu, oldumort, blindinc = 0;
351 notonhead = FALSE; /* reset potentially stale value */
353 if (obj->quan == 1L) {
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
360 * VENOM is not in minvent - it should already be OBJ_FREE.
361 * The extract below does nothing.
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);
370 obj = (struct obj *) 0;
372 singleobj = splitobj(obj, 1L);
373 obj_extract_self(singleobj);
376 singleobj->owornmask = 0; /* threw one of multiple weapons in hand? */
378 if ((singleobj->cursed || singleobj->greased) && (dx || dy) && !rn2(7)) {
379 if (canseemon(mon) && flags.verbose) {
380 if (is_ammo(singleobj))
382 pline("%s misfires!", Monnam(mon));
384 pline("%s
\82Í
\82Í
\82¸
\82µ
\82½
\81I", Monnam(mon));
387 pline("%s as %s throws it!", Tobjnam(singleobj, "slip"),
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));
396 /* check validity of new direction */
398 (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
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);
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.
421 tmp_at(DISP_FLASH, obj_to_glyph(singleobj));
422 while (range-- > 0) { /* Actually the loop is always exited by break */
425 if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
426 if (ohitmon(mtmp, singleobj, range, TRUE))
428 } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) {
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) {
437 You("catch the %s.", xname(singleobj));
439 You("%s
\82ð
\82Â
\82©
\82Ü
\82¦
\82½
\81D", xname(singleobj));
441 You("are not interested in %s junk.",
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);
450 "accept %s gift in the spirit in which it was intended.",
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)));
455 (void) hold_another_object(
456 singleobj, "You catch, but drop, %s.",
457 xname(singleobj), "You catch:");
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");
466 if (singleobj->oclass == POTION_CLASS) {
468 singleobj->dknown = 1;
469 potionhit(&youmonst, singleobj, FALSE);
472 oldumort = u.umortality;
473 switch (singleobj->otyp) {
476 if (!touch_petrifies(&mons[singleobj->corpsenm])) {
477 impossible("monster throwing egg type %d",
478 singleobj->corpsenm);
485 hitu = thitu(8, 0, singleobj, (char *) 0);
488 dam = dmgval(singleobj, &youmonst);
489 hitv = 3 - distmin(u.ux, u.uy, mon->mx, mon->my);
492 if (is_elf(mon->data)
493 && objects[singleobj->otyp].oc_skill == P_BOW) {
495 if (MON_WEP(mon) && MON_WEP(mon)->otyp == ELVEN_BOW)
497 if (singleobj->otyp == ELVEN_ARROW)
500 if (bigmonst(youmonst.data))
502 hitv += 8 + singleobj->spe;
505 hitu = thitu(hitv, dam, singleobj, (char *) 0);
507 if (hitu && singleobj->opoisoned && is_poisonable(singleobj)) {
508 char onmbuf[BUFSZ], knmbuf[BUFSZ];
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);
517 if (hitu && can_blnd((struct monst *) 0, &youmonst,
518 (uchar) (singleobj->otyp == BLINDING_VENOM
523 if (singleobj->otyp == CREAM_PIE) {
526 pline("Yecch! You've been creamed.");
528 pline("
\83E
\83F
\81[
\81D
\83N
\83\8a\81[
\83\80\82ð
\82©
\82Ô
\82Á
\82½
\81D");
531 pline("There's %s sticky all over your %s.",
532 something, body_part(FACE));
534 pline("
\82 \82È
\82½
\82Í%s
\82É
\82×
\82Æ
\82Â
\82
\82à
\82Ì
\82ð
\8a´
\82¶
\82½
\81D",
537 } else if (singleobj->otyp == BLINDING_VENOM) {
539 const char *eyes = body_part(EYE);
541 if (eyecount(youmonst.data) != 1)
542 eyes = makeplural(eyes);
543 /* venom in the eyes */
545 pline_The("venom blinds you.");
547 Your("%s %s.", eyes, vtense(eyes, "sting"));
550 pline("
\93Å
\82Å
\96Ú
\82ª
\8c©
\82¦
\82È
\82
\82È
\82Á
\82½
\81D");
552 Your("%s
\82Í
\82¿
\82
\82¿
\82
\82µ
\82½
\81D", body_part(EYE));
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, "");
564 if (hitu || !range) {
565 (void) drop_throw(singleobj, hitu, u.ux, u.uy);
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);
585 tmp_at(bhitpos.x, bhitpos.y);
588 tmp_at(bhitpos.x, bhitpos.y);
593 u.ucreamed += blindinc;
594 make_blinded(Blinded + (long) blindinc, FALSE);
596 Your1(vision_clears);
600 /* remove an entire item from a monster's inventory; destroy that item */
606 obj_extract_self(obj);
607 if (obj->owornmask) {
608 if (obj == MON_WEP(mon))
610 mon->misc_worn_check &= ~obj->owornmask;
611 update_mon_intrinsics(mon, obj, FALSE, FALSE);
614 obfree(obj, (struct obj *) 0);
617 /* remove one instance of an item from a monster's inventory */
623 if (obj->quan > 1L) {
625 obj->owt = weight(obj);
627 m_useupall(mon, obj);
631 /* monster attempts ranged weapon attack against player */
636 struct obj *otmp, *mwep;
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)
650 otmp = select_rwep(mtmp);
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 */
663 if (canseemon(mtmp)) {
666 pline("%s thrusts %s.", Monnam(mtmp),
667 obj_is_pname(otmp) ? the(onm) : an(onm));
669 pline("%s
\82Í%s
\82ð
\93Ë
\82«
\8eh
\82µ
\82½
\81D", Monnam(mtmp), onm);
673 dam = dmgval(otmp, &youmonst);
674 hitv = 3 - distmin(u.ux, u.uy, mtmp->mx, mtmp->my);
677 if (bigmonst(youmonst.data))
679 hitv += 8 + otmp->spe;
683 (void) thitu(hitv, dam, otmp, (char *) 0);
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.
696 || (URETREATING(x, y)
697 && rn2(BOLT_LIM - distmin(x, y, mtmp->mux, mtmp->muy))))
700 mwep = MON_WEP(mtmp); /* wielded weapon */
702 /* Multishot calculations */
704 if (otmp->quan > 1L /* no point checking if there's only 1 */
705 /* ammo requires corresponding launcher be wielded */
707 ? matching_launcher(otmp, mwep)
708 /* otherwise any stackable (non-ammo) weapon */
709 : otmp->oclass == WEAPON_CLASS)
711 int skill = (int) objects[otmp->otyp].oc_skill;
713 /* Assumes lords are skilled, princes are expert */
714 if (is_prince(mtmp->data))
716 else if (is_lord(mtmp->data))
718 /* fake players treated as skilled (regardless of role limits) */
719 else if (is_mplayer(mtmp->data))
723 switch (monsndx(mtmp->data)) {
725 if (skill == -P_SHURIKEN)
732 if (skill == P_DAGGER)
736 if (skill == -P_SHURIKEN || skill == -P_DART)
740 if (otmp->otyp == YA && mwep && mwep->otyp == YUMI)
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))
753 multishot = rnd(multishot);
754 if ((long) multishot > otmp->quan)
755 multishot = (int) otmp->quan;
758 if (canseemon(mtmp)) {
762 /* "N arrows"; multishot > 1 implies otmp->quan > 1, so
763 xname()'s result will already be pluralized */
765 Sprintf(onmbuf, "%d %s", multishot, xname(otmp));
767 Sprintf(onmbuf, "%d%s
\82Ì%s", multishot, numeral(otmp), xname(otmp));
771 onm = singular(otmp, xname);
772 onm = obj_is_pname(otmp) ? the(onm) : an(onm);
774 m_shot.s = ammo_and_launcher(otmp, mwep) ? TRUE : FALSE;
776 pline("%s %s %s!", Monnam(mtmp), m_shot.s ? "shoots" : "throws", onm);
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;
781 m_shot.o = STRANGE_OBJECT; /* don't give multishot feedback */
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); */
798 m_shot.n = m_shot.i = 0;
799 m_shot.o = STRANGE_OBJECT;
805 /* monster spits substance at you */
809 struct attack *mattk;
816 pline("A dry rattle comes from %s throat.",
818 pline("%s
\82Ì
\8dA
\82ª
\83K
\83\89\83K
\83\89\82Æ
\96Â
\82Á
\82½
\81D",
819 s_suffix(mon_nam(mtmp)));
822 if (lined_up(mtmp)) {
823 switch (mattk->adtyp) {
826 otmp = mksobj(BLINDING_VENOM, TRUE, FALSE);
829 impossible("bad attack type in spitmu");
832 otmp = mksobj(ACID_VENOM, TRUE, FALSE);
836 - distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy))) {
839 pline("%s spits venom!", Monnam(mtmp));
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);
847 obj_extract_self(otmp);
848 obfree(otmp, (struct obj *) 0);
854 /* monster breathes at you (ranged) */
858 struct attack *mattk;
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;
863 if (lined_up(mtmp)) {
868 pline("%s coughs.", Monnam(mtmp));
870 pline("%s
\82Í
\82¹
\82«
\82ð
\82µ
\82½
\81D", Monnam(mtmp));
873 You_hear("a cough.");
875 You_hear("
\82¹
\82«
\82Ì
\89¹
\82ð
\95·
\82¢
\82½
\81D");
879 if (!mtmp->mspec_used && rn2(3)) {
880 if ((typ >= AD_MAGM) && (typ <= AD_ACID)) {
883 pline("%s breathes %s!", Monnam(mtmp),
886 pline("%s
\82Í%s
\82ð
\93f
\82¢
\82½
\81I", Monnam(mtmp),
889 buzz((int) (-20 - (typ - 1)), (int) mattk->damn, mtmp->mx,
890 mtmp->my, sgn(tbx), sgn(tby));
892 /* breath runs out sometimes. Also, give monster some
893 * cunning; don't breath if the player fell asleep.
896 mtmp->mspec_used = 10 + rn2(20);
897 if (typ == AD_SLEE && !Sleep_resistance)
898 mtmp->mspec_used += rnd(20);
900 impossible("Breath weapon %d used", typ - 1);
907 linedup(ax, ay, bx, by, boulderhandling)
908 register xchar ax, ay, bx, by;
909 int boulderhandling; /* 0=block, 1=ignore, 2=conditionally block */
911 int dx, dy, boulderspots;
913 /* These two values are set for use after successful return. */
917 /* sometimes displacement makes a monster think that you're at its
918 own location; prevent it from throwing and zapping in that case */
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))
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)
931 dx = sgn(ax - bx), dy = sgn(ay - by);
934 /* <bx,by> is guaranteed to eventually converge with <ax,ay> */
936 if (IS_ROCK(levl[bx][by].typ) || closed_door(bx, by))
938 if (sobj_at(BOULDER, bx, by))
940 } while (bx != ax || by != ay);
941 /* reached target position without encountering obstacle */
942 if (boulderhandling == 1 || rn2(2 + boulderspots) < 2)
948 /* is mtmp in position to use ranged attack? */
951 register struct monst *mtmp;
953 boolean ignore_boulders;
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)))
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);
967 /* check if a monster is carrying a particular item */
969 m_carrying(mtmp, type)
973 register struct obj *otmp;
975 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
976 if (otmp->otyp == type)
978 return (struct obj *) 0;
981 /* TRUE iff thrown/kicked/rolled object doesn't pass through iron bars */
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 */
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 */
989 struct obj *otmp = *obj_p;
990 int obj_type = otmp->otyp;
991 boolean hits = always_hit;
994 switch (otmp->oclass) {
996 int oskill = objects[obj_type].oc_skill;
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 */
1005 hits = (objects[obj_type].oc_armcat != ARM_GLOVES);
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);
1013 case ROCK_CLASS: /* includes boulder */
1014 if (obj_type != STATUE || mons[otmp->corpsenm].msize > MZ_TINY)
1018 if (obj_type == CORPSE && mons[otmp->corpsenm].msize > MZ_TINY)
1021 hits = (obj_type == MEAT_STICK
1022 || obj_type == HUGE_CHUNK_OF_MEAT);
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)
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)
1049 pline("
\83`
\83\83\83\8a\83\93\81I");
1054 pline("
\83S
\83c
\83\93\81I");