fix #4206 - feedback for pet's weapon
[aNetHack.git] / src / uhitm.c
blobed22d5d821767e7afa80ac6bb1f4db366168a32f
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. */
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); /* 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);
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);
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(
666 monwep, 50 + 15 * greatest_erosion(obj),
667 100))) {
669 * 2.5% chance of shattering defender's weapon when
670 * using a two-handed weapon; less if uwep is rusted.
671 * [dieroll == 2 is most successful non-beheading or
672 * -bisecting hit, in case of special artifact damage;
673 * the percentage chance is (1/20)*(50/100).]
675 setmnotwielded(mon, monwep);
676 mon->weapon_check = NEED_WEAPON;
677 pline("%s from the force of your blow!",
678 Yobjnam2(monwep, "shatter"));
679 m_useupall(mon, monwep);
680 /* If someone just shattered MY weapon, I'd flee! */
681 if (rn2(4)) {
682 monflee(mon, d(2, 3), TRUE, TRUE);
684 hittxt = TRUE;
687 if (obj->oartifact
688 && artifact_hit(&youmonst, mon, obj, &tmp, dieroll)) {
689 if (mon->mhp <= 0) /* artifact killed monster */
690 return FALSE;
691 if (tmp == 0)
692 return TRUE;
693 hittxt = TRUE;
695 if (objects[obj->otyp].oc_material == SILVER
696 && mon_hates_silver(mon)) {
697 silvermsg = TRUE;
698 silverobj = TRUE;
700 if (u.usteed && !thrown && tmp > 0
701 && weapon_type(obj) == P_LANCE && mon != u.ustuck) {
702 jousting = joust(mon, obj);
703 /* exercise skill even for minimal damage hits */
704 if (jousting)
705 valid_weapon_attack = TRUE;
707 if (thrown == HMON_THROWN
708 && (is_ammo(obj) || is_missile(obj))) {
709 if (ammo_and_launcher(obj, uwep)) {
710 /* Elves and Samurai do extra damage using
711 * their bows&arrows; they're highly trained.
713 if (Role_if(PM_SAMURAI) && obj->otyp == YA
714 && uwep->otyp == YUMI)
715 tmp++;
716 else if (Race_if(PM_ELF) && obj->otyp == ELVEN_ARROW
717 && uwep->otyp == ELVEN_BOW)
718 tmp++;
720 if (obj->opoisoned && is_poisonable(obj))
721 ispoisoned = TRUE;
724 } else if (obj->oclass == POTION_CLASS) {
725 if (obj->quan > 1L)
726 obj = splitobj(obj, 1L);
727 else
728 setuwep((struct obj *) 0);
729 freeinv(obj);
730 potionhit(mon, obj, TRUE);
731 if (mon->mhp <= 0)
732 return FALSE; /* killed */
733 hittxt = TRUE;
734 /* in case potion effect causes transformation */
735 mdat = mon->data;
736 tmp = (mdat == &mons[PM_SHADE]) ? 0 : 1;
737 } else {
738 if (mdat == &mons[PM_SHADE] && !shade_aware(obj)) {
739 tmp = 0;
740 Strcpy(unconventional, cxname(obj));
741 } else {
742 switch (obj->otyp) {
743 case BOULDER: /* 1d20 */
744 case HEAVY_IRON_BALL: /* 1d25 */
745 case IRON_CHAIN: /* 1d4+1 */
746 tmp = dmgval(obj, mon);
747 break;
748 case MIRROR:
749 if (breaktest(obj)) {
750 You("break %s. That's bad luck!", ysimple_name(obj));
751 change_luck(-2);
752 useup(obj);
753 obj = (struct obj *) 0;
754 unarmed = FALSE; /* avoid obj==0 confusion */
755 get_dmg_bonus = FALSE;
756 hittxt = TRUE;
758 tmp = 1;
759 break;
760 case EXPENSIVE_CAMERA:
761 You("succeed in destroying %s. Congratulations!",
762 ysimple_name(obj));
763 release_camera_demon(obj, u.ux, u.uy);
764 useup(obj);
765 return TRUE;
766 case CORPSE: /* fixed by polder@cs.vu.nl */
767 if (touch_petrifies(&mons[obj->corpsenm])) {
768 tmp = 1;
769 hittxt = TRUE;
770 You("hit %s with %s.", mon_nam(mon),
771 corpse_xname(obj, (const char *) 0,
772 obj->dknown ? CXN_PFX_THE
773 : CXN_ARTICLE));
774 obj->dknown = 1;
775 if (!munstone(mon, TRUE))
776 minstapetrify(mon, TRUE);
777 if (resists_ston(mon))
778 break;
779 /* note: hp may be <= 0 even if munstoned==TRUE */
780 return (boolean) (mon->mhp > 0);
781 #if 0
782 } else if (touch_petrifies(mdat)) {
783 ; /* maybe turn the corpse into a statue? */
784 #endif
786 tmp = (obj->corpsenm >= LOW_PM ? mons[obj->corpsenm].msize
787 : 0) + 1;
788 break;
790 #define useup_eggs(o) \
792 if (thrown) \
793 obfree(o, (struct obj *) 0); \
794 else \
795 useupall(o); \
796 o = (struct obj *) 0; \
797 } /* now gone */
798 case EGG: {
799 long cnt = obj->quan;
801 tmp = 1; /* nominal physical damage */
802 get_dmg_bonus = FALSE;
803 hittxt = TRUE; /* message always given */
804 /* egg is always either used up or transformed, so next
805 hand-to-hand attack should yield a "bashing" mesg */
806 if (obj == uwep)
807 unweapon = TRUE;
808 if (obj->spe && obj->corpsenm >= LOW_PM) {
809 if (obj->quan < 5L)
810 change_luck((schar) - (obj->quan));
811 else
812 change_luck(-5);
815 if (touch_petrifies(&mons[obj->corpsenm])) {
816 /*learn_egg_type(obj->corpsenm);*/
817 pline("Splat! You hit %s with %s %s egg%s!",
818 mon_nam(mon),
819 obj->known ? "the" : cnt > 1L ? "some" : "a",
820 obj->known ? mons[obj->corpsenm].mname
821 : "petrifying",
822 plur(cnt));
823 obj->known = 1; /* (not much point...) */
824 useup_eggs(obj);
825 if (!munstone(mon, TRUE))
826 minstapetrify(mon, TRUE);
827 if (resists_ston(mon))
828 break;
829 return (boolean) (mon->mhp > 0);
830 } else { /* ordinary egg(s) */
831 const char *eggp =
832 (obj->corpsenm != NON_PM && obj->known)
833 ? the(mons[obj->corpsenm].mname)
834 : (cnt > 1L) ? "some" : "an";
835 You("hit %s with %s egg%s.", mon_nam(mon), eggp,
836 plur(cnt));
837 if (touch_petrifies(mdat) && !stale_egg(obj)) {
838 pline_The("egg%s %s alive any more...", plur(cnt),
839 (cnt == 1L) ? "isn't" : "aren't");
840 if (obj->timed)
841 obj_stop_timers(obj);
842 obj->otyp = ROCK;
843 obj->oclass = GEM_CLASS;
844 obj->oartifact = 0;
845 obj->spe = 0;
846 obj->known = obj->dknown = obj->bknown = 0;
847 obj->owt = weight(obj);
848 if (thrown)
849 place_object(obj, mon->mx, mon->my);
850 } else {
851 pline("Splat!");
852 useup_eggs(obj);
853 exercise(A_WIS, FALSE);
856 break;
857 #undef useup_eggs
859 case CLOVE_OF_GARLIC: /* no effect against demons */
860 if (is_undead(mdat) || is_vampshifter(mon)) {
861 monflee(mon, d(2, 4), FALSE, TRUE);
863 tmp = 1;
864 break;
865 case CREAM_PIE:
866 case BLINDING_VENOM:
867 mon->msleeping = 0;
868 if (can_blnd(&youmonst, mon,
869 (uchar) (obj->otyp == BLINDING_VENOM
870 ? AT_SPIT
871 : AT_WEAP),
872 obj)) {
873 if (Blind) {
874 pline(obj->otyp == CREAM_PIE ? "Splat!"
875 : "Splash!");
876 } else if (obj->otyp == BLINDING_VENOM) {
877 pline_The("venom blinds %s%s!", mon_nam(mon),
878 mon->mcansee ? "" : " further");
879 } else {
880 char *whom = mon_nam(mon);
881 char *what = The(xname(obj));
883 if (!thrown && obj->quan > 1L)
884 what = An(singular(obj, xname));
885 /* note: s_suffix returns a modifiable buffer */
886 if (haseyes(mdat)
887 && mdat != &mons[PM_FLOATING_EYE])
888 whom = strcat(strcat(s_suffix(whom), " "),
889 mbodypart(mon, FACE));
890 pline("%s %s over %s!", what,
891 vtense(what, "splash"), whom);
893 setmangry(mon);
894 mon->mcansee = 0;
895 tmp = rn1(25, 21);
896 if (((int) mon->mblinded + tmp) > 127)
897 mon->mblinded = 127;
898 else
899 mon->mblinded += tmp;
900 } else {
901 pline(obj->otyp == CREAM_PIE ? "Splat!" : "Splash!");
902 setmangry(mon);
904 if (thrown)
905 obfree(obj, (struct obj *) 0);
906 else
907 useup(obj);
908 hittxt = TRUE;
909 get_dmg_bonus = FALSE;
910 tmp = 0;
911 break;
912 case ACID_VENOM: /* thrown (or spit) */
913 if (resists_acid(mon)) {
914 Your("venom hits %s harmlessly.", mon_nam(mon));
915 tmp = 0;
916 } else {
917 Your("venom burns %s!", mon_nam(mon));
918 tmp = dmgval(obj, mon);
920 if (thrown)
921 obfree(obj, (struct obj *) 0);
922 else
923 useup(obj);
924 hittxt = TRUE;
925 get_dmg_bonus = FALSE;
926 break;
927 default:
928 /* non-weapons can damage because of their weight */
929 /* (but not too much) */
930 tmp = obj->owt / 100;
931 if (is_wet_towel(obj)) {
932 /* wielded wet towel should probably use whip skill
933 (but not by setting objects[TOWEL].oc_skill==P_WHIP
934 because that would turn towel into a weptool) */
935 tmp += obj->spe;
936 if (rn2(obj->spe + 1)) /* usually lose some wetness */
937 dry_a_towel(obj, -1, TRUE);
939 if (tmp < 1)
940 tmp = 1;
941 else
942 tmp = rnd(tmp);
943 if (tmp > 6)
944 tmp = 6;
946 * Things like silver wands can arrive here so
947 * so we need another silver check.
949 if (objects[obj->otyp].oc_material == SILVER
950 && mon_hates_silver(mon)) {
951 tmp += rnd(20);
952 silvermsg = TRUE;
953 silverobj = TRUE;
960 /****** NOTE: perhaps obj is undefined!! (if !thrown && BOOMERANG)
961 * *OR* if attacking bare-handed!! */
963 if (get_dmg_bonus && tmp > 0) {
964 tmp += u.udaminc;
965 /* If you throw using a propellor, you don't get a strength
966 * bonus but you do get an increase-damage bonus.
968 if (thrown != HMON_THROWN || !obj || !uwep
969 || !ammo_and_launcher(obj, uwep))
970 tmp += dbon();
973 if (valid_weapon_attack) {
974 struct obj *wep;
976 /* to be valid a projectile must have had the correct projector */
977 wep = PROJECTILE(obj) ? uwep : obj;
978 tmp += weapon_dam_bonus(wep);
979 /* [this assumes that `!thrown' implies wielded...] */
980 wtype = thrown ? weapon_type(wep) : uwep_skill_type();
981 use_skill(wtype, 1);
984 if (ispoisoned) {
985 int nopoison = (10 - (obj->owt / 10));
987 if (nopoison < 2)
988 nopoison = 2;
989 if (Role_if(PM_SAMURAI)) {
990 You("dishonorably use a poisoned weapon!");
991 adjalign(-sgn(u.ualign.type));
992 } else if (u.ualign.type == A_LAWFUL && u.ualign.record > -10) {
993 You_feel("like an evil coward for using a poisoned weapon.");
994 adjalign(-1);
996 if (obj && !rn2(nopoison)) {
997 /* remove poison now in case obj ends up in a bones file */
998 obj->opoisoned = FALSE;
999 /* defer "obj is no longer poisoned" until after hit message */
1000 unpoisonmsg = TRUE;
1002 if (resists_poison(mon))
1003 needpoismsg = TRUE;
1004 else if (rn2(10))
1005 tmp += rnd(6);
1006 else
1007 poiskilled = TRUE;
1009 if (tmp < 1) {
1010 /* make sure that negative damage adjustment can't result
1011 in inadvertently boosting the victim's hit points */
1012 tmp = 0;
1013 if (mdat == &mons[PM_SHADE]) {
1014 if (!hittxt) {
1015 const char *what = *unconventional ? unconventional : "attack";
1017 Your("%s %s harmlessly through %s.", what,
1018 vtense(what, "pass"), mon_nam(mon));
1019 hittxt = TRUE;
1021 } else {
1022 if (get_dmg_bonus)
1023 tmp = 1;
1027 if (jousting) {
1028 tmp += d(2, (obj == uwep) ? 10 : 2); /* [was in dmgval()] */
1029 You("joust %s%s", mon_nam(mon), canseemon(mon) ? exclam(tmp) : ".");
1030 if (jousting < 0) {
1031 pline("%s shatters on impact!", Yname2(obj));
1032 /* (must be either primary or secondary weapon to get here) */
1033 u.twoweap = FALSE; /* untwoweapon() is too verbose here */
1034 if (obj == uwep)
1035 uwepgone(); /* set unweapon */
1036 /* minor side-effect: broken lance won't split puddings */
1037 useup(obj);
1038 obj = 0;
1040 /* avoid migrating a dead monster */
1041 if (mon->mhp > tmp) {
1042 mhurtle(mon, u.dx, u.dy, 1);
1043 mdat = mon->data; /* in case of a polymorph trap */
1044 if (DEADMONSTER(mon))
1045 already_killed = TRUE;
1047 hittxt = TRUE;
1048 } else if (unarmed && tmp > 1 && !thrown && !obj && !Upolyd) {
1049 /* VERY small chance of stunning opponent if unarmed. */
1050 if (rnd(100) < P_SKILL(P_BARE_HANDED_COMBAT) && !bigmonst(mdat)
1051 && !thick_skinned(mdat)) {
1052 if (canspotmon(mon))
1053 pline("%s %s from your powerful strike!", Monnam(mon),
1054 makeplural(stagger(mon->data, "stagger")));
1055 /* avoid migrating a dead monster */
1056 if (mon->mhp > tmp) {
1057 mhurtle(mon, u.dx, u.dy, 1);
1058 mdat = mon->data; /* in case of a polymorph trap */
1059 if (DEADMONSTER(mon))
1060 already_killed = TRUE;
1062 hittxt = TRUE;
1066 if (!already_killed)
1067 mon->mhp -= tmp;
1068 /* adjustments might have made tmp become less than what
1069 a level draining artifact has already done to max HP */
1070 if (mon->mhp > mon->mhpmax)
1071 mon->mhp = mon->mhpmax;
1072 if (mon->mhp < 1)
1073 destroyed = TRUE;
1074 if (mon->mtame && tmp > 0) {
1075 /* do this even if the pet is being killed (affects revival) */
1076 abuse_dog(mon); /* reduces tameness */
1077 /* flee if still alive and still tame; if already suffering from
1078 untimed fleeing, no effect, otherwise increases timed fleeing */
1079 if (mon->mtame && !destroyed)
1080 monflee(mon, 10 * rnd(tmp), FALSE, FALSE);
1082 if ((mdat == &mons[PM_BLACK_PUDDING] || mdat == &mons[PM_BROWN_PUDDING])
1083 /* pudding is alive and healthy enough to split */
1084 && mon->mhp > 1 && !mon->mcan
1085 /* iron weapon using melee or polearm hit */
1086 && obj && obj == uwep && objects[obj->otyp].oc_material == IRON
1087 && hand_to_hand) {
1088 if (clone_mon(mon, 0, 0)) {
1089 pline("%s divides as you hit it!", Monnam(mon));
1090 hittxt = TRUE;
1094 if (!hittxt /*( thrown => obj exists )*/
1095 && (!destroyed
1096 || (thrown && m_shot.n > 1 && m_shot.o == obj->otyp))) {
1097 if (thrown)
1098 hit(mshot_xname(obj), mon, exclam(tmp));
1099 else if (!flags.verbose)
1100 You("hit it.");
1101 else
1102 You("%s %s%s", Role_if(PM_BARBARIAN) ? "smite" : "hit",
1103 mon_nam(mon), canseemon(mon) ? exclam(tmp) : ".");
1106 if (silvermsg) {
1107 const char *fmt;
1108 char *whom = mon_nam(mon);
1109 char silverobjbuf[BUFSZ];
1111 if (canspotmon(mon)) {
1112 if (barehand_silver_rings == 1)
1113 fmt = "Your silver ring sears %s!";
1114 else if (barehand_silver_rings == 2)
1115 fmt = "Your silver rings sear %s!";
1116 else if (silverobj && saved_oname[0]) {
1117 Sprintf(silverobjbuf, "Your %s%s %s %%s!",
1118 strstri(saved_oname, "silver") ? "" : "silver ",
1119 saved_oname, vtense(saved_oname, "sear"));
1120 fmt = silverobjbuf;
1121 } else
1122 fmt = "The silver sears %s!";
1123 } else {
1124 *whom = highc(*whom); /* "it" -> "It" */
1125 fmt = "%s is seared!";
1127 /* note: s_suffix returns a modifiable buffer */
1128 if (!noncorporeal(mdat) && !amorphous(mdat))
1129 whom = strcat(s_suffix(whom), " flesh");
1130 pline(fmt, whom);
1132 /* if a "no longer poisoned" message is coming, it will be last;
1133 obj->opoisoned was cleared above and any message referring to
1134 "poisoned <obj>" has now been given; we want just "<obj>" for
1135 last message, so reformat while obj is still accessible */
1136 if (unpoisonmsg)
1137 Strcpy(saved_oname, cxname(obj));
1139 /* [note: thrown obj might go away during killed/xkilled call] */
1141 if (needpoismsg)
1142 pline_The("poison doesn't seem to affect %s.", mon_nam(mon));
1143 if (poiskilled) {
1144 pline_The("poison was deadly...");
1145 if (!already_killed)
1146 xkilled(mon, 0);
1147 destroyed = TRUE; /* return FALSE; */
1148 } else if (destroyed) {
1149 if (!already_killed)
1150 killed(mon); /* takes care of most messages */
1151 } else if (u.umconf && hand_to_hand) {
1152 nohandglow(mon);
1153 if (!mon->mconf && !resist(mon, SPBOOK_CLASS, 0, NOTELL)) {
1154 mon->mconf = 1;
1155 if (!mon->mstun && mon->mcanmove && !mon->msleeping
1156 && canseemon(mon))
1157 pline("%s appears confused.", Monnam(mon));
1160 if (unpoisonmsg)
1161 Your("%s %s no longer poisoned.", saved_oname,
1162 vtense(saved_oname, "are"));
1164 return destroyed ? FALSE : TRUE;
1167 STATIC_OVL boolean
1168 shade_aware(obj)
1169 struct obj *obj;
1171 if (!obj)
1172 return FALSE;
1174 * The things in this list either
1175 * 1) affect shades.
1176 * OR
1177 * 2) are dealt with properly by other routines
1178 * when it comes to shades.
1180 if (obj->otyp == BOULDER
1181 || obj->otyp == HEAVY_IRON_BALL
1182 || obj->otyp == IRON_CHAIN /* dmgval handles those first three */
1183 || obj->otyp == MIRROR /* silver in the reflective surface */
1184 || obj->otyp == CLOVE_OF_GARLIC /* causes shades to flee */
1185 || objects[obj->otyp].oc_material == SILVER)
1186 return TRUE;
1187 return FALSE;
1190 /* check whether slippery clothing protects from hug or wrap attack */
1191 /* [currently assumes that you are the attacker] */
1192 STATIC_OVL boolean
1193 m_slips_free(mdef, mattk)
1194 struct monst *mdef;
1195 struct attack *mattk;
1197 struct obj *obj;
1199 if (mattk->adtyp == AD_DRIN) {
1200 /* intelligence drain attacks the head */
1201 obj = which_armor(mdef, W_ARMH);
1202 } else {
1203 /* grabbing attacks the body */
1204 obj = which_armor(mdef, W_ARMC); /* cloak */
1205 if (!obj)
1206 obj = which_armor(mdef, W_ARM); /* suit */
1207 if (!obj)
1208 obj = which_armor(mdef, W_ARMU); /* shirt */
1211 /* if monster's cloak/armor is greased, your grab slips off; this
1212 protection might fail (33% chance) when the armor is cursed */
1213 if (obj && (obj->greased || obj->otyp == OILSKIN_CLOAK)
1214 && (!obj->cursed || rn2(3))) {
1215 You("%s %s %s %s!",
1216 mattk->adtyp == AD_WRAP ? "slip off of"
1217 : "grab, but cannot hold onto",
1218 s_suffix(mon_nam(mdef)), obj->greased ? "greased" : "slippery",
1219 /* avoid "slippery slippery cloak"
1220 for undiscovered oilskin cloak */
1221 (obj->greased || objects[obj->otyp].oc_name_known)
1222 ? xname(obj)
1223 : cloak_simple_name(obj));
1225 if (obj->greased && !rn2(2)) {
1226 pline_The("grease wears off.");
1227 obj->greased = 0;
1229 return TRUE;
1231 return FALSE;
1234 /* used when hitting a monster with a lance while mounted;
1235 1: joust hit; 0: ordinary hit; -1: joust but break lance */
1236 STATIC_OVL int
1237 joust(mon, obj)
1238 struct monst *mon; /* target */
1239 struct obj *obj; /* weapon */
1241 int skill_rating, joust_dieroll;
1243 if (Fumbling || Stunned)
1244 return 0;
1245 /* sanity check; lance must be wielded in order to joust */
1246 if (obj != uwep && (obj != uswapwep || !u.twoweap))
1247 return 0;
1249 /* if using two weapons, use worse of lance and two-weapon skills */
1250 skill_rating = P_SKILL(weapon_type(obj)); /* lance skill */
1251 if (u.twoweap && P_SKILL(P_TWO_WEAPON_COMBAT) < skill_rating)
1252 skill_rating = P_SKILL(P_TWO_WEAPON_COMBAT);
1253 if (skill_rating == P_ISRESTRICTED)
1254 skill_rating = P_UNSKILLED; /* 0=>1 */
1256 /* odds to joust are expert:80%, skilled:60%, basic:40%, unskilled:20% */
1257 if ((joust_dieroll = rn2(5)) < skill_rating) {
1258 if (joust_dieroll == 0 && rnl(50) == (50 - 1) && !unsolid(mon->data)
1259 && !obj_resists(obj, 0, 100))
1260 return -1; /* hit that breaks lance */
1261 return 1; /* successful joust */
1263 return 0; /* no joust bonus; revert to ordinary attack */
1267 * Send in a demon pet for the hero. Exercise wisdom.
1269 * This function used to be inline to damageum(), but the Metrowerks compiler
1270 * (DR4 and DR4.5) screws up with an internal error 5 "Expression Too
1271 * Complex."
1272 * Pulling it out makes it work.
1274 STATIC_OVL void
1275 demonpet()
1277 int i;
1278 struct permonst *pm;
1279 struct monst *dtmp;
1281 pline("Some hell-p has arrived!");
1282 i = !rn2(6) ? ndemon(u.ualign.type) : NON_PM;
1283 pm = i != NON_PM ? &mons[i] : youmonst.data;
1284 if ((dtmp = makemon(pm, u.ux, u.uy, NO_MM_FLAGS)) != 0)
1285 (void) tamedog(dtmp, (struct obj *) 0);
1286 exercise(A_WIS, TRUE);
1289 STATIC_OVL boolean
1290 theft_petrifies(otmp)
1291 struct obj *otmp;
1293 if (uarmg || otmp->otyp != CORPSE
1294 || !touch_petrifies(&mons[otmp->corpsenm]) || Stone_resistance)
1295 return FALSE;
1297 #if 0 /* no poly_when_stoned() critter has theft capability */
1298 if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) {
1299 display_nhwindow(WIN_MESSAGE, FALSE); /* --More-- */
1300 return TRUE;
1302 #endif
1304 /* stealing this corpse is fatal... */
1305 instapetrify(corpse_xname(otmp, "stolen", CXN_ARTICLE));
1306 /* apparently wasn't fatal after all... */
1307 return TRUE;
1311 * Player uses theft attack against monster.
1313 * If the target is wearing body armor, take all of its possessions;
1314 * otherwise, take one object. [Is this really the behavior we want?]
1316 STATIC_OVL void
1317 steal_it(mdef, mattk)
1318 struct monst *mdef;
1319 struct attack *mattk;
1321 struct obj *otmp, *stealoid, **minvent_ptr;
1322 long unwornmask;
1324 if (!mdef->minvent)
1325 return; /* nothing to take */
1327 /* look for worn body armor */
1328 stealoid = (struct obj *) 0;
1329 if (could_seduce(&youmonst, mdef, mattk)) {
1330 /* find armor, and move it to end of inventory in the process */
1331 minvent_ptr = &mdef->minvent;
1332 while ((otmp = *minvent_ptr) != 0)
1333 if (otmp->owornmask & W_ARM) {
1334 if (stealoid)
1335 panic("steal_it: multiple worn suits");
1336 *minvent_ptr = otmp->nobj; /* take armor out of minvent */
1337 stealoid = otmp;
1338 stealoid->nobj = (struct obj *) 0;
1339 } else {
1340 minvent_ptr = &otmp->nobj;
1342 *minvent_ptr = stealoid; /* put armor back into minvent */
1345 if (stealoid) { /* we will be taking everything */
1346 if (gender(mdef) == (int) u.mfemale && youmonst.data->mlet == S_NYMPH)
1347 You("charm %s. She gladly hands over her possessions.",
1348 mon_nam(mdef));
1349 else
1350 You("seduce %s and %s starts to take off %s clothes.",
1351 mon_nam(mdef), mhe(mdef), mhis(mdef));
1354 while ((otmp = mdef->minvent) != 0) {
1355 if (!Upolyd)
1356 break; /* no longer have ability to steal */
1357 /* take the object away from the monster */
1358 obj_extract_self(otmp);
1359 if ((unwornmask = otmp->owornmask) != 0L) {
1360 mdef->misc_worn_check &= ~unwornmask;
1361 if (otmp->owornmask & W_WEP)
1362 setmnotwielded(mdef, otmp);
1363 otmp->owornmask = 0L;
1364 update_mon_intrinsics(mdef, otmp, FALSE, FALSE);
1366 if (otmp == stealoid) /* special message for final item */
1367 pline("%s finishes taking off %s suit.", Monnam(mdef),
1368 mhis(mdef));
1370 /* give the object to the character */
1371 otmp = hold_another_object(otmp, "You snatched but dropped %s.",
1372 doname(otmp), "You steal: ");
1373 if (otmp->where != OBJ_INVENT)
1374 continue;
1375 if (theft_petrifies(otmp))
1376 break; /* stop thieving even though hero survived */
1377 /* more take-away handling, after theft message */
1378 if (unwornmask & W_WEP) { /* stole wielded weapon */
1379 possibly_unwield(mdef, FALSE);
1380 } else if (unwornmask & W_ARMG) { /* stole worn gloves */
1381 mselftouch(mdef, (const char *) 0, TRUE);
1382 if (mdef->mhp <= 0) /* it's now a statue */
1383 return; /* can't continue stealing */
1386 if (!stealoid)
1387 break; /* only taking one item */
1392 damageum(mdef, mattk)
1393 register struct monst *mdef;
1394 register struct attack *mattk;
1396 register struct permonst *pd = mdef->data;
1397 int armpro, tmp = d((int) mattk->damn, (int) mattk->damd);
1398 boolean negated;
1400 armpro = magic_negation(mdef);
1401 /* since hero can't be cancelled, only defender's armor applies */
1402 negated = !(rn2(10) >= 3 * armpro);
1404 if (is_demon(youmonst.data) && !rn2(13) && !uwep
1405 && u.umonnum != PM_SUCCUBUS && u.umonnum != PM_INCUBUS
1406 && u.umonnum != PM_BALROG) {
1407 demonpet();
1408 return 0;
1410 switch (mattk->adtyp) {
1411 case AD_STUN:
1412 if (!Blind)
1413 pline("%s %s for a moment.", Monnam(mdef),
1414 makeplural(stagger(pd, "stagger")));
1415 mdef->mstun = 1;
1416 goto physical;
1417 case AD_LEGS:
1418 #if 0
1419 if (u.ucancelled) {
1420 tmp = 0;
1421 break;
1423 #endif
1424 goto physical;
1425 case AD_WERE: /* no special effect on monsters */
1426 case AD_HEAL: /* likewise */
1427 case AD_PHYS:
1428 physical:
1429 if (mattk->aatyp == AT_WEAP) {
1430 if (uwep)
1431 tmp = 0;
1432 } else if (mattk->aatyp == AT_KICK) {
1433 if (thick_skinned(pd))
1434 tmp = 0;
1435 if (pd == &mons[PM_SHADE]) {
1436 if (!(uarmf && uarmf->blessed)) {
1437 impossible("bad shade attack function flow?");
1438 tmp = 0;
1439 } else
1440 tmp = rnd(4); /* bless damage */
1442 /* add ring(s) of increase damage */
1443 if (u.udaminc > 0) {
1444 /* applies even if damage was 0 */
1445 tmp += u.udaminc;
1446 } else if (tmp > 0) {
1447 /* ring(s) might be negative; avoid converting
1448 0 to non-0 or positive to non-positive */
1449 tmp += u.udaminc;
1450 if (tmp < 1)
1451 tmp = 1;
1454 break;
1455 case AD_FIRE:
1456 if (negated) {
1457 tmp = 0;
1458 break;
1460 if (!Blind)
1461 pline("%s is %s!", Monnam(mdef), on_fire(pd, mattk));
1462 if (pd == &mons[PM_STRAW_GOLEM] || pd == &mons[PM_PAPER_GOLEM]) {
1463 if (!Blind)
1464 pline("%s burns completely!", Monnam(mdef));
1465 xkilled(mdef, 2);
1466 tmp = 0;
1467 break;
1468 /* Don't return yet; keep hp<1 and tmp=0 for pet msg */
1470 tmp += destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE);
1471 tmp += destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE);
1472 if (resists_fire(mdef)) {
1473 if (!Blind)
1474 pline_The("fire doesn't heat %s!", mon_nam(mdef));
1475 golemeffects(mdef, AD_FIRE, tmp);
1476 shieldeff(mdef->mx, mdef->my);
1477 tmp = 0;
1479 /* only potions damage resistant players in destroy_item */
1480 tmp += destroy_mitem(mdef, POTION_CLASS, AD_FIRE);
1481 break;
1482 case AD_COLD:
1483 if (negated) {
1484 tmp = 0;
1485 break;
1487 if (!Blind)
1488 pline("%s is covered in frost!", Monnam(mdef));
1489 if (resists_cold(mdef)) {
1490 shieldeff(mdef->mx, mdef->my);
1491 if (!Blind)
1492 pline_The("frost doesn't chill %s!", mon_nam(mdef));
1493 golemeffects(mdef, AD_COLD, tmp);
1494 tmp = 0;
1496 tmp += destroy_mitem(mdef, POTION_CLASS, AD_COLD);
1497 break;
1498 case AD_ELEC:
1499 if (negated) {
1500 tmp = 0;
1501 break;
1503 if (!Blind)
1504 pline("%s is zapped!", Monnam(mdef));
1505 tmp += destroy_mitem(mdef, WAND_CLASS, AD_ELEC);
1506 if (resists_elec(mdef)) {
1507 if (!Blind)
1508 pline_The("zap doesn't shock %s!", mon_nam(mdef));
1509 golemeffects(mdef, AD_ELEC, tmp);
1510 shieldeff(mdef->mx, mdef->my);
1511 tmp = 0;
1513 /* only rings damage resistant players in destroy_item */
1514 tmp += destroy_mitem(mdef, RING_CLASS, AD_ELEC);
1515 break;
1516 case AD_ACID:
1517 if (resists_acid(mdef))
1518 tmp = 0;
1519 break;
1520 case AD_STON:
1521 if (!munstone(mdef, TRUE))
1522 minstapetrify(mdef, TRUE);
1523 tmp = 0;
1524 break;
1525 case AD_SSEX:
1526 case AD_SEDU:
1527 case AD_SITM:
1528 steal_it(mdef, mattk);
1529 tmp = 0;
1530 break;
1531 case AD_SGLD:
1532 /* This you as a leprechaun, so steal
1533 real gold only, no lesser coins */
1535 struct obj *mongold = findgold(mdef->minvent);
1536 if (mongold) {
1537 obj_extract_self(mongold);
1538 if (merge_choice(invent, mongold) || inv_cnt(FALSE) < 52) {
1539 addinv(mongold);
1540 Your("purse feels heavier.");
1541 } else {
1542 You("grab %s's gold, but find no room in your knapsack.",
1543 mon_nam(mdef));
1544 dropy(mongold);
1548 exercise(A_DEX, TRUE);
1549 tmp = 0;
1550 break;
1551 case AD_TLPT:
1552 if (tmp <= 0)
1553 tmp = 1;
1554 if (!negated && tmp < mdef->mhp) {
1555 char nambuf[BUFSZ];
1556 boolean u_saw_mon =
1557 canseemon(mdef) || (u.uswallow && u.ustuck == mdef);
1558 /* record the name before losing sight of monster */
1559 Strcpy(nambuf, Monnam(mdef));
1560 if (u_teleport_mon(mdef, FALSE) && u_saw_mon
1561 && !(canseemon(mdef) || (u.uswallow && u.ustuck == mdef)))
1562 pline("%s suddenly disappears!", nambuf);
1564 break;
1565 case AD_BLND:
1566 if (can_blnd(&youmonst, mdef, mattk->aatyp, (struct obj *) 0)) {
1567 if (!Blind && mdef->mcansee)
1568 pline("%s is blinded.", Monnam(mdef));
1569 mdef->mcansee = 0;
1570 tmp += mdef->mblinded;
1571 if (tmp > 127)
1572 tmp = 127;
1573 mdef->mblinded = tmp;
1575 tmp = 0;
1576 break;
1577 case AD_CURS:
1578 if (night() && !rn2(10) && !mdef->mcan) {
1579 if (pd == &mons[PM_CLAY_GOLEM]) {
1580 if (!Blind)
1581 pline("Some writing vanishes from %s head!",
1582 s_suffix(mon_nam(mdef)));
1583 xkilled(mdef, 0);
1584 /* Don't return yet; keep hp<1 and tmp=0 for pet msg */
1585 } else {
1586 mdef->mcan = 1;
1587 You("chuckle.");
1590 tmp = 0;
1591 break;
1592 case AD_DRLI:
1593 if (!negated && !rn2(3) && !resists_drli(mdef)) {
1594 int xtmp = d(2, 6);
1595 pline("%s suddenly seems weaker!", Monnam(mdef));
1596 mdef->mhpmax -= xtmp;
1597 if ((mdef->mhp -= xtmp) <= 0 || !mdef->m_lev) {
1598 pline("%s dies!", Monnam(mdef));
1599 xkilled(mdef, 0);
1600 } else
1601 mdef->m_lev--;
1602 tmp = 0;
1604 break;
1605 case AD_RUST:
1606 if (pd == &mons[PM_IRON_GOLEM]) {
1607 pline("%s falls to pieces!", Monnam(mdef));
1608 xkilled(mdef, 0);
1610 erode_armor(mdef, ERODE_RUST);
1611 tmp = 0;
1612 break;
1613 case AD_CORR:
1614 erode_armor(mdef, ERODE_CORRODE);
1615 tmp = 0;
1616 break;
1617 case AD_DCAY:
1618 if (pd == &mons[PM_WOOD_GOLEM] || pd == &mons[PM_LEATHER_GOLEM]) {
1619 pline("%s falls to pieces!", Monnam(mdef));
1620 xkilled(mdef, 0);
1622 erode_armor(mdef, ERODE_ROT);
1623 tmp = 0;
1624 break;
1625 case AD_DREN:
1626 if (!negated && !rn2(4))
1627 xdrainenergym(mdef, TRUE);
1628 tmp = 0;
1629 break;
1630 case AD_DRST:
1631 case AD_DRDX:
1632 case AD_DRCO:
1633 if (!negated && !rn2(8)) {
1634 Your("%s was poisoned!", mpoisons_subj(&youmonst, mattk));
1635 if (resists_poison(mdef))
1636 pline_The("poison doesn't seem to affect %s.", mon_nam(mdef));
1637 else {
1638 if (!rn2(10)) {
1639 Your("poison was deadly...");
1640 tmp = mdef->mhp;
1641 } else
1642 tmp += rn1(10, 6);
1645 break;
1646 case AD_DRIN: {
1647 struct obj *helmet;
1649 if (notonhead || !has_head(pd)) {
1650 pline("%s doesn't seem harmed.", Monnam(mdef));
1651 tmp = 0;
1652 if (!Unchanging && pd == &mons[PM_GREEN_SLIME]) {
1653 if (!Slimed) {
1654 You("suck in some slime and don't feel very well.");
1655 make_slimed(10L, (char *) 0);
1658 break;
1660 if (m_slips_free(mdef, mattk))
1661 break;
1663 if ((helmet = which_armor(mdef, W_ARMH)) != 0 && rn2(8)) {
1664 pline("%s %s blocks your attack to %s head.",
1665 s_suffix(Monnam(mdef)), helm_simple_name(helmet),
1666 mhis(mdef));
1667 break;
1670 (void) eat_brains(&youmonst, mdef, TRUE, &tmp);
1671 break;
1673 case AD_STCK:
1674 if (!negated && !sticks(pd))
1675 u.ustuck = mdef; /* it's now stuck to you */
1676 break;
1677 case AD_WRAP:
1678 if (!sticks(pd)) {
1679 if (!u.ustuck && !rn2(10)) {
1680 if (m_slips_free(mdef, mattk)) {
1681 tmp = 0;
1682 } else {
1683 You("swing yourself around %s!", mon_nam(mdef));
1684 u.ustuck = mdef;
1686 } else if (u.ustuck == mdef) {
1687 /* Monsters don't wear amulets of magical breathing */
1688 if (is_pool(u.ux, u.uy) && !is_swimmer(pd)
1689 && !amphibious(pd)) {
1690 You("drown %s...", mon_nam(mdef));
1691 tmp = mdef->mhp;
1692 } else if (mattk->aatyp == AT_HUGS)
1693 pline("%s is being crushed.", Monnam(mdef));
1694 } else {
1695 tmp = 0;
1696 if (flags.verbose)
1697 You("brush against %s %s.", s_suffix(mon_nam(mdef)),
1698 mbodypart(mdef, LEG));
1700 } else
1701 tmp = 0;
1702 break;
1703 case AD_PLYS:
1704 if (!negated && mdef->mcanmove && !rn2(3) && tmp < mdef->mhp) {
1705 if (!Blind)
1706 pline("%s is frozen by you!", Monnam(mdef));
1707 paralyze_monst(mdef, rnd(10));
1709 break;
1710 case AD_SLEE:
1711 if (!negated && !mdef->msleeping && sleep_monst(mdef, rnd(10), -1)) {
1712 if (!Blind)
1713 pline("%s is put to sleep by you!", Monnam(mdef));
1714 slept_monst(mdef);
1716 break;
1717 case AD_SLIM:
1718 if (negated)
1719 break; /* physical damage only */
1720 if (!rn2(4) && !slimeproof(pd)) {
1721 if (!munslime(mdef, TRUE) && mdef->mhp > 0) {
1722 /* this assumes newcham() won't fail; since hero has
1723 a slime attack, green slimes haven't been geno'd */
1724 You("turn %s into slime.", mon_nam(mdef));
1725 if (newcham(mdef, &mons[PM_GREEN_SLIME], FALSE, FALSE))
1726 pd = mdef->data;
1728 /* munslime attempt could have been fatal */
1729 if (mdef->mhp < 1)
1730 return 2; /* skip death message */
1731 tmp = 0;
1733 break;
1734 case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */
1735 /* there's no msomearmor() function, so just do damage */
1736 /* if (negated) break; */
1737 break;
1738 case AD_SLOW:
1739 if (!negated && mdef->mspeed != MSLOW) {
1740 unsigned int oldspeed = mdef->mspeed;
1742 mon_adjust_speed(mdef, -1, (struct obj *) 0);
1743 if (mdef->mspeed != oldspeed && canseemon(mdef))
1744 pline("%s slows down.", Monnam(mdef));
1746 break;
1747 case AD_CONF:
1748 if (!mdef->mconf) {
1749 if (canseemon(mdef))
1750 pline("%s looks confused.", Monnam(mdef));
1751 mdef->mconf = 1;
1753 break;
1754 default:
1755 tmp = 0;
1756 break;
1759 mdef->mstrategy &= ~STRAT_WAITFORU; /* in case player is very fast */
1760 if ((mdef->mhp -= tmp) < 1) {
1761 if (mdef->mtame && !cansee(mdef->mx, mdef->my)) {
1762 You_feel("embarrassed for a moment.");
1763 if (tmp)
1764 xkilled(mdef, 0); /* !tmp but hp<1: already killed */
1765 } else if (!flags.verbose) {
1766 You("destroy it!");
1767 if (tmp)
1768 xkilled(mdef, 0);
1769 } else if (tmp)
1770 killed(mdef);
1771 return 2;
1773 return 1;
1776 STATIC_OVL int
1777 explum(mdef, mattk)
1778 register struct monst *mdef;
1779 register struct attack *mattk;
1781 register int tmp = d((int) mattk->damn, (int) mattk->damd);
1783 You("explode!");
1784 switch (mattk->adtyp) {
1785 boolean resistance; /* only for cold/fire/elec */
1787 case AD_BLND:
1788 if (!resists_blnd(mdef)) {
1789 pline("%s is blinded by your flash of light!", Monnam(mdef));
1790 mdef->mblinded = min((int) mdef->mblinded + tmp, 127);
1791 mdef->mcansee = 0;
1793 break;
1794 case AD_HALU:
1795 if (haseyes(mdef->data) && mdef->mcansee) {
1796 pline("%s is affected by your flash of light!", Monnam(mdef));
1797 mdef->mconf = 1;
1799 break;
1800 case AD_COLD:
1801 resistance = resists_cold(mdef);
1802 goto common;
1803 case AD_FIRE:
1804 resistance = resists_fire(mdef);
1805 goto common;
1806 case AD_ELEC:
1807 resistance = resists_elec(mdef);
1808 common:
1809 if (!resistance) {
1810 pline("%s gets blasted!", Monnam(mdef));
1811 mdef->mhp -= tmp;
1812 if (mdef->mhp <= 0) {
1813 killed(mdef);
1814 return 2;
1816 } else {
1817 shieldeff(mdef->mx, mdef->my);
1818 if (is_golem(mdef->data))
1819 golemeffects(mdef, (int) mattk->adtyp, tmp);
1820 else
1821 pline_The("blast doesn't seem to affect %s.", mon_nam(mdef));
1823 break;
1824 default:
1825 break;
1827 return 1;
1830 STATIC_OVL void
1831 start_engulf(mdef)
1832 struct monst *mdef;
1834 if (!Invisible) {
1835 map_location(u.ux, u.uy, TRUE);
1836 tmp_at(DISP_ALWAYS, mon_to_glyph(&youmonst));
1837 tmp_at(mdef->mx, mdef->my);
1839 You("engulf %s!", mon_nam(mdef));
1840 delay_output();
1841 delay_output();
1844 STATIC_OVL void
1845 end_engulf()
1847 if (!Invisible) {
1848 tmp_at(DISP_END, 0);
1849 newsym(u.ux, u.uy);
1853 STATIC_OVL int
1854 gulpum(mdef, mattk)
1855 register struct monst *mdef;
1856 register struct attack *mattk;
1858 #ifdef LINT /* static char msgbuf[BUFSZ]; */
1859 char msgbuf[BUFSZ];
1860 #else
1861 static char msgbuf[BUFSZ]; /* for nomovemsg */
1862 #endif
1863 register int tmp;
1864 register int dam = d((int) mattk->damn, (int) mattk->damd);
1865 boolean fatal_gulp;
1866 struct obj *otmp;
1867 struct permonst *pd = mdef->data;
1869 /* Not totally the same as for real monsters. Specifically, these
1870 * don't take multiple moves. (It's just too hard, for too little
1871 * result, to program monsters which attack from inside you, which
1872 * would be necessary if done accurately.) Instead, we arbitrarily
1873 * kill the monster immediately for AD_DGST and we regurgitate them
1874 * after exactly 1 round of attack otherwise. -KAA
1877 if (!engulf_target(&youmonst, mdef))
1878 return 0;
1880 if (u.uhunger < 1500 && !u.uswallow) {
1881 for (otmp = mdef->minvent; otmp; otmp = otmp->nobj)
1882 (void) snuff_lit(otmp);
1884 /* engulfing a cockatrice or digesting a Rider or Medusa */
1885 fatal_gulp = (touch_petrifies(pd) && !Stone_resistance)
1886 || (mattk->adtyp == AD_DGST
1887 && (is_rider(pd) || (pd == &mons[PM_MEDUSA]
1888 && !Stone_resistance)));
1890 if ((mattk->adtyp == AD_DGST && !Slow_digestion) || fatal_gulp)
1891 eating_conducts(pd);
1893 if (fatal_gulp && !is_rider(pd)) { /* petrification */
1894 char kbuf[BUFSZ];
1895 const char *mname = pd->mname;
1897 if (!type_is_pname(pd))
1898 mname = an(mname);
1899 You("englut %s.", mon_nam(mdef));
1900 Sprintf(kbuf, "swallowing %s whole", mname);
1901 instapetrify(kbuf);
1902 } else {
1903 start_engulf(mdef);
1904 switch (mattk->adtyp) {
1905 case AD_DGST:
1906 /* eating a Rider or its corpse is fatal */
1907 if (is_rider(pd)) {
1908 pline("Unfortunately, digesting any of it is fatal.");
1909 end_engulf();
1910 Sprintf(killer.name, "unwisely tried to eat %s",
1911 pd->mname);
1912 killer.format = NO_KILLER_PREFIX;
1913 done(DIED);
1914 return 0; /* lifesaved */
1917 if (Slow_digestion) {
1918 dam = 0;
1919 break;
1922 /* Use up amulet of life saving */
1923 if (!!(otmp = mlifesaver(mdef)))
1924 m_useup(mdef, otmp);
1926 newuhs(FALSE);
1927 xkilled(mdef, 2);
1928 if (mdef->mhp > 0) { /* monster lifesaved */
1929 You("hurriedly regurgitate the sizzling in your %s.",
1930 body_part(STOMACH));
1931 } else {
1932 tmp = 1 + (pd->cwt >> 8);
1933 if (corpse_chance(mdef, &youmonst, TRUE)
1934 && !(mvitals[monsndx(pd)].mvflags & G_NOCORPSE)) {
1935 /* nutrition only if there can be a corpse */
1936 u.uhunger += (pd->cnutrit + 1) / 2;
1937 } else
1938 tmp = 0;
1939 Sprintf(msgbuf, "You totally digest %s.", mon_nam(mdef));
1940 if (tmp != 0) {
1941 /* setting afternmv = end_engulf is tempting,
1942 * but will cause problems if the player is
1943 * attacked (which uses his real location) or
1944 * if his See_invisible wears off
1946 You("digest %s.", mon_nam(mdef));
1947 if (Slow_digestion)
1948 tmp *= 2;
1949 nomul(-tmp);
1950 multi_reason = "digesting something";
1951 nomovemsg = msgbuf;
1952 } else
1953 pline1(msgbuf);
1954 if (pd == &mons[PM_GREEN_SLIME]) {
1955 Sprintf(msgbuf, "%s isn't sitting well with you.",
1956 The(pd->mname));
1957 if (!Unchanging) {
1958 make_slimed(5L, (char *) 0);
1960 } else
1961 exercise(A_CON, TRUE);
1963 end_engulf();
1964 return 2;
1965 case AD_PHYS:
1966 if (youmonst.data == &mons[PM_FOG_CLOUD]) {
1967 pline("%s is laden with your moisture.", Monnam(mdef));
1968 if (amphibious(pd) && !flaming(pd)) {
1969 dam = 0;
1970 pline("%s seems unharmed.", Monnam(mdef));
1972 } else
1973 pline("%s is pummeled with your debris!", Monnam(mdef));
1974 break;
1975 case AD_ACID:
1976 pline("%s is covered with your goo!", Monnam(mdef));
1977 if (resists_acid(mdef)) {
1978 pline("It seems harmless to %s.", mon_nam(mdef));
1979 dam = 0;
1981 break;
1982 case AD_BLND:
1983 if (can_blnd(&youmonst, mdef, mattk->aatyp,
1984 (struct obj *) 0)) {
1985 if (mdef->mcansee)
1986 pline("%s can't see in there!", Monnam(mdef));
1987 mdef->mcansee = 0;
1988 dam += mdef->mblinded;
1989 if (dam > 127)
1990 dam = 127;
1991 mdef->mblinded = dam;
1993 dam = 0;
1994 break;
1995 case AD_ELEC:
1996 if (rn2(2)) {
1997 pline_The("air around %s crackles with electricity.",
1998 mon_nam(mdef));
1999 if (resists_elec(mdef)) {
2000 pline("%s seems unhurt.", Monnam(mdef));
2001 dam = 0;
2003 golemeffects(mdef, (int) mattk->adtyp, dam);
2004 } else
2005 dam = 0;
2006 break;
2007 case AD_COLD:
2008 if (rn2(2)) {
2009 if (resists_cold(mdef)) {
2010 pline("%s seems mildly chilly.", Monnam(mdef));
2011 dam = 0;
2012 } else
2013 pline("%s is freezing to death!", Monnam(mdef));
2014 golemeffects(mdef, (int) mattk->adtyp, dam);
2015 } else
2016 dam = 0;
2017 break;
2018 case AD_FIRE:
2019 if (rn2(2)) {
2020 if (resists_fire(mdef)) {
2021 pline("%s seems mildly hot.", Monnam(mdef));
2022 dam = 0;
2023 } else
2024 pline("%s is burning to a crisp!", Monnam(mdef));
2025 golemeffects(mdef, (int) mattk->adtyp, dam);
2026 } else
2027 dam = 0;
2028 break;
2029 case AD_DREN:
2030 if (!rn2(4))
2031 xdrainenergym(mdef, TRUE);
2032 dam = 0;
2033 break;
2035 end_engulf();
2036 if ((mdef->mhp -= dam) <= 0) {
2037 killed(mdef);
2038 if (mdef->mhp <= 0) /* not lifesaved */
2039 return 2;
2041 You("%s %s!", is_animal(youmonst.data) ? "regurgitate" : "expel",
2042 mon_nam(mdef));
2043 if (Slow_digestion || is_animal(youmonst.data)) {
2044 pline("Obviously, you didn't like %s taste.",
2045 s_suffix(mon_nam(mdef)));
2049 return 0;
2052 void
2053 missum(mdef, mattk, wouldhavehit)
2054 register struct monst *mdef;
2055 register struct attack *mattk;
2056 boolean wouldhavehit;
2058 if (wouldhavehit) /* monk is missing due to penalty for wearing suit */
2059 Your("armor is rather cumbersome...");
2061 if (could_seduce(&youmonst, mdef, mattk))
2062 You("pretend to be friendly to %s.", mon_nam(mdef));
2063 else if (canspotmon(mdef) && flags.verbose)
2064 You("miss %s.", mon_nam(mdef));
2065 else
2066 You("miss it.");
2067 if (!mdef->msleeping && mdef->mcanmove)
2068 wakeup(mdef);
2071 /* attack monster as a monster. */
2072 STATIC_OVL boolean
2073 hmonas(mon)
2074 register struct monst *mon;
2076 struct attack *mattk, alt_attk;
2077 struct obj *weapon;
2078 boolean altwep = FALSE, weapon_used = FALSE;
2079 int i, tmp, armorpenalty, sum[NATTK], nsum = 0, dhit = 0, attknum = 0;
2081 for (i = 0; i < NATTK; i++) {
2082 sum[i] = 0;
2083 mattk = getmattk(youmonst.data, i, sum, &alt_attk);
2084 switch (mattk->aatyp) {
2085 case AT_WEAP:
2086 use_weapon:
2087 /* Certain monsters don't use weapons when encountered as enemies,
2088 * but players who polymorph into them have hands or claws and
2089 * thus should be able to use weapons. This shouldn't prohibit
2090 * the use of most special abilities, either.
2091 * If monster has multiple claw attacks, only one can use weapon.
2093 weapon_used = TRUE;
2094 /* Potential problem: if the monster gets multiple weapon attacks,
2095 * we currently allow the player to get each of these as a weapon
2096 * attack. Is this really desirable?
2098 /* approximate two-weapon mode */
2099 weapon = (altwep && uswapwep) ? uswapwep : uwep;
2100 altwep = !altwep; /* toggle for next attack */
2101 tmp = find_roll_to_hit(mon, AT_WEAP, weapon, &attknum,
2102 &armorpenalty);
2103 dhit = (tmp > (dieroll = rnd(20)) || u.uswallow);
2104 /* Enemy dead, before any special abilities used */
2105 if (!known_hitum(mon, weapon, &dhit, tmp, armorpenalty, mattk)) {
2106 sum[i] = 2;
2107 break;
2108 } else
2109 sum[i] = dhit;
2110 /* might be a worm that gets cut in half */
2111 if (m_at(u.ux + u.dx, u.uy + u.dy) != mon)
2112 return (boolean) (nsum != 0);
2113 /* Do not print "You hit" message, since known_hitum
2114 * already did it.
2116 if (dhit && mattk->adtyp != AD_SPEL && mattk->adtyp != AD_PHYS)
2117 sum[i] = damageum(mon, mattk);
2118 break;
2119 case AT_CLAW:
2120 if (uwep && !cantwield(youmonst.data) && !weapon_used)
2121 goto use_weapon;
2122 /*FALLTHRU*/
2123 case AT_TUCH:
2124 if (uwep && youmonst.data->mlet == S_LICH && !weapon_used)
2125 goto use_weapon;
2126 /*FALLTHRU*/
2127 case AT_KICK:
2128 case AT_BITE:
2129 case AT_STNG:
2130 case AT_BUTT:
2131 case AT_TENT:
2132 tmp = find_roll_to_hit(mon, mattk->aatyp, (struct obj *) 0,
2133 &attknum, &armorpenalty);
2134 dhit = (tmp > (dieroll = rnd(20)) || u.uswallow);
2135 if (dhit) {
2136 int compat;
2138 if (!u.uswallow
2139 && (compat = could_seduce(&youmonst, mon, mattk))) {
2140 You("%s %s %s.",
2141 mon->mcansee && haseyes(mon->data) ? "smile at"
2142 : "talk to",
2143 mon_nam(mon),
2144 compat == 2 ? "engagingly" : "seductively");
2145 /* doesn't anger it; no wakeup() */
2146 sum[i] = damageum(mon, mattk);
2147 break;
2149 wakeup(mon);
2150 /* maybe this check should be in damageum()? */
2151 if (mon->data == &mons[PM_SHADE]
2152 && !(mattk->aatyp == AT_KICK && uarmf
2153 && uarmf->blessed)) {
2154 Your("attack passes harmlessly through %s.",
2155 mon_nam(mon));
2156 break;
2158 if (mattk->aatyp == AT_KICK)
2159 You("kick %s.", mon_nam(mon));
2160 else if (mattk->aatyp == AT_BITE)
2161 You("bite %s.", mon_nam(mon));
2162 else if (mattk->aatyp == AT_STNG)
2163 You("sting %s.", mon_nam(mon));
2164 else if (mattk->aatyp == AT_BUTT)
2165 You("butt %s.", mon_nam(mon));
2166 else if (mattk->aatyp == AT_TUCH)
2167 You("touch %s.", mon_nam(mon));
2168 else if (mattk->aatyp == AT_TENT)
2169 Your("tentacles suck %s.", mon_nam(mon));
2170 else
2171 You("hit %s.", mon_nam(mon));
2172 sum[i] = damageum(mon, mattk);
2173 } else {
2174 missum(mon, mattk, (tmp + armorpenalty > dieroll));
2176 break;
2178 case AT_HUGS:
2179 /* automatic if prev two attacks succeed, or if
2180 * already grabbed in a previous attack
2182 dhit = 1;
2183 wakeup(mon);
2184 if (mon->data == &mons[PM_SHADE])
2185 Your("hug passes harmlessly through %s.", mon_nam(mon));
2186 else if (!sticks(mon->data) && !u.uswallow) {
2187 if (mon == u.ustuck) {
2188 pline("%s is being %s.", Monnam(mon),
2189 u.umonnum == PM_ROPE_GOLEM ? "choked" : "crushed");
2190 sum[i] = damageum(mon, mattk);
2191 } else if (i >= 2 && sum[i - 1] && sum[i - 2]) {
2192 You("grab %s!", mon_nam(mon));
2193 u.ustuck = mon;
2194 sum[i] = damageum(mon, mattk);
2197 break;
2199 case AT_EXPL: /* automatic hit if next to */
2200 dhit = -1;
2201 wakeup(mon);
2202 sum[i] = explum(mon, mattk);
2203 break;
2205 case AT_ENGL:
2206 tmp = find_roll_to_hit(mon, mattk->aatyp, (struct obj *) 0,
2207 &attknum, &armorpenalty);
2208 if ((dhit = (tmp > rnd(20 + i)))) {
2209 wakeup(mon);
2210 if (mon->data == &mons[PM_SHADE])
2211 Your("attempt to surround %s is harmless.", mon_nam(mon));
2212 else {
2213 sum[i] = gulpum(mon, mattk);
2214 if (sum[i] == 2 && (mon->data->mlet == S_ZOMBIE
2215 || mon->data->mlet == S_MUMMY)
2216 && rn2(5) && !Sick_resistance) {
2217 You_feel("%ssick.", (Sick) ? "very " : "");
2218 mdamageu(mon, rnd(8));
2221 } else {
2222 missum(mon, mattk, FALSE);
2224 break;
2226 case AT_MAGC:
2227 /* No check for uwep; if wielding nothing we want to
2228 * do the normal 1-2 points bare hand damage...
2230 if ((youmonst.data->mlet == S_KOBOLD
2231 || youmonst.data->mlet == S_ORC
2232 || youmonst.data->mlet == S_GNOME) && !weapon_used)
2233 goto use_weapon;
2235 case AT_NONE:
2236 case AT_BOOM:
2237 continue;
2238 /* Not break--avoid passive attacks from enemy */
2240 case AT_BREA:
2241 case AT_SPIT:
2242 case AT_GAZE: /* all done using #monster command */
2243 dhit = 0;
2244 break;
2246 default: /* Strange... */
2247 impossible("strange attack of yours (%d)", mattk->aatyp);
2249 if (dhit == -1) {
2250 u.mh = -1; /* dead in the current form */
2251 rehumanize();
2253 if (sum[i] == 2)
2254 return (boolean) passive(mon, 1, 0, mattk->aatyp, FALSE);
2255 /* defender dead */
2256 else {
2257 (void) passive(mon, sum[i], 1, mattk->aatyp, FALSE);
2258 nsum |= sum[i];
2260 if (!Upolyd)
2261 break; /* No extra attacks if no longer a monster */
2262 if (multi < 0)
2263 break; /* If paralyzed while attacking, i.e. floating eye */
2265 return (boolean) (nsum != 0);
2268 /* Special (passive) attacks on you by monsters done here.
2271 passive(mon, mhit, malive, aatyp, wep_was_destroyed)
2272 register struct monst *mon;
2273 register boolean mhit;
2274 register int malive;
2275 uchar aatyp;
2276 boolean wep_was_destroyed;
2278 register struct permonst *ptr = mon->data;
2279 register int i, tmp;
2281 for (i = 0;; i++) {
2282 if (i >= NATTK)
2283 return (malive | mhit); /* no passive attacks */
2284 if (ptr->mattk[i].aatyp == AT_NONE)
2285 break; /* try this one */
2287 /* Note: tmp not always used */
2288 if (ptr->mattk[i].damn)
2289 tmp = d((int) ptr->mattk[i].damn, (int) ptr->mattk[i].damd);
2290 else if (ptr->mattk[i].damd)
2291 tmp = d((int) mon->m_lev + 1, (int) ptr->mattk[i].damd);
2292 else
2293 tmp = 0;
2295 /* These affect you even if they just died.
2297 switch (ptr->mattk[i].adtyp) {
2298 case AD_FIRE:
2299 if (mhit && !mon->mcan) {
2300 if (aatyp == AT_KICK) {
2301 if (uarmf && !rn2(6))
2302 (void) erode_obj(uarmf, xname(uarmf), ERODE_BURN,
2303 EF_GREASE | EF_VERBOSE);
2304 } else if (aatyp == AT_WEAP || aatyp == AT_CLAW
2305 || aatyp == AT_MAGC || aatyp == AT_TUCH)
2306 passive_obj(mon, (struct obj *) 0, &(ptr->mattk[i]));
2308 break;
2309 case AD_ACID:
2310 if (mhit && rn2(2)) {
2311 if (Blind || !flags.verbose)
2312 You("are splashed!");
2313 else
2314 You("are splashed by %s acid!", s_suffix(mon_nam(mon)));
2316 if (!Acid_resistance)
2317 mdamageu(mon, tmp);
2318 if (!rn2(30))
2319 erode_armor(&youmonst, ERODE_CORRODE);
2321 if (mhit) {
2322 if (aatyp == AT_KICK) {
2323 if (uarmf && !rn2(6))
2324 (void) erode_obj(uarmf, xname(uarmf), ERODE_CORRODE,
2325 EF_GREASE | EF_VERBOSE);
2326 } else if (aatyp == AT_WEAP || aatyp == AT_CLAW
2327 || aatyp == AT_MAGC || aatyp == AT_TUCH)
2328 passive_obj(mon, (struct obj *) 0, &(ptr->mattk[i]));
2330 exercise(A_STR, FALSE);
2331 break;
2332 case AD_STON:
2333 if (mhit) { /* successful attack */
2334 long protector = attk_protection((int) aatyp);
2336 /* hero using monsters' AT_MAGC attack is hitting hand to
2337 hand rather than casting a spell */
2338 if (aatyp == AT_MAGC)
2339 protector = W_ARMG;
2341 if (protector == 0L /* no protection */
2342 || (protector == W_ARMG && !uarmg
2343 && !uwep && !wep_was_destroyed)
2344 || (protector == W_ARMF && !uarmf)
2345 || (protector == W_ARMH && !uarmh)
2346 || (protector == (W_ARMC | W_ARMG) && (!uarmc || !uarmg))) {
2347 if (!Stone_resistance
2348 && !(poly_when_stoned(youmonst.data)
2349 && polymon(PM_STONE_GOLEM))) {
2350 done_in_by(mon, STONING); /* "You turn to stone..." */
2351 return 2;
2355 break;
2356 case AD_RUST:
2357 if (mhit && !mon->mcan) {
2358 if (aatyp == AT_KICK) {
2359 if (uarmf)
2360 (void) erode_obj(uarmf, xname(uarmf), ERODE_RUST,
2361 EF_GREASE | EF_VERBOSE);
2362 } else if (aatyp == AT_WEAP || aatyp == AT_CLAW
2363 || aatyp == AT_MAGC || aatyp == AT_TUCH)
2364 passive_obj(mon, (struct obj *) 0, &(ptr->mattk[i]));
2366 break;
2367 case AD_CORR:
2368 if (mhit && !mon->mcan) {
2369 if (aatyp == AT_KICK) {
2370 if (uarmf)
2371 (void) erode_obj(uarmf, xname(uarmf), ERODE_CORRODE,
2372 EF_GREASE | EF_VERBOSE);
2373 } else if (aatyp == AT_WEAP || aatyp == AT_CLAW
2374 || aatyp == AT_MAGC || aatyp == AT_TUCH)
2375 passive_obj(mon, (struct obj *) 0, &(ptr->mattk[i]));
2377 break;
2378 case AD_MAGM:
2379 /* wrath of gods for attacking Oracle */
2380 if (Antimagic) {
2381 shieldeff(u.ux, u.uy);
2382 pline("A hail of magic missiles narrowly misses you!");
2383 } else {
2384 You("are hit by magic missiles appearing from thin air!");
2385 mdamageu(mon, tmp);
2387 break;
2388 case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */
2389 if (mhit) {
2390 struct obj *obj = (struct obj *) 0;
2392 if (aatyp == AT_KICK) {
2393 obj = uarmf;
2394 if (!obj)
2395 break;
2396 } else if (aatyp == AT_BITE || aatyp == AT_BUTT
2397 || (aatyp >= AT_STNG && aatyp < AT_WEAP)) {
2398 break; /* no object involved */
2400 passive_obj(mon, obj, &(ptr->mattk[i]));
2402 break;
2403 default:
2404 break;
2407 /* These only affect you if they still live.
2409 if (malive && !mon->mcan && rn2(3)) {
2410 switch (ptr->mattk[i].adtyp) {
2411 case AD_PLYS:
2412 if (ptr == &mons[PM_FLOATING_EYE]) {
2413 if (!canseemon(mon)) {
2414 break;
2416 if (mon->mcansee) {
2417 if (ureflects("%s gaze is reflected by your %s.",
2418 s_suffix(Monnam(mon)))) {
2420 } else if (Free_action) {
2421 You("momentarily stiffen under %s gaze!",
2422 s_suffix(mon_nam(mon)));
2423 } else if (Hallucination && rn2(4)) {
2424 pline("%s looks %s%s.", Monnam(mon),
2425 !rn2(2) ? "" : "rather ",
2426 !rn2(2) ? "numb" : "stupified");
2427 } else {
2428 You("are frozen by %s gaze!", s_suffix(mon_nam(mon)));
2429 nomul((ACURR(A_WIS) > 12 || rn2(4)) ? -tmp : -127);
2430 multi_reason = "frozen by a monster's gaze";
2431 nomovemsg = 0;
2433 } else {
2434 pline("%s cannot defend itself.",
2435 Adjmonnam(mon, "blind"));
2436 if (!rn2(500))
2437 change_luck(-1);
2439 } else if (Free_action) {
2440 You("momentarily stiffen.");
2441 } else { /* gelatinous cube */
2442 You("are frozen by %s!", mon_nam(mon));
2443 nomovemsg = You_can_move_again;
2444 nomul(-tmp);
2445 multi_reason = "frozen by a monster";
2446 exercise(A_DEX, FALSE);
2448 break;
2449 case AD_COLD: /* brown mold or blue jelly */
2450 if (monnear(mon, u.ux, u.uy)) {
2451 if (Cold_resistance) {
2452 shieldeff(u.ux, u.uy);
2453 You_feel("a mild chill.");
2454 ugolemeffects(AD_COLD, tmp);
2455 break;
2457 You("are suddenly very cold!");
2458 mdamageu(mon, tmp);
2459 /* monster gets stronger with your heat! */
2460 mon->mhp += tmp / 2;
2461 if (mon->mhpmax < mon->mhp)
2462 mon->mhpmax = mon->mhp;
2463 /* at a certain point, the monster will reproduce! */
2464 if (mon->mhpmax > ((int) (mon->m_lev + 1) * 8))
2465 (void) split_mon(mon, &youmonst);
2467 break;
2468 case AD_STUN: /* specifically yellow mold */
2469 if (!Stunned)
2470 make_stunned((long) tmp, TRUE);
2471 break;
2472 case AD_FIRE:
2473 if (monnear(mon, u.ux, u.uy)) {
2474 if (Fire_resistance) {
2475 shieldeff(u.ux, u.uy);
2476 You_feel("mildly warm.");
2477 ugolemeffects(AD_FIRE, tmp);
2478 break;
2480 You("are suddenly very hot!");
2481 mdamageu(mon, tmp); /* fire damage */
2483 break;
2484 case AD_ELEC:
2485 if (Shock_resistance) {
2486 shieldeff(u.ux, u.uy);
2487 You_feel("a mild tingle.");
2488 ugolemeffects(AD_ELEC, tmp);
2489 break;
2491 You("are jolted with electricity!");
2492 mdamageu(mon, tmp);
2493 break;
2494 default:
2495 break;
2498 return (malive | mhit);
2502 * Special (passive) attacks on an attacking object by monsters done here.
2503 * Assumes the attack was successful.
2505 void
2506 passive_obj(mon, obj, mattk)
2507 register struct monst *mon;
2508 register struct obj *obj; /* null means pick uwep, uswapwep or uarmg */
2509 struct attack *mattk; /* null means we find one internally */
2511 struct permonst *ptr = mon->data;
2512 register int i;
2514 /* if caller hasn't specified an object, use uwep, uswapwep or uarmg */
2515 if (!obj) {
2516 obj = (u.twoweap && uswapwep && !rn2(2)) ? uswapwep : uwep;
2517 if (!obj && mattk->adtyp == AD_ENCH)
2518 obj = uarmg; /* no weapon? then must be gloves */
2519 if (!obj)
2520 return; /* no object to affect */
2523 /* if caller hasn't specified an attack, find one */
2524 if (!mattk) {
2525 for (i = 0;; i++) {
2526 if (i >= NATTK)
2527 return; /* no passive attacks */
2528 if (ptr->mattk[i].aatyp == AT_NONE)
2529 break; /* try this one */
2531 mattk = &(ptr->mattk[i]);
2534 switch (mattk->adtyp) {
2535 case AD_FIRE:
2536 if (!rn2(6) && !mon->mcan
2537 /* steam vortex: fire resist applies, fire damage doesn't */
2538 && mon->data != &mons[PM_STEAM_VORTEX]) {
2539 (void) erode_obj(obj, NULL, ERODE_BURN, EF_NONE);
2541 break;
2542 case AD_ACID:
2543 if (!rn2(6)) {
2544 (void) erode_obj(obj, NULL, ERODE_CORRODE, EF_NONE);
2546 break;
2547 case AD_RUST:
2548 if (!mon->mcan) {
2549 (void) erode_obj(obj, NULL, ERODE_RUST, EF_NONE);
2551 break;
2552 case AD_CORR:
2553 if (!mon->mcan) {
2554 (void) erode_obj(obj, NULL, ERODE_CORRODE, EF_NONE);
2556 break;
2557 case AD_ENCH:
2558 if (!mon->mcan) {
2559 if (drain_item(obj) && carried(obj)
2560 && (obj->known || obj->oclass == ARMOR_CLASS)) {
2561 pline("%s less effective.", Yobjnam2(obj, "seem"));
2563 break;
2565 default:
2566 break;
2569 if (carried(obj))
2570 update_inventory();
2573 /* Note: caller must ascertain mtmp is mimicking... */
2574 void
2575 stumble_onto_mimic(mtmp)
2576 struct monst *mtmp;
2578 const char *fmt = "Wait! That's %s!", *generic = "a monster", *what = 0;
2580 if (!u.ustuck && !mtmp->mflee && dmgtype(mtmp->data, AD_STCK))
2581 u.ustuck = mtmp;
2583 if (Blind) {
2584 if (!Blind_telepat)
2585 what = generic; /* with default fmt */
2586 else if (mtmp->m_ap_type == M_AP_MONSTER)
2587 what = a_monnam(mtmp); /* differs from what was sensed */
2588 } else {
2589 int glyph = levl[u.ux + u.dx][u.uy + u.dy].glyph;
2591 if (glyph_is_cmap(glyph) && (glyph_to_cmap(glyph) == S_hcdoor
2592 || glyph_to_cmap(glyph) == S_vcdoor))
2593 fmt = "The door actually was %s!";
2594 else if (glyph_is_object(glyph) && glyph_to_obj(glyph) == GOLD_PIECE)
2595 fmt = "That gold was %s!";
2597 /* cloned Wiz starts out mimicking some other monster and
2598 might make himself invisible before being revealed */
2599 if (mtmp->minvis && !See_invisible)
2600 what = generic;
2601 else
2602 what = a_monnam(mtmp);
2604 if (what)
2605 pline(fmt, what);
2607 wakeup(mtmp); /* clears mimicking */
2608 /* if hero is blind, wakeup() won't display the monster even though
2609 it's no longer concealed */
2610 if (!canspotmon(mtmp)
2611 && !glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph))
2612 map_invisible(mtmp->mx, mtmp->my);
2615 STATIC_OVL void
2616 nohandglow(mon)
2617 struct monst *mon;
2619 char *hands = makeplural(body_part(HAND));
2621 if (!u.umconf || mon->mconf)
2622 return;
2623 if (u.umconf == 1) {
2624 if (Blind)
2625 Your("%s stop tingling.", hands);
2626 else
2627 Your("%s stop glowing %s.", hands, hcolor(NH_RED));
2628 } else {
2629 if (Blind)
2630 pline_The("tingling in your %s lessens.", hands);
2631 else
2632 Your("%s no longer glow so brightly %s.", hands, hcolor(NH_RED));
2634 u.umconf--;
2638 flash_hits_mon(mtmp, otmp)
2639 struct monst *mtmp;
2640 struct obj *otmp; /* source of flash */
2642 int tmp, amt, res = 0, useeit = canseemon(mtmp);
2644 if (mtmp->msleeping) {
2645 mtmp->msleeping = 0;
2646 if (useeit) {
2647 pline_The("flash awakens %s.", mon_nam(mtmp));
2648 res = 1;
2650 } else if (mtmp->data->mlet != S_LIGHT) {
2651 if (!resists_blnd(mtmp)) {
2652 tmp = dist2(otmp->ox, otmp->oy, mtmp->mx, mtmp->my);
2653 if (useeit) {
2654 pline("%s is blinded by the flash!", Monnam(mtmp));
2655 res = 1;
2657 if (mtmp->data == &mons[PM_GREMLIN]) {
2658 /* Rule #1: Keep them out of the light. */
2659 amt = otmp->otyp == WAN_LIGHT ? d(1 + otmp->spe, 4)
2660 : rn2(min(mtmp->mhp, 4));
2661 light_hits_gremlin(mtmp, amt);
2663 if (mtmp->mhp > 0) {
2664 if (!context.mon_moving)
2665 setmangry(mtmp);
2666 if (tmp < 9 && !mtmp->isshk && rn2(4))
2667 monflee(mtmp, rn2(4) ? rnd(100) : 0, FALSE, TRUE);
2668 mtmp->mcansee = 0;
2669 mtmp->mblinded = (tmp < 3) ? 0 : rnd(1 + 50 / tmp);
2673 return res;
2676 void
2677 light_hits_gremlin(mon, dmg)
2678 struct monst *mon;
2679 int dmg;
2681 pline("%s %s!", Monnam(mon),
2682 (dmg > mon->mhp / 2) ? "wails in agony" : "cries out in pain");
2683 if ((mon->mhp -= dmg) <= 0) {
2684 if (context.mon_moving)
2685 monkilled(mon, (char *) 0, AD_BLND);
2686 else
2687 killed(mon);
2688 } else if (cansee(mon->mx, mon->my) && !canspotmon(mon)) {
2689 map_invisible(mon->mx, mon->my);
2693 /*uhitm.c*/