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, bhitpos.x, bhitpos.y, 0, 0))) {
322 (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
326 /* Note: drop_throw may destroy singleobj. Since obj must be destroyed
327 * early to avoid the dagger bug, anyone who modifies this code should
328 * be careful not to use either one after it's been freed.
331 tmp_at(DISP_FLASH, obj_to_glyph(singleobj));
332 while (range-- > 0) { /* Actually the loop is always exited by break */
335 if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
336 if (ohitmon(mtmp, singleobj, range, TRUE))
338 } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) {
342 if (singleobj->oclass == GEM_CLASS
343 && singleobj->otyp <= LAST_GEM + 9 /* 9 glass colors */
344 && is_unicorn(youmonst.data)) {
345 if (singleobj->otyp > LAST_GEM) {
346 You("catch the %s.", xname(singleobj));
347 You("are not interested in %s junk.",
348 s_suffix(mon_nam(mon)));
349 makeknown(singleobj->otyp);
353 "accept %s gift in the spirit in which it was intended.",
354 s_suffix(mon_nam(mon)));
355 (void) hold_another_object(
356 singleobj, "You catch, but drop, %s.",
357 xname(singleobj), "You catch:");
361 if (singleobj->oclass == POTION_CLASS) {
363 singleobj->dknown = 1;
364 potionhit(&youmonst, singleobj, FALSE);
367 oldumort = u.umortality;
368 switch (singleobj->otyp) {
371 if (!touch_petrifies(&mons[singleobj->corpsenm])) {
372 impossible("monster throwing egg type %d",
373 singleobj->corpsenm);
380 hitu = thitu(8, 0, singleobj, (char *) 0);
383 dam = dmgval(singleobj, &youmonst);
384 hitv = 3 - distmin(u.ux, u.uy, mon->mx, mon->my);
387 if (is_elf(mon->data)
388 && objects[singleobj->otyp].oc_skill == P_BOW) {
390 if (MON_WEP(mon) && MON_WEP(mon)->otyp == ELVEN_BOW)
392 if (singleobj->otyp == ELVEN_ARROW)
395 if (bigmonst(youmonst.data))
397 hitv += 8 + singleobj->spe;
400 hitu = thitu(hitv, dam, singleobj, (char *) 0);
402 if (hitu && singleobj->opoisoned && is_poisonable(singleobj)) {
403 char onmbuf[BUFSZ], knmbuf[BUFSZ];
405 Strcpy(onmbuf, xname(singleobj));
406 Strcpy(knmbuf, killer_xname(singleobj));
407 poisoned(onmbuf, A_STR, knmbuf,
408 /* if damage triggered life-saving,
409 poison is limited to attrib loss */
410 (u.umortality > oldumort) ? 0 : 10, TRUE);
412 if (hitu && can_blnd((struct monst *) 0, &youmonst,
413 (uchar) (singleobj->otyp == BLINDING_VENOM
418 if (singleobj->otyp == CREAM_PIE) {
420 pline("Yecch! You've been creamed.");
422 pline("There's %s sticky all over your %s.",
423 something, body_part(FACE));
424 } else if (singleobj->otyp == BLINDING_VENOM) {
425 const char *eyes = body_part(EYE);
427 if (eyecount(youmonst.data) != 1)
428 eyes = makeplural(eyes);
429 /* venom in the eyes */
431 pline_The("venom blinds you.");
433 Your("%s %s.", eyes, vtense(eyes, "sting"));
436 if (hitu && singleobj->otyp == EGG) {
437 if (!Stoned && !Stone_resistance
438 && !(poly_when_stoned(youmonst.data)
439 && polymon(PM_STONE_GOLEM))) {
440 make_stoned(5L, (char *) 0, KILLED_BY, "");
444 if (hitu || !range) {
445 (void) drop_throw(singleobj, hitu, u.ux, u.uy);
449 if (!range /* reached end of path */
450 /* missile hits edge of screen */
451 || !isok(bhitpos.x + dx, bhitpos.y + dy)
452 /* missile hits the wall */
453 || IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ)
454 /* missile hit closed door */
455 || closed_door(bhitpos.x + dx, bhitpos.y + dy)
456 /* missile might hit iron bars */
457 || (levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS
458 && hits_bars(&singleobj, bhitpos.x, bhitpos.y, !rn2(5), 0))
459 /* Thrown objects "sink" */
460 || IS_SINK(levl[bhitpos.x][bhitpos.y].typ)) {
461 if (singleobj) /* hits_bars might have destroyed it */
462 (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
465 tmp_at(bhitpos.x, bhitpos.y);
468 tmp_at(bhitpos.x, bhitpos.y);
473 u.ucreamed += blindinc;
474 make_blinded(Blinded + (long) blindinc, FALSE);
476 Your1(vision_clears);
480 /* remove an entire item from a monster's inventory; destroy that item */
486 obj_extract_self(obj);
487 if (obj->owornmask) {
488 if (obj == MON_WEP(mon))
490 mon->misc_worn_check &= ~obj->owornmask;
491 update_mon_intrinsics(mon, obj, FALSE, FALSE);
494 obfree(obj, (struct obj *) 0);
497 /* remove one instance of an item from a monster's inventory */
503 if (obj->quan > 1L) {
505 obj->owt = weight(obj);
507 m_useupall(mon, obj);
511 /* monster attempts ranged weapon attack against player */
516 struct obj *otmp, *mwep;
521 /* Rearranged beginning so monsters can use polearms not in a line */
522 if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) {
523 mtmp->weapon_check = NEED_RANGED_WEAPON;
524 /* mon_wield_item resets weapon_check as appropriate */
525 if (mon_wield_item(mtmp) != 0)
530 otmp = select_rwep(mtmp);
537 if (otmp != MON_WEP(mtmp))
538 return; /* polearm must be wielded */
539 if (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) > POLE_LIM
540 || !couldsee(mtmp->mx, mtmp->my))
541 return; /* Out of range, or intervening wall */
543 if (canseemon(mtmp)) {
545 pline("%s thrusts %s.", Monnam(mtmp),
546 obj_is_pname(otmp) ? the(onm) : an(onm));
549 dam = dmgval(otmp, &youmonst);
550 hitv = 3 - distmin(u.ux, u.uy, mtmp->mx, mtmp->my);
553 if (bigmonst(youmonst.data))
555 hitv += 8 + otmp->spe;
559 (void) thitu(hitv, dam, otmp, (char *) 0);
566 /* If you are coming toward the monster, the monster
567 * should try to soften you up with missiles. If you are
568 * going away, you are probably hurt or running. Give
569 * chase, but if you are getting too far away, throw.
572 || (URETREATING(x, y)
573 && rn2(BOLT_LIM - distmin(x, y, mtmp->mux, mtmp->muy))))
576 mwep = MON_WEP(mtmp); /* wielded weapon */
578 /* Multishot calculations */
580 if (otmp->quan > 1L /* no point checking if there's only 1 */
581 /* ammo requires corresponding launcher be wielded */
583 ? matching_launcher(otmp, mwep)
584 /* otherwise any stackable (non-ammo) weapon */
585 : otmp->oclass == WEAPON_CLASS)
587 int skill = (int) objects[otmp->otyp].oc_skill;
589 /* Assumes lords are skilled, princes are expert */
590 if (is_prince(mtmp->data))
592 else if (is_lord(mtmp->data))
594 /* fake players treated as skilled (regardless of role limits) */
595 else if (is_mplayer(mtmp->data))
599 switch (monsndx(mtmp->data)) {
601 if (skill == -P_SHURIKEN)
608 if (skill == P_DAGGER)
612 if (skill == -P_SHURIKEN || skill == -P_DART)
616 if (otmp->otyp == YA && mwep && mwep->otyp == YUMI)
623 if ((is_elf(mtmp->data) && otmp->otyp == ELVEN_ARROW && mwep
624 && mwep->otyp == ELVEN_BOW)
625 || (is_orc(mtmp->data) && otmp->otyp == ORCISH_ARROW && mwep
626 && mwep->otyp == ORCISH_BOW))
629 multishot = rnd(multishot);
630 if ((long) multishot > otmp->quan)
631 multishot = (int) otmp->quan;
634 if (canseemon(mtmp)) {
638 /* "N arrows"; multishot > 1 implies otmp->quan > 1, so
639 xname()'s result will already be pluralized */
640 Sprintf(onmbuf, "%d %s", multishot, xname(otmp));
644 onm = singular(otmp, xname);
645 onm = obj_is_pname(otmp) ? the(onm) : an(onm);
647 m_shot.s = ammo_and_launcher(otmp, mwep) ? TRUE : FALSE;
648 pline("%s %s %s!", Monnam(mtmp), m_shot.s ? "shoots" : "throws", onm);
649 m_shot.o = otmp->otyp;
651 m_shot.o = STRANGE_OBJECT; /* don't give multishot feedback */
654 m_shot.n = multishot;
655 for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) {
656 m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
657 distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy), otmp);
658 /* conceptually all N missiles are in flight at once, but
659 if mtmp gets killed (shot kills adjacent gas spore and
660 triggers explosion, perhaps), inventory will be dropped
661 and otmp might go away via merging into another stack */
662 if (mtmp->mhp <= 0 && m_shot.i < m_shot.n) {
663 /* cancel pending shots (ought to give a message here since
664 we gave one above about throwing/shooting N missiles) */
665 break; /* endmultishot(FALSE); */
668 m_shot.n = m_shot.i = 0;
669 m_shot.o = STRANGE_OBJECT;
675 /* monster spits substance at you */
679 struct attack *mattk;
685 pline("A dry rattle comes from %s throat.",
686 s_suffix(mon_nam(mtmp)));
689 if (lined_up(mtmp)) {
690 switch (mattk->adtyp) {
693 otmp = mksobj(BLINDING_VENOM, TRUE, FALSE);
696 impossible("bad attack type in spitmu");
699 otmp = mksobj(ACID_VENOM, TRUE, FALSE);
703 - distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy))) {
705 pline("%s spits venom!", Monnam(mtmp));
706 m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
707 distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy), otmp);
711 obj_extract_self(otmp);
712 obfree(otmp, (struct obj *) 0);
718 /* monster breathes at you (ranged) */
722 struct attack *mattk;
724 /* if new breath types are added, change AD_ACID to max type */
725 int typ = (mattk->adtyp == AD_RBRE) ? rnd(AD_ACID) : mattk->adtyp;
727 if (lined_up(mtmp)) {
731 pline("%s coughs.", Monnam(mtmp));
733 You_hear("a cough.");
737 if (!mtmp->mspec_used && rn2(3)) {
738 if ((typ >= AD_MAGM) && (typ <= AD_ACID)) {
740 pline("%s breathes %s!", Monnam(mtmp),
742 buzz((int) (-20 - (typ - 1)), (int) mattk->damn, mtmp->mx,
743 mtmp->my, sgn(tbx), sgn(tby));
745 /* breath runs out sometimes. Also, give monster some
746 * cunning; don't breath if the player fell asleep.
749 mtmp->mspec_used = 10 + rn2(20);
750 if (typ == AD_SLEE && !Sleep_resistance)
751 mtmp->mspec_used += rnd(20);
753 impossible("Breath weapon %d used", typ - 1);
760 linedup(ax, ay, bx, by, boulderhandling)
761 register xchar ax, ay, bx, by;
762 int boulderhandling; /* 0=block, 1=ignore, 2=conditionally block */
764 int dx, dy, boulderspots;
766 /* These two values are set for use after successful return. */
770 /* sometimes displacement makes a monster think that you're at its
771 own location; prevent it from throwing and zapping in that case */
775 if ((!tbx || !tby || abs(tbx) == abs(tby)) /* straight line or diagonal */
776 && distmin(tbx, tby, 0, 0) < BOLT_LIM) {
777 if ((ax == u.ux && ay == u.uy) ? (boolean) couldsee(bx, by)
778 : clear_path(ax, ay, bx, by))
780 /* don't have line of sight, but might still be lined up
781 if that lack of sight is due solely to boulders */
782 if (boulderhandling == 0)
784 dx = sgn(ax - bx), dy = sgn(ay - by);
787 /* <bx,by> is guaranteed to eventually converge with <ax,ay> */
789 if (IS_ROCK(levl[bx][by].typ) || closed_door(bx, by))
791 if (sobj_at(BOULDER, bx, by))
793 } while (bx != ax || by != ay);
794 /* reached target position without encountering obstacle */
795 if (boulderhandling == 1 || rn2(2 + boulderspots) < 2)
801 /* is mtmp in position to use ranged attack? */
804 register struct monst *mtmp;
806 boolean ignore_boulders;
808 /* hero concealment usually trumps monst awareness of being lined up */
809 if (Upolyd && rn2(25)
810 && (u.uundetected || (youmonst.m_ap_type != M_AP_NOTHING
811 && youmonst.m_ap_type != M_AP_MONSTER)))
814 ignore_boulders = (throws_rocks(mtmp->data)
815 || m_carrying(mtmp, WAN_STRIKING));
816 return linedup(mtmp->mux, mtmp->muy, mtmp->mx, mtmp->my,
817 ignore_boulders ? 1 : 2);
820 /* check if a monster is carrying a particular item */
822 m_carrying(mtmp, type)
826 register struct obj *otmp;
828 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
829 if (otmp->otyp == type)
831 return (struct obj *) 0;
834 /* TRUE iff thrown/kicked/rolled object doesn't pass through iron bars */
836 hits_bars(obj_p, x, y, always_hit, whodidit)
837 struct obj **obj_p; /* *obj_p will be set to NULL if object breaks */
839 int always_hit; /* caller can force a hit for items which would fit through */
840 int whodidit; /* 1==hero, 0=other, -1==just check whether it'll pass thru */
842 struct obj *otmp = *obj_p;
843 int obj_type = otmp->otyp;
844 boolean hits = always_hit;
847 switch (otmp->oclass) {
849 int oskill = objects[obj_type].oc_skill;
851 hits = (oskill != -P_BOW && oskill != -P_CROSSBOW
852 && oskill != -P_DART && oskill != -P_SHURIKEN
854 && oskill != P_KNIFE); /* but not dagger */
858 hits = (objects[obj_type].oc_armcat != ARM_GLOVES);
861 hits = (obj_type != SKELETON_KEY && obj_type != LOCK_PICK
862 && obj_type != CREDIT_CARD && obj_type != TALLOW_CANDLE
863 && obj_type != WAX_CANDLE && obj_type != LENSES
864 && obj_type != TIN_WHISTLE && obj_type != MAGIC_WHISTLE);
866 case ROCK_CLASS: /* includes boulder */
867 if (obj_type != STATUE || mons[otmp->corpsenm].msize > MZ_TINY)
871 if (obj_type == CORPSE && mons[otmp->corpsenm].msize > MZ_TINY)
874 hits = (obj_type == MEAT_STICK
875 || obj_type == HUGE_CHUNK_OF_MEAT);
887 if (hits && whodidit != -1) {
888 if (whodidit ? hero_breaks(otmp, x, y, FALSE) : breaks(otmp, x, y))
889 *obj_p = otmp = 0; /* object is now gone */
890 /* breakage makes its own noises */
891 else if (obj_type == BOULDER || obj_type == HEAVY_IRON_BALL)
893 else if (otmp->oclass == COIN_CLASS
894 || objects[obj_type].oc_material == GOLD
895 || objects[obj_type].oc_material == SILVER)