1 /* NetHack 3.6 uhitm.c $NHDT-Date: 1446887537 2015/11/07 09:12:17 $ $NHDT-Branch: master $:$NHDT-Revision: 1.151 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
7 STATIC_DCL boolean FDECL(known_hitum, (struct monst *, struct obj *, int *,
8 int, int, struct attack *));
9 STATIC_DCL boolean FDECL(theft_petrifies, (struct obj *));
10 STATIC_DCL void FDECL(steal_it, (struct monst *, struct attack *));
11 STATIC_DCL boolean FDECL(hitum, (struct monst *, struct attack *));
12 STATIC_DCL boolean FDECL(hmon_hitmon, (struct monst *, struct obj *, int));
13 STATIC_DCL int FDECL(joust, (struct monst *, struct obj *));
14 STATIC_DCL void NDECL(demonpet);
15 STATIC_DCL boolean FDECL(m_slips_free, (struct monst * mtmp,
16 struct attack *mattk));
17 STATIC_DCL int FDECL(explum, (struct monst *, struct attack *));
18 STATIC_DCL void FDECL(start_engulf, (struct monst *));
19 STATIC_DCL void NDECL(end_engulf);
20 STATIC_DCL int FDECL(gulpum, (struct monst *, struct attack *));
21 STATIC_DCL boolean FDECL(hmonas, (struct monst *));
22 STATIC_DCL void FDECL(nohandglow, (struct monst *));
23 STATIC_DCL boolean FDECL(shade_aware, (struct obj *));
25 extern boolean notonhead; /* for long worms */
26 /* The below might become a parameter instead if we use it a lot */
28 /* Used to flag attacks caused by Stormbringer's maliciousness. */
29 static boolean override_confirmation = FALSE;
31 #define PROJECTILE(obj) ((obj) && is_ammo(obj))
34 erode_armor(mdef, hurt)
40 /* What the following code does: it keeps looping until it
41 * finds a target for the rust monster.
42 * Head, feet, etc... not covered by metal, or covered by
43 * rusty metal, are not targets. However, your body always
44 * is, no matter what covers it.
49 target = which_armor(mdef, W_ARMH);
51 || erode_obj(target, xname(target), hurt, EF_GREASE)
56 target = which_armor(mdef, W_ARMC);
58 (void) erode_obj(target, xname(target), hurt,
59 EF_GREASE | EF_VERBOSE);
62 if ((target = which_armor(mdef, W_ARM)) != (struct obj *) 0) {
63 (void) erode_obj(target, xname(target), hurt,
64 EF_GREASE | EF_VERBOSE);
65 } else if ((target = which_armor(mdef, W_ARMU))
66 != (struct obj *) 0) {
67 (void) erode_obj(target, xname(target), hurt,
68 EF_GREASE | EF_VERBOSE);
72 target = which_armor(mdef, W_ARMS);
74 || erode_obj(target, xname(target), hurt, EF_GREASE)
79 target = which_armor(mdef, W_ARMG);
81 || erode_obj(target, xname(target), hurt, EF_GREASE)
86 target = which_armor(mdef, W_ARMF);
88 || erode_obj(target, xname(target), hurt, EF_GREASE)
93 break; /* Out of while loop */
97 /* FALSE means it's OK to attack */
99 attack_checks(mtmp, wep)
100 register struct monst *mtmp;
101 struct obj *wep; /* uwep for attack(), null for kick_monster() */
105 /* if you're close enough to attack, alert any waiting monster */
106 mtmp->mstrategy &= ~STRAT_WAITMASK;
108 if (u.uswallow && mtmp == u.ustuck)
111 if (context.forcefight) {
112 /* Do this in the caller, after we checked that the monster
113 * didn't die from the blow. Reason: putting the 'I' there
114 * causes the hero to forget the square's contents since
115 * both 'I' and remembered contents are stored in .glyph.
116 * If the monster dies immediately from the blow, the 'I' will
117 * not stay there, so the player will have suddenly forgotten
118 * the square's contents for no apparent reason.
119 if (!canspotmon(mtmp)
120 && !glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph))
121 map_invisible(bhitpos.x, bhitpos.y);
126 /* Put up an invisible monster marker, but with exceptions for
127 * monsters that hide and monsters you've been warned about.
128 * The former already prints a warning message and
129 * prevents you from hitting the monster just via the hidden monster
130 * code below; if we also did that here, similar behavior would be
131 * happening two turns in a row. The latter shows a glyph on
132 * the screen, so you know something is there.
134 if (!canspotmon(mtmp) && !glyph_is_warning(glyph_at(bhitpos.x, bhitpos.y))
135 && !glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph)
136 && !(!Blind && mtmp->mundetected && hides_under(mtmp->data))) {
137 pline("Wait! There's %s there you can't see!", something);
138 map_invisible(bhitpos.x, bhitpos.y);
139 /* if it was an invisible mimic, treat it as if we stumbled
140 * onto a visible mimic
142 if (mtmp->m_ap_type && !Protection_from_shape_changers
143 /* applied pole-arm attack is too far to get stuck */
144 && distu(mtmp->mx, mtmp->my) <= 2) {
145 if (!u.ustuck && !mtmp->mflee && dmgtype(mtmp->data, AD_STCK))
148 wakeup(mtmp); /* always necessary; also un-mimics mimics */
152 if (mtmp->m_ap_type && !Protection_from_shape_changers && !sensemon(mtmp)
153 && !glyph_is_warning(glyph_at(bhitpos.x, bhitpos.y))) {
154 /* If a hidden mimic was in a square where a player remembers
155 * some (probably different) unseen monster, the player is in
156 * luck--he attacks it even though it's hidden.
158 if (glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph)) {
162 stumble_onto_mimic(mtmp);
166 if (mtmp->mundetected && !canseemon(mtmp)
167 && !glyph_is_warning(glyph_at(bhitpos.x, bhitpos.y))
168 && (hides_under(mtmp->data) || mtmp->data->mlet == S_EEL)) {
169 mtmp->mundetected = mtmp->msleeping = 0;
170 newsym(mtmp->mx, mtmp->my);
171 if (glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph)) {
175 if (!((Blind ? Blind_telepat : Unblind_telepat) || Detect_monsters)) {
178 if (Blind || (is_pool(mtmp->mx, mtmp->my) && !Underwater))
179 pline("Wait! There's a hidden monster there!");
180 else if ((obj = level.objects[mtmp->mx][mtmp->my]) != 0)
181 pline("Wait! There's %s hiding under %s!",
182 an(l_monnam(mtmp)), doname(obj));
188 * make sure to wake up a monster from the above cases if the
189 * hero can sense that the monster is there.
191 if ((mtmp->mundetected || mtmp->m_ap_type) && sensemon(mtmp)) {
192 mtmp->mundetected = 0;
196 if (flags.confirm && mtmp->mpeaceful && !Confusion && !Hallucination
198 /* Intelligent chaotic weapons (Stormbringer) want blood */
199 if (wep && wep->oartifact == ART_STORMBRINGER) {
200 override_confirmation = TRUE;
203 if (canspotmon(mtmp)) {
204 Sprintf(qbuf, "Really attack %s?", mon_nam(mtmp));
205 if (!paranoid_query(ParanoidHit, qbuf)) {
216 * It is unchivalrous for a knight to attack the defenseless or from behind.
222 if (u.ualign.record <= -10)
225 if (Role_if(PM_KNIGHT) && u.ualign.type == A_LAWFUL
226 && (!mtmp->mcanmove || mtmp->msleeping
227 || (mtmp->mflee && !mtmp->mavenge))) {
230 } else if (Role_if(PM_SAMURAI) && mtmp->mpeaceful) {
231 /* attacking peaceful creatures is bad for the samurai's giri */
232 You("dishonorably attack the innocent!");
238 find_roll_to_hit(mtmp, aatyp, weapon, attk_count, role_roll_penalty)
239 register struct monst *mtmp;
240 uchar aatyp; /* usually AT_WEAP or AT_KICK */
241 struct obj *weapon; /* uwep or uswapwep or NULL */
242 int *attk_count, *role_roll_penalty;
246 *role_roll_penalty = 0; /* default is `none' */
248 tmp = 1 + Luck + abon() + find_mac(mtmp) + u.uhitinc
249 + maybe_polyd(youmonst.data->mlevel, u.ulevel);
251 /* some actions should occur only once during multiple attacks */
252 if (!(*attk_count)++) {
253 /* knight's chivalry or samurai's giri */
257 /* adjust vs. (and possibly modify) monster state */
263 if (mtmp->msleeping) {
267 if (!mtmp->mcanmove) {
275 /* role/race adjustments */
276 if (Role_if(PM_MONK) && !Upolyd) {
278 tmp -= (*role_roll_penalty = urole.spelarmr);
279 else if (!uwep && !uarms)
280 tmp += (u.ulevel / 3) + 2;
282 if (is_orc(mtmp->data)
283 && maybe_polyd(is_elf(youmonst.data), Race_if(PM_ELF)))
286 /* encumbrance: with a lot of luggage, your agility diminishes */
287 if ((tmp2 = near_capacity()) != 0)
288 tmp -= (tmp2 * 2) - 1;
293 * hitval applies if making a weapon attack while wielding a weapon;
294 * weapon_hit_bonus applies if doing a weapon attack even bare-handed
295 * or if kicking as martial artist
297 if (aatyp == AT_WEAP || aatyp == AT_CLAW) {
299 tmp += hitval(weapon, mtmp);
300 tmp += weapon_hit_bonus(weapon);
301 } else if (aatyp == AT_KICK && martial_bonus()) {
302 tmp += weapon_hit_bonus((struct obj *) 0);
308 /* try to attack; return False if monster evaded;
309 u.dx and u.dy must be set */
312 register struct monst *mtmp;
314 register struct permonst *mdat = mtmp->data;
316 /* This section of code provides protection against accidentally
317 * hitting peaceful (like '@') and tame (like 'd') monsters.
318 * Protection is provided as long as player is not: blind, confused,
319 * hallucinating or stunned.
320 * changes by wwp 5/16/85
321 * More changes 12/90, -dkh-. if its tame and safepet, (and protected
322 * 07/92) then we assume that you're not trying to attack. Instead,
323 * you'll usually just swap places if this is a movement command
325 /* Intelligent chaotic weapons (Stormbringer) want blood */
326 if (is_safepet(mtmp) && !context.forcefight) {
327 if (!uwep || uwep->oartifact != ART_STORMBRINGER) {
328 /* there are some additional considerations: this won't work
329 * if in a shop or Punished or you miss a random roll or
330 * if you can walk thru walls and your pet cannot (KAA) or
331 * if your pet is a long worm (unless someone does better).
332 * there's also a chance of displacing a "frozen" monster.
333 * sleeping monsters might magically walk in their sleep.
335 boolean foo = (Punished || !rn2(7) || is_longworm(mtmp->data)),
339 for (p = in_rooms(mtmp->mx, mtmp->my, SHOPBASE); *p; p++)
340 if (tended_shop(&rooms[*p - ROOMOFFSET])) {
345 if (inshop || foo || (IS_ROCK(levl[u.ux][u.uy].typ)
346 && !passes_walls(mtmp->data))) {
349 monflee(mtmp, rnd(6), FALSE, FALSE);
350 Strcpy(buf, y_monnam(mtmp));
351 buf[0] = highc(buf[0]);
352 You("stop. %s is in the way!", buf);
354 } else if ((mtmp->mfrozen || (!mtmp->mcanmove)
355 || (mtmp->data->mmove == 0)) && rn2(6)) {
356 pline("%s doesn't seem to move!", Monnam(mtmp));
363 /* possibly set in attack_checks;
364 examined in known_hitum, called via hitum or hmonas below */
365 override_confirmation = FALSE;
366 /* attack_checks() used to use <u.ux+u.dx,u.uy+u.dy> directly, now
367 it uses bhitpos instead; it might map an invisible monster there */
368 bhitpos.x = u.ux + u.dx;
369 bhitpos.y = u.uy + u.dy;
370 if (attack_checks(mtmp, uwep))
373 if (Upolyd && noattacks(youmonst.data)) {
374 /* certain "pacifist" monsters don't attack */
375 You("have no way to attack monsters physically.");
376 mtmp->mstrategy &= ~STRAT_WAITMASK;
380 if (check_capacity("You cannot fight while so heavily loaded.")
381 /* consume extra nutrition during combat; maybe pass out */
385 if (u.twoweap && !can_twoweapon())
392 You("begin bashing monsters with %s.",
393 yobjnam(uwep, (char *) 0));
394 else if (!cantwield(youmonst.data))
395 You("begin %sing monsters with your %s %s.",
396 Role_if(PM_MONK) ? "strik" : "bash",
397 uarmg ? "gloved" : "bare", /* Del Lamb */
398 makeplural(body_part(HAND)));
401 exercise(A_STR, TRUE); /* you're exercising muscles */
402 /* andrew@orca: prevent unlimited pick-axe attacks */
405 /* Is the "it died" check actually correct? */
406 if (mdat->mlet == S_LEPRECHAUN && !mtmp->mfrozen && !mtmp->msleeping
407 && !mtmp->mconf && mtmp->mcansee && !rn2(7)
408 && (m_move(mtmp, 0) == 2 /* it died */
409 || mtmp->mx != u.ux + u.dx
410 || mtmp->my != u.uy + u.dy)) /* it moved */
416 (void) hitum(mtmp, youmonst.data->mattk);
417 mtmp->mstrategy &= ~STRAT_WAITMASK;
420 /* see comment in attack_checks() */
421 /* we only need to check for this if we did an attack_checks()
422 * and it returned 0 (it's okay to attack), and the monster didn't
425 if (context.forcefight && mtmp->mhp > 0 && !canspotmon(mtmp)
426 && !glyph_is_invisible(levl[u.ux + u.dx][u.uy + u.dy].glyph)
427 && !(u.uswallow && mtmp == u.ustuck))
428 map_invisible(u.ux + u.dx, u.uy + u.dy);
433 /* really hit target monster; returns TRUE if it still lives */
435 known_hitum(mon, weapon, mhit, rollneeded, armorpenalty, uattk)
436 register struct monst *mon;
439 int rollneeded, armorpenalty; /* for monks */
440 struct attack *uattk;
442 register boolean malive = TRUE;
444 if (override_confirmation) {
445 /* this may need to be generalized if weapons other than
446 Stormbringer acquire similar anti-social behavior... */
448 Your("bloodthirsty blade attacks!");
452 missum(mon, uattk, (rollneeded + armorpenalty > dieroll));
454 int oldhp = mon->mhp, x = u.ux + u.dx, y = u.uy + u.dy;
455 long oldweaphit = u.uconduct.weaphit;
458 if (weapon && (weapon->oclass == WEAPON_CLASS || is_weptool(weapon)))
459 u.uconduct.weaphit++;
461 /* we hit the monster; be careful: it might die or
462 be knocked into a different location */
463 notonhead = (mon->mx != x || mon->my != y);
464 malive = hmon(mon, weapon, HMON_MELEE);
466 /* monster still alive */
467 if (!rn2(25) && mon->mhp < mon->mhpmax / 2
468 && !(u.uswallow && mon == u.ustuck)) {
469 /* maybe should regurgitate if swallowed? */
470 monflee(mon, !rn2(3) ? rnd(100) : 0, FALSE, TRUE);
472 if (u.ustuck == mon && !u.uswallow && !sticks(youmonst.data))
475 /* Vorpal Blade hit converted to miss */
476 /* could be headless monster or worm tail */
477 if (mon->mhp == oldhp) {
479 /* a miss does not break conduct */
480 u.uconduct.weaphit = oldweaphit;
482 if (mon->wormno && *mhit)
483 cutworm(mon, x, y, weapon);
489 /* hit target monster; returns TRUE if it still lives */
493 struct attack *uattk;
495 boolean malive, wep_was_destroyed = FALSE;
496 struct obj *wepbefore = uwep;
497 int armorpenalty, attknum = 0, x = u.ux + u.dx, y = u.uy + u.dy,
498 tmp = find_roll_to_hit(mon, uattk->aatyp, uwep,
499 &attknum, &armorpenalty);
500 int mhit = (tmp > (dieroll = rnd(20)) || u.uswallow);
503 exercise(A_DEX, TRUE);
504 malive = known_hitum(mon, uwep, &mhit, tmp, armorpenalty, uattk);
505 /* second attack for two-weapon combat; won't occur if Stormbringer
506 overrode confirmation (assumes Stormbringer is primary weapon)
507 or if the monster was killed or knocked to different location */
508 if (u.twoweap && !override_confirmation && malive && m_at(x, y) == mon) {
509 tmp = find_roll_to_hit(mon, uattk->aatyp, uswapwep, &attknum,
511 mhit = (tmp > (dieroll = rnd(20)) || u.uswallow);
512 malive = known_hitum(mon, uswapwep, &mhit, tmp, armorpenalty, uattk);
514 if (wepbefore && !uwep)
515 wep_was_destroyed = TRUE;
516 (void) passive(mon, mhit, malive, AT_WEAP, wep_was_destroyed);
520 /* general "damage monster" routine; return True if mon still alive */
522 hmon(mon, obj, thrown)
525 int thrown; /* HMON_xxx (0 => hand-to-hand, other => ranged) */
527 boolean result, anger_guards;
529 anger_guards = (mon->mpeaceful
530 && (mon->ispriest || mon->isshk || is_watch(mon->data)));
531 result = hmon_hitmon(mon, obj, thrown);
532 if (mon->ispriest && !rn2(2))
535 (void) angry_guards(!!Deaf);
541 hmon_hitmon(mon, obj, thrown)
544 int thrown; /* HMON_xxx (0 => hand-to-hand, other => ranged) */
547 struct permonst *mdat = mon->data;
548 int barehand_silver_rings = 0;
549 /* The basic reason we need all these booleans is that we don't want
550 * a "hit" message when a monster dies, so we have to know how much
551 * damage it did _before_ outputting a hit message, but any messages
552 * associated with the damage don't come out until _after_ outputting
555 boolean hittxt = FALSE, destroyed = FALSE, already_killed = FALSE;
556 boolean get_dmg_bonus = TRUE;
557 boolean ispoisoned = FALSE, needpoismsg = FALSE, poiskilled = FALSE,
559 boolean silvermsg = FALSE, silverobj = FALSE;
560 boolean valid_weapon_attack = FALSE;
561 boolean unarmed = !uwep && !uarm && !uarms;
562 boolean hand_to_hand = (thrown == HMON_MELEE
563 /* not grapnels; applied implies uwep */
564 || (thrown == HMON_APPLIED && is_pole(uwep)));
568 char unconventional[BUFSZ]; /* substituted for word "attack" in msg */
569 char saved_oname[BUFSZ];
571 unconventional[0] = '\0';
572 saved_oname[0] = '\0';
575 if (!obj) { /* attack with bare hands */
576 if (mdat == &mons[PM_SHADE])
578 else if (martial_bonus())
579 tmp = rnd(4); /* bonus for martial arts */
582 valid_weapon_attack = (tmp > 1);
583 /* blessed gloves give bonuses when fighting 'bare-handed' */
584 if (uarmg && uarmg->blessed
585 && (is_undead(mdat) || is_demon(mdat) || is_vampshifter(mon)))
587 /* So do silver rings. Note: rings are worn under gloves, so you
588 * don't get both bonuses.
591 if (uleft && objects[uleft->otyp].oc_material == SILVER)
592 barehand_silver_rings++;
593 if (uright && objects[uright->otyp].oc_material == SILVER)
594 barehand_silver_rings++;
595 if (barehand_silver_rings && mon_hates_silver(mon)) {
601 Strcpy(saved_oname, cxname(obj));
602 if (obj->oclass == WEAPON_CLASS || is_weptool(obj)
603 || obj->oclass == GEM_CLASS) {
604 /* is it not a melee weapon? */
605 if (/* if you strike with a bow... */
607 /* or strike with a missile in your hand... */
608 || (!thrown && (is_missile(obj) || is_ammo(obj)))
609 /* or use a pole at short range and not mounted... */
610 || (!thrown && !u.usteed && is_pole(obj))
611 /* or throw a missile without the proper bow... */
612 || (is_ammo(obj) && (thrown != HMON_THROWN
613 || !ammo_and_launcher(obj, uwep)))) {
614 /* then do only 1-2 points of damage */
615 if (mdat == &mons[PM_SHADE] && !shade_glare(obj))
619 if (objects[obj->otyp].oc_material == SILVER
620 && mon_hates_silver(mon)) {
623 /* if it will already inflict dmg, make it worse */
624 tmp += rnd((tmp) ? 20 : 10);
626 if (!thrown && obj == uwep && obj->otyp == BOOMERANG
627 && rnl(4) == 4 - 1) {
628 boolean more_than_1 = (obj->quan > 1L);
630 pline("As you hit %s, %s%s breaks into splinters.",
631 mon_nam(mon), more_than_1 ? "one of " : "",
634 uwepgone(); /* set unweapon */
637 obj = (struct obj *) 0;
639 if (mdat != &mons[PM_SHADE])
643 tmp = dmgval(obj, mon);
644 /* a minimal hit doesn't exercise proficiency */
645 valid_weapon_attack = (tmp > 1);
646 if (!valid_weapon_attack || mon == u.ustuck || u.twoweap) {
647 ; /* no special bonuses */
648 } else if (mon->mflee && Role_if(PM_ROGUE) && !Upolyd
649 /* multi-shot throwing is too powerful here */
651 You("strike %s from behind!", mon_nam(mon));
652 tmp += rnd(u.ulevel);
654 } else if (dieroll == 2 && obj == uwep
655 && obj->oclass == WEAPON_CLASS
657 || (Role_if(PM_SAMURAI) && obj->otyp == KATANA
659 && ((wtype = uwep_skill_type()) != P_NONE
660 && P_SKILL(wtype) >= P_SKILLED)
661 && ((monwep = MON_WEP(mon)) != 0
662 && !is_flimsy(monwep)
664 monwep, 50 + 15 * greatest_erosion(obj),
667 * 2.5% chance of shattering defender's weapon when
668 * using a two-handed weapon; less if uwep is rusted.
669 * [dieroll == 2 is most successful non-beheading or
670 * -bisecting hit, in case of special artifact damage;
671 * the percentage chance is (1/20)*(50/100).]
673 setmnotwielded(mon, monwep);
674 mon->weapon_check = NEED_WEAPON;
675 pline("%s from the force of your blow!",
676 Yobjnam2(monwep, "shatter"));
677 m_useupall(mon, monwep);
678 /* If someone just shattered MY weapon, I'd flee! */
680 monflee(mon, d(2, 3), TRUE, TRUE);
686 && artifact_hit(&youmonst, mon, obj, &tmp, dieroll)) {
687 if (mon->mhp <= 0) /* artifact killed monster */
693 if (objects[obj->otyp].oc_material == SILVER
694 && mon_hates_silver(mon)) {
698 if (u.usteed && !thrown && tmp > 0
699 && weapon_type(obj) == P_LANCE && mon != u.ustuck) {
700 jousting = joust(mon, obj);
701 /* exercise skill even for minimal damage hits */
703 valid_weapon_attack = TRUE;
705 if (thrown == HMON_THROWN
706 && (is_ammo(obj) || is_missile(obj))) {
707 if (ammo_and_launcher(obj, uwep)) {
708 /* Elves and Samurai do extra damage using
709 * their bows&arrows; they're highly trained.
711 if (Role_if(PM_SAMURAI) && obj->otyp == YA
712 && uwep->otyp == YUMI)
714 else if (Race_if(PM_ELF) && obj->otyp == ELVEN_ARROW
715 && uwep->otyp == ELVEN_BOW)
718 if (obj->opoisoned && is_poisonable(obj))
722 } else if (obj->oclass == POTION_CLASS) {
724 obj = splitobj(obj, 1L);
726 setuwep((struct obj *) 0);
728 potionhit(mon, obj, TRUE);
730 return FALSE; /* killed */
732 /* in case potion effect causes transformation */
734 tmp = (mdat == &mons[PM_SHADE]) ? 0 : 1;
736 if (mdat == &mons[PM_SHADE] && !shade_aware(obj)) {
738 Strcpy(unconventional, cxname(obj));
741 case BOULDER: /* 1d20 */
742 case HEAVY_IRON_BALL: /* 1d25 */
743 case IRON_CHAIN: /* 1d4+1 */
744 tmp = dmgval(obj, mon);
747 if (breaktest(obj)) {
748 You("break %s. That's bad luck!", ysimple_name(obj));
751 obj = (struct obj *) 0;
752 unarmed = FALSE; /* avoid obj==0 confusion */
753 get_dmg_bonus = FALSE;
758 case EXPENSIVE_CAMERA:
759 You("succeed in destroying %s. Congratulations!",
761 release_camera_demon(obj, u.ux, u.uy);
764 case CORPSE: /* fixed by polder@cs.vu.nl */
765 if (touch_petrifies(&mons[obj->corpsenm])) {
768 You("hit %s with %s.", mon_nam(mon),
769 corpse_xname(obj, (const char *) 0,
770 obj->dknown ? CXN_PFX_THE
773 if (!munstone(mon, TRUE))
774 minstapetrify(mon, TRUE);
775 if (resists_ston(mon))
777 /* note: hp may be <= 0 even if munstoned==TRUE */
778 return (boolean) (mon->mhp > 0);
780 } else if (touch_petrifies(mdat)) {
781 ; /* maybe turn the corpse into a statue? */
784 tmp = (obj->corpsenm >= LOW_PM ? mons[obj->corpsenm].msize
788 #define useup_eggs(o) \
791 obfree(o, (struct obj *) 0); \
794 o = (struct obj *) 0; \
797 long cnt = obj->quan;
799 tmp = 1; /* nominal physical damage */
800 get_dmg_bonus = FALSE;
801 hittxt = TRUE; /* message always given */
802 /* egg is always either used up or transformed, so next
803 hand-to-hand attack should yield a "bashing" mesg */
806 if (obj->spe && obj->corpsenm >= LOW_PM) {
808 change_luck((schar) - (obj->quan));
813 if (touch_petrifies(&mons[obj->corpsenm])) {
814 /*learn_egg_type(obj->corpsenm);*/
815 pline("Splat! You hit %s with %s %s egg%s!",
817 obj->known ? "the" : cnt > 1L ? "some" : "a",
818 obj->known ? mons[obj->corpsenm].mname
821 obj->known = 1; /* (not much point...) */
823 if (!munstone(mon, TRUE))
824 minstapetrify(mon, TRUE);
825 if (resists_ston(mon))
827 return (boolean) (mon->mhp > 0);
828 } else { /* ordinary egg(s) */
830 (obj->corpsenm != NON_PM && obj->known)
831 ? the(mons[obj->corpsenm].mname)
832 : (cnt > 1L) ? "some" : "an";
833 You("hit %s with %s egg%s.", mon_nam(mon), eggp,
835 if (touch_petrifies(mdat) && !stale_egg(obj)) {
836 pline_The("egg%s %s alive any more...", plur(cnt),
837 (cnt == 1L) ? "isn't" : "aren't");
839 obj_stop_timers(obj);
841 obj->oclass = GEM_CLASS;
844 obj->known = obj->dknown = obj->bknown = 0;
845 obj->owt = weight(obj);
847 place_object(obj, mon->mx, mon->my);
851 exercise(A_WIS, FALSE);
857 case CLOVE_OF_GARLIC: /* no effect against demons */
858 if (is_undead(mdat) || is_vampshifter(mon)) {
859 monflee(mon, d(2, 4), FALSE, TRUE);
866 if (can_blnd(&youmonst, mon,
867 (uchar) (obj->otyp == BLINDING_VENOM
872 pline(obj->otyp == CREAM_PIE ? "Splat!"
874 } else if (obj->otyp == BLINDING_VENOM) {
875 pline_The("venom blinds %s%s!", mon_nam(mon),
876 mon->mcansee ? "" : " further");
878 char *whom = mon_nam(mon);
879 char *what = The(xname(obj));
881 if (!thrown && obj->quan > 1L)
882 what = An(singular(obj, xname));
883 /* note: s_suffix returns a modifiable buffer */
885 && mdat != &mons[PM_FLOATING_EYE])
886 whom = strcat(strcat(s_suffix(whom), " "),
887 mbodypart(mon, FACE));
888 pline("%s %s over %s!", what,
889 vtense(what, "splash"), whom);
894 if (((int) mon->mblinded + tmp) > 127)
897 mon->mblinded += tmp;
899 pline(obj->otyp == CREAM_PIE ? "Splat!" : "Splash!");
903 obfree(obj, (struct obj *) 0);
907 get_dmg_bonus = FALSE;
910 case ACID_VENOM: /* thrown (or spit) */
911 if (resists_acid(mon)) {
912 Your("venom hits %s harmlessly.", mon_nam(mon));
915 Your("venom burns %s!", mon_nam(mon));
916 tmp = dmgval(obj, mon);
919 obfree(obj, (struct obj *) 0);
923 get_dmg_bonus = FALSE;
926 /* non-weapons can damage because of their weight */
927 /* (but not too much) */
928 tmp = obj->owt / 100;
929 if (is_wet_towel(obj)) {
930 /* wielded wet towel should probably use whip skill
931 (but not by setting objects[TOWEL].oc_skill==P_WHIP
932 because that would turn towel into a weptool) */
934 if (rn2(obj->spe + 1)) /* usually lose some wetness */
935 dry_a_towel(obj, -1, TRUE);
944 * Things like silver wands can arrive here so
945 * so we need another silver check.
947 if (objects[obj->otyp].oc_material == SILVER
948 && mon_hates_silver(mon)) {
958 /****** NOTE: perhaps obj is undefined!! (if !thrown && BOOMERANG)
959 * *OR* if attacking bare-handed!! */
961 if (get_dmg_bonus && tmp > 0) {
963 /* If you throw using a propellor, you don't get a strength
964 * bonus but you do get an increase-damage bonus.
966 if (thrown != HMON_THROWN || !obj || !uwep
967 || !ammo_and_launcher(obj, uwep))
971 if (valid_weapon_attack) {
974 /* to be valid a projectile must have had the correct projector */
975 wep = PROJECTILE(obj) ? uwep : obj;
976 tmp += weapon_dam_bonus(wep);
977 /* [this assumes that `!thrown' implies wielded...] */
978 wtype = thrown ? weapon_type(wep) : uwep_skill_type();
983 int nopoison = (10 - (obj->owt / 10));
987 if (Role_if(PM_SAMURAI)) {
988 You("dishonorably use a poisoned weapon!");
989 adjalign(-sgn(u.ualign.type));
990 } else if (u.ualign.type == A_LAWFUL && u.ualign.record > -10) {
991 You_feel("like an evil coward for using a poisoned weapon.");
994 if (obj && !rn2(nopoison)) {
995 /* remove poison now in case obj ends up in a bones file */
996 obj->opoisoned = FALSE;
997 /* defer "obj is no longer poisoned" until after hit message */
1000 if (resists_poison(mon))
1008 /* make sure that negative damage adjustment can't result
1009 in inadvertently boosting the victim's hit points */
1011 if (mdat == &mons[PM_SHADE]) {
1013 const char *what = *unconventional ? unconventional : "attack";
1015 Your("%s %s harmlessly through %s.", what,
1016 vtense(what, "pass"), mon_nam(mon));
1026 tmp += d(2, (obj == uwep) ? 10 : 2); /* [was in dmgval()] */
1027 You("joust %s%s", mon_nam(mon), canseemon(mon) ? exclam(tmp) : ".");
1029 pline("%s shatters on impact!", Yname2(obj));
1030 /* (must be either primary or secondary weapon to get here) */
1031 u.twoweap = FALSE; /* untwoweapon() is too verbose here */
1033 uwepgone(); /* set unweapon */
1034 /* minor side-effect: broken lance won't split puddings */
1038 /* avoid migrating a dead monster */
1039 if (mon->mhp > tmp) {
1040 mhurtle(mon, u.dx, u.dy, 1);
1041 mdat = mon->data; /* in case of a polymorph trap */
1042 if (DEADMONSTER(mon))
1043 already_killed = TRUE;
1046 } else if (unarmed && tmp > 1 && !thrown && !obj && !Upolyd) {
1047 /* VERY small chance of stunning opponent if unarmed. */
1048 if (rnd(100) < P_SKILL(P_BARE_HANDED_COMBAT) && !bigmonst(mdat)
1049 && !thick_skinned(mdat)) {
1050 if (canspotmon(mon))
1051 pline("%s %s from your powerful strike!", Monnam(mon),
1052 makeplural(stagger(mon->data, "stagger")));
1053 /* avoid migrating a dead monster */
1054 if (mon->mhp > tmp) {
1055 mhurtle(mon, u.dx, u.dy, 1);
1056 mdat = mon->data; /* in case of a polymorph trap */
1057 if (DEADMONSTER(mon))
1058 already_killed = TRUE;
1064 if (!already_killed)
1066 /* adjustments might have made tmp become less than what
1067 a level draining artifact has already done to max HP */
1068 if (mon->mhp > mon->mhpmax)
1069 mon->mhp = mon->mhpmax;
1072 if (mon->mtame && tmp > 0) {
1073 /* do this even if the pet is being killed (affects revival) */
1074 abuse_dog(mon); /* reduces tameness */
1075 /* flee if still alive and still tame; if already suffering from
1076 untimed fleeing, no effect, otherwise increases timed fleeing */
1077 if (mon->mtame && !destroyed)
1078 monflee(mon, 10 * rnd(tmp), FALSE, FALSE);
1080 if ((mdat == &mons[PM_BLACK_PUDDING] || mdat == &mons[PM_BROWN_PUDDING])
1081 /* pudding is alive and healthy enough to split */
1082 && mon->mhp > 1 && !mon->mcan
1083 /* iron weapon using melee or polearm hit */
1084 && obj && obj == uwep && objects[obj->otyp].oc_material == IRON
1086 if (clone_mon(mon, 0, 0)) {
1087 pline("%s divides as you hit it!", Monnam(mon));
1092 if (!hittxt /*( thrown => obj exists )*/
1094 || (thrown && m_shot.n > 1 && m_shot.o == obj->otyp))) {
1096 hit(mshot_xname(obj), mon, exclam(tmp));
1097 else if (!flags.verbose)
1100 You("%s %s%s", Role_if(PM_BARBARIAN) ? "smite" : "hit",
1101 mon_nam(mon), canseemon(mon) ? exclam(tmp) : ".");
1106 char *whom = mon_nam(mon);
1107 char silverobjbuf[BUFSZ];
1109 if (canspotmon(mon)) {
1110 if (barehand_silver_rings == 1)
1111 fmt = "Your silver ring sears %s!";
1112 else if (barehand_silver_rings == 2)
1113 fmt = "Your silver rings sear %s!";
1114 else if (silverobj && saved_oname[0]) {
1115 Sprintf(silverobjbuf, "Your %s%s %s %%s!",
1116 strstri(saved_oname, "silver") ? "" : "silver ",
1117 saved_oname, vtense(saved_oname, "sear"));
1120 fmt = "The silver sears %s!";
1122 *whom = highc(*whom); /* "it" -> "It" */
1123 fmt = "%s is seared!";
1125 /* note: s_suffix returns a modifiable buffer */
1126 if (!noncorporeal(mdat) && !amorphous(mdat))
1127 whom = strcat(s_suffix(whom), " flesh");
1130 /* if a "no longer poisoned" message is coming, it will be last;
1131 obj->opoisoned was cleared above and any message referring to
1132 "poisoned <obj>" has now been given; we want just "<obj>" for
1133 last message, so reformat while obj is still accessible */
1135 Strcpy(saved_oname, cxname(obj));
1137 /* [note: thrown obj might go away during killed/xkilled call] */
1140 pline_The("poison doesn't seem to affect %s.", mon_nam(mon));
1142 pline_The("poison was deadly...");
1143 if (!already_killed)
1145 destroyed = TRUE; /* return FALSE; */
1146 } else if (destroyed) {
1147 if (!already_killed)
1148 killed(mon); /* takes care of most messages */
1149 } else if (u.umconf && hand_to_hand) {
1151 if (!mon->mconf && !resist(mon, SPBOOK_CLASS, 0, NOTELL)) {
1153 if (!mon->mstun && mon->mcanmove && !mon->msleeping
1155 pline("%s appears confused.", Monnam(mon));
1159 Your("%s %s no longer poisoned.", saved_oname,
1160 vtense(saved_oname, "are"));
1162 return destroyed ? FALSE : TRUE;
1172 * The things in this list either
1175 * 2) are dealt with properly by other routines
1176 * when it comes to shades.
1178 if (obj->otyp == BOULDER
1179 || obj->otyp == HEAVY_IRON_BALL
1180 || obj->otyp == IRON_CHAIN /* dmgval handles those first three */
1181 || obj->otyp == MIRROR /* silver in the reflective surface */
1182 || obj->otyp == CLOVE_OF_GARLIC /* causes shades to flee */
1183 || objects[obj->otyp].oc_material == SILVER)
1188 /* check whether slippery clothing protects from hug or wrap attack */
1189 /* [currently assumes that you are the attacker] */
1191 m_slips_free(mdef, mattk)
1193 struct attack *mattk;
1197 if (mattk->adtyp == AD_DRIN) {
1198 /* intelligence drain attacks the head */
1199 obj = which_armor(mdef, W_ARMH);
1201 /* grabbing attacks the body */
1202 obj = which_armor(mdef, W_ARMC); /* cloak */
1204 obj = which_armor(mdef, W_ARM); /* suit */
1206 obj = which_armor(mdef, W_ARMU); /* shirt */
1209 /* if monster's cloak/armor is greased, your grab slips off; this
1210 protection might fail (33% chance) when the armor is cursed */
1211 if (obj && (obj->greased || obj->otyp == OILSKIN_CLOAK)
1212 && (!obj->cursed || rn2(3))) {
1214 mattk->adtyp == AD_WRAP ? "slip off of"
1215 : "grab, but cannot hold onto",
1216 s_suffix(mon_nam(mdef)), obj->greased ? "greased" : "slippery",
1217 /* avoid "slippery slippery cloak"
1218 for undiscovered oilskin cloak */
1219 (obj->greased || objects[obj->otyp].oc_name_known)
1221 : cloak_simple_name(obj));
1223 if (obj->greased && !rn2(2)) {
1224 pline_The("grease wears off.");
1232 /* used when hitting a monster with a lance while mounted;
1233 1: joust hit; 0: ordinary hit; -1: joust but break lance */
1236 struct monst *mon; /* target */
1237 struct obj *obj; /* weapon */
1239 int skill_rating, joust_dieroll;
1241 if (Fumbling || Stunned)
1243 /* sanity check; lance must be wielded in order to joust */
1244 if (obj != uwep && (obj != uswapwep || !u.twoweap))
1247 /* if using two weapons, use worse of lance and two-weapon skills */
1248 skill_rating = P_SKILL(weapon_type(obj)); /* lance skill */
1249 if (u.twoweap && P_SKILL(P_TWO_WEAPON_COMBAT) < skill_rating)
1250 skill_rating = P_SKILL(P_TWO_WEAPON_COMBAT);
1251 if (skill_rating == P_ISRESTRICTED)
1252 skill_rating = P_UNSKILLED; /* 0=>1 */
1254 /* odds to joust are expert:80%, skilled:60%, basic:40%, unskilled:20% */
1255 if ((joust_dieroll = rn2(5)) < skill_rating) {
1256 if (joust_dieroll == 0 && rnl(50) == (50 - 1) && !unsolid(mon->data)
1257 && !obj_resists(obj, 0, 100))
1258 return -1; /* hit that breaks lance */
1259 return 1; /* successful joust */
1261 return 0; /* no joust bonus; revert to ordinary attack */
1265 * Send in a demon pet for the hero. Exercise wisdom.
1267 * This function used to be inline to damageum(), but the Metrowerks compiler
1268 * (DR4 and DR4.5) screws up with an internal error 5 "Expression Too
1270 * Pulling it out makes it work.
1276 struct permonst *pm;
1279 pline("Some hell-p has arrived!");
1280 i = !rn2(6) ? ndemon(u.ualign.type) : NON_PM;
1281 pm = i != NON_PM ? &mons[i] : youmonst.data;
1282 if ((dtmp = makemon(pm, u.ux, u.uy, NO_MM_FLAGS)) != 0)
1283 (void) tamedog(dtmp, (struct obj *) 0);
1284 exercise(A_WIS, TRUE);
1288 theft_petrifies(otmp)
1291 if (uarmg || otmp->otyp != CORPSE
1292 || !touch_petrifies(&mons[otmp->corpsenm]) || Stone_resistance)
1295 #if 0 /* no poly_when_stoned() critter has theft capability */
1296 if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) {
1297 display_nhwindow(WIN_MESSAGE, FALSE); /* --More-- */
1302 /* stealing this corpse is fatal... */
1303 instapetrify(corpse_xname(otmp, "stolen", CXN_ARTICLE));
1304 /* apparently wasn't fatal after all... */
1309 * Player uses theft attack against monster.
1311 * If the target is wearing body armor, take all of its possessions;
1312 * otherwise, take one object. [Is this really the behavior we want?]
1315 steal_it(mdef, mattk)
1317 struct attack *mattk;
1319 struct obj *otmp, *stealoid, **minvent_ptr;
1323 return; /* nothing to take */
1325 /* look for worn body armor */
1326 stealoid = (struct obj *) 0;
1327 if (could_seduce(&youmonst, mdef, mattk)) {
1328 /* find armor, and move it to end of inventory in the process */
1329 minvent_ptr = &mdef->minvent;
1330 while ((otmp = *minvent_ptr) != 0)
1331 if (otmp->owornmask & W_ARM) {
1333 panic("steal_it: multiple worn suits");
1334 *minvent_ptr = otmp->nobj; /* take armor out of minvent */
1336 stealoid->nobj = (struct obj *) 0;
1338 minvent_ptr = &otmp->nobj;
1340 *minvent_ptr = stealoid; /* put armor back into minvent */
1343 if (stealoid) { /* we will be taking everything */
1344 if (gender(mdef) == (int) u.mfemale && youmonst.data->mlet == S_NYMPH)
1345 You("charm %s. She gladly hands over her possessions.",
1348 You("seduce %s and %s starts to take off %s clothes.",
1349 mon_nam(mdef), mhe(mdef), mhis(mdef));
1352 while ((otmp = mdef->minvent) != 0) {
1354 break; /* no longer have ability to steal */
1355 /* take the object away from the monster */
1356 obj_extract_self(otmp);
1357 if ((unwornmask = otmp->owornmask) != 0L) {
1358 mdef->misc_worn_check &= ~unwornmask;
1359 if (otmp->owornmask & W_WEP)
1360 setmnotwielded(mdef, otmp);
1361 otmp->owornmask = 0L;
1362 update_mon_intrinsics(mdef, otmp, FALSE, FALSE);
1364 if (otmp == stealoid) /* special message for final item */
1365 pline("%s finishes taking off %s suit.", Monnam(mdef),
1368 /* give the object to the character */
1369 otmp = hold_another_object(otmp, "You snatched but dropped %s.",
1370 doname(otmp), "You steal: ");
1371 if (otmp->where != OBJ_INVENT)
1373 if (theft_petrifies(otmp))
1374 break; /* stop thieving even though hero survived */
1375 /* more take-away handling, after theft message */
1376 if (unwornmask & W_WEP) { /* stole wielded weapon */
1377 possibly_unwield(mdef, FALSE);
1378 } else if (unwornmask & W_ARMG) { /* stole worn gloves */
1379 mselftouch(mdef, (const char *) 0, TRUE);
1380 if (mdef->mhp <= 0) /* it's now a statue */
1381 return; /* can't continue stealing */
1385 break; /* only taking one item */
1390 damageum(mdef, mattk)
1391 register struct monst *mdef;
1392 register struct attack *mattk;
1394 register struct permonst *pd = mdef->data;
1395 int armpro, tmp = d((int) mattk->damn, (int) mattk->damd);
1398 armpro = magic_negation(mdef);
1399 /* since hero can't be cancelled, only defender's armor applies */
1400 negated = !(rn2(10) >= 3 * armpro);
1402 if (is_demon(youmonst.data) && !rn2(13) && !uwep
1403 && u.umonnum != PM_SUCCUBUS && u.umonnum != PM_INCUBUS
1404 && u.umonnum != PM_BALROG) {
1408 switch (mattk->adtyp) {
1411 pline("%s %s for a moment.", Monnam(mdef),
1412 makeplural(stagger(pd, "stagger")));
1423 case AD_WERE: /* no special effect on monsters */
1424 case AD_HEAL: /* likewise */
1427 if (mattk->aatyp == AT_WEAP) {
1430 } else if (mattk->aatyp == AT_KICK) {
1431 if (thick_skinned(pd))
1433 if (pd == &mons[PM_SHADE]) {
1434 if (!(uarmf && uarmf->blessed)) {
1435 impossible("bad shade attack function flow?");
1438 tmp = rnd(4); /* bless damage */
1440 /* add ring(s) of increase damage */
1441 if (u.udaminc > 0) {
1442 /* applies even if damage was 0 */
1444 } else if (tmp > 0) {
1445 /* ring(s) might be negative; avoid converting
1446 0 to non-0 or positive to non-positive */
1459 pline("%s is %s!", Monnam(mdef), on_fire(pd, mattk));
1460 if (pd == &mons[PM_STRAW_GOLEM] || pd == &mons[PM_PAPER_GOLEM]) {
1462 pline("%s burns completely!", Monnam(mdef));
1466 /* Don't return yet; keep hp<1 and tmp=0 for pet msg */
1468 tmp += destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE);
1469 tmp += destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE);
1470 if (resists_fire(mdef)) {
1472 pline_The("fire doesn't heat %s!", mon_nam(mdef));
1473 golemeffects(mdef, AD_FIRE, tmp);
1474 shieldeff(mdef->mx, mdef->my);
1477 /* only potions damage resistant players in destroy_item */
1478 tmp += destroy_mitem(mdef, POTION_CLASS, AD_FIRE);
1486 pline("%s is covered in frost!", Monnam(mdef));
1487 if (resists_cold(mdef)) {
1488 shieldeff(mdef->mx, mdef->my);
1490 pline_The("frost doesn't chill %s!", mon_nam(mdef));
1491 golemeffects(mdef, AD_COLD, tmp);
1494 tmp += destroy_mitem(mdef, POTION_CLASS, AD_COLD);
1502 pline("%s is zapped!", Monnam(mdef));
1503 tmp += destroy_mitem(mdef, WAND_CLASS, AD_ELEC);
1504 if (resists_elec(mdef)) {
1506 pline_The("zap doesn't shock %s!", mon_nam(mdef));
1507 golemeffects(mdef, AD_ELEC, tmp);
1508 shieldeff(mdef->mx, mdef->my);
1511 /* only rings damage resistant players in destroy_item */
1512 tmp += destroy_mitem(mdef, RING_CLASS, AD_ELEC);
1515 if (resists_acid(mdef))
1519 if (!munstone(mdef, TRUE))
1520 minstapetrify(mdef, TRUE);
1526 steal_it(mdef, mattk);
1530 /* This you as a leprechaun, so steal
1531 real gold only, no lesser coins */
1533 struct obj *mongold = findgold(mdef->minvent);
1535 obj_extract_self(mongold);
1536 if (merge_choice(invent, mongold) || inv_cnt(FALSE) < 52) {
1538 Your("purse feels heavier.");
1540 You("grab %s's gold, but find no room in your knapsack.",
1546 exercise(A_DEX, TRUE);
1552 if (!negated && tmp < mdef->mhp) {
1555 canseemon(mdef) || (u.uswallow && u.ustuck == mdef);
1556 /* record the name before losing sight of monster */
1557 Strcpy(nambuf, Monnam(mdef));
1558 if (u_teleport_mon(mdef, FALSE) && u_saw_mon
1559 && !(canseemon(mdef) || (u.uswallow && u.ustuck == mdef)))
1560 pline("%s suddenly disappears!", nambuf);
1564 if (can_blnd(&youmonst, mdef, mattk->aatyp, (struct obj *) 0)) {
1565 if (!Blind && mdef->mcansee)
1566 pline("%s is blinded.", Monnam(mdef));
1568 tmp += mdef->mblinded;
1571 mdef->mblinded = tmp;
1576 if (night() && !rn2(10) && !mdef->mcan) {
1577 if (pd == &mons[PM_CLAY_GOLEM]) {
1579 pline("Some writing vanishes from %s head!",
1580 s_suffix(mon_nam(mdef)));
1582 /* Don't return yet; keep hp<1 and tmp=0 for pet msg */
1591 if (!negated && !rn2(3) && !resists_drli(mdef)) {
1593 pline("%s suddenly seems weaker!", Monnam(mdef));
1594 mdef->mhpmax -= xtmp;
1595 if ((mdef->mhp -= xtmp) <= 0 || !mdef->m_lev) {
1596 pline("%s dies!", Monnam(mdef));
1604 if (pd == &mons[PM_IRON_GOLEM]) {
1605 pline("%s falls to pieces!", Monnam(mdef));
1608 erode_armor(mdef, ERODE_RUST);
1612 erode_armor(mdef, ERODE_CORRODE);
1616 if (pd == &mons[PM_WOOD_GOLEM] || pd == &mons[PM_LEATHER_GOLEM]) {
1617 pline("%s falls to pieces!", Monnam(mdef));
1620 erode_armor(mdef, ERODE_ROT);
1624 if (!negated && !rn2(4))
1625 xdrainenergym(mdef, TRUE);
1631 if (!negated && !rn2(8)) {
1632 Your("%s was poisoned!", mpoisons_subj(&youmonst, mattk));
1633 if (resists_poison(mdef))
1634 pline_The("poison doesn't seem to affect %s.", mon_nam(mdef));
1637 Your("poison was deadly...");
1647 if (notonhead || !has_head(pd)) {
1648 pline("%s doesn't seem harmed.", Monnam(mdef));
1650 if (!Unchanging && pd == &mons[PM_GREEN_SLIME]) {
1652 You("suck in some slime and don't feel very well.");
1653 make_slimed(10L, (char *) 0);
1658 if (m_slips_free(mdef, mattk))
1661 if ((helmet = which_armor(mdef, W_ARMH)) != 0 && rn2(8)) {
1662 pline("%s %s blocks your attack to %s head.",
1663 s_suffix(Monnam(mdef)), helm_simple_name(helmet),
1668 (void) eat_brains(&youmonst, mdef, TRUE, &tmp);
1672 if (!negated && !sticks(pd))
1673 u.ustuck = mdef; /* it's now stuck to you */
1677 if (!u.ustuck && !rn2(10)) {
1678 if (m_slips_free(mdef, mattk)) {
1681 You("swing yourself around %s!", mon_nam(mdef));
1684 } else if (u.ustuck == mdef) {
1685 /* Monsters don't wear amulets of magical breathing */
1686 if (is_pool(u.ux, u.uy) && !is_swimmer(pd)
1687 && !amphibious(pd)) {
1688 You("drown %s...", mon_nam(mdef));
1690 } else if (mattk->aatyp == AT_HUGS)
1691 pline("%s is being crushed.", Monnam(mdef));
1695 You("brush against %s %s.", s_suffix(mon_nam(mdef)),
1696 mbodypart(mdef, LEG));
1702 if (!negated && mdef->mcanmove && !rn2(3) && tmp < mdef->mhp) {
1704 pline("%s is frozen by you!", Monnam(mdef));
1705 paralyze_monst(mdef, rnd(10));
1709 if (!negated && !mdef->msleeping && sleep_monst(mdef, rnd(10), -1)) {
1711 pline("%s is put to sleep by you!", Monnam(mdef));
1717 break; /* physical damage only */
1718 if (!rn2(4) && !slimeproof(pd)) {
1719 if (!munslime(mdef, TRUE) && mdef->mhp > 0) {
1720 /* this assumes newcham() won't fail; since hero has
1721 a slime attack, green slimes haven't been geno'd */
1722 You("turn %s into slime.", mon_nam(mdef));
1723 if (newcham(mdef, &mons[PM_GREEN_SLIME], FALSE, FALSE))
1726 /* munslime attempt could have been fatal */
1728 return 2; /* skip death message */
1732 case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */
1733 /* there's no msomearmor() function, so just do damage */
1734 /* if (negated) break; */
1737 if (!negated && mdef->mspeed != MSLOW) {
1738 unsigned int oldspeed = mdef->mspeed;
1740 mon_adjust_speed(mdef, -1, (struct obj *) 0);
1741 if (mdef->mspeed != oldspeed && canseemon(mdef))
1742 pline("%s slows down.", Monnam(mdef));
1747 if (canseemon(mdef))
1748 pline("%s looks confused.", Monnam(mdef));
1757 mdef->mstrategy &= ~STRAT_WAITFORU; /* in case player is very fast */
1758 if ((mdef->mhp -= tmp) < 1) {
1759 if (mdef->mtame && !cansee(mdef->mx, mdef->my)) {
1760 You_feel("embarrassed for a moment.");
1762 xkilled(mdef, 0); /* !tmp but hp<1: already killed */
1763 } else if (!flags.verbose) {
1776 register struct monst *mdef;
1777 register struct attack *mattk;
1779 register int tmp = d((int) mattk->damn, (int) mattk->damd);
1782 switch (mattk->adtyp) {
1783 boolean resistance; /* only for cold/fire/elec */
1786 if (!resists_blnd(mdef)) {
1787 pline("%s is blinded by your flash of light!", Monnam(mdef));
1788 mdef->mblinded = min((int) mdef->mblinded + tmp, 127);
1793 if (haseyes(mdef->data) && mdef->mcansee) {
1794 pline("%s is affected by your flash of light!", Monnam(mdef));
1799 resistance = resists_cold(mdef);
1802 resistance = resists_fire(mdef);
1805 resistance = resists_elec(mdef);
1808 pline("%s gets blasted!", Monnam(mdef));
1810 if (mdef->mhp <= 0) {
1815 shieldeff(mdef->mx, mdef->my);
1816 if (is_golem(mdef->data))
1817 golemeffects(mdef, (int) mattk->adtyp, tmp);
1819 pline_The("blast doesn't seem to affect %s.", mon_nam(mdef));
1833 map_location(u.ux, u.uy, TRUE);
1834 tmp_at(DISP_ALWAYS, mon_to_glyph(&youmonst));
1835 tmp_at(mdef->mx, mdef->my);
1837 You("engulf %s!", mon_nam(mdef));
1846 tmp_at(DISP_END, 0);
1853 register struct monst *mdef;
1854 register struct attack *mattk;
1856 #ifdef LINT /* static char msgbuf[BUFSZ]; */
1859 static char msgbuf[BUFSZ]; /* for nomovemsg */
1862 register int dam = d((int) mattk->damn, (int) mattk->damd);
1865 struct permonst *pd = mdef->data;
1867 /* Not totally the same as for real monsters. Specifically, these
1868 * don't take multiple moves. (It's just too hard, for too little
1869 * result, to program monsters which attack from inside you, which
1870 * would be necessary if done accurately.) Instead, we arbitrarily
1871 * kill the monster immediately for AD_DGST and we regurgitate them
1872 * after exactly 1 round of attack otherwise. -KAA
1875 if (!engulf_target(&youmonst, mdef))
1878 if (u.uhunger < 1500 && !u.uswallow) {
1879 for (otmp = mdef->minvent; otmp; otmp = otmp->nobj)
1880 (void) snuff_lit(otmp);
1882 /* engulfing a cockatrice or digesting a Rider or Medusa */
1883 fatal_gulp = (touch_petrifies(pd) && !Stone_resistance)
1884 || (mattk->adtyp == AD_DGST
1885 && (is_rider(pd) || (pd == &mons[PM_MEDUSA]
1886 && !Stone_resistance)));
1888 if ((mattk->adtyp == AD_DGST && !Slow_digestion) || fatal_gulp)
1889 eating_conducts(pd);
1891 if (fatal_gulp && !is_rider(pd)) { /* petrification */
1893 const char *mname = pd->mname;
1895 if (!type_is_pname(pd))
1897 You("englut %s.", mon_nam(mdef));
1898 Sprintf(kbuf, "swallowing %s whole", mname);
1902 switch (mattk->adtyp) {
1904 /* eating a Rider or its corpse is fatal */
1906 pline("Unfortunately, digesting any of it is fatal.");
1908 Sprintf(killer.name, "unwisely tried to eat %s",
1910 killer.format = NO_KILLER_PREFIX;
1912 return 0; /* lifesaved */
1915 if (Slow_digestion) {
1920 /* Use up amulet of life saving */
1921 if (!!(otmp = mlifesaver(mdef)))
1922 m_useup(mdef, otmp);
1926 if (mdef->mhp > 0) { /* monster lifesaved */
1927 You("hurriedly regurgitate the sizzling in your %s.",
1928 body_part(STOMACH));
1930 tmp = 1 + (pd->cwt >> 8);
1931 if (corpse_chance(mdef, &youmonst, TRUE)
1932 && !(mvitals[monsndx(pd)].mvflags & G_NOCORPSE)) {
1933 /* nutrition only if there can be a corpse */
1934 u.uhunger += (pd->cnutrit + 1) / 2;
1937 Sprintf(msgbuf, "You totally digest %s.", mon_nam(mdef));
1939 /* setting afternmv = end_engulf is tempting,
1940 * but will cause problems if the player is
1941 * attacked (which uses his real location) or
1942 * if his See_invisible wears off
1944 You("digest %s.", mon_nam(mdef));
1948 multi_reason = "digesting something";
1952 if (pd == &mons[PM_GREEN_SLIME]) {
1953 Sprintf(msgbuf, "%s isn't sitting well with you.",
1956 make_slimed(5L, (char *) 0);
1959 exercise(A_CON, TRUE);
1964 if (youmonst.data == &mons[PM_FOG_CLOUD]) {
1965 pline("%s is laden with your moisture.", Monnam(mdef));
1966 if (amphibious(pd) && !flaming(pd)) {
1968 pline("%s seems unharmed.", Monnam(mdef));
1971 pline("%s is pummeled with your debris!", Monnam(mdef));
1974 pline("%s is covered with your goo!", Monnam(mdef));
1975 if (resists_acid(mdef)) {
1976 pline("It seems harmless to %s.", mon_nam(mdef));
1981 if (can_blnd(&youmonst, mdef, mattk->aatyp,
1982 (struct obj *) 0)) {
1984 pline("%s can't see in there!", Monnam(mdef));
1986 dam += mdef->mblinded;
1989 mdef->mblinded = dam;
1995 pline_The("air around %s crackles with electricity.",
1997 if (resists_elec(mdef)) {
1998 pline("%s seems unhurt.", Monnam(mdef));
2001 golemeffects(mdef, (int) mattk->adtyp, dam);
2007 if (resists_cold(mdef)) {
2008 pline("%s seems mildly chilly.", Monnam(mdef));
2011 pline("%s is freezing to death!", Monnam(mdef));
2012 golemeffects(mdef, (int) mattk->adtyp, dam);
2018 if (resists_fire(mdef)) {
2019 pline("%s seems mildly hot.", Monnam(mdef));
2022 pline("%s is burning to a crisp!", Monnam(mdef));
2023 golemeffects(mdef, (int) mattk->adtyp, dam);
2029 xdrainenergym(mdef, TRUE);
2034 if ((mdef->mhp -= dam) <= 0) {
2036 if (mdef->mhp <= 0) /* not lifesaved */
2039 You("%s %s!", is_animal(youmonst.data) ? "regurgitate" : "expel",
2041 if (Slow_digestion || is_animal(youmonst.data)) {
2042 pline("Obviously, you didn't like %s taste.",
2043 s_suffix(mon_nam(mdef)));
2051 missum(mdef, mattk, wouldhavehit)
2052 register struct monst *mdef;
2053 register struct attack *mattk;
2054 boolean wouldhavehit;
2056 if (wouldhavehit) /* monk is missing due to penalty for wearing suit */
2057 Your("armor is rather cumbersome...");
2059 if (could_seduce(&youmonst, mdef, mattk))
2060 You("pretend to be friendly to %s.", mon_nam(mdef));
2061 else if (canspotmon(mdef) && flags.verbose)
2062 You("miss %s.", mon_nam(mdef));
2065 if (!mdef->msleeping && mdef->mcanmove)
2069 /* attack monster as a monster. */
2072 register struct monst *mon;
2074 struct attack *mattk, alt_attk;
2076 boolean altwep = FALSE, weapon_used = FALSE;
2077 int i, tmp, armorpenalty, sum[NATTK], nsum = 0, dhit = 0, attknum = 0;
2079 for (i = 0; i < NATTK; i++) {
2081 mattk = getmattk(youmonst.data, i, sum, &alt_attk);
2082 switch (mattk->aatyp) {
2085 /* Certain monsters don't use weapons when encountered as enemies,
2086 * but players who polymorph into them have hands or claws and
2087 * thus should be able to use weapons. This shouldn't prohibit
2088 * the use of most special abilities, either.
2089 * If monster has multiple claw attacks, only one can use weapon.
2092 /* Potential problem: if the monster gets multiple weapon attacks,
2093 * we currently allow the player to get each of these as a weapon
2094 * attack. Is this really desirable?
2096 /* approximate two-weapon mode */
2097 weapon = (altwep && uswapwep) ? uswapwep : uwep;
2098 altwep = !altwep; /* toggle for next attack */
2099 tmp = find_roll_to_hit(mon, AT_WEAP, weapon, &attknum,
2101 dhit = (tmp > (dieroll = rnd(20)) || u.uswallow);
2102 /* Enemy dead, before any special abilities used */
2103 if (!known_hitum(mon, weapon, &dhit, tmp, armorpenalty, mattk)) {
2108 /* might be a worm that gets cut in half */
2109 if (m_at(u.ux + u.dx, u.uy + u.dy) != mon)
2110 return (boolean) (nsum != 0);
2111 /* Do not print "You hit" message, since known_hitum
2114 if (dhit && mattk->adtyp != AD_SPEL && mattk->adtyp != AD_PHYS)
2115 sum[i] = damageum(mon, mattk);
2118 if (uwep && !cantwield(youmonst.data) && !weapon_used)
2122 if (uwep && youmonst.data->mlet == S_LICH && !weapon_used)
2130 tmp = find_roll_to_hit(mon, mattk->aatyp, (struct obj *) 0,
2131 &attknum, &armorpenalty);
2132 dhit = (tmp > (dieroll = rnd(20)) || u.uswallow);
2137 && (compat = could_seduce(&youmonst, mon, mattk))) {
2139 mon->mcansee && haseyes(mon->data) ? "smile at"
2142 compat == 2 ? "engagingly" : "seductively");
2143 /* doesn't anger it; no wakeup() */
2144 sum[i] = damageum(mon, mattk);
2148 /* maybe this check should be in damageum()? */
2149 if (mon->data == &mons[PM_SHADE]
2150 && !(mattk->aatyp == AT_KICK && uarmf
2151 && uarmf->blessed)) {
2152 Your("attack passes harmlessly through %s.",
2156 if (mattk->aatyp == AT_KICK)
2157 You("kick %s.", mon_nam(mon));
2158 else if (mattk->aatyp == AT_BITE)
2159 You("bite %s.", mon_nam(mon));
2160 else if (mattk->aatyp == AT_STNG)
2161 You("sting %s.", mon_nam(mon));
2162 else if (mattk->aatyp == AT_BUTT)
2163 You("butt %s.", mon_nam(mon));
2164 else if (mattk->aatyp == AT_TUCH)
2165 You("touch %s.", mon_nam(mon));
2166 else if (mattk->aatyp == AT_TENT)
2167 Your("tentacles suck %s.", mon_nam(mon));
2169 You("hit %s.", mon_nam(mon));
2170 sum[i] = damageum(mon, mattk);
2172 missum(mon, mattk, (tmp + armorpenalty > dieroll));
2177 /* automatic if prev two attacks succeed, or if
2178 * already grabbed in a previous attack
2182 if (mon->data == &mons[PM_SHADE])
2183 Your("hug passes harmlessly through %s.", mon_nam(mon));
2184 else if (!sticks(mon->data) && !u.uswallow) {
2185 if (mon == u.ustuck) {
2186 pline("%s is being %s.", Monnam(mon),
2187 u.umonnum == PM_ROPE_GOLEM ? "choked" : "crushed");
2188 sum[i] = damageum(mon, mattk);
2189 } else if (i >= 2 && sum[i - 1] && sum[i - 2]) {
2190 You("grab %s!", mon_nam(mon));
2192 sum[i] = damageum(mon, mattk);
2197 case AT_EXPL: /* automatic hit if next to */
2200 sum[i] = explum(mon, mattk);
2204 tmp = find_roll_to_hit(mon, mattk->aatyp, (struct obj *) 0,
2205 &attknum, &armorpenalty);
2206 if ((dhit = (tmp > rnd(20 + i)))) {
2208 if (mon->data == &mons[PM_SHADE])
2209 Your("attempt to surround %s is harmless.", mon_nam(mon));
2211 sum[i] = gulpum(mon, mattk);
2212 if (sum[i] == 2 && (mon->data->mlet == S_ZOMBIE
2213 || mon->data->mlet == S_MUMMY)
2214 && rn2(5) && !Sick_resistance) {
2215 You_feel("%ssick.", (Sick) ? "very " : "");
2216 mdamageu(mon, rnd(8));
2220 missum(mon, mattk, FALSE);
2225 /* No check for uwep; if wielding nothing we want to
2226 * do the normal 1-2 points bare hand damage...
2228 if ((youmonst.data->mlet == S_KOBOLD
2229 || youmonst.data->mlet == S_ORC
2230 || youmonst.data->mlet == S_GNOME) && !weapon_used)
2236 /* Not break--avoid passive attacks from enemy */
2240 case AT_GAZE: /* all done using #monster command */
2244 default: /* Strange... */
2245 impossible("strange attack of yours (%d)", mattk->aatyp);
2248 u.mh = -1; /* dead in the current form */
2252 return (boolean) passive(mon, 1, 0, mattk->aatyp, FALSE);
2255 (void) passive(mon, sum[i], 1, mattk->aatyp, FALSE);
2259 break; /* No extra attacks if no longer a monster */
2261 break; /* If paralyzed while attacking, i.e. floating eye */
2263 return (boolean) (nsum != 0);
2266 /* Special (passive) attacks on you by monsters done here.
2269 passive(mon, mhit, malive, aatyp, wep_was_destroyed)
2270 register struct monst *mon;
2271 register boolean mhit;
2272 register int malive;
2274 boolean wep_was_destroyed;
2276 register struct permonst *ptr = mon->data;
2277 register int i, tmp;
2281 return (malive | mhit); /* no passive attacks */
2282 if (ptr->mattk[i].aatyp == AT_NONE)
2283 break; /* try this one */
2285 /* Note: tmp not always used */
2286 if (ptr->mattk[i].damn)
2287 tmp = d((int) ptr->mattk[i].damn, (int) ptr->mattk[i].damd);
2288 else if (ptr->mattk[i].damd)
2289 tmp = d((int) mon->m_lev + 1, (int) ptr->mattk[i].damd);
2293 /* These affect you even if they just died.
2295 switch (ptr->mattk[i].adtyp) {
2297 if (mhit && !mon->mcan) {
2298 if (aatyp == AT_KICK) {
2299 if (uarmf && !rn2(6))
2300 (void) erode_obj(uarmf, xname(uarmf), ERODE_BURN,
2301 EF_GREASE | EF_VERBOSE);
2302 } else if (aatyp == AT_WEAP || aatyp == AT_CLAW
2303 || aatyp == AT_MAGC || aatyp == AT_TUCH)
2304 passive_obj(mon, (struct obj *) 0, &(ptr->mattk[i]));
2308 if (mhit && rn2(2)) {
2309 if (Blind || !flags.verbose)
2310 You("are splashed!");
2312 You("are splashed by %s acid!", s_suffix(mon_nam(mon)));
2314 if (!Acid_resistance)
2317 erode_armor(&youmonst, ERODE_CORRODE);
2320 if (aatyp == AT_KICK) {
2321 if (uarmf && !rn2(6))
2322 (void) erode_obj(uarmf, xname(uarmf), ERODE_CORRODE,
2323 EF_GREASE | EF_VERBOSE);
2324 } else if (aatyp == AT_WEAP || aatyp == AT_CLAW
2325 || aatyp == AT_MAGC || aatyp == AT_TUCH)
2326 passive_obj(mon, (struct obj *) 0, &(ptr->mattk[i]));
2328 exercise(A_STR, FALSE);
2331 if (mhit) { /* successful attack */
2332 long protector = attk_protection((int) aatyp);
2334 /* hero using monsters' AT_MAGC attack is hitting hand to
2335 hand rather than casting a spell */
2336 if (aatyp == AT_MAGC)
2339 if (protector == 0L /* no protection */
2340 || (protector == W_ARMG && !uarmg
2341 && !uwep && !wep_was_destroyed)
2342 || (protector == W_ARMF && !uarmf)
2343 || (protector == W_ARMH && !uarmh)
2344 || (protector == (W_ARMC | W_ARMG) && (!uarmc || !uarmg))) {
2345 if (!Stone_resistance
2346 && !(poly_when_stoned(youmonst.data)
2347 && polymon(PM_STONE_GOLEM))) {
2348 done_in_by(mon, STONING); /* "You turn to stone..." */
2355 if (mhit && !mon->mcan) {
2356 if (aatyp == AT_KICK) {
2358 (void) erode_obj(uarmf, xname(uarmf), ERODE_RUST,
2359 EF_GREASE | EF_VERBOSE);
2360 } else if (aatyp == AT_WEAP || aatyp == AT_CLAW
2361 || aatyp == AT_MAGC || aatyp == AT_TUCH)
2362 passive_obj(mon, (struct obj *) 0, &(ptr->mattk[i]));
2366 if (mhit && !mon->mcan) {
2367 if (aatyp == AT_KICK) {
2369 (void) erode_obj(uarmf, xname(uarmf), ERODE_CORRODE,
2370 EF_GREASE | EF_VERBOSE);
2371 } else if (aatyp == AT_WEAP || aatyp == AT_CLAW
2372 || aatyp == AT_MAGC || aatyp == AT_TUCH)
2373 passive_obj(mon, (struct obj *) 0, &(ptr->mattk[i]));
2377 /* wrath of gods for attacking Oracle */
2379 shieldeff(u.ux, u.uy);
2380 pline("A hail of magic missiles narrowly misses you!");
2382 You("are hit by magic missiles appearing from thin air!");
2386 case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */
2388 struct obj *obj = (struct obj *) 0;
2390 if (aatyp == AT_KICK) {
2394 } else if (aatyp == AT_BITE || aatyp == AT_BUTT
2395 || (aatyp >= AT_STNG && aatyp < AT_WEAP)) {
2396 break; /* no object involved */
2398 passive_obj(mon, obj, &(ptr->mattk[i]));
2405 /* These only affect you if they still live.
2407 if (malive && !mon->mcan && rn2(3)) {
2408 switch (ptr->mattk[i].adtyp) {
2410 if (ptr == &mons[PM_FLOATING_EYE]) {
2411 if (!canseemon(mon)) {
2415 if (ureflects("%s gaze is reflected by your %s.",
2416 s_suffix(Monnam(mon)))) {
2418 } else if (Free_action) {
2419 You("momentarily stiffen under %s gaze!",
2420 s_suffix(mon_nam(mon)));
2421 } else if (Hallucination && rn2(4)) {
2422 pline("%s looks %s%s.", Monnam(mon),
2423 !rn2(2) ? "" : "rather ",
2424 !rn2(2) ? "numb" : "stupified");
2426 You("are frozen by %s gaze!", s_suffix(mon_nam(mon)));
2427 nomul((ACURR(A_WIS) > 12 || rn2(4)) ? -tmp : -127);
2428 multi_reason = "frozen by a monster's gaze";
2432 pline("%s cannot defend itself.",
2433 Adjmonnam(mon, "blind"));
2437 } else if (Free_action) {
2438 You("momentarily stiffen.");
2439 } else { /* gelatinous cube */
2440 You("are frozen by %s!", mon_nam(mon));
2441 nomovemsg = You_can_move_again;
2443 multi_reason = "frozen by a monster";
2444 exercise(A_DEX, FALSE);
2447 case AD_COLD: /* brown mold or blue jelly */
2448 if (monnear(mon, u.ux, u.uy)) {
2449 if (Cold_resistance) {
2450 shieldeff(u.ux, u.uy);
2451 You_feel("a mild chill.");
2452 ugolemeffects(AD_COLD, tmp);
2455 You("are suddenly very cold!");
2457 /* monster gets stronger with your heat! */
2458 mon->mhp += tmp / 2;
2459 if (mon->mhpmax < mon->mhp)
2460 mon->mhpmax = mon->mhp;
2461 /* at a certain point, the monster will reproduce! */
2462 if (mon->mhpmax > ((int) (mon->m_lev + 1) * 8))
2463 (void) split_mon(mon, &youmonst);
2466 case AD_STUN: /* specifically yellow mold */
2468 make_stunned((long) tmp, TRUE);
2471 if (monnear(mon, u.ux, u.uy)) {
2472 if (Fire_resistance) {
2473 shieldeff(u.ux, u.uy);
2474 You_feel("mildly warm.");
2475 ugolemeffects(AD_FIRE, tmp);
2478 You("are suddenly very hot!");
2479 mdamageu(mon, tmp); /* fire damage */
2483 if (Shock_resistance) {
2484 shieldeff(u.ux, u.uy);
2485 You_feel("a mild tingle.");
2486 ugolemeffects(AD_ELEC, tmp);
2489 You("are jolted with electricity!");
2496 return (malive | mhit);
2500 * Special (passive) attacks on an attacking object by monsters done here.
2501 * Assumes the attack was successful.
2504 passive_obj(mon, obj, mattk)
2505 register struct monst *mon;
2506 register struct obj *obj; /* null means pick uwep, uswapwep or uarmg */
2507 struct attack *mattk; /* null means we find one internally */
2509 struct permonst *ptr = mon->data;
2512 /* if caller hasn't specified an object, use uwep, uswapwep or uarmg */
2514 obj = (u.twoweap && uswapwep && !rn2(2)) ? uswapwep : uwep;
2515 if (!obj && mattk->adtyp == AD_ENCH)
2516 obj = uarmg; /* no weapon? then must be gloves */
2518 return; /* no object to affect */
2521 /* if caller hasn't specified an attack, find one */
2525 return; /* no passive attacks */
2526 if (ptr->mattk[i].aatyp == AT_NONE)
2527 break; /* try this one */
2529 mattk = &(ptr->mattk[i]);
2532 switch (mattk->adtyp) {
2534 if (!rn2(6) && !mon->mcan) {
2535 (void) erode_obj(obj, NULL, ERODE_BURN, EF_NONE);
2540 (void) erode_obj(obj, NULL, ERODE_CORRODE, EF_NONE);
2545 (void) erode_obj(obj, NULL, ERODE_RUST, EF_NONE);
2550 (void) erode_obj(obj, NULL, ERODE_CORRODE, EF_NONE);
2555 if (drain_item(obj) && carried(obj)
2556 && (obj->known || obj->oclass == ARMOR_CLASS)) {
2557 pline("%s less effective.", Yobjnam2(obj, "seem"));
2569 /* Note: caller must ascertain mtmp is mimicking... */
2571 stumble_onto_mimic(mtmp)
2574 const char *fmt = "Wait! That's %s!", *generic = "a monster", *what = 0;
2576 if (!u.ustuck && !mtmp->mflee && dmgtype(mtmp->data, AD_STCK))
2581 what = generic; /* with default fmt */
2582 else if (mtmp->m_ap_type == M_AP_MONSTER)
2583 what = a_monnam(mtmp); /* differs from what was sensed */
2585 int glyph = levl[u.ux + u.dx][u.uy + u.dy].glyph;
2587 if (glyph_is_cmap(glyph) && (glyph_to_cmap(glyph) == S_hcdoor
2588 || glyph_to_cmap(glyph) == S_vcdoor))
2589 fmt = "The door actually was %s!";
2590 else if (glyph_is_object(glyph) && glyph_to_obj(glyph) == GOLD_PIECE)
2591 fmt = "That gold was %s!";
2593 /* cloned Wiz starts out mimicking some other monster and
2594 might make himself invisible before being revealed */
2595 if (mtmp->minvis && !See_invisible)
2598 what = a_monnam(mtmp);
2603 wakeup(mtmp); /* clears mimicking */
2604 /* if hero is blind, wakeup() won't display the monster even though
2605 it's no longer concealed */
2606 if (!canspotmon(mtmp)
2607 && !glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph))
2608 map_invisible(mtmp->mx, mtmp->my);
2615 char *hands = makeplural(body_part(HAND));
2617 if (!u.umconf || mon->mconf)
2619 if (u.umconf == 1) {
2621 Your("%s stop tingling.", hands);
2623 Your("%s stop glowing %s.", hands, hcolor(NH_RED));
2626 pline_The("tingling in your %s lessens.", hands);
2628 Your("%s no longer glow so brightly %s.", hands, hcolor(NH_RED));
2634 flash_hits_mon(mtmp, otmp)
2636 struct obj *otmp; /* source of flash */
2638 int tmp, amt, res = 0, useeit = canseemon(mtmp);
2640 if (mtmp->msleeping) {
2641 mtmp->msleeping = 0;
2643 pline_The("flash awakens %s.", mon_nam(mtmp));
2646 } else if (mtmp->data->mlet != S_LIGHT) {
2647 if (!resists_blnd(mtmp)) {
2648 tmp = dist2(otmp->ox, otmp->oy, mtmp->mx, mtmp->my);
2650 pline("%s is blinded by the flash!", Monnam(mtmp));
2653 if (mtmp->data == &mons[PM_GREMLIN]) {
2654 /* Rule #1: Keep them out of the light. */
2655 amt = otmp->otyp == WAN_LIGHT ? d(1 + otmp->spe, 4)
2656 : rn2(min(mtmp->mhp, 4));
2657 light_hits_gremlin(mtmp, amt);
2659 if (mtmp->mhp > 0) {
2660 if (!context.mon_moving)
2662 if (tmp < 9 && !mtmp->isshk && rn2(4))
2663 monflee(mtmp, rn2(4) ? rnd(100) : 0, FALSE, TRUE);
2665 mtmp->mblinded = (tmp < 3) ? 0 : rnd(1 + 50 / tmp);
2673 light_hits_gremlin(mon, dmg)
2677 pline("%s %s!", Monnam(mon),
2678 (dmg > mon->mhp / 2) ? "wails in agony" : "cries out in pain");
2679 if ((mon->mhp -= dmg) <= 0) {
2680 if (context.mon_moving)
2681 monkilled(mon, (char *) 0, AD_BLND);
2684 } else if (cansee(mon->mx, mon->my) && !canspotmon(mon)) {
2685 map_invisible(mon->mx, mon->my);