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. */
7 STATIC_DCL
int FDECL(drop_throw
, (struct obj
*, BOOLEAN_P
, int, int));
9 #define URETREATING(x, y) \
10 (distmin(u.ux, u.uy, x, y) > distmin(u.ux0, u.uy0, x, y))
12 #define POLE_LIM 5 /* How far monsters can use pole-weapons */
15 * Keep consistent with breath weapons in zap.c, and AD_* in monattk.h.
17 STATIC_OVL NEARDATA
const char *breathwep
[] = {
18 "fragments", "fire", "frost", "sleep gas", "a disintegration blast",
19 "lightning", "poison gas", "acid", "strange breath #8",
23 extern boolean notonhead
; /* for long worms */
25 /* hero is hit by something other than a monster */
27 thitu(tlev
, dam
, obj
, name
)
30 const char *name
; /* if null, then format `obj' */
32 const char *onm
, *knm
;
34 int kprefix
= KILLED_BY_AN
;
35 char onmbuf
[BUFSZ
], knmbuf
[BUFSZ
];
39 panic("thitu: name & obj both null?");
41 strcpy(onmbuf
, (obj
->quan
> 1L) ? doname(obj
) : mshot_xname(obj
));
42 knm
= strcpy(knmbuf
, killer_xname(obj
));
43 kprefix
= KILLED_BY
; /* killer_name supplies "an" if warranted */
46 /* [perhaps ought to check for plural here to] */
47 if (!strncmpi(name
, "the ", 4) || !strncmpi(name
, "an ", 3)
48 || !strncmpi(name
, "a ", 2))
51 onm
= (obj
&& obj_is_pname(obj
)) ? the(name
) : (obj
&& obj
->quan
> 1L)
54 is_acid
= (obj
&& obj
->otyp
== ACID_VENOM
);
56 if (u
.uac
+ tlev
<= rnd(20)) {
57 if (Blind
|| !flags
.verbose
)
60 You("are almost hit by %s.", onm
);
63 if (Blind
|| !flags
.verbose
)
64 You("are hit%s", exclam(dam
));
66 You("are hit by %s%s", onm
, exclam(dam
));
68 if (obj
&& objects
[obj
->otyp
].oc_material
== SILVER
&& Hate_silver
) {
69 /* extra damage already applied by dmgval() */
70 pline_The("silver sears your flesh!");
71 exercise(A_CON
, FALSE
);
73 if (is_acid
&& Acid_resistance
)
74 pline("It doesn't seem to hurt you.");
78 losehp(dam
, knm
, kprefix
); /* acid damage */
79 exercise(A_STR
, FALSE
);
85 /* Be sure this corresponds with what happens to player-thrown objects in
86 * dothrow.c (for consistency). --KAA
87 * Returns 0 if object still exists (not destroyed).
90 drop_throw(obj
, ohit
, x
, y
)
91 register struct obj
*obj
;
100 if (obj
->otyp
== CREAM_PIE
|| obj
->oclass
== VENOM_CLASS
101 || (ohit
&& obj
->otyp
== EGG
))
103 else if (ohit
&& (is_multigen(obj
) || obj
->otyp
== ROCK
))
109 && !((mtmp
= m_at(x
, y
)) && (mtmp
->mtrapped
) && (t
= t_at(x
, y
))
110 && ((t
->ttyp
== PIT
) || (t
->ttyp
== SPIKED_PIT
)))) {
113 if (down_gate(x
, y
) != -1)
114 objgone
= ship_object(obj
, x
, y
, FALSE
);
116 if (!flooreffects(obj
, x
, y
,
117 "fall")) { /* don't double-dip on damage */
118 place_object(obj
, x
, y
);
119 if (!mtmp
&& x
== u
.ux
&& y
== u
.uy
)
122 passive_obj(mtmp
, obj
, (struct attack
*) 0);
128 obfree(obj
, (struct obj
*) 0);
132 /* an object launched by someone/thing other than player attacks a monster;
133 return 1 if the object has stopped moving (hit or its range used up) */
135 ohitmon(mtmp
, otmp
, range
, verbose
)
136 struct monst
*mtmp
; /* accidental target, located at <bhitpos.x,.y> */
137 struct obj
*otmp
; /* missile; might be destroyed by drop_throw */
138 int range
; /* how much farther will object travel if it misses;
139 use -1 to signify to keep going even after hit,
140 unless it's gone (used for rolling_boulder_traps) */
141 boolean verbose
; /* give message(s) even when you can't see what happened */
144 boolean vis
, ismimic
;
147 notonhead
= (bhitpos
.x
!= mtmp
->mx
|| bhitpos
.y
!= mtmp
->my
);
148 ismimic
= mtmp
->m_ap_type
&& mtmp
->m_ap_type
!= M_AP_MONSTER
;
149 vis
= cansee(bhitpos
.x
, bhitpos
.y
);
151 tmp
= 5 + find_mac(mtmp
) + omon_adj(mtmp
, otmp
, FALSE
);
155 miss(distant_name(otmp
, mshot_xname
), mtmp
);
157 pline("It is missed.");
159 if (!range
) { /* Last position; object drops */
160 (void) drop_throw(otmp
, 0, mtmp
->mx
, mtmp
->my
);
163 } else if (otmp
->oclass
== POTION_CLASS
) {
169 potionhit(mtmp
, otmp
, FALSE
);
172 damage
= dmgval(otmp
, mtmp
);
173 if (otmp
->otyp
== ACID_VENOM
&& resists_acid(mtmp
))
179 hit(distant_name(otmp
, mshot_xname
), mtmp
, exclam(damage
));
181 pline("%s is hit%s", Monnam(mtmp
), exclam(damage
));
183 if (otmp
->opoisoned
&& is_poisonable(otmp
)) {
184 if (resists_poison(mtmp
)) {
186 pline_The("poison doesn't seem to affect %s.",
193 pline_The("poison was deadly...");
198 if (objects
[otmp
->otyp
].oc_material
== SILVER
199 && mon_hates_silver(mtmp
)) {
201 pline_The("silver sears %s flesh!", s_suffix(mon_nam(mtmp
)));
203 pline("Its flesh is seared!");
205 if (otmp
->otyp
== ACID_VENOM
&& cansee(mtmp
->mx
, mtmp
->my
)) {
206 if (resists_acid(mtmp
)) {
208 pline("%s is unaffected.", Monnam(mtmp
));
212 pline_The("acid burns %s!", mon_nam(mtmp
));
214 pline("It is burned!");
220 pline("%s is %s!", Monnam(mtmp
),
221 (nonliving(mtmp
->data
) || is_vampshifter(mtmp
)
222 || !canspotmon(mtmp
))
225 /* don't blame hero for unknown rolling boulder trap */
226 if (!context
.mon_moving
227 && (otmp
->otyp
!= BOULDER
|| range
>= 0 || otmp
->otrapped
))
233 if (can_blnd((struct monst
*) 0, mtmp
,
234 (uchar
) (otmp
->otyp
== BLINDING_VENOM
? AT_SPIT
237 if (vis
&& mtmp
->mcansee
)
238 pline("%s is blinded by %s.", Monnam(mtmp
), the(xname(otmp
)));
240 tmp
= (int) mtmp
->mblinded
+ rnd(25) + 20;
243 mtmp
->mblinded
= tmp
;
246 objgone
= drop_throw(otmp
, 1, bhitpos
.x
, bhitpos
.y
);
247 if (!objgone
&& range
== -1) { /* special case */
248 obj_extract_self(otmp
); /* free it for motion again */
257 m_throw(mon
, x
, y
, dx
, dy
, range
, obj
)
258 struct monst
*mon
; /* launching monster */
259 int x
, y
, dx
, dy
, range
; /* launch point, direction, and range */
260 struct obj
*obj
; /* missile (or stack providing it) */
263 struct obj
*singleobj
;
264 char sym
= obj
->oclass
;
265 int hitu
, oldumort
, blindinc
= 0;
269 notonhead
= FALSE
; /* reset potentially stale value */
271 if (obj
->quan
== 1L) {
273 * Remove object from minvent. This cannot be done later on;
274 * what if the player dies before then, leaving the monster
275 * with 0 daggers? (This caused the infamous 2^32-1 orcish
278 * VENOM is not in minvent - it should already be OBJ_FREE.
279 * The extract below does nothing.
282 /* not possibly_unwield, which checks the object's */
283 /* location, not its existence */
284 if (MON_WEP(mon
) == obj
)
285 setmnotwielded(mon
, obj
);
286 obj_extract_self(obj
);
288 obj
= (struct obj
*) 0;
290 singleobj
= splitobj(obj
, 1L);
291 obj_extract_self(singleobj
);
294 singleobj
->owornmask
= 0; /* threw one of multiple weapons in hand? */
296 if ((singleobj
->cursed
|| singleobj
->greased
) && (dx
|| dy
) && !rn2(7)) {
297 if (canseemon(mon
) && flags
.verbose
) {
298 if (is_ammo(singleobj
))
299 pline("%s misfires!", Monnam(mon
));
301 pline("%s as %s throws it!", Tobjnam(singleobj
, "slip"),
306 /* check validity of new direction */
308 (void) drop_throw(singleobj
, 0, bhitpos
.x
, bhitpos
.y
);
313 /* pre-check for doors, walls and boundaries.
314 Also need to pre-check for bars regardless of direction;
315 the random chance for small objects hitting bars is
316 skipped when reaching them at point blank range */
317 if (!isok(bhitpos
.x
+ dx
, bhitpos
.y
+ dy
)
318 || IS_ROCK(levl
[bhitpos
.x
+ dx
][bhitpos
.y
+ dy
].typ
)
319 || closed_door(bhitpos
.x
+ dx
, bhitpos
.y
+ dy
)
320 || (levl
[bhitpos
.x
+ dx
][bhitpos
.y
+ dy
].typ
== IRONBARS
321 && hits_bars(&singleobj
,
322 bhitpos
.x
, bhitpos
.y
,
323 bhitpos
.x
+ dx
, bhitpos
.y
+ dy
, 0, 0))) {
324 (void) drop_throw(singleobj
, 0, bhitpos
.x
, bhitpos
.y
);
328 /* Note: drop_throw may destroy singleobj. Since obj must be destroyed
329 * early to avoid the dagger bug, anyone who modifies this code should
330 * be careful not to use either one after it's been freed.
333 tmp_at(DISP_FLASH
, obj_to_glyph(singleobj
));
334 while (range
-- > 0) { /* Actually the loop is always exited by break */
337 if ((mtmp
= m_at(bhitpos
.x
, bhitpos
.y
)) != 0) {
338 if (ohitmon(mtmp
, singleobj
, range
, TRUE
))
340 } else if (bhitpos
.x
== u
.ux
&& bhitpos
.y
== u
.uy
) {
344 if (singleobj
->oclass
== GEM_CLASS
345 && singleobj
->otyp
<= LAST_GEM
+ 9 /* 9 glass colors */
346 && is_unicorn(youmonst
.data
)) {
347 if (singleobj
->otyp
> LAST_GEM
) {
348 You("catch the %s.", xname(singleobj
));
349 You("are not interested in %s junk.",
350 s_suffix(mon_nam(mon
)));
351 makeknown(singleobj
->otyp
);
355 "accept %s gift in the spirit in which it was intended.",
356 s_suffix(mon_nam(mon
)));
357 (void) hold_another_object(
358 singleobj
, "You catch, but drop, %s.",
359 xname(singleobj
), "You catch:");
363 if (singleobj
->oclass
== POTION_CLASS
) {
365 singleobj
->dknown
= 1;
366 potionhit(&youmonst
, singleobj
, FALSE
);
369 oldumort
= u
.umortality
;
370 switch (singleobj
->otyp
) {
373 if (!touch_petrifies(&mons
[singleobj
->corpsenm
])) {
374 impossible("monster throwing egg type %d",
375 singleobj
->corpsenm
);
382 hitu
= thitu(8, 0, singleobj
, (char *) 0);
385 dam
= dmgval(singleobj
, &youmonst
);
386 hitv
= 3 - distmin(u
.ux
, u
.uy
, mon
->mx
, mon
->my
);
389 if (is_elf(mon
->data
)
390 && objects
[singleobj
->otyp
].oc_skill
== P_BOW
) {
392 if (MON_WEP(mon
) && MON_WEP(mon
)->otyp
== ELVEN_BOW
)
394 if (singleobj
->otyp
== ELVEN_ARROW
)
397 if (bigmonst(youmonst
.data
))
399 hitv
+= 8 + singleobj
->spe
;
402 hitu
= thitu(hitv
, dam
, singleobj
, (char *) 0);
404 if (hitu
&& singleobj
->opoisoned
&& is_poisonable(singleobj
)) {
405 char onmbuf
[BUFSZ
], knmbuf
[BUFSZ
];
407 Strcpy(onmbuf
, xname(singleobj
));
408 Strcpy(knmbuf
, killer_xname(singleobj
));
409 poisoned(onmbuf
, A_STR
, knmbuf
,
410 /* if damage triggered life-saving,
411 poison is limited to attrib loss */
412 (u
.umortality
> oldumort
) ? 0 : 10, TRUE
);
414 if (hitu
&& can_blnd((struct monst
*) 0, &youmonst
,
415 (uchar
) (singleobj
->otyp
== BLINDING_VENOM
420 if (singleobj
->otyp
== CREAM_PIE
) {
422 pline("Yecch! You've been creamed.");
424 pline("There's %s sticky all over your %s.",
425 something
, body_part(FACE
));
426 } else if (singleobj
->otyp
== BLINDING_VENOM
) {
427 const char *eyes
= body_part(EYE
);
429 if (eyecount(youmonst
.data
) != 1)
430 eyes
= makeplural(eyes
);
431 /* venom in the eyes */
433 pline_The("venom blinds you.");
435 Your("%s %s.", eyes
, vtense(eyes
, "sting"));
438 if (hitu
&& singleobj
->otyp
== EGG
) {
439 if (!Stoned
&& !Stone_resistance
440 && !(poly_when_stoned(youmonst
.data
)
441 && polymon(PM_STONE_GOLEM
))) {
442 make_stoned(5L, (char *) 0, KILLED_BY
, "");
446 if (hitu
|| !range
) {
447 (void) drop_throw(singleobj
, hitu
, u
.ux
, u
.uy
);
451 if (!range
/* reached end of path */
452 /* missile hits edge of screen */
453 || !isok(bhitpos
.x
+ dx
, bhitpos
.y
+ dy
)
454 /* missile hits the wall */
455 || IS_ROCK(levl
[bhitpos
.x
+ dx
][bhitpos
.y
+ dy
].typ
)
456 /* missile hit closed door */
457 || closed_door(bhitpos
.x
+ dx
, bhitpos
.y
+ dy
)
458 /* missile might hit iron bars */
459 || (levl
[bhitpos
.x
+ dx
][bhitpos
.y
+ dy
].typ
== IRONBARS
460 && hits_bars(&singleobj
,
461 bhitpos
.x
, bhitpos
.y
,
462 bhitpos
.x
+ dx
, bhitpos
.y
+ dy
,
464 /* Thrown objects "sink" */
465 || IS_SINK(levl
[bhitpos
.x
][bhitpos
.y
].typ
)) {
466 if (singleobj
) /* hits_bars might have destroyed it */
467 (void) drop_throw(singleobj
, 0, bhitpos
.x
, bhitpos
.y
);
470 tmp_at(bhitpos
.x
, bhitpos
.y
);
473 tmp_at(bhitpos
.x
, bhitpos
.y
);
478 u
.ucreamed
+= blindinc
;
479 make_blinded(Blinded
+ (long) blindinc
, FALSE
);
481 Your1(vision_clears
);
485 /* remove an entire item from a monster's inventory; destroy that item */
491 obj_extract_self(obj
);
492 if (obj
->owornmask
) {
493 if (obj
== MON_WEP(mon
))
495 mon
->misc_worn_check
&= ~obj
->owornmask
;
496 update_mon_intrinsics(mon
, obj
, FALSE
, FALSE
);
499 obfree(obj
, (struct obj
*) 0);
502 /* remove one instance of an item from a monster's inventory */
508 if (obj
->quan
> 1L) {
510 obj
->owt
= weight(obj
);
512 m_useupall(mon
, obj
);
516 /* monster attempts ranged weapon attack against player */
521 struct obj
*otmp
, *mwep
;
526 /* Rearranged beginning so monsters can use polearms not in a line */
527 if (mtmp
->weapon_check
== NEED_WEAPON
|| !MON_WEP(mtmp
)) {
528 mtmp
->weapon_check
= NEED_RANGED_WEAPON
;
529 /* mon_wield_item resets weapon_check as appropriate */
530 if (mon_wield_item(mtmp
) != 0)
535 otmp
= select_rwep(mtmp
);
542 if (otmp
!= MON_WEP(mtmp
))
543 return; /* polearm must be wielded */
544 if (dist2(mtmp
->mx
, mtmp
->my
, mtmp
->mux
, mtmp
->muy
) > POLE_LIM
545 || !couldsee(mtmp
->mx
, mtmp
->my
))
546 return; /* Out of range, or intervening wall */
548 if (canseemon(mtmp
)) {
550 pline("%s thrusts %s.", Monnam(mtmp
),
551 obj_is_pname(otmp
) ? the(onm
) : an(onm
));
554 dam
= dmgval(otmp
, &youmonst
);
555 hitv
= 3 - distmin(u
.ux
, u
.uy
, mtmp
->mx
, mtmp
->my
);
558 if (bigmonst(youmonst
.data
))
560 hitv
+= 8 + otmp
->spe
;
564 (void) thitu(hitv
, dam
, otmp
, (char *) 0);
571 /* If you are coming toward the monster, the monster
572 * should try to soften you up with missiles. If you are
573 * going away, you are probably hurt or running. Give
574 * chase, but if you are getting too far away, throw.
577 || (URETREATING(x
, y
)
578 && rn2(BOLT_LIM
- distmin(x
, y
, mtmp
->mux
, mtmp
->muy
))))
581 mwep
= MON_WEP(mtmp
); /* wielded weapon */
583 /* Multishot calculations */
585 if (otmp
->quan
> 1L /* no point checking if there's only 1 */
586 /* ammo requires corresponding launcher be wielded */
588 ? matching_launcher(otmp
, mwep
)
589 /* otherwise any stackable (non-ammo) weapon */
590 : otmp
->oclass
== WEAPON_CLASS
)
592 int skill
= (int) objects
[otmp
->otyp
].oc_skill
;
594 /* Assumes lords are skilled, princes are expert */
595 if (is_prince(mtmp
->data
))
597 else if (is_lord(mtmp
->data
))
599 /* fake players treated as skilled (regardless of role limits) */
600 else if (is_mplayer(mtmp
->data
))
604 switch (monsndx(mtmp
->data
)) {
606 if (skill
== -P_SHURIKEN
)
613 if (skill
== P_DAGGER
)
617 if (skill
== -P_SHURIKEN
|| skill
== -P_DART
)
621 if (otmp
->otyp
== YA
&& mwep
&& mwep
->otyp
== YUMI
)
628 if ((is_elf(mtmp
->data
) && otmp
->otyp
== ELVEN_ARROW
&& mwep
629 && mwep
->otyp
== ELVEN_BOW
)
630 || (is_orc(mtmp
->data
) && otmp
->otyp
== ORCISH_ARROW
&& mwep
631 && mwep
->otyp
== ORCISH_BOW
))
634 multishot
= rnd(multishot
);
635 if ((long) multishot
> otmp
->quan
)
636 multishot
= (int) otmp
->quan
;
639 if (canseemon(mtmp
)) {
643 /* "N arrows"; multishot > 1 implies otmp->quan > 1, so
644 xname()'s result will already be pluralized */
645 Sprintf(onmbuf
, "%d %s", multishot
, xname(otmp
));
649 onm
= singular(otmp
, xname
);
650 onm
= obj_is_pname(otmp
) ? the(onm
) : an(onm
);
652 m_shot
.s
= ammo_and_launcher(otmp
, mwep
) ? TRUE
: FALSE
;
653 pline("%s %s %s!", Monnam(mtmp
), m_shot
.s
? "shoots" : "throws", onm
);
654 m_shot
.o
= otmp
->otyp
;
656 m_shot
.o
= STRANGE_OBJECT
; /* don't give multishot feedback */
659 m_shot
.n
= multishot
;
660 for (m_shot
.i
= 1; m_shot
.i
<= m_shot
.n
; m_shot
.i
++) {
661 m_throw(mtmp
, mtmp
->mx
, mtmp
->my
, sgn(tbx
), sgn(tby
),
662 distmin(mtmp
->mx
, mtmp
->my
, mtmp
->mux
, mtmp
->muy
), otmp
);
663 /* conceptually all N missiles are in flight at once, but
664 if mtmp gets killed (shot kills adjacent gas spore and
665 triggers explosion, perhaps), inventory will be dropped
666 and otmp might go away via merging into another stack */
667 if (mtmp
->mhp
<= 0 && m_shot
.i
< m_shot
.n
) {
668 /* cancel pending shots (ought to give a message here since
669 we gave one above about throwing/shooting N missiles) */
670 break; /* endmultishot(FALSE); */
673 m_shot
.n
= m_shot
.i
= 0;
674 m_shot
.o
= STRANGE_OBJECT
;
680 /* monster spits substance at you */
684 struct attack
*mattk
;
690 pline("A dry rattle comes from %s throat.",
691 s_suffix(mon_nam(mtmp
)));
694 if (lined_up(mtmp
)) {
695 switch (mattk
->adtyp
) {
698 otmp
= mksobj(BLINDING_VENOM
, TRUE
, FALSE
);
701 impossible("bad attack type in spitmu");
704 otmp
= mksobj(ACID_VENOM
, TRUE
, FALSE
);
708 - distmin(mtmp
->mx
, mtmp
->my
, mtmp
->mux
, mtmp
->muy
))) {
710 pline("%s spits venom!", Monnam(mtmp
));
711 m_throw(mtmp
, mtmp
->mx
, mtmp
->my
, sgn(tbx
), sgn(tby
),
712 distmin(mtmp
->mx
, mtmp
->my
, mtmp
->mux
, mtmp
->muy
), otmp
);
716 obj_extract_self(otmp
);
717 obfree(otmp
, (struct obj
*) 0);
723 /* monster breathes at you (ranged) */
727 struct attack
*mattk
;
729 /* if new breath types are added, change AD_ACID to max type */
730 int typ
= (mattk
->adtyp
== AD_RBRE
) ? rnd(AD_ACID
) : mattk
->adtyp
;
732 if (lined_up(mtmp
)) {
736 pline("%s coughs.", Monnam(mtmp
));
738 You_hear("a cough.");
742 if (!mtmp
->mspec_used
&& rn2(3)) {
743 if ((typ
>= AD_MAGM
) && (typ
<= AD_ACID
)) {
745 pline("%s breathes %s!", Monnam(mtmp
),
747 buzz((int) (-20 - (typ
- 1)), (int) mattk
->damn
, mtmp
->mx
,
748 mtmp
->my
, sgn(tbx
), sgn(tby
));
750 /* breath runs out sometimes. Also, give monster some
751 * cunning; don't breath if the player fell asleep.
754 mtmp
->mspec_used
= 10 + rn2(20);
755 if (typ
== AD_SLEE
&& !Sleep_resistance
)
756 mtmp
->mspec_used
+= rnd(20);
758 impossible("Breath weapon %d used", typ
- 1);
765 linedup(ax
, ay
, bx
, by
, boulderhandling
)
766 register xchar ax
, ay
, bx
, by
;
767 int boulderhandling
; /* 0=block, 1=ignore, 2=conditionally block */
769 int dx
, dy
, boulderspots
;
771 /* These two values are set for use after successful return. */
775 /* sometimes displacement makes a monster think that you're at its
776 own location; prevent it from throwing and zapping in that case */
780 if ((!tbx
|| !tby
|| abs(tbx
) == abs(tby
)) /* straight line or diagonal */
781 && distmin(tbx
, tby
, 0, 0) < BOLT_LIM
) {
782 if ((ax
== u
.ux
&& ay
== u
.uy
) ? (boolean
) couldsee(bx
, by
)
783 : clear_path(ax
, ay
, bx
, by
))
785 /* don't have line of sight, but might still be lined up
786 if that lack of sight is due solely to boulders */
787 if (boulderhandling
== 0)
789 dx
= sgn(ax
- bx
), dy
= sgn(ay
- by
);
792 /* <bx,by> is guaranteed to eventually converge with <ax,ay> */
794 if (IS_ROCK(levl
[bx
][by
].typ
) || closed_door(bx
, by
))
796 if (sobj_at(BOULDER
, bx
, by
))
798 } while (bx
!= ax
|| by
!= ay
);
799 /* reached target position without encountering obstacle */
800 if (boulderhandling
== 1 || rn2(2 + boulderspots
) < 2)
806 /* is mtmp in position to use ranged attack? */
809 register struct monst
*mtmp
;
811 boolean ignore_boulders
;
813 /* hero concealment usually trumps monst awareness of being lined up */
814 if (Upolyd
&& rn2(25)
815 && (u
.uundetected
|| (youmonst
.m_ap_type
!= M_AP_NOTHING
816 && youmonst
.m_ap_type
!= M_AP_MONSTER
)))
819 ignore_boulders
= (throws_rocks(mtmp
->data
)
820 || m_carrying(mtmp
, WAN_STRIKING
));
821 return linedup(mtmp
->mux
, mtmp
->muy
, mtmp
->mx
, mtmp
->my
,
822 ignore_boulders
? 1 : 2);
825 /* check if a monster is carrying a particular item */
827 m_carrying(mtmp
, type
)
831 register struct obj
*otmp
;
833 for (otmp
= mtmp
->minvent
; otmp
; otmp
= otmp
->nobj
)
834 if (otmp
->otyp
== type
)
836 return (struct obj
*) 0;
840 hit_bars(objp
, objx
, objy
, barsx
, barsy
, your_fault
, from_invent
)
841 struct obj
**objp
; /* *objp will be set to NULL if object breaks */
842 int objx
, objy
, barsx
, barsy
;
843 boolean your_fault
, from_invent
;
845 struct obj
*otmp
= *objp
;
846 int obj_type
= otmp
->otyp
;
847 boolean unbreakable
= (levl
[barsx
][barsy
].wall_info
& W_NONDIGGABLE
) != 0;
850 ? hero_breaks(otmp
, objx
, objy
, from_invent
)
851 : breaks(otmp
, objx
, objy
)) {
852 *objp
= 0; /* object is now gone */
853 /* breakage makes its own noises */
854 if (obj_type
== POT_ACID
) {
855 if (cansee(barsx
, barsy
) && !unbreakable
)
856 pline_The("iron bars are dissolved!");
858 You_hear(Hallucination
? "angry snakes!" : "a hissing noise.");
860 dissolve_bars(barsx
, barsy
);
863 else if (obj_type
== BOULDER
|| obj_type
== HEAVY_IRON_BALL
)
865 else if (otmp
->oclass
== COIN_CLASS
866 || objects
[obj_type
].oc_material
== GOLD
867 || objects
[obj_type
].oc_material
== SILVER
)
873 /* TRUE iff thrown/kicked/rolled object doesn't pass through iron bars */
875 hits_bars(obj_p
, x
, y
, barsx
, barsy
, always_hit
, whodidit
)
876 struct obj
**obj_p
; /* *obj_p will be set to NULL if object breaks */
877 int x
, y
, barsx
, barsy
;
878 int always_hit
; /* caller can force a hit for items which would fit through */
879 int whodidit
; /* 1==hero, 0=other, -1==just check whether it'll pass thru */
881 struct obj
*otmp
= *obj_p
;
882 int obj_type
= otmp
->otyp
;
883 boolean hits
= always_hit
;
886 switch (otmp
->oclass
) {
888 int oskill
= objects
[obj_type
].oc_skill
;
890 hits
= (oskill
!= -P_BOW
&& oskill
!= -P_CROSSBOW
891 && oskill
!= -P_DART
&& oskill
!= -P_SHURIKEN
893 && oskill
!= P_KNIFE
); /* but not dagger */
897 hits
= (objects
[obj_type
].oc_armcat
!= ARM_GLOVES
);
900 hits
= (obj_type
!= SKELETON_KEY
&& obj_type
!= LOCK_PICK
901 && obj_type
!= CREDIT_CARD
&& obj_type
!= TALLOW_CANDLE
902 && obj_type
!= WAX_CANDLE
&& obj_type
!= LENSES
903 && obj_type
!= TIN_WHISTLE
&& obj_type
!= MAGIC_WHISTLE
);
905 case ROCK_CLASS
: /* includes boulder */
906 if (obj_type
!= STATUE
|| mons
[otmp
->corpsenm
].msize
> MZ_TINY
)
910 if (obj_type
== CORPSE
&& mons
[otmp
->corpsenm
].msize
> MZ_TINY
)
913 hits
= (obj_type
== MEAT_STICK
914 || obj_type
== HUGE_CHUNK_OF_MEAT
);
926 if (hits
&& whodidit
!= -1) {
927 hit_bars(obj_p
, x
,y
, barsx
,barsy
, whodidit
, FALSE
);