miscellaneous formatting
[aNetHack.git] / src / uhitm.c
bloba4a31cde0c90b23588e7a43c7296c6c8a10b5b1b
1 /* NetHack 3.6 uhitm.c $NHDT-Date: 1470819843 2016/08/10 09:04:03 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.164 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 #include "hack.h"
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 */
27 static int dieroll;
28 /* Used to flag attacks caused by Stormbringer's maliciousness. */
29 static boolean override_confirmation = FALSE;
31 #define PROJECTILE(obj) ((obj) && is_ammo(obj))
33 void
34 erode_armor(mdef, hurt)
35 struct monst *mdef;
36 int hurt;
38 struct obj *target;
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.
46 while (1) {
47 switch (rn2(5)) {
48 case 0:
49 target = which_armor(mdef, W_ARMH);
50 if (!target
51 || erode_obj(target, xname(target), hurt, EF_GREASE)
52 == ER_NOTHING)
53 continue;
54 break;
55 case 1:
56 target = which_armor(mdef, W_ARMC);
57 if (target) {
58 (void) erode_obj(target, xname(target), hurt,
59 EF_GREASE | EF_VERBOSE);
60 break;
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);
70 break;
71 case 2:
72 target = which_armor(mdef, W_ARMS);
73 if (!target
74 || erode_obj(target, xname(target), hurt, EF_GREASE)
75 == ER_NOTHING)
76 continue;
77 break;
78 case 3:
79 target = which_armor(mdef, W_ARMG);
80 if (!target
81 || erode_obj(target, xname(target), hurt, EF_GREASE)
82 == ER_NOTHING)
83 continue;
84 break;
85 case 4:
86 target = which_armor(mdef, W_ARMF);
87 if (!target
88 || erode_obj(target, xname(target), hurt, EF_GREASE)
89 == ER_NOTHING)
90 continue;
91 break;
93 break; /* Out of while loop */
97 /* FALSE means it's OK to attack */
98 boolean
99 attack_checks(mtmp, wep)
100 register struct monst *mtmp;
101 struct obj *wep; /* uwep for attack(), null for kick_monster() */
103 char qbuf[QBUFSZ];
105 /* if you're close enough to attack, alert any waiting monster */
106 mtmp->mstrategy &= ~STRAT_WAITMASK;
108 if (u.uswallow && mtmp == u.ustuck)
109 return FALSE;
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);
123 return FALSE;
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))
146 u.ustuck = mtmp;
148 wakeup(mtmp, TRUE); /* always necessary; also un-mimics mimics */
149 return TRUE;
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)) {
159 seemimic(mtmp);
160 return FALSE;
162 stumble_onto_mimic(mtmp);
163 return TRUE;
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)) {
172 seemimic(mtmp);
173 return FALSE;
175 if (!((Blind ? Blind_telepat : Unblind_telepat) || Detect_monsters)) {
176 struct obj *obj;
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));
183 return TRUE;
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;
193 wakeup(mtmp, TRUE);
196 if (flags.confirm && mtmp->mpeaceful && !Confusion && !Hallucination
197 && !Stunned) {
198 /* Intelligent chaotic weapons (Stormbringer) want blood */
199 if (wep && wep->oartifact == ART_STORMBRINGER) {
200 override_confirmation = TRUE;
201 return FALSE;
203 if (canspotmon(mtmp)) {
204 Sprintf(qbuf, "Really attack %s?", mon_nam(mtmp));
205 if (!paranoid_query(ParanoidHit, qbuf)) {
206 context.move = 0;
207 return TRUE;
212 return FALSE;
216 * It is unchivalrous for a knight to attack the defenseless or from behind.
218 void
219 check_caitiff(mtmp)
220 struct monst *mtmp;
222 if (u.ualign.record <= -10)
223 return;
225 if (Role_if(PM_KNIGHT) && u.ualign.type == A_LAWFUL
226 && (!mtmp->mcanmove || mtmp->msleeping
227 || (mtmp->mflee && !mtmp->mavenge))) {
228 You("caitiff!");
229 adjalign(-1);
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!");
233 adjalign(-1);
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;
244 int tmp, tmp2;
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 */
254 check_caitiff(mtmp);
257 /* adjust vs. (and possibly modify) monster state */
258 if (mtmp->mstun)
259 tmp += 2;
260 if (mtmp->mflee)
261 tmp += 2;
263 if (mtmp->msleeping) {
264 mtmp->msleeping = 0;
265 tmp += 2;
267 if (!mtmp->mcanmove) {
268 tmp += 4;
269 if (!rn2(10)) {
270 mtmp->mcanmove = 1;
271 mtmp->mfrozen = 0;
275 /* role/race adjustments */
276 if (Role_if(PM_MONK) && !Upolyd) {
277 if (uarm)
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)))
284 tmp++;
286 /* encumbrance: with a lot of luggage, your agility diminishes */
287 if ((tmp2 = near_capacity()) != 0)
288 tmp -= (tmp2 * 2) - 1;
289 if (u.utrap)
290 tmp -= 3;
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) {
298 if (weapon)
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);
305 return tmp;
308 /* try to attack; return False if monster evaded;
309 u.dx and u.dy must be set */
310 boolean
311 attack(mtmp)
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)),
336 inshop = FALSE;
337 char *p;
339 for (p = in_rooms(mtmp->mx, mtmp->my, SHOPBASE); *p; p++)
340 if (tended_shop(&rooms[*p - ROOMOFFSET])) {
341 inshop = TRUE;
342 break;
345 if (inshop || foo || (IS_ROCK(levl[u.ux][u.uy].typ)
346 && !passes_walls(mtmp->data))) {
347 char buf[BUFSZ];
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);
353 context.travel = context.travel1 = context.mv = context.run = 0;
354 return TRUE;
355 } else if ((mtmp->mfrozen || (!mtmp->mcanmove)
356 || (mtmp->data->mmove == 0)) && rn2(6)) {
357 pline("%s doesn't seem to move!", Monnam(mtmp));
358 context.travel = context.travel1 = context.mv = context.run = 0;
359 return TRUE;
360 } else
361 return FALSE;
365 /* possibly set in attack_checks;
366 examined in known_hitum, called via hitum or hmonas below */
367 override_confirmation = FALSE;
368 /* attack_checks() used to use <u.ux+u.dx,u.uy+u.dy> directly, now
369 it uses bhitpos instead; it might map an invisible monster there */
370 bhitpos.x = u.ux + u.dx;
371 bhitpos.y = u.uy + u.dy;
372 if (attack_checks(mtmp, uwep))
373 return TRUE;
375 if (Upolyd && noattacks(youmonst.data)) {
376 /* certain "pacifist" monsters don't attack */
377 You("have no way to attack monsters physically.");
378 mtmp->mstrategy &= ~STRAT_WAITMASK;
379 goto atk_done;
382 if (check_capacity("You cannot fight while so heavily loaded.")
383 /* consume extra nutrition during combat; maybe pass out */
384 || overexertion())
385 goto atk_done;
387 if (u.twoweap && !can_twoweapon())
388 untwoweapon();
390 if (unweapon) {
391 unweapon = FALSE;
392 if (flags.verbose) {
393 if (uwep)
394 You("begin bashing monsters with %s.",
395 yobjnam(uwep, (char *) 0));
396 else if (!cantwield(youmonst.data))
397 You("begin %sing monsters with your %s %s.",
398 Role_if(PM_MONK) ? "strik" : "bash",
399 uarmg ? "gloved" : "bare", /* Del Lamb */
400 makeplural(body_part(HAND)));
403 exercise(A_STR, TRUE); /* you're exercising muscles */
404 /* andrew@orca: prevent unlimited pick-axe attacks */
405 u_wipe_engr(3);
407 /* Is the "it died" check actually correct? */
408 if (mdat->mlet == S_LEPRECHAUN && !mtmp->mfrozen && !mtmp->msleeping
409 && !mtmp->mconf && mtmp->mcansee && !rn2(7)
410 && (m_move(mtmp, 0) == 2 /* it died */
411 || mtmp->mx != u.ux + u.dx
412 || mtmp->my != u.uy + u.dy)) /* it moved */
413 return FALSE;
415 if (Upolyd)
416 (void) hmonas(mtmp);
417 else
418 (void) hitum(mtmp, youmonst.data->mattk);
419 mtmp->mstrategy &= ~STRAT_WAITMASK;
421 atk_done:
422 /* see comment in attack_checks() */
423 /* we only need to check for this if we did an attack_checks()
424 * and it returned 0 (it's okay to attack), and the monster didn't
425 * evade.
427 if (context.forcefight && mtmp->mhp > 0 && !canspotmon(mtmp)
428 && !glyph_is_invisible(levl[u.ux + u.dx][u.uy + u.dy].glyph)
429 && !(u.uswallow && mtmp == u.ustuck))
430 map_invisible(u.ux + u.dx, u.uy + u.dy);
432 return TRUE;
435 /* really hit target monster; returns TRUE if it still lives */
436 STATIC_OVL boolean
437 known_hitum(mon, weapon, mhit, rollneeded, armorpenalty, uattk)
438 register struct monst *mon;
439 struct obj *weapon;
440 int *mhit;
441 int rollneeded, armorpenalty; /* for monks */
442 struct attack *uattk;
444 register boolean malive = TRUE;
446 if (override_confirmation) {
447 /* this may need to be generalized if weapons other than
448 Stormbringer acquire similar anti-social behavior... */
449 if (flags.verbose)
450 Your("bloodthirsty blade attacks!");
453 if (!*mhit) {
454 missum(mon, uattk, (rollneeded + armorpenalty > dieroll));
455 } else {
456 int oldhp = mon->mhp, x = u.ux + u.dx, y = u.uy + u.dy;
457 long oldweaphit = u.uconduct.weaphit;
459 /* KMH, conduct */
460 if (weapon && (weapon->oclass == WEAPON_CLASS || is_weptool(weapon)))
461 u.uconduct.weaphit++;
463 /* we hit the monster; be careful: it might die or
464 be knocked into a different location */
465 notonhead = (mon->mx != x || mon->my != y);
466 malive = hmon(mon, weapon, HMON_MELEE);
467 if (malive) {
468 /* monster still alive */
469 if (!rn2(25) && mon->mhp < mon->mhpmax / 2
470 && !(u.uswallow && mon == u.ustuck)) {
471 /* maybe should regurgitate if swallowed? */
472 monflee(mon, !rn2(3) ? rnd(100) : 0, FALSE, TRUE);
474 if (u.ustuck == mon && !u.uswallow && !sticks(youmonst.data))
475 u.ustuck = 0;
477 /* Vorpal Blade hit converted to miss */
478 /* could be headless monster or worm tail */
479 if (mon->mhp == oldhp) {
480 *mhit = 0;
481 /* a miss does not break conduct */
482 u.uconduct.weaphit = oldweaphit;
484 if (mon->wormno && *mhit)
485 cutworm(mon, x, y, weapon);
488 return malive;
491 /* hit target monster; returns TRUE if it still lives */
492 STATIC_OVL boolean
493 hitum(mon, uattk)
494 struct monst *mon;
495 struct attack *uattk;
497 boolean malive, wep_was_destroyed = FALSE;
498 struct obj *wepbefore = uwep;
499 int armorpenalty, attknum = 0, x = u.ux + u.dx, y = u.uy + u.dy,
500 tmp = find_roll_to_hit(mon, uattk->aatyp, uwep,
501 &attknum, &armorpenalty);
502 int mhit = (tmp > (dieroll = rnd(20)) || u.uswallow);
504 if (tmp > dieroll)
505 exercise(A_DEX, TRUE);
506 malive = known_hitum(mon, uwep, &mhit, tmp, armorpenalty, uattk);
507 /* second attack for two-weapon combat; won't occur if Stormbringer
508 overrode confirmation (assumes Stormbringer is primary weapon)
509 or if the monster was killed or knocked to different location */
510 if (u.twoweap && !override_confirmation && malive && m_at(x, y) == mon) {
511 tmp = find_roll_to_hit(mon, uattk->aatyp, uswapwep, &attknum,
512 &armorpenalty);
513 mhit = (tmp > (dieroll = rnd(20)) || u.uswallow);
514 malive = known_hitum(mon, uswapwep, &mhit, tmp, armorpenalty, uattk);
516 if (wepbefore && !uwep)
517 wep_was_destroyed = TRUE;
518 (void) passive(mon, mhit, malive, AT_WEAP, wep_was_destroyed);
519 return malive;
522 /* general "damage monster" routine; return True if mon still alive */
523 boolean
524 hmon(mon, obj, thrown)
525 struct monst *mon;
526 struct obj *obj;
527 int thrown; /* HMON_xxx (0 => hand-to-hand, other => ranged) */
529 boolean result, anger_guards;
531 anger_guards = (mon->mpeaceful
532 && (mon->ispriest || mon->isshk || is_watch(mon->data)));
533 result = hmon_hitmon(mon, obj, thrown);
534 if (mon->ispriest && !rn2(2))
535 ghod_hitsu(mon);
536 if (anger_guards)
537 (void) angry_guards(!!Deaf);
538 return result;
541 /* guts of hmon() */
542 STATIC_OVL boolean
543 hmon_hitmon(mon, obj, thrown)
544 struct monst *mon;
545 struct obj *obj;
546 int thrown; /* HMON_xxx (0 => hand-to-hand, other => ranged) */
548 int tmp;
549 struct permonst *mdat = mon->data;
550 int barehand_silver_rings = 0;
551 /* The basic reason we need all these booleans is that we don't want
552 * a "hit" message when a monster dies, so we have to know how much
553 * damage it did _before_ outputting a hit message, but any messages
554 * associated with the damage don't come out until _after_ outputting
555 * a hit message.
557 boolean hittxt = FALSE, destroyed = FALSE, already_killed = FALSE;
558 boolean get_dmg_bonus = TRUE;
559 boolean ispoisoned = FALSE, needpoismsg = FALSE, poiskilled = FALSE,
560 unpoisonmsg = FALSE;
561 boolean silvermsg = FALSE, silverobj = FALSE;
562 boolean valid_weapon_attack = FALSE;
563 boolean unarmed = !uwep && !uarm && !uarms;
564 boolean hand_to_hand = (thrown == HMON_MELEE
565 /* not grapnels; applied implies uwep */
566 || (thrown == HMON_APPLIED && is_pole(uwep)));
567 int jousting = 0;
568 int wtype;
569 struct obj *monwep;
570 char unconventional[BUFSZ]; /* substituted for word "attack" in msg */
571 char saved_oname[BUFSZ];
573 unconventional[0] = '\0';
574 saved_oname[0] = '\0';
576 wakeup(mon, TRUE);
577 if (!obj) { /* attack with bare hands */
578 if (mdat == &mons[PM_SHADE])
579 tmp = 0;
580 else if (martial_bonus())
581 tmp = rnd(4); /* bonus for martial arts */
582 else
583 tmp = rnd(2);
584 valid_weapon_attack = (tmp > 1);
585 /* blessed gloves give bonuses when fighting 'bare-handed' */
586 if (uarmg && uarmg->blessed
587 && (is_undead(mdat) || is_demon(mdat) || is_vampshifter(mon)))
588 tmp += rnd(4);
589 /* So do silver rings. Note: rings are worn under gloves, so you
590 * don't get both bonuses.
592 if (!uarmg) {
593 if (uleft && objects[uleft->otyp].oc_material == SILVER)
594 barehand_silver_rings++;
595 if (uright && objects[uright->otyp].oc_material == SILVER)
596 barehand_silver_rings++;
597 if (barehand_silver_rings && mon_hates_silver(mon)) {
598 tmp += rnd(20);
599 silvermsg = TRUE;
602 } else {
603 Strcpy(saved_oname, cxname(obj));
604 if (obj->oclass == WEAPON_CLASS || is_weptool(obj)
605 || obj->oclass == GEM_CLASS) {
606 /* is it not a melee weapon? */
607 if (/* if you strike with a bow... */
608 is_launcher(obj)
609 /* or strike with a missile in your hand... */
610 || (!thrown && (is_missile(obj) || is_ammo(obj)))
611 /* or use a pole at short range and not mounted... */
612 || (!thrown && !u.usteed && is_pole(obj))
613 /* or throw a missile without the proper bow... */
614 || (is_ammo(obj) && (thrown != HMON_THROWN
615 || !ammo_and_launcher(obj, uwep)))) {
616 /* then do only 1-2 points of damage */
617 if (mdat == &mons[PM_SHADE] && !shade_glare(obj))
618 tmp = 0;
619 else
620 tmp = rnd(2);
621 if (objects[obj->otyp].oc_material == SILVER
622 && mon_hates_silver(mon)) {
623 silvermsg = TRUE;
624 silverobj = TRUE;
625 /* if it will already inflict dmg, make it worse */
626 tmp += rnd((tmp) ? 20 : 10);
628 if (!thrown && obj == uwep && obj->otyp == BOOMERANG
629 && rnl(4) == 4 - 1) {
630 boolean more_than_1 = (obj->quan > 1L);
632 pline("As you hit %s, %s%s breaks into splinters.",
633 mon_nam(mon), more_than_1 ? "one of " : "",
634 yname(obj));
635 if (!more_than_1)
636 uwepgone(); /* set unweapon */
637 useup(obj);
638 if (!more_than_1)
639 obj = (struct obj *) 0;
640 hittxt = TRUE;
641 if (mdat != &mons[PM_SHADE])
642 tmp++;
644 } else {
645 tmp = dmgval(obj, mon);
646 /* a minimal hit doesn't exercise proficiency */
647 valid_weapon_attack = (tmp > 1);
648 if (!valid_weapon_attack || mon == u.ustuck || u.twoweap) {
649 ; /* no special bonuses */
650 } else if (mon->mflee && Role_if(PM_ROGUE) && !Upolyd
651 /* multi-shot throwing is too powerful here */
652 && hand_to_hand) {
653 You("strike %s from behind!", mon_nam(mon));
654 tmp += rnd(u.ulevel);
655 hittxt = TRUE;
656 } else if (dieroll == 2 && obj == uwep
657 && obj->oclass == WEAPON_CLASS
658 && (bimanual(obj)
659 || (Role_if(PM_SAMURAI) && obj->otyp == KATANA
660 && !uarms))
661 && ((wtype = uwep_skill_type()) != P_NONE
662 && P_SKILL(wtype) >= P_SKILLED)
663 && ((monwep = MON_WEP(mon)) != 0
664 && !is_flimsy(monwep)
665 && !obj_resists(monwep,
666 50 + 15 * (greatest_erosion(obj)
667 - greatest_erosion(monwep)),
668 100))) {
670 * 2.5% chance of shattering defender's weapon when
671 * using a two-handed weapon; less if uwep is rusted.
672 * [dieroll == 2 is most successful non-beheading or
673 * -bisecting hit, in case of special artifact damage;
674 * the percentage chance is (1/20)*(50/100).]
675 * If attacker's weapon is rustier than defender's,
676 * the obj_resists chance is increased so the shatter
677 * chance is decreased; if less rusty, then vice versa.
679 setmnotwielded(mon, monwep);
680 mon->weapon_check = NEED_WEAPON;
681 pline("%s from the force of your blow!",
682 Yobjnam2(monwep, "shatter"));
683 m_useupall(mon, monwep);
684 /* If someone just shattered MY weapon, I'd flee! */
685 if (rn2(4)) {
686 monflee(mon, d(2, 3), TRUE, TRUE);
688 hittxt = TRUE;
691 if (obj->oartifact
692 && artifact_hit(&youmonst, mon, obj, &tmp, dieroll)) {
693 if (mon->mhp <= 0) /* artifact killed monster */
694 return FALSE;
695 if (tmp == 0)
696 return TRUE;
697 hittxt = TRUE;
699 if (objects[obj->otyp].oc_material == SILVER
700 && mon_hates_silver(mon)) {
701 silvermsg = TRUE;
702 silverobj = TRUE;
704 if (u.usteed && !thrown && tmp > 0
705 && weapon_type(obj) == P_LANCE && mon != u.ustuck) {
706 jousting = joust(mon, obj);
707 /* exercise skill even for minimal damage hits */
708 if (jousting)
709 valid_weapon_attack = TRUE;
711 if (thrown == HMON_THROWN
712 && (is_ammo(obj) || is_missile(obj))) {
713 if (ammo_and_launcher(obj, uwep)) {
714 /* Elves and Samurai do extra damage using
715 * their bows&arrows; they're highly trained.
717 if (Role_if(PM_SAMURAI) && obj->otyp == YA
718 && uwep->otyp == YUMI)
719 tmp++;
720 else if (Race_if(PM_ELF) && obj->otyp == ELVEN_ARROW
721 && uwep->otyp == ELVEN_BOW)
722 tmp++;
724 if (obj->opoisoned && is_poisonable(obj))
725 ispoisoned = TRUE;
728 } else if (obj->oclass == POTION_CLASS) {
729 if (obj->quan > 1L)
730 obj = splitobj(obj, 1L);
731 else
732 setuwep((struct obj *) 0);
733 freeinv(obj);
734 potionhit(mon, obj, TRUE);
735 if (mon->mhp <= 0)
736 return FALSE; /* killed */
737 hittxt = TRUE;
738 /* in case potion effect causes transformation */
739 mdat = mon->data;
740 tmp = (mdat == &mons[PM_SHADE]) ? 0 : 1;
741 } else {
742 if (mdat == &mons[PM_SHADE] && !shade_aware(obj)) {
743 tmp = 0;
744 Strcpy(unconventional, cxname(obj));
745 } else {
746 switch (obj->otyp) {
747 case BOULDER: /* 1d20 */
748 case HEAVY_IRON_BALL: /* 1d25 */
749 case IRON_CHAIN: /* 1d4+1 */
750 tmp = dmgval(obj, mon);
751 break;
752 case MIRROR:
753 if (breaktest(obj)) {
754 You("break %s. That's bad luck!", ysimple_name(obj));
755 change_luck(-2);
756 useup(obj);
757 obj = (struct obj *) 0;
758 unarmed = FALSE; /* avoid obj==0 confusion */
759 get_dmg_bonus = FALSE;
760 hittxt = TRUE;
762 tmp = 1;
763 break;
764 case EXPENSIVE_CAMERA:
765 You("succeed in destroying %s. Congratulations!",
766 ysimple_name(obj));
767 release_camera_demon(obj, u.ux, u.uy);
768 useup(obj);
769 return TRUE;
770 case CORPSE: /* fixed by polder@cs.vu.nl */
771 if (touch_petrifies(&mons[obj->corpsenm])) {
772 tmp = 1;
773 hittxt = TRUE;
774 You("hit %s with %s.", mon_nam(mon),
775 corpse_xname(obj, (const char *) 0,
776 obj->dknown ? CXN_PFX_THE
777 : CXN_ARTICLE));
778 obj->dknown = 1;
779 if (!munstone(mon, TRUE))
780 minstapetrify(mon, TRUE);
781 if (resists_ston(mon))
782 break;
783 /* note: hp may be <= 0 even if munstoned==TRUE */
784 return (boolean) (mon->mhp > 0);
785 #if 0
786 } else if (touch_petrifies(mdat)) {
787 ; /* maybe turn the corpse into a statue? */
788 #endif
790 tmp = (obj->corpsenm >= LOW_PM ? mons[obj->corpsenm].msize
791 : 0) + 1;
792 break;
794 #define useup_eggs(o) \
796 if (thrown) \
797 obfree(o, (struct obj *) 0); \
798 else \
799 useupall(o); \
800 o = (struct obj *) 0; \
801 } /* now gone */
802 case EGG: {
803 long cnt = obj->quan;
805 tmp = 1; /* nominal physical damage */
806 get_dmg_bonus = FALSE;
807 hittxt = TRUE; /* message always given */
808 /* egg is always either used up or transformed, so next
809 hand-to-hand attack should yield a "bashing" mesg */
810 if (obj == uwep)
811 unweapon = TRUE;
812 if (obj->spe && obj->corpsenm >= LOW_PM) {
813 if (obj->quan < 5L)
814 change_luck((schar) - (obj->quan));
815 else
816 change_luck(-5);
819 if (touch_petrifies(&mons[obj->corpsenm])) {
820 /*learn_egg_type(obj->corpsenm);*/
821 pline("Splat! You hit %s with %s %s egg%s!",
822 mon_nam(mon),
823 obj->known ? "the" : cnt > 1L ? "some" : "a",
824 obj->known ? mons[obj->corpsenm].mname
825 : "petrifying",
826 plur(cnt));
827 obj->known = 1; /* (not much point...) */
828 useup_eggs(obj);
829 if (!munstone(mon, TRUE))
830 minstapetrify(mon, TRUE);
831 if (resists_ston(mon))
832 break;
833 return (boolean) (mon->mhp > 0);
834 } else { /* ordinary egg(s) */
835 const char *eggp =
836 (obj->corpsenm != NON_PM && obj->known)
837 ? the(mons[obj->corpsenm].mname)
838 : (cnt > 1L) ? "some" : "an";
839 You("hit %s with %s egg%s.", mon_nam(mon), eggp,
840 plur(cnt));
841 if (touch_petrifies(mdat) && !stale_egg(obj)) {
842 pline_The("egg%s %s alive any more...", plur(cnt),
843 (cnt == 1L) ? "isn't" : "aren't");
844 if (obj->timed)
845 obj_stop_timers(obj);
846 obj->otyp = ROCK;
847 obj->oclass = GEM_CLASS;
848 obj->oartifact = 0;
849 obj->spe = 0;
850 obj->known = obj->dknown = obj->bknown = 0;
851 obj->owt = weight(obj);
852 if (thrown)
853 place_object(obj, mon->mx, mon->my);
854 } else {
855 pline("Splat!");
856 useup_eggs(obj);
857 exercise(A_WIS, FALSE);
860 break;
861 #undef useup_eggs
863 case CLOVE_OF_GARLIC: /* no effect against demons */
864 if (is_undead(mdat) || is_vampshifter(mon)) {
865 monflee(mon, d(2, 4), FALSE, TRUE);
867 tmp = 1;
868 break;
869 case CREAM_PIE:
870 case BLINDING_VENOM:
871 mon->msleeping = 0;
872 if (can_blnd(&youmonst, mon,
873 (uchar) (obj->otyp == BLINDING_VENOM
874 ? AT_SPIT
875 : AT_WEAP),
876 obj)) {
877 if (Blind) {
878 pline(obj->otyp == CREAM_PIE ? "Splat!"
879 : "Splash!");
880 } else if (obj->otyp == BLINDING_VENOM) {
881 pline_The("venom blinds %s%s!", mon_nam(mon),
882 mon->mcansee ? "" : " further");
883 } else {
884 char *whom = mon_nam(mon);
885 char *what = The(xname(obj));
887 if (!thrown && obj->quan > 1L)
888 what = An(singular(obj, xname));
889 /* note: s_suffix returns a modifiable buffer */
890 if (haseyes(mdat)
891 && mdat != &mons[PM_FLOATING_EYE])
892 whom = strcat(strcat(s_suffix(whom), " "),
893 mbodypart(mon, FACE));
894 pline("%s %s over %s!", what,
895 vtense(what, "splash"), whom);
897 setmangry(mon, TRUE);
898 mon->mcansee = 0;
899 tmp = rn1(25, 21);
900 if (((int) mon->mblinded + tmp) > 127)
901 mon->mblinded = 127;
902 else
903 mon->mblinded += tmp;
904 } else {
905 pline(obj->otyp == CREAM_PIE ? "Splat!" : "Splash!");
906 setmangry(mon, TRUE);
908 if (thrown)
909 obfree(obj, (struct obj *) 0);
910 else
911 useup(obj);
912 hittxt = TRUE;
913 get_dmg_bonus = FALSE;
914 tmp = 0;
915 break;
916 case ACID_VENOM: /* thrown (or spit) */
917 if (resists_acid(mon)) {
918 Your("venom hits %s harmlessly.", mon_nam(mon));
919 tmp = 0;
920 } else {
921 Your("venom burns %s!", mon_nam(mon));
922 tmp = dmgval(obj, mon);
924 if (thrown)
925 obfree(obj, (struct obj *) 0);
926 else
927 useup(obj);
928 hittxt = TRUE;
929 get_dmg_bonus = FALSE;
930 break;
931 default:
932 /* non-weapons can damage because of their weight */
933 /* (but not too much) */
934 tmp = obj->owt / 100;
935 if (is_wet_towel(obj)) {
936 /* wielded wet towel should probably use whip skill
937 (but not by setting objects[TOWEL].oc_skill==P_WHIP
938 because that would turn towel into a weptool) */
939 tmp += obj->spe;
940 if (rn2(obj->spe + 1)) /* usually lose some wetness */
941 dry_a_towel(obj, -1, TRUE);
943 if (tmp < 1)
944 tmp = 1;
945 else
946 tmp = rnd(tmp);
947 if (tmp > 6)
948 tmp = 6;
950 * Things like silver wands can arrive here so
951 * so we need another silver check.
953 if (objects[obj->otyp].oc_material == SILVER
954 && mon_hates_silver(mon)) {
955 tmp += rnd(20);
956 silvermsg = TRUE;
957 silverobj = TRUE;
964 /****** NOTE: perhaps obj is undefined!! (if !thrown && BOOMERANG)
965 * *OR* if attacking bare-handed!! */
967 if (get_dmg_bonus && tmp > 0) {
968 tmp += u.udaminc;
969 /* If you throw using a propellor, you don't get a strength
970 * bonus but you do get an increase-damage bonus.
972 if (thrown != HMON_THROWN || !obj || !uwep
973 || !ammo_and_launcher(obj, uwep))
974 tmp += dbon();
977 if (valid_weapon_attack) {
978 struct obj *wep;
980 /* to be valid a projectile must have had the correct projector */
981 wep = PROJECTILE(obj) ? uwep : obj;
982 tmp += weapon_dam_bonus(wep);
983 /* [this assumes that `!thrown' implies wielded...] */
984 wtype = thrown ? weapon_type(wep) : uwep_skill_type();
985 use_skill(wtype, 1);
988 if (ispoisoned) {
989 int nopoison = (10 - (obj->owt / 10));
991 if (nopoison < 2)
992 nopoison = 2;
993 if (Role_if(PM_SAMURAI)) {
994 You("dishonorably use a poisoned weapon!");
995 adjalign(-sgn(u.ualign.type));
996 } else if (u.ualign.type == A_LAWFUL && u.ualign.record > -10) {
997 You_feel("like an evil coward for using a poisoned weapon.");
998 adjalign(-1);
1000 if (obj && !rn2(nopoison)) {
1001 /* remove poison now in case obj ends up in a bones file */
1002 obj->opoisoned = FALSE;
1003 /* defer "obj is no longer poisoned" until after hit message */
1004 unpoisonmsg = TRUE;
1006 if (resists_poison(mon))
1007 needpoismsg = TRUE;
1008 else if (rn2(10))
1009 tmp += rnd(6);
1010 else
1011 poiskilled = TRUE;
1013 if (tmp < 1) {
1014 /* make sure that negative damage adjustment can't result
1015 in inadvertently boosting the victim's hit points */
1016 tmp = 0;
1017 if (mdat == &mons[PM_SHADE]) {
1018 if (!hittxt) {
1019 const char *what = *unconventional ? unconventional : "attack";
1021 Your("%s %s harmlessly through %s.", what,
1022 vtense(what, "pass"), mon_nam(mon));
1023 hittxt = TRUE;
1025 } else {
1026 if (get_dmg_bonus)
1027 tmp = 1;
1031 if (jousting) {
1032 tmp += d(2, (obj == uwep) ? 10 : 2); /* [was in dmgval()] */
1033 You("joust %s%s", mon_nam(mon), canseemon(mon) ? exclam(tmp) : ".");
1034 if (jousting < 0) {
1035 pline("%s shatters on impact!", Yname2(obj));
1036 /* (must be either primary or secondary weapon to get here) */
1037 u.twoweap = FALSE; /* untwoweapon() is too verbose here */
1038 if (obj == uwep)
1039 uwepgone(); /* set unweapon */
1040 /* minor side-effect: broken lance won't split puddings */
1041 useup(obj);
1042 obj = 0;
1044 /* avoid migrating a dead monster */
1045 if (mon->mhp > tmp) {
1046 mhurtle(mon, u.dx, u.dy, 1);
1047 mdat = mon->data; /* in case of a polymorph trap */
1048 if (DEADMONSTER(mon))
1049 already_killed = TRUE;
1051 hittxt = TRUE;
1052 } else if (unarmed && tmp > 1 && !thrown && !obj && !Upolyd) {
1053 /* VERY small chance of stunning opponent if unarmed. */
1054 if (rnd(100) < P_SKILL(P_BARE_HANDED_COMBAT) && !bigmonst(mdat)
1055 && !thick_skinned(mdat)) {
1056 if (canspotmon(mon))
1057 pline("%s %s from your powerful strike!", Monnam(mon),
1058 makeplural(stagger(mon->data, "stagger")));
1059 /* avoid migrating a dead monster */
1060 if (mon->mhp > tmp) {
1061 mhurtle(mon, u.dx, u.dy, 1);
1062 mdat = mon->data; /* in case of a polymorph trap */
1063 if (DEADMONSTER(mon))
1064 already_killed = TRUE;
1066 hittxt = TRUE;
1070 if (!already_killed)
1071 mon->mhp -= tmp;
1072 /* adjustments might have made tmp become less than what
1073 a level draining artifact has already done to max HP */
1074 if (mon->mhp > mon->mhpmax)
1075 mon->mhp = mon->mhpmax;
1076 if (mon->mhp < 1)
1077 destroyed = TRUE;
1078 if (mon->mtame && tmp > 0) {
1079 /* do this even if the pet is being killed (affects revival) */
1080 abuse_dog(mon); /* reduces tameness */
1081 /* flee if still alive and still tame; if already suffering from
1082 untimed fleeing, no effect, otherwise increases timed fleeing */
1083 if (mon->mtame && !destroyed)
1084 monflee(mon, 10 * rnd(tmp), FALSE, FALSE);
1086 if ((mdat == &mons[PM_BLACK_PUDDING] || mdat == &mons[PM_BROWN_PUDDING])
1087 /* pudding is alive and healthy enough to split */
1088 && mon->mhp > 1 && !mon->mcan
1089 /* iron weapon using melee or polearm hit [3.6.1: metal weapon too] */
1090 && obj && obj == uwep
1091 && ((objects[obj->otyp].oc_material == IRON
1092 /* allow scalpel and tsurugi to split puddings */
1093 || objects[obj->otyp].oc_material == METAL)
1094 /* but not bashing with darts, arrows or ya */
1095 && !(is_ammo(obj) || is_missile(obj)))
1096 && hand_to_hand) {
1097 if (clone_mon(mon, 0, 0)) {
1098 pline("%s divides as you hit it!", Monnam(mon));
1099 hittxt = TRUE;
1103 if (!hittxt /*( thrown => obj exists )*/
1104 && (!destroyed
1105 || (thrown && m_shot.n > 1 && m_shot.o == obj->otyp))) {
1106 if (thrown)
1107 hit(mshot_xname(obj), mon, exclam(tmp));
1108 else if (!flags.verbose)
1109 You("hit it.");
1110 else
1111 You("%s %s%s", Role_if(PM_BARBARIAN) ? "smite" : "hit",
1112 mon_nam(mon), canseemon(mon) ? exclam(tmp) : ".");
1115 if (silvermsg) {
1116 const char *fmt;
1117 char *whom = mon_nam(mon);
1118 char silverobjbuf[BUFSZ];
1120 if (canspotmon(mon)) {
1121 if (barehand_silver_rings == 1)
1122 fmt = "Your silver ring sears %s!";
1123 else if (barehand_silver_rings == 2)
1124 fmt = "Your silver rings sear %s!";
1125 else if (silverobj && saved_oname[0]) {
1126 Sprintf(silverobjbuf, "Your %s%s %s %%s!",
1127 strstri(saved_oname, "silver") ? "" : "silver ",
1128 saved_oname, vtense(saved_oname, "sear"));
1129 fmt = silverobjbuf;
1130 } else
1131 fmt = "The silver sears %s!";
1132 } else {
1133 *whom = highc(*whom); /* "it" -> "It" */
1134 fmt = "%s is seared!";
1136 /* note: s_suffix returns a modifiable buffer */
1137 if (!noncorporeal(mdat) && !amorphous(mdat))
1138 whom = strcat(s_suffix(whom), " flesh");
1139 pline(fmt, whom);
1141 /* if a "no longer poisoned" message is coming, it will be last;
1142 obj->opoisoned was cleared above and any message referring to
1143 "poisoned <obj>" has now been given; we want just "<obj>" for
1144 last message, so reformat while obj is still accessible */
1145 if (unpoisonmsg)
1146 Strcpy(saved_oname, cxname(obj));
1148 /* [note: thrown obj might go away during killed/xkilled call] */
1150 if (needpoismsg)
1151 pline_The("poison doesn't seem to affect %s.", mon_nam(mon));
1152 if (poiskilled) {
1153 pline_The("poison was deadly...");
1154 if (!already_killed)
1155 xkilled(mon, XKILL_NOMSG);
1156 destroyed = TRUE; /* return FALSE; */
1157 } else if (destroyed) {
1158 if (!already_killed)
1159 killed(mon); /* takes care of most messages */
1160 } else if (u.umconf && hand_to_hand) {
1161 nohandglow(mon);
1162 if (!mon->mconf && !resist(mon, SPBOOK_CLASS, 0, NOTELL)) {
1163 mon->mconf = 1;
1164 if (!mon->mstun && mon->mcanmove && !mon->msleeping
1165 && canseemon(mon))
1166 pline("%s appears confused.", Monnam(mon));
1169 if (unpoisonmsg)
1170 Your("%s %s no longer poisoned.", saved_oname,
1171 vtense(saved_oname, "are"));
1173 return destroyed ? FALSE : TRUE;
1176 STATIC_OVL boolean
1177 shade_aware(obj)
1178 struct obj *obj;
1180 if (!obj)
1181 return FALSE;
1183 * The things in this list either
1184 * 1) affect shades.
1185 * OR
1186 * 2) are dealt with properly by other routines
1187 * when it comes to shades.
1189 if (obj->otyp == BOULDER
1190 || obj->otyp == HEAVY_IRON_BALL
1191 || obj->otyp == IRON_CHAIN /* dmgval handles those first three */
1192 || obj->otyp == MIRROR /* silver in the reflective surface */
1193 || obj->otyp == CLOVE_OF_GARLIC /* causes shades to flee */
1194 || objects[obj->otyp].oc_material == SILVER)
1195 return TRUE;
1196 return FALSE;
1199 /* check whether slippery clothing protects from hug or wrap attack */
1200 /* [currently assumes that you are the attacker] */
1201 STATIC_OVL boolean
1202 m_slips_free(mdef, mattk)
1203 struct monst *mdef;
1204 struct attack *mattk;
1206 struct obj *obj;
1208 if (mattk->adtyp == AD_DRIN) {
1209 /* intelligence drain attacks the head */
1210 obj = which_armor(mdef, W_ARMH);
1211 } else {
1212 /* grabbing attacks the body */
1213 obj = which_armor(mdef, W_ARMC); /* cloak */
1214 if (!obj)
1215 obj = which_armor(mdef, W_ARM); /* suit */
1216 if (!obj)
1217 obj = which_armor(mdef, W_ARMU); /* shirt */
1220 /* if monster's cloak/armor is greased, your grab slips off; this
1221 protection might fail (33% chance) when the armor is cursed */
1222 if (obj && (obj->greased || obj->otyp == OILSKIN_CLOAK)
1223 && (!obj->cursed || rn2(3))) {
1224 You("%s %s %s %s!",
1225 mattk->adtyp == AD_WRAP ? "slip off of"
1226 : "grab, but cannot hold onto",
1227 s_suffix(mon_nam(mdef)), obj->greased ? "greased" : "slippery",
1228 /* avoid "slippery slippery cloak"
1229 for undiscovered oilskin cloak */
1230 (obj->greased || objects[obj->otyp].oc_name_known)
1231 ? xname(obj)
1232 : cloak_simple_name(obj));
1234 if (obj->greased && !rn2(2)) {
1235 pline_The("grease wears off.");
1236 obj->greased = 0;
1238 return TRUE;
1240 return FALSE;
1243 /* used when hitting a monster with a lance while mounted;
1244 1: joust hit; 0: ordinary hit; -1: joust but break lance */
1245 STATIC_OVL int
1246 joust(mon, obj)
1247 struct monst *mon; /* target */
1248 struct obj *obj; /* weapon */
1250 int skill_rating, joust_dieroll;
1252 if (Fumbling || Stunned)
1253 return 0;
1254 /* sanity check; lance must be wielded in order to joust */
1255 if (obj != uwep && (obj != uswapwep || !u.twoweap))
1256 return 0;
1258 /* if using two weapons, use worse of lance and two-weapon skills */
1259 skill_rating = P_SKILL(weapon_type(obj)); /* lance skill */
1260 if (u.twoweap && P_SKILL(P_TWO_WEAPON_COMBAT) < skill_rating)
1261 skill_rating = P_SKILL(P_TWO_WEAPON_COMBAT);
1262 if (skill_rating == P_ISRESTRICTED)
1263 skill_rating = P_UNSKILLED; /* 0=>1 */
1265 /* odds to joust are expert:80%, skilled:60%, basic:40%, unskilled:20% */
1266 if ((joust_dieroll = rn2(5)) < skill_rating) {
1267 if (joust_dieroll == 0 && rnl(50) == (50 - 1) && !unsolid(mon->data)
1268 && !obj_resists(obj, 0, 100))
1269 return -1; /* hit that breaks lance */
1270 return 1; /* successful joust */
1272 return 0; /* no joust bonus; revert to ordinary attack */
1276 * Send in a demon pet for the hero. Exercise wisdom.
1278 * This function used to be inline to damageum(), but the Metrowerks compiler
1279 * (DR4 and DR4.5) screws up with an internal error 5 "Expression Too
1280 * Complex."
1281 * Pulling it out makes it work.
1283 STATIC_OVL void
1284 demonpet()
1286 int i;
1287 struct permonst *pm;
1288 struct monst *dtmp;
1290 pline("Some hell-p has arrived!");
1291 i = !rn2(6) ? ndemon(u.ualign.type) : NON_PM;
1292 pm = i != NON_PM ? &mons[i] : youmonst.data;
1293 if ((dtmp = makemon(pm, u.ux, u.uy, NO_MM_FLAGS)) != 0)
1294 (void) tamedog(dtmp, (struct obj *) 0);
1295 exercise(A_WIS, TRUE);
1298 STATIC_OVL boolean
1299 theft_petrifies(otmp)
1300 struct obj *otmp;
1302 if (uarmg || otmp->otyp != CORPSE
1303 || !touch_petrifies(&mons[otmp->corpsenm]) || Stone_resistance)
1304 return FALSE;
1306 #if 0 /* no poly_when_stoned() critter has theft capability */
1307 if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) {
1308 display_nhwindow(WIN_MESSAGE, FALSE); /* --More-- */
1309 return TRUE;
1311 #endif
1313 /* stealing this corpse is fatal... */
1314 instapetrify(corpse_xname(otmp, "stolen", CXN_ARTICLE));
1315 /* apparently wasn't fatal after all... */
1316 return TRUE;
1320 * Player uses theft attack against monster.
1322 * If the target is wearing body armor, take all of its possessions;
1323 * otherwise, take one object. [Is this really the behavior we want?]
1325 STATIC_OVL void
1326 steal_it(mdef, mattk)
1327 struct monst *mdef;
1328 struct attack *mattk;
1330 struct obj *otmp, *stealoid, **minvent_ptr;
1331 long unwornmask;
1333 if (!mdef->minvent)
1334 return; /* nothing to take */
1336 /* look for worn body armor */
1337 stealoid = (struct obj *) 0;
1338 if (could_seduce(&youmonst, mdef, mattk)) {
1339 /* find armor, and move it to end of inventory in the process */
1340 minvent_ptr = &mdef->minvent;
1341 while ((otmp = *minvent_ptr) != 0)
1342 if (otmp->owornmask & W_ARM) {
1343 if (stealoid)
1344 panic("steal_it: multiple worn suits");
1345 *minvent_ptr = otmp->nobj; /* take armor out of minvent */
1346 stealoid = otmp;
1347 stealoid->nobj = (struct obj *) 0;
1348 } else {
1349 minvent_ptr = &otmp->nobj;
1351 *minvent_ptr = stealoid; /* put armor back into minvent */
1354 if (stealoid) { /* we will be taking everything */
1355 if (gender(mdef) == (int) u.mfemale && youmonst.data->mlet == S_NYMPH)
1356 You("charm %s. She gladly hands over her possessions.",
1357 mon_nam(mdef));
1358 else
1359 You("seduce %s and %s starts to take off %s clothes.",
1360 mon_nam(mdef), mhe(mdef), mhis(mdef));
1363 while ((otmp = mdef->minvent) != 0) {
1364 if (!Upolyd)
1365 break; /* no longer have ability to steal */
1366 /* take the object away from the monster */
1367 obj_extract_self(otmp);
1368 if ((unwornmask = otmp->owornmask) != 0L) {
1369 mdef->misc_worn_check &= ~unwornmask;
1370 if (otmp->owornmask & W_WEP)
1371 setmnotwielded(mdef, otmp);
1372 otmp->owornmask = 0L;
1373 update_mon_intrinsics(mdef, otmp, FALSE, FALSE);
1375 if (otmp == stealoid) /* special message for final item */
1376 pline("%s finishes taking off %s suit.", Monnam(mdef),
1377 mhis(mdef));
1379 /* give the object to the character */
1380 otmp = hold_another_object(otmp, "You snatched but dropped %s.",
1381 doname(otmp), "You steal: ");
1382 if (otmp->where != OBJ_INVENT)
1383 continue;
1384 if (theft_petrifies(otmp))
1385 break; /* stop thieving even though hero survived */
1386 /* more take-away handling, after theft message */
1387 if (unwornmask & W_WEP) { /* stole wielded weapon */
1388 possibly_unwield(mdef, FALSE);
1389 } else if (unwornmask & W_ARMG) { /* stole worn gloves */
1390 mselftouch(mdef, (const char *) 0, TRUE);
1391 if (mdef->mhp <= 0) /* it's now a statue */
1392 return; /* can't continue stealing */
1395 if (!stealoid)
1396 break; /* only taking one item */
1401 damageum(mdef, mattk)
1402 register struct monst *mdef;
1403 register struct attack *mattk;
1405 register struct permonst *pd = mdef->data;
1406 int armpro, tmp = d((int) mattk->damn, (int) mattk->damd);
1407 boolean negated;
1409 armpro = magic_negation(mdef);
1410 /* since hero can't be cancelled, only defender's armor applies */
1411 negated = !(rn2(10) >= 3 * armpro);
1413 if (is_demon(youmonst.data) && !rn2(13) && !uwep
1414 && u.umonnum != PM_SUCCUBUS && u.umonnum != PM_INCUBUS
1415 && u.umonnum != PM_BALROG) {
1416 demonpet();
1417 return 0;
1419 switch (mattk->adtyp) {
1420 case AD_STUN:
1421 if (!Blind)
1422 pline("%s %s for a moment.", Monnam(mdef),
1423 makeplural(stagger(pd, "stagger")));
1424 mdef->mstun = 1;
1425 goto physical;
1426 case AD_LEGS:
1427 #if 0
1428 if (u.ucancelled) {
1429 tmp = 0;
1430 break;
1432 #endif
1433 goto physical;
1434 case AD_WERE: /* no special effect on monsters */
1435 case AD_HEAL: /* likewise */
1436 case AD_PHYS:
1437 physical:
1438 if (mattk->aatyp == AT_WEAP) {
1439 if (uwep)
1440 tmp = 0;
1441 } else if (mattk->aatyp == AT_KICK) {
1442 if (thick_skinned(pd))
1443 tmp = 0;
1444 if (pd == &mons[PM_SHADE]) {
1445 if (!(uarmf && uarmf->blessed)) {
1446 impossible("bad shade attack function flow?");
1447 tmp = 0;
1448 } else
1449 tmp = rnd(4); /* bless damage */
1451 /* add ring(s) of increase damage */
1452 if (u.udaminc > 0) {
1453 /* applies even if damage was 0 */
1454 tmp += u.udaminc;
1455 } else if (tmp > 0) {
1456 /* ring(s) might be negative; avoid converting
1457 0 to non-0 or positive to non-positive */
1458 tmp += u.udaminc;
1459 if (tmp < 1)
1460 tmp = 1;
1463 break;
1464 case AD_FIRE:
1465 if (negated) {
1466 tmp = 0;
1467 break;
1469 if (!Blind)
1470 pline("%s is %s!", Monnam(mdef), on_fire(pd, mattk));
1471 if (pd == &mons[PM_STRAW_GOLEM] || pd == &mons[PM_PAPER_GOLEM]) {
1472 if (!Blind)
1473 pline("%s burns completely!", Monnam(mdef));
1474 xkilled(mdef, XKILL_NOMSG | XKILL_NOCORPSE);
1475 tmp = 0;
1476 break;
1477 /* Don't return yet; keep hp<1 and tmp=0 for pet msg */
1479 tmp += destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE);
1480 tmp += destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE);
1481 if (resists_fire(mdef)) {
1482 if (!Blind)
1483 pline_The("fire doesn't heat %s!", mon_nam(mdef));
1484 golemeffects(mdef, AD_FIRE, tmp);
1485 shieldeff(mdef->mx, mdef->my);
1486 tmp = 0;
1488 /* only potions damage resistant players in destroy_item */
1489 tmp += destroy_mitem(mdef, POTION_CLASS, AD_FIRE);
1490 break;
1491 case AD_COLD:
1492 if (negated) {
1493 tmp = 0;
1494 break;
1496 if (!Blind)
1497 pline("%s is covered in frost!", Monnam(mdef));
1498 if (resists_cold(mdef)) {
1499 shieldeff(mdef->mx, mdef->my);
1500 if (!Blind)
1501 pline_The("frost doesn't chill %s!", mon_nam(mdef));
1502 golemeffects(mdef, AD_COLD, tmp);
1503 tmp = 0;
1505 tmp += destroy_mitem(mdef, POTION_CLASS, AD_COLD);
1506 break;
1507 case AD_ELEC:
1508 if (negated) {
1509 tmp = 0;
1510 break;
1512 if (!Blind)
1513 pline("%s is zapped!", Monnam(mdef));
1514 tmp += destroy_mitem(mdef, WAND_CLASS, AD_ELEC);
1515 if (resists_elec(mdef)) {
1516 if (!Blind)
1517 pline_The("zap doesn't shock %s!", mon_nam(mdef));
1518 golemeffects(mdef, AD_ELEC, tmp);
1519 shieldeff(mdef->mx, mdef->my);
1520 tmp = 0;
1522 /* only rings damage resistant players in destroy_item */
1523 tmp += destroy_mitem(mdef, RING_CLASS, AD_ELEC);
1524 break;
1525 case AD_ACID:
1526 if (resists_acid(mdef))
1527 tmp = 0;
1528 break;
1529 case AD_STON:
1530 if (!munstone(mdef, TRUE))
1531 minstapetrify(mdef, TRUE);
1532 tmp = 0;
1533 break;
1534 case AD_SSEX:
1535 case AD_SEDU:
1536 case AD_SITM:
1537 steal_it(mdef, mattk);
1538 tmp = 0;
1539 break;
1540 case AD_SGLD:
1541 /* This you as a leprechaun, so steal
1542 real gold only, no lesser coins */
1544 struct obj *mongold = findgold(mdef->minvent);
1545 if (mongold) {
1546 obj_extract_self(mongold);
1547 if (merge_choice(invent, mongold) || inv_cnt(FALSE) < 52) {
1548 addinv(mongold);
1549 Your("purse feels heavier.");
1550 } else {
1551 You("grab %s's gold, but find no room in your knapsack.",
1552 mon_nam(mdef));
1553 dropy(mongold);
1557 exercise(A_DEX, TRUE);
1558 tmp = 0;
1559 break;
1560 case AD_TLPT:
1561 if (tmp <= 0)
1562 tmp = 1;
1563 if (!negated && tmp < mdef->mhp) {
1564 char nambuf[BUFSZ];
1565 boolean u_saw_mon =
1566 canseemon(mdef) || (u.uswallow && u.ustuck == mdef);
1567 /* record the name before losing sight of monster */
1568 Strcpy(nambuf, Monnam(mdef));
1569 if (u_teleport_mon(mdef, FALSE) && u_saw_mon
1570 && !(canseemon(mdef) || (u.uswallow && u.ustuck == mdef)))
1571 pline("%s suddenly disappears!", nambuf);
1573 break;
1574 case AD_BLND:
1575 if (can_blnd(&youmonst, mdef, mattk->aatyp, (struct obj *) 0)) {
1576 if (!Blind && mdef->mcansee)
1577 pline("%s is blinded.", Monnam(mdef));
1578 mdef->mcansee = 0;
1579 tmp += mdef->mblinded;
1580 if (tmp > 127)
1581 tmp = 127;
1582 mdef->mblinded = tmp;
1584 tmp = 0;
1585 break;
1586 case AD_CURS:
1587 if (night() && !rn2(10) && !mdef->mcan) {
1588 if (pd == &mons[PM_CLAY_GOLEM]) {
1589 if (!Blind)
1590 pline("Some writing vanishes from %s head!",
1591 s_suffix(mon_nam(mdef)));
1592 xkilled(mdef, XKILL_NOMSG);
1593 /* Don't return yet; keep hp<1 and tmp=0 for pet msg */
1594 } else {
1595 mdef->mcan = 1;
1596 You("chuckle.");
1599 tmp = 0;
1600 break;
1601 case AD_DRLI:
1602 if (!negated && !rn2(3) && !resists_drli(mdef)) {
1603 int xtmp = d(2, 6);
1605 pline("%s suddenly seems weaker!", Monnam(mdef));
1606 mdef->mhpmax -= xtmp;
1607 mdef->mhp -= xtmp;
1608 /* !m_lev: level 0 monster is killed rather than drop to -1 */
1609 if (mdef->mhp <= 0 && !mdef->m_lev) {
1610 pline("%s dies!", Monnam(mdef));
1611 xkilled(mdef, XKILL_NOMSG);
1612 } else
1613 mdef->m_lev--;
1614 tmp = 0;
1616 break;
1617 case AD_RUST:
1618 if (pd == &mons[PM_IRON_GOLEM]) {
1619 pline("%s falls to pieces!", Monnam(mdef));
1620 xkilled(mdef, XKILL_NOMSG);
1622 erode_armor(mdef, ERODE_RUST);
1623 tmp = 0;
1624 break;
1625 case AD_CORR:
1626 erode_armor(mdef, ERODE_CORRODE);
1627 tmp = 0;
1628 break;
1629 case AD_DCAY:
1630 if (pd == &mons[PM_WOOD_GOLEM] || pd == &mons[PM_LEATHER_GOLEM]) {
1631 pline("%s falls to pieces!", Monnam(mdef));
1632 xkilled(mdef, XKILL_NOMSG);
1634 erode_armor(mdef, ERODE_ROT);
1635 tmp = 0;
1636 break;
1637 case AD_DREN:
1638 if (!negated && !rn2(4))
1639 xdrainenergym(mdef, TRUE);
1640 tmp = 0;
1641 break;
1642 case AD_DRST:
1643 case AD_DRDX:
1644 case AD_DRCO:
1645 if (!negated && !rn2(8)) {
1646 Your("%s was poisoned!", mpoisons_subj(&youmonst, mattk));
1647 if (resists_poison(mdef))
1648 pline_The("poison doesn't seem to affect %s.", mon_nam(mdef));
1649 else {
1650 if (!rn2(10)) {
1651 Your("poison was deadly...");
1652 tmp = mdef->mhp;
1653 } else
1654 tmp += rn1(10, 6);
1657 break;
1658 case AD_DRIN: {
1659 struct obj *helmet;
1661 if (notonhead || !has_head(pd)) {
1662 pline("%s doesn't seem harmed.", Monnam(mdef));
1663 tmp = 0;
1664 if (!Unchanging && pd == &mons[PM_GREEN_SLIME]) {
1665 if (!Slimed) {
1666 You("suck in some slime and don't feel very well.");
1667 make_slimed(10L, (char *) 0);
1670 break;
1672 if (m_slips_free(mdef, mattk))
1673 break;
1675 if ((helmet = which_armor(mdef, W_ARMH)) != 0 && rn2(8)) {
1676 pline("%s %s blocks your attack to %s head.",
1677 s_suffix(Monnam(mdef)), helm_simple_name(helmet),
1678 mhis(mdef));
1679 break;
1682 (void) eat_brains(&youmonst, mdef, TRUE, &tmp);
1683 break;
1685 case AD_STCK:
1686 if (!negated && !sticks(pd))
1687 u.ustuck = mdef; /* it's now stuck to you */
1688 break;
1689 case AD_WRAP:
1690 if (!sticks(pd)) {
1691 if (!u.ustuck && !rn2(10)) {
1692 if (m_slips_free(mdef, mattk)) {
1693 tmp = 0;
1694 } else {
1695 You("swing yourself around %s!", mon_nam(mdef));
1696 u.ustuck = mdef;
1698 } else if (u.ustuck == mdef) {
1699 /* Monsters don't wear amulets of magical breathing */
1700 if (is_pool(u.ux, u.uy) && !is_swimmer(pd)
1701 && !amphibious(pd)) {
1702 You("drown %s...", mon_nam(mdef));
1703 tmp = mdef->mhp;
1704 } else if (mattk->aatyp == AT_HUGS)
1705 pline("%s is being crushed.", Monnam(mdef));
1706 } else {
1707 tmp = 0;
1708 if (flags.verbose)
1709 You("brush against %s %s.", s_suffix(mon_nam(mdef)),
1710 mbodypart(mdef, LEG));
1712 } else
1713 tmp = 0;
1714 break;
1715 case AD_PLYS:
1716 if (!negated && mdef->mcanmove && !rn2(3) && tmp < mdef->mhp) {
1717 if (!Blind)
1718 pline("%s is frozen by you!", Monnam(mdef));
1719 paralyze_monst(mdef, rnd(10));
1721 break;
1722 case AD_SLEE:
1723 if (!negated && !mdef->msleeping && sleep_monst(mdef, rnd(10), -1)) {
1724 if (!Blind)
1725 pline("%s is put to sleep by you!", Monnam(mdef));
1726 slept_monst(mdef);
1728 break;
1729 case AD_SLIM:
1730 if (negated)
1731 break; /* physical damage only */
1732 if (!rn2(4) && !slimeproof(pd)) {
1733 if (!munslime(mdef, TRUE) && mdef->mhp > 0) {
1734 /* this assumes newcham() won't fail; since hero has
1735 a slime attack, green slimes haven't been geno'd */
1736 You("turn %s into slime.", mon_nam(mdef));
1737 if (newcham(mdef, &mons[PM_GREEN_SLIME], FALSE, FALSE))
1738 pd = mdef->data;
1740 /* munslime attempt could have been fatal */
1741 if (mdef->mhp < 1)
1742 return 2; /* skip death message */
1743 tmp = 0;
1745 break;
1746 case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */
1747 /* there's no msomearmor() function, so just do damage */
1748 /* if (negated) break; */
1749 break;
1750 case AD_SLOW:
1751 if (!negated && mdef->mspeed != MSLOW) {
1752 unsigned int oldspeed = mdef->mspeed;
1754 mon_adjust_speed(mdef, -1, (struct obj *) 0);
1755 if (mdef->mspeed != oldspeed && canseemon(mdef))
1756 pline("%s slows down.", Monnam(mdef));
1758 break;
1759 case AD_CONF:
1760 if (!mdef->mconf) {
1761 if (canseemon(mdef))
1762 pline("%s looks confused.", Monnam(mdef));
1763 mdef->mconf = 1;
1765 break;
1766 default:
1767 tmp = 0;
1768 break;
1771 mdef->mstrategy &= ~STRAT_WAITFORU; /* in case player is very fast */
1772 mdef->mhp -= tmp;
1773 if (mdef->mhp < 1) {
1774 if (mdef->mtame && !cansee(mdef->mx, mdef->my)) {
1775 You_feel("embarrassed for a moment.");
1776 if (tmp)
1777 xkilled(mdef, XKILL_NOMSG); /* !tmp but hp<1: already killed */
1778 } else if (!flags.verbose) {
1779 You("destroy it!");
1780 if (tmp)
1781 xkilled(mdef, XKILL_NOMSG);
1782 } else if (tmp)
1783 killed(mdef);
1784 return 2;
1786 return 1;
1789 STATIC_OVL int
1790 explum(mdef, mattk)
1791 register struct monst *mdef;
1792 register struct attack *mattk;
1794 register int tmp = d((int) mattk->damn, (int) mattk->damd);
1796 You("explode!");
1797 switch (mattk->adtyp) {
1798 boolean resistance; /* only for cold/fire/elec */
1800 case AD_BLND:
1801 if (!resists_blnd(mdef)) {
1802 pline("%s is blinded by your flash of light!", Monnam(mdef));
1803 mdef->mblinded = min((int) mdef->mblinded + tmp, 127);
1804 mdef->mcansee = 0;
1806 break;
1807 case AD_HALU:
1808 if (haseyes(mdef->data) && mdef->mcansee) {
1809 pline("%s is affected by your flash of light!", Monnam(mdef));
1810 mdef->mconf = 1;
1812 break;
1813 case AD_COLD:
1814 resistance = resists_cold(mdef);
1815 goto common;
1816 case AD_FIRE:
1817 resistance = resists_fire(mdef);
1818 goto common;
1819 case AD_ELEC:
1820 resistance = resists_elec(mdef);
1821 common:
1822 if (!resistance) {
1823 pline("%s gets blasted!", Monnam(mdef));
1824 mdef->mhp -= tmp;
1825 if (mdef->mhp <= 0) {
1826 killed(mdef);
1827 return 2;
1829 } else {
1830 shieldeff(mdef->mx, mdef->my);
1831 if (is_golem(mdef->data))
1832 golemeffects(mdef, (int) mattk->adtyp, tmp);
1833 else
1834 pline_The("blast doesn't seem to affect %s.", mon_nam(mdef));
1836 break;
1837 default:
1838 break;
1840 return 1;
1843 STATIC_OVL void
1844 start_engulf(mdef)
1845 struct monst *mdef;
1847 if (!Invisible) {
1848 map_location(u.ux, u.uy, TRUE);
1849 tmp_at(DISP_ALWAYS, mon_to_glyph(&youmonst));
1850 tmp_at(mdef->mx, mdef->my);
1852 You("engulf %s!", mon_nam(mdef));
1853 delay_output();
1854 delay_output();
1857 STATIC_OVL void
1858 end_engulf()
1860 if (!Invisible) {
1861 tmp_at(DISP_END, 0);
1862 newsym(u.ux, u.uy);
1866 STATIC_OVL int
1867 gulpum(mdef, mattk)
1868 register struct monst *mdef;
1869 register struct attack *mattk;
1871 #ifdef LINT /* static char msgbuf[BUFSZ]; */
1872 char msgbuf[BUFSZ];
1873 #else
1874 static char msgbuf[BUFSZ]; /* for nomovemsg */
1875 #endif
1876 register int tmp;
1877 register int dam = d((int) mattk->damn, (int) mattk->damd);
1878 boolean fatal_gulp;
1879 struct obj *otmp;
1880 struct permonst *pd = mdef->data;
1882 /* Not totally the same as for real monsters. Specifically, these
1883 * don't take multiple moves. (It's just too hard, for too little
1884 * result, to program monsters which attack from inside you, which
1885 * would be necessary if done accurately.) Instead, we arbitrarily
1886 * kill the monster immediately for AD_DGST and we regurgitate them
1887 * after exactly 1 round of attack otherwise. -KAA
1890 if (!engulf_target(&youmonst, mdef))
1891 return 0;
1893 if (u.uhunger < 1500 && !u.uswallow) {
1894 for (otmp = mdef->minvent; otmp; otmp = otmp->nobj)
1895 (void) snuff_lit(otmp);
1897 /* force vampire in bat, cloud, or wolf form to revert back to
1898 vampire form now instead of dealing with that when it dies */
1899 if (is_vampshifter(mdef)
1900 && newcham(mdef, &mons[mdef->cham], FALSE, FALSE)) {
1901 You("engulf it, then expel it.");
1902 if (canspotmon(mdef))
1903 pline("It turns into %s.", a_monnam(mdef));
1904 else
1905 map_invisible(mdef->mx, mdef->my);
1906 return 1;
1909 /* engulfing a cockatrice or digesting a Rider or Medusa */
1910 fatal_gulp = (touch_petrifies(pd) && !Stone_resistance)
1911 || (mattk->adtyp == AD_DGST
1912 && (is_rider(pd) || (pd == &mons[PM_MEDUSA]
1913 && !Stone_resistance)));
1915 if ((mattk->adtyp == AD_DGST && !Slow_digestion) || fatal_gulp)
1916 eating_conducts(pd);
1918 if (fatal_gulp && !is_rider(pd)) { /* petrification */
1919 char kbuf[BUFSZ];
1920 const char *mname = pd->mname;
1922 if (!type_is_pname(pd))
1923 mname = an(mname);
1924 You("englut %s.", mon_nam(mdef));
1925 Sprintf(kbuf, "swallowing %s whole", mname);
1926 instapetrify(kbuf);
1927 } else {
1928 start_engulf(mdef);
1929 switch (mattk->adtyp) {
1930 case AD_DGST:
1931 /* eating a Rider or its corpse is fatal */
1932 if (is_rider(pd)) {
1933 pline("Unfortunately, digesting any of it is fatal.");
1934 end_engulf();
1935 Sprintf(killer.name, "unwisely tried to eat %s",
1936 pd->mname);
1937 killer.format = NO_KILLER_PREFIX;
1938 done(DIED);
1939 return 0; /* lifesaved */
1942 if (Slow_digestion) {
1943 dam = 0;
1944 break;
1947 /* Use up amulet of life saving */
1948 if (!!(otmp = mlifesaver(mdef)))
1949 m_useup(mdef, otmp);
1951 newuhs(FALSE);
1952 /* start_engulf() issues "you engulf <mdef>" above; this
1953 used to specify XKILL_NOMSG but we need "you kill <mdef>"
1954 in case we're also going to get "welcome to level N+1";
1955 "you totally digest <mdef>" will be coming soon (after
1956 several turns) but the level-gain message seems out of
1957 order if the kill message is left implicit */
1958 xkilled(mdef, XKILL_GIVEMSG | XKILL_NOCORPSE);
1959 if (mdef->mhp > 0) { /* monster lifesaved */
1960 You("hurriedly regurgitate the sizzling in your %s.",
1961 body_part(STOMACH));
1962 } else {
1963 tmp = 1 + (pd->cwt >> 8);
1964 if (corpse_chance(mdef, &youmonst, TRUE)
1965 && !(mvitals[monsndx(pd)].mvflags & G_NOCORPSE)) {
1966 /* nutrition only if there can be a corpse */
1967 u.uhunger += (pd->cnutrit + 1) / 2;
1968 } else
1969 tmp = 0;
1970 Sprintf(msgbuf, "You totally digest %s.", mon_nam(mdef));
1971 if (tmp != 0) {
1972 /* setting afternmv = end_engulf is tempting,
1973 * but will cause problems if the player is
1974 * attacked (which uses his real location) or
1975 * if his See_invisible wears off
1977 You("digest %s.", mon_nam(mdef));
1978 if (Slow_digestion)
1979 tmp *= 2;
1980 nomul(-tmp);
1981 multi_reason = "digesting something";
1982 nomovemsg = msgbuf;
1983 } else
1984 pline1(msgbuf);
1985 if (pd == &mons[PM_GREEN_SLIME]) {
1986 Sprintf(msgbuf, "%s isn't sitting well with you.",
1987 The(pd->mname));
1988 if (!Unchanging) {
1989 make_slimed(5L, (char *) 0);
1991 } else
1992 exercise(A_CON, TRUE);
1994 end_engulf();
1995 return 2;
1996 case AD_PHYS:
1997 if (youmonst.data == &mons[PM_FOG_CLOUD]) {
1998 pline("%s is laden with your moisture.", Monnam(mdef));
1999 if (amphibious(pd) && !flaming(pd)) {
2000 dam = 0;
2001 pline("%s seems unharmed.", Monnam(mdef));
2003 } else
2004 pline("%s is pummeled with your debris!", Monnam(mdef));
2005 break;
2006 case AD_ACID:
2007 pline("%s is covered with your goo!", Monnam(mdef));
2008 if (resists_acid(mdef)) {
2009 pline("It seems harmless to %s.", mon_nam(mdef));
2010 dam = 0;
2012 break;
2013 case AD_BLND:
2014 if (can_blnd(&youmonst, mdef, mattk->aatyp,
2015 (struct obj *) 0)) {
2016 if (mdef->mcansee)
2017 pline("%s can't see in there!", Monnam(mdef));
2018 mdef->mcansee = 0;
2019 dam += mdef->mblinded;
2020 if (dam > 127)
2021 dam = 127;
2022 mdef->mblinded = dam;
2024 dam = 0;
2025 break;
2026 case AD_ELEC:
2027 if (rn2(2)) {
2028 pline_The("air around %s crackles with electricity.",
2029 mon_nam(mdef));
2030 if (resists_elec(mdef)) {
2031 pline("%s seems unhurt.", Monnam(mdef));
2032 dam = 0;
2034 golemeffects(mdef, (int) mattk->adtyp, dam);
2035 } else
2036 dam = 0;
2037 break;
2038 case AD_COLD:
2039 if (rn2(2)) {
2040 if (resists_cold(mdef)) {
2041 pline("%s seems mildly chilly.", Monnam(mdef));
2042 dam = 0;
2043 } else
2044 pline("%s is freezing to death!", Monnam(mdef));
2045 golemeffects(mdef, (int) mattk->adtyp, dam);
2046 } else
2047 dam = 0;
2048 break;
2049 case AD_FIRE:
2050 if (rn2(2)) {
2051 if (resists_fire(mdef)) {
2052 pline("%s seems mildly hot.", Monnam(mdef));
2053 dam = 0;
2054 } else
2055 pline("%s is burning to a crisp!", Monnam(mdef));
2056 golemeffects(mdef, (int) mattk->adtyp, dam);
2057 } else
2058 dam = 0;
2059 break;
2060 case AD_DREN:
2061 if (!rn2(4))
2062 xdrainenergym(mdef, TRUE);
2063 dam = 0;
2064 break;
2066 end_engulf();
2067 mdef->mhp -= dam;
2068 if (mdef->mhp <= 0) {
2069 killed(mdef);
2070 if (mdef->mhp <= 0) /* not lifesaved */
2071 return 2;
2073 You("%s %s!", is_animal(youmonst.data) ? "regurgitate" : "expel",
2074 mon_nam(mdef));
2075 if (Slow_digestion || is_animal(youmonst.data)) {
2076 pline("Obviously, you didn't like %s taste.",
2077 s_suffix(mon_nam(mdef)));
2081 return 0;
2084 void
2085 missum(mdef, mattk, wouldhavehit)
2086 register struct monst *mdef;
2087 register struct attack *mattk;
2088 boolean wouldhavehit;
2090 if (wouldhavehit) /* monk is missing due to penalty for wearing suit */
2091 Your("armor is rather cumbersome...");
2093 if (could_seduce(&youmonst, mdef, mattk))
2094 You("pretend to be friendly to %s.", mon_nam(mdef));
2095 else if (canspotmon(mdef) && flags.verbose)
2096 You("miss %s.", mon_nam(mdef));
2097 else
2098 You("miss it.");
2099 if (!mdef->msleeping && mdef->mcanmove)
2100 wakeup(mdef, TRUE);
2103 /* attack monster as a monster. */
2104 STATIC_OVL boolean
2105 hmonas(mon)
2106 register struct monst *mon;
2108 struct attack *mattk, alt_attk;
2109 struct obj *weapon;
2110 boolean altwep = FALSE, weapon_used = FALSE;
2111 int i, tmp, armorpenalty, sum[NATTK], nsum = 0, dhit = 0, attknum = 0;
2113 for (i = 0; i < NATTK; i++) {
2114 sum[i] = 0;
2115 mattk = getmattk(&youmonst, mon, i, sum, &alt_attk);
2116 switch (mattk->aatyp) {
2117 case AT_WEAP:
2118 use_weapon:
2119 /* Certain monsters don't use weapons when encountered as enemies,
2120 * but players who polymorph into them have hands or claws and
2121 * thus should be able to use weapons. This shouldn't prohibit
2122 * the use of most special abilities, either.
2123 * If monster has multiple claw attacks, only one can use weapon.
2125 weapon_used = TRUE;
2126 /* Potential problem: if the monster gets multiple weapon attacks,
2127 * we currently allow the player to get each of these as a weapon
2128 * attack. Is this really desirable?
2130 /* approximate two-weapon mode */
2131 weapon = (altwep && uswapwep) ? uswapwep : uwep;
2132 altwep = !altwep; /* toggle for next attack */
2133 tmp = find_roll_to_hit(mon, AT_WEAP, weapon, &attknum,
2134 &armorpenalty);
2135 dhit = (tmp > (dieroll = rnd(20)) || u.uswallow);
2136 /* Enemy dead, before any special abilities used */
2137 if (!known_hitum(mon, weapon, &dhit, tmp, armorpenalty, mattk)) {
2138 sum[i] = 2;
2139 break;
2140 } else
2141 sum[i] = dhit;
2142 /* might be a worm that gets cut in half */
2143 if (m_at(u.ux + u.dx, u.uy + u.dy) != mon)
2144 return (boolean) (nsum != 0);
2145 /* Do not print "You hit" message, since known_hitum
2146 * already did it.
2148 if (dhit && mattk->adtyp != AD_SPEL && mattk->adtyp != AD_PHYS)
2149 sum[i] = damageum(mon, mattk);
2150 break;
2151 case AT_CLAW:
2152 if (uwep && !cantwield(youmonst.data) && !weapon_used)
2153 goto use_weapon;
2154 /*FALLTHRU*/
2155 case AT_TUCH:
2156 if (uwep && youmonst.data->mlet == S_LICH && !weapon_used)
2157 goto use_weapon;
2158 /*FALLTHRU*/
2159 case AT_KICK:
2160 case AT_BITE:
2161 case AT_STNG:
2162 case AT_BUTT:
2163 case AT_TENT:
2164 tmp = find_roll_to_hit(mon, mattk->aatyp, (struct obj *) 0,
2165 &attknum, &armorpenalty);
2166 dhit = (tmp > (dieroll = rnd(20)) || u.uswallow);
2167 if (dhit) {
2168 int compat;
2170 if (!u.uswallow
2171 && (compat = could_seduce(&youmonst, mon, mattk))) {
2172 You("%s %s %s.",
2173 mon->mcansee && haseyes(mon->data) ? "smile at"
2174 : "talk to",
2175 mon_nam(mon),
2176 compat == 2 ? "engagingly" : "seductively");
2177 /* doesn't anger it; no wakeup() */
2178 sum[i] = damageum(mon, mattk);
2179 break;
2181 wakeup(mon, TRUE);
2182 /* maybe this check should be in damageum()? */
2183 if (mon->data == &mons[PM_SHADE]
2184 && !(mattk->aatyp == AT_KICK && uarmf
2185 && uarmf->blessed)) {
2186 Your("attack passes harmlessly through %s.",
2187 mon_nam(mon));
2188 break;
2190 if (mattk->aatyp == AT_KICK)
2191 You("kick %s.", mon_nam(mon));
2192 else if (mattk->aatyp == AT_BITE)
2193 You("bite %s.", mon_nam(mon));
2194 else if (mattk->aatyp == AT_STNG)
2195 You("sting %s.", mon_nam(mon));
2196 else if (mattk->aatyp == AT_BUTT)
2197 You("butt %s.", mon_nam(mon));
2198 else if (mattk->aatyp == AT_TUCH)
2199 You("touch %s.", mon_nam(mon));
2200 else if (mattk->aatyp == AT_TENT)
2201 Your("tentacles suck %s.", mon_nam(mon));
2202 else
2203 You("hit %s.", mon_nam(mon));
2204 sum[i] = damageum(mon, mattk);
2205 } else {
2206 missum(mon, mattk, (tmp + armorpenalty > dieroll));
2208 break;
2210 case AT_HUGS:
2211 /* automatic if prev two attacks succeed, or if
2212 * already grabbed in a previous attack
2214 dhit = 1;
2215 wakeup(mon, TRUE);
2216 if (mon->data == &mons[PM_SHADE])
2217 Your("hug passes harmlessly through %s.", mon_nam(mon));
2218 else if (!sticks(mon->data) && !u.uswallow) {
2219 if (mon == u.ustuck) {
2220 pline("%s is being %s.", Monnam(mon),
2221 u.umonnum == PM_ROPE_GOLEM ? "choked" : "crushed");
2222 sum[i] = damageum(mon, mattk);
2223 } else if (i >= 2 && sum[i - 1] && sum[i - 2]) {
2224 You("grab %s!", mon_nam(mon));
2225 u.ustuck = mon;
2226 sum[i] = damageum(mon, mattk);
2229 break;
2231 case AT_EXPL: /* automatic hit if next to */
2232 dhit = -1;
2233 wakeup(mon, TRUE);
2234 sum[i] = explum(mon, mattk);
2235 break;
2237 case AT_ENGL:
2238 tmp = find_roll_to_hit(mon, mattk->aatyp, (struct obj *) 0,
2239 &attknum, &armorpenalty);
2240 if ((dhit = (tmp > rnd(20 + i)))) {
2241 wakeup(mon, TRUE);
2242 if (mon->data == &mons[PM_SHADE])
2243 Your("attempt to surround %s is harmless.", mon_nam(mon));
2244 else {
2245 sum[i] = gulpum(mon, mattk);
2246 if (sum[i] == 2 && (mon->data->mlet == S_ZOMBIE
2247 || mon->data->mlet == S_MUMMY)
2248 && rn2(5) && !Sick_resistance) {
2249 You_feel("%ssick.", (Sick) ? "very " : "");
2250 mdamageu(mon, rnd(8));
2253 } else {
2254 missum(mon, mattk, FALSE);
2256 break;
2258 case AT_MAGC:
2259 /* No check for uwep; if wielding nothing we want to
2260 * do the normal 1-2 points bare hand damage...
2262 if ((youmonst.data->mlet == S_KOBOLD
2263 || youmonst.data->mlet == S_ORC
2264 || youmonst.data->mlet == S_GNOME) && !weapon_used)
2265 goto use_weapon;
2267 case AT_NONE:
2268 case AT_BOOM:
2269 continue;
2270 /* Not break--avoid passive attacks from enemy */
2272 case AT_BREA:
2273 case AT_SPIT:
2274 case AT_GAZE: /* all done using #monster command */
2275 dhit = 0;
2276 break;
2278 default: /* Strange... */
2279 impossible("strange attack of yours (%d)", mattk->aatyp);
2281 if (dhit == -1) {
2282 u.mh = -1; /* dead in the current form */
2283 rehumanize();
2285 if (sum[i] == 2)
2286 return (boolean) passive(mon, 1, 0, mattk->aatyp, FALSE);
2287 /* defender dead */
2288 else {
2289 (void) passive(mon, sum[i], 1, mattk->aatyp, FALSE);
2290 nsum |= sum[i];
2292 if (!Upolyd)
2293 break; /* No extra attacks if no longer a monster */
2294 if (multi < 0)
2295 break; /* If paralyzed while attacking, i.e. floating eye */
2297 return (boolean) (nsum != 0);
2300 /* Special (passive) attacks on you by monsters done here.
2303 passive(mon, mhit, malive, aatyp, wep_was_destroyed)
2304 register struct monst *mon;
2305 register boolean mhit;
2306 register int malive;
2307 uchar aatyp;
2308 boolean wep_was_destroyed;
2310 register struct permonst *ptr = mon->data;
2311 register int i, tmp;
2313 for (i = 0;; i++) {
2314 if (i >= NATTK)
2315 return (malive | mhit); /* no passive attacks */
2316 if (ptr->mattk[i].aatyp == AT_NONE)
2317 break; /* try this one */
2319 /* Note: tmp not always used */
2320 if (ptr->mattk[i].damn)
2321 tmp = d((int) ptr->mattk[i].damn, (int) ptr->mattk[i].damd);
2322 else if (ptr->mattk[i].damd)
2323 tmp = d((int) mon->m_lev + 1, (int) ptr->mattk[i].damd);
2324 else
2325 tmp = 0;
2327 /* These affect you even if they just died.
2329 switch (ptr->mattk[i].adtyp) {
2330 case AD_FIRE:
2331 if (mhit && !mon->mcan) {
2332 if (aatyp == AT_KICK) {
2333 if (uarmf && !rn2(6))
2334 (void) erode_obj(uarmf, xname(uarmf), ERODE_BURN,
2335 EF_GREASE | EF_VERBOSE);
2336 } else if (aatyp == AT_WEAP || aatyp == AT_CLAW
2337 || aatyp == AT_MAGC || aatyp == AT_TUCH)
2338 passive_obj(mon, (struct obj *) 0, &(ptr->mattk[i]));
2340 break;
2341 case AD_ACID:
2342 if (mhit && rn2(2)) {
2343 if (Blind || !flags.verbose)
2344 You("are splashed!");
2345 else
2346 You("are splashed by %s %s!", s_suffix(mon_nam(mon)),
2347 hliquid("acid"));
2349 if (!Acid_resistance)
2350 mdamageu(mon, tmp);
2351 if (!rn2(30))
2352 erode_armor(&youmonst, ERODE_CORRODE);
2354 if (mhit) {
2355 if (aatyp == AT_KICK) {
2356 if (uarmf && !rn2(6))
2357 (void) erode_obj(uarmf, xname(uarmf), ERODE_CORRODE,
2358 EF_GREASE | EF_VERBOSE);
2359 } else if (aatyp == AT_WEAP || aatyp == AT_CLAW
2360 || aatyp == AT_MAGC || aatyp == AT_TUCH)
2361 passive_obj(mon, (struct obj *) 0, &(ptr->mattk[i]));
2363 exercise(A_STR, FALSE);
2364 break;
2365 case AD_STON:
2366 if (mhit) { /* successful attack */
2367 long protector = attk_protection((int) aatyp);
2369 /* hero using monsters' AT_MAGC attack is hitting hand to
2370 hand rather than casting a spell */
2371 if (aatyp == AT_MAGC)
2372 protector = W_ARMG;
2374 if (protector == 0L /* no protection */
2375 || (protector == W_ARMG && !uarmg
2376 && !uwep && !wep_was_destroyed)
2377 || (protector == W_ARMF && !uarmf)
2378 || (protector == W_ARMH && !uarmh)
2379 || (protector == (W_ARMC | W_ARMG) && (!uarmc || !uarmg))) {
2380 if (!Stone_resistance
2381 && !(poly_when_stoned(youmonst.data)
2382 && polymon(PM_STONE_GOLEM))) {
2383 done_in_by(mon, STONING); /* "You turn to stone..." */
2384 return 2;
2388 break;
2389 case AD_RUST:
2390 if (mhit && !mon->mcan) {
2391 if (aatyp == AT_KICK) {
2392 if (uarmf)
2393 (void) erode_obj(uarmf, xname(uarmf), ERODE_RUST,
2394 EF_GREASE | EF_VERBOSE);
2395 } else if (aatyp == AT_WEAP || aatyp == AT_CLAW
2396 || aatyp == AT_MAGC || aatyp == AT_TUCH)
2397 passive_obj(mon, (struct obj *) 0, &(ptr->mattk[i]));
2399 break;
2400 case AD_CORR:
2401 if (mhit && !mon->mcan) {
2402 if (aatyp == AT_KICK) {
2403 if (uarmf)
2404 (void) erode_obj(uarmf, xname(uarmf), ERODE_CORRODE,
2405 EF_GREASE | EF_VERBOSE);
2406 } else if (aatyp == AT_WEAP || aatyp == AT_CLAW
2407 || aatyp == AT_MAGC || aatyp == AT_TUCH)
2408 passive_obj(mon, (struct obj *) 0, &(ptr->mattk[i]));
2410 break;
2411 case AD_MAGM:
2412 /* wrath of gods for attacking Oracle */
2413 if (Antimagic) {
2414 shieldeff(u.ux, u.uy);
2415 pline("A hail of magic missiles narrowly misses you!");
2416 } else {
2417 You("are hit by magic missiles appearing from thin air!");
2418 mdamageu(mon, tmp);
2420 break;
2421 case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */
2422 if (mhit) {
2423 struct obj *obj = (struct obj *) 0;
2425 if (aatyp == AT_KICK) {
2426 obj = uarmf;
2427 if (!obj)
2428 break;
2429 } else if (aatyp == AT_BITE || aatyp == AT_BUTT
2430 || (aatyp >= AT_STNG && aatyp < AT_WEAP)) {
2431 break; /* no object involved */
2433 passive_obj(mon, obj, &(ptr->mattk[i]));
2435 break;
2436 default:
2437 break;
2440 /* These only affect you if they still live.
2442 if (malive && !mon->mcan && rn2(3)) {
2443 switch (ptr->mattk[i].adtyp) {
2444 case AD_PLYS:
2445 if (ptr == &mons[PM_FLOATING_EYE]) {
2446 if (!canseemon(mon)) {
2447 break;
2449 if (mon->mcansee) {
2450 if (ureflects("%s gaze is reflected by your %s.",
2451 s_suffix(Monnam(mon)))) {
2453 } else if (Free_action) {
2454 You("momentarily stiffen under %s gaze!",
2455 s_suffix(mon_nam(mon)));
2456 } else if (Hallucination && rn2(4)) {
2457 pline("%s looks %s%s.", Monnam(mon),
2458 !rn2(2) ? "" : "rather ",
2459 !rn2(2) ? "numb" : "stupified");
2460 } else {
2461 You("are frozen by %s gaze!", s_suffix(mon_nam(mon)));
2462 nomul((ACURR(A_WIS) > 12 || rn2(4)) ? -tmp : -127);
2463 multi_reason = "frozen by a monster's gaze";
2464 nomovemsg = 0;
2466 } else {
2467 pline("%s cannot defend itself.",
2468 Adjmonnam(mon, "blind"));
2469 if (!rn2(500))
2470 change_luck(-1);
2472 } else if (Free_action) {
2473 You("momentarily stiffen.");
2474 } else { /* gelatinous cube */
2475 You("are frozen by %s!", mon_nam(mon));
2476 nomovemsg = You_can_move_again;
2477 nomul(-tmp);
2478 multi_reason = "frozen by a monster";
2479 exercise(A_DEX, FALSE);
2481 break;
2482 case AD_COLD: /* brown mold or blue jelly */
2483 if (monnear(mon, u.ux, u.uy)) {
2484 if (Cold_resistance) {
2485 shieldeff(u.ux, u.uy);
2486 You_feel("a mild chill.");
2487 ugolemeffects(AD_COLD, tmp);
2488 break;
2490 You("are suddenly very cold!");
2491 mdamageu(mon, tmp);
2492 /* monster gets stronger with your heat! */
2493 mon->mhp += tmp / 2;
2494 if (mon->mhpmax < mon->mhp)
2495 mon->mhpmax = mon->mhp;
2496 /* at a certain point, the monster will reproduce! */
2497 if (mon->mhpmax > ((int) (mon->m_lev + 1) * 8))
2498 (void) split_mon(mon, &youmonst);
2500 break;
2501 case AD_STUN: /* specifically yellow mold */
2502 if (!Stunned)
2503 make_stunned((long) tmp, TRUE);
2504 break;
2505 case AD_FIRE:
2506 if (monnear(mon, u.ux, u.uy)) {
2507 if (Fire_resistance) {
2508 shieldeff(u.ux, u.uy);
2509 You_feel("mildly warm.");
2510 ugolemeffects(AD_FIRE, tmp);
2511 break;
2513 You("are suddenly very hot!");
2514 mdamageu(mon, tmp); /* fire damage */
2516 break;
2517 case AD_ELEC:
2518 if (Shock_resistance) {
2519 shieldeff(u.ux, u.uy);
2520 You_feel("a mild tingle.");
2521 ugolemeffects(AD_ELEC, tmp);
2522 break;
2524 You("are jolted with electricity!");
2525 mdamageu(mon, tmp);
2526 break;
2527 default:
2528 break;
2531 return (malive | mhit);
2535 * Special (passive) attacks on an attacking object by monsters done here.
2536 * Assumes the attack was successful.
2538 void
2539 passive_obj(mon, obj, mattk)
2540 struct monst *mon;
2541 struct obj *obj; /* null means pick uwep, uswapwep or uarmg */
2542 struct attack *mattk; /* null means we find one internally */
2544 struct permonst *ptr = mon->data;
2545 int i;
2547 /* if caller hasn't specified an object, use uwep, uswapwep or uarmg */
2548 if (!obj) {
2549 obj = (u.twoweap && uswapwep && !rn2(2)) ? uswapwep : uwep;
2550 if (!obj && mattk->adtyp == AD_ENCH)
2551 obj = uarmg; /* no weapon? then must be gloves */
2552 if (!obj)
2553 return; /* no object to affect */
2556 /* if caller hasn't specified an attack, find one */
2557 if (!mattk) {
2558 for (i = 0;; i++) {
2559 if (i >= NATTK)
2560 return; /* no passive attacks */
2561 if (ptr->mattk[i].aatyp == AT_NONE)
2562 break; /* try this one */
2564 mattk = &(ptr->mattk[i]);
2567 switch (mattk->adtyp) {
2568 case AD_FIRE:
2569 if (!rn2(6) && !mon->mcan
2570 /* steam vortex: fire resist applies, fire damage doesn't */
2571 && mon->data != &mons[PM_STEAM_VORTEX]) {
2572 (void) erode_obj(obj, NULL, ERODE_BURN, EF_NONE);
2574 break;
2575 case AD_ACID:
2576 if (!rn2(6)) {
2577 (void) erode_obj(obj, NULL, ERODE_CORRODE, EF_GREASE);
2579 break;
2580 case AD_RUST:
2581 if (!mon->mcan) {
2582 (void) erode_obj(obj, (char *) 0, ERODE_RUST, EF_GREASE);
2584 break;
2585 case AD_CORR:
2586 if (!mon->mcan) {
2587 (void) erode_obj(obj, (char *) 0, ERODE_CORRODE, EF_GREASE);
2589 break;
2590 case AD_ENCH:
2591 if (!mon->mcan) {
2592 if (drain_item(obj, TRUE) && carried(obj)
2593 && (obj->known || obj->oclass == ARMOR_CLASS)) {
2594 pline("%s less effective.", Yobjnam2(obj, "seem"));
2596 break;
2598 default:
2599 break;
2602 if (carried(obj))
2603 update_inventory();
2606 /* Note: caller must ascertain mtmp is mimicking... */
2607 void
2608 stumble_onto_mimic(mtmp)
2609 struct monst *mtmp;
2611 const char *fmt = "Wait! That's %s!", *generic = "a monster", *what = 0;
2613 if (!u.ustuck && !mtmp->mflee && dmgtype(mtmp->data, AD_STCK))
2614 u.ustuck = mtmp;
2616 if (Blind) {
2617 if (!Blind_telepat)
2618 what = generic; /* with default fmt */
2619 else if (mtmp->m_ap_type == M_AP_MONSTER)
2620 what = a_monnam(mtmp); /* differs from what was sensed */
2621 } else {
2622 int glyph = levl[u.ux + u.dx][u.uy + u.dy].glyph;
2624 if (glyph_is_cmap(glyph) && (glyph_to_cmap(glyph) == S_hcdoor
2625 || glyph_to_cmap(glyph) == S_vcdoor))
2626 fmt = "The door actually was %s!";
2627 else if (glyph_is_object(glyph) && glyph_to_obj(glyph) == GOLD_PIECE)
2628 fmt = "That gold was %s!";
2630 /* cloned Wiz starts out mimicking some other monster and
2631 might make himself invisible before being revealed */
2632 if (mtmp->minvis && !See_invisible)
2633 what = generic;
2634 else
2635 what = a_monnam(mtmp);
2637 if (what)
2638 pline(fmt, what);
2640 wakeup(mtmp, FALSE); /* clears mimicking */
2641 /* if hero is blind, wakeup() won't display the monster even though
2642 it's no longer concealed */
2643 if (!canspotmon(mtmp)
2644 && !glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph))
2645 map_invisible(mtmp->mx, mtmp->my);
2648 STATIC_OVL void
2649 nohandglow(mon)
2650 struct monst *mon;
2652 char *hands = makeplural(body_part(HAND));
2654 if (!u.umconf || mon->mconf)
2655 return;
2656 if (u.umconf == 1) {
2657 if (Blind)
2658 Your("%s stop tingling.", hands);
2659 else
2660 Your("%s stop glowing %s.", hands, hcolor(NH_RED));
2661 } else {
2662 if (Blind)
2663 pline_The("tingling in your %s lessens.", hands);
2664 else
2665 Your("%s no longer glow so brightly %s.", hands, hcolor(NH_RED));
2667 u.umconf--;
2671 flash_hits_mon(mtmp, otmp)
2672 struct monst *mtmp;
2673 struct obj *otmp; /* source of flash */
2675 int tmp, amt, res = 0, useeit = canseemon(mtmp);
2677 if (mtmp->msleeping) {
2678 mtmp->msleeping = 0;
2679 if (useeit) {
2680 pline_The("flash awakens %s.", mon_nam(mtmp));
2681 res = 1;
2683 } else if (mtmp->data->mlet != S_LIGHT) {
2684 if (!resists_blnd(mtmp)) {
2685 tmp = dist2(otmp->ox, otmp->oy, mtmp->mx, mtmp->my);
2686 if (useeit) {
2687 pline("%s is blinded by the flash!", Monnam(mtmp));
2688 res = 1;
2690 if (mtmp->data == &mons[PM_GREMLIN]) {
2691 /* Rule #1: Keep them out of the light. */
2692 amt = otmp->otyp == WAN_LIGHT ? d(1 + otmp->spe, 4)
2693 : rn2(min(mtmp->mhp, 4));
2694 light_hits_gremlin(mtmp, amt);
2696 if (mtmp->mhp > 0) {
2697 if (!context.mon_moving)
2698 setmangry(mtmp, TRUE);
2699 if (tmp < 9 && !mtmp->isshk && rn2(4))
2700 monflee(mtmp, rn2(4) ? rnd(100) : 0, FALSE, TRUE);
2701 mtmp->mcansee = 0;
2702 mtmp->mblinded = (tmp < 3) ? 0 : rnd(1 + 50 / tmp);
2706 return res;
2709 void
2710 light_hits_gremlin(mon, dmg)
2711 struct monst *mon;
2712 int dmg;
2714 pline("%s %s!", Monnam(mon),
2715 (dmg > mon->mhp / 2) ? "wails in agony" : "cries out in pain");
2716 mon->mhp -= dmg;
2717 wake_nearto(mon->mx, mon->my, 30);
2718 if (mon->mhp <= 0) {
2719 if (context.mon_moving)
2720 monkilled(mon, (char *) 0, AD_BLND);
2721 else
2722 killed(mon);
2723 } else if (cansee(mon->mx, mon->my) && !canspotmon(mon)) {
2724 map_invisible(mon->mx, mon->my);
2728 /*uhitm.c*/