NHDT->ANH, in most cases
[aNetHack.git] / src / mhitu.c
blobea17cbc55c471d32e75a07b9941759b61f6db724
1 /* NetHack 3.6 mhitu.c $ANH-Date: 1470819843 2016/08/10 09:04:03 $ $ANH-Branch: master $:$ANH-Revision: 1.144 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 #include "hack.h"
6 #include "artifact.h"
8 STATIC_VAR NEARDATA struct obj *mon_currwep = (struct obj *) 0;
10 STATIC_DCL boolean FDECL(u_slip_free, (struct monst *, struct attack *));
11 STATIC_DCL int FDECL(passiveum, (struct permonst *, struct monst *,
12 struct attack *));
13 STATIC_DCL void FDECL(mayberem, (struct obj *, const char *));
14 STATIC_DCL boolean FDECL(diseasemu, (struct permonst *));
15 STATIC_DCL int FDECL(hitmu, (struct monst *, struct attack *));
16 STATIC_DCL int FDECL(gulpmu, (struct monst *, struct attack *));
17 STATIC_DCL int FDECL(explmu, (struct monst *, struct attack *, BOOLEAN_P));
18 STATIC_DCL void FDECL(missmu, (struct monst *, BOOLEAN_P, struct attack *));
19 STATIC_DCL void FDECL(mswings, (struct monst *, struct obj *));
20 STATIC_DCL void FDECL(wildmiss, (struct monst *, struct attack *));
21 STATIC_DCL void FDECL(hitmsg, (struct monst *, struct attack *));
23 /* See comment in mhitm.c. If we use this a lot it probably should be */
24 /* changed to a parameter to mhitu. */
25 static int dieroll;
27 STATIC_OVL void
28 hitmsg(mtmp, mattk)
29 register struct monst *mtmp;
30 register struct attack *mattk;
32 int compat;
33 const char *pfmt = 0;
34 char *Monst_name = Monnam(mtmp);
36 /* Note: if opposite gender, "seductively" */
37 /* If same gender, "engagingly" for nymph, normal msg for others */
38 if ((compat = could_seduce(mtmp, &youmonst, mattk)) != 0
39 && !mtmp->mcan && !mtmp->mspec_used) {
40 pline("%s %s you %s.", Monst_name,
41 Blind ? "talks to" : "smiles at",
42 (compat == 2) ? "engagingly" : "seductively");
43 } else {
44 switch (mattk->aatyp) {
45 case AT_BITE:
46 pfmt = "%s bites!";
47 break;
48 case AT_KICK:
49 pline("%s kicks%c", Monst_name,
50 thick_skinned(youmonst.data) ? '.' : '!');
51 break;
52 case AT_STNG:
53 pfmt = "%s stings!";
54 break;
55 case AT_BUTT:
56 pfmt = "%s butts!";
57 break;
58 case AT_TUCH:
59 pfmt = "%s touches you!";
60 break;
61 case AT_TENT:
62 pfmt = "%s tentacles suck you!";
63 Monst_name = s_suffix(Monst_name);
64 break;
65 case AT_EXPL:
66 case AT_BOOM:
67 pfmt = "%s explodes!";
68 break;
69 default:
70 pfmt = "%s hits!";
72 if (pfmt)
73 pline(pfmt, Monst_name);
77 /* monster missed you */
78 STATIC_OVL void
79 missmu(mtmp, nearmiss, mattk)
80 struct monst *mtmp;
81 boolean nearmiss;
82 struct attack *mattk;
84 if (!canspotmon(mtmp))
85 map_invisible(mtmp->mx, mtmp->my);
87 if (could_seduce(mtmp, &youmonst, mattk) && !mtmp->mcan)
88 pline("%s pretends to be friendly.", Monnam(mtmp));
89 else
90 pline("%s %smisses!", Monnam(mtmp),
91 (nearmiss && flags.verbose) ? "just " : "");
93 stop_occupation();
96 /* monster swings obj */
97 STATIC_OVL void
98 mswings(mtmp, otemp)
99 struct monst *mtmp;
100 struct obj *otemp;
102 if (flags.verbose && !Blind && mon_visible(mtmp)) {
103 pline("%s %s %s%s %s.", Monnam(mtmp),
104 (objects[otemp->otyp].oc_dir & PIERCE) ? "thrusts" : "swings",
105 (otemp->quan > 1L) ? "one of " : "", mhis(mtmp), xname(otemp));
109 /* return how a poison attack was delivered */
110 const char *
111 mpoisons_subj(mtmp, mattk)
112 struct monst *mtmp;
113 struct attack *mattk;
115 if (mattk->aatyp == AT_WEAP) {
116 struct obj *mwep = (mtmp == &youmonst) ? uwep : MON_WEP(mtmp);
117 /* "Foo's attack was poisoned." is pretty lame, but at least
118 it's better than "sting" when not a stinging attack... */
119 return (!mwep || !mwep->opoisoned) ? "attack" : "weapon";
120 } else {
121 return (mattk->aatyp == AT_TUCH) ? "contact"
122 : (mattk->aatyp == AT_GAZE) ? "gaze"
123 : (mattk->aatyp == AT_BITE) ? "bite" : "sting";
127 /* called when your intrinsic speed is taken away */
128 void
129 u_slow_down()
131 HFast = 0L;
132 if (!Fast)
133 You("slow down.");
134 else /* speed boots */
135 Your("quickness feels less natural.");
136 exercise(A_DEX, FALSE);
139 /* monster attacked your displaced image */
140 STATIC_OVL void
141 wildmiss(mtmp, mattk)
142 register struct monst *mtmp;
143 register struct attack *mattk;
145 int compat;
146 const char *Monst_name; /* Monnam(mtmp) */
148 /* no map_invisible() -- no way to tell where _this_ is coming from */
150 if (!flags.verbose)
151 return;
152 if (!cansee(mtmp->mx, mtmp->my))
153 return;
154 /* maybe it's attacking an image around the corner? */
156 compat = ((mattk->adtyp == AD_SEDU || mattk->adtyp == AD_SSEX)
157 && could_seduce(mtmp, &youmonst, (struct attack *) 0));
158 Monst_name = Monnam(mtmp);
160 if (!mtmp->mcansee || (Invis && !perceives(mtmp->data))) {
161 const char *swings = (mattk->aatyp == AT_BITE) ? "snaps"
162 : (mattk->aatyp == AT_KICK) ? "kicks"
163 : (mattk->aatyp == AT_STNG
164 || mattk->aatyp == AT_BUTT
165 || nolimbs(mtmp->data)) ? "lunges"
166 : "swings";
168 if (compat)
169 pline("%s tries to touch you and misses!", Monst_name);
170 else
171 switch (rn2(3)) {
172 case 0:
173 pline("%s %s wildly and misses!", Monst_name, swings);
174 break;
175 case 1:
176 pline("%s attacks a spot beside you.", Monst_name);
177 break;
178 case 2:
179 pline("%s strikes at %s!", Monst_name,
180 (levl[mtmp->mux][mtmp->muy].typ == WATER)
181 ? "empty water"
182 : "thin air");
183 break;
184 default:
185 pline("%s %s wildly!", Monst_name, swings);
186 break;
189 } else if (Displaced) {
190 if (compat)
191 pline("%s smiles %s at your %sdisplaced image...", Monst_name,
192 (compat == 2) ? "engagingly" : "seductively",
193 Invis ? "invisible " : "");
194 else
195 pline("%s strikes at your %sdisplaced image and misses you!",
196 /* Note: if you're both invisible and displaced,
197 * only monsters which see invisible will attack your
198 * displaced image, since the displaced image is also
199 * invisible.
201 Monst_name, Invis ? "invisible " : "");
203 } else if (Underwater) {
204 /* monsters may miss especially on water level where
205 bubbles shake the player here and there */
206 if (compat)
207 pline("%s reaches towards your distorted image.", Monst_name);
208 else
209 pline("%s is fooled by water reflections and misses!",
210 Monst_name);
212 } else
213 impossible("%s attacks you without knowing your location?",
214 Monst_name);
217 void
218 expels(mtmp, mdat, message)
219 struct monst *mtmp;
220 struct permonst *mdat; /* if mtmp is polymorphed, mdat != mtmp->data */
221 boolean message;
223 if (message) {
224 if (is_animal(mdat)) {
225 You("get regurgitated!");
226 } else {
227 char blast[40];
228 register int i;
230 blast[0] = '\0';
231 for (i = 0; i < NATTK; i++)
232 if (mdat->mattk[i].aatyp == AT_ENGL)
233 break;
234 if (mdat->mattk[i].aatyp != AT_ENGL) {
235 impossible("Swallower has no engulfing attack?");
236 } else {
237 if (is_whirly(mdat)) {
238 switch (mdat->mattk[i].adtyp) {
239 case AD_ELEC:
240 Strcpy(blast, " in a shower of sparks");
241 break;
242 case AD_COLD:
243 Strcpy(blast, " in a blast of frost");
244 break;
246 } else
247 Strcpy(blast, " with a squelch");
248 You("get expelled from %s%s!", mon_nam(mtmp), blast);
252 unstuck(mtmp); /* ball&chain returned in unstuck() */
253 mnexto(mtmp);
254 newsym(u.ux, u.uy);
255 spoteffects(TRUE);
256 /* to cover for a case where mtmp is not in a next square */
257 if (um_dist(mtmp->mx, mtmp->my, 1))
258 pline("Brrooaa... You land hard at some distance.");
261 /* select a monster's next attack, possibly substituting for its usual one */
262 struct attack *
263 getmattk(magr, mdef, indx, prev_result, alt_attk_buf)
264 struct monst *magr, *mdef;
265 int indx, prev_result[];
266 struct attack *alt_attk_buf;
268 struct permonst *mptr = magr->data;
269 struct attack *attk = &mptr->mattk[indx];
270 struct obj *weap = (magr == &youmonst) ? uwep : MON_WEP(magr);
272 /* prevent a monster with two consecutive disease or hunger attacks
273 from hitting with both of them on the same turn; if the first has
274 already hit, switch to a stun attack for the second */
275 if (indx > 0 && prev_result[indx - 1] > 0
276 && (attk->adtyp == AD_DISE || attk->adtyp == AD_PEST
277 || attk->adtyp == AD_FAMN)
278 && attk->adtyp == mptr->mattk[indx - 1].adtyp) {
279 *alt_attk_buf = *attk;
280 attk = alt_attk_buf;
281 attk->adtyp = AD_STUN;
283 /* make drain-energy damage be somewhat in proportion to energy */
284 } else if (attk->adtyp == AD_DREN && mdef == &youmonst) {
285 int ulev = max(u.ulevel, 6);
287 *alt_attk_buf = *attk;
288 attk = alt_attk_buf;
289 /* 3.6.0 used 4d6 but since energy drain came out of max energy
290 once current energy was gone, that tended to have a severe
291 effect on low energy characters; it's now 2d6 with ajustments */
292 if (u.uen <= 5 * ulev && attk->damn > 1) {
293 attk->damn -= 1; /* low energy: 2d6 -> 1d6 */
294 if (u.uenmax <= 2 * ulev && attk->damd > 3)
295 attk->damd -= 3; /* very low energy: 1d6 -> 1d3 */
296 } else if (u.uen > 12 * ulev) {
297 attk->damn += 1; /* high energy: 2d6 -> 3d6 */
298 if (u.uenmax > 20 * ulev)
299 attk->damd += 3; /* very high energy: 3d6 -> 3d9 */
300 /* note: 3d9 is slightly higher than previous 4d6 */
303 } else if (attk->aatyp == AT_ENGL && magr->mspec_used) {
304 /* can't re-engulf yet; switch to simpler attack */
305 *alt_attk_buf = *attk;
306 attk = alt_attk_buf;
307 if (attk->adtyp == AD_ACID || attk->adtyp == AD_ELEC
308 || attk->adtyp == AD_COLD || attk->adtyp == AD_FIRE) {
309 attk->aatyp = AT_TUCH;
310 } else {
311 attk->aatyp = AT_CLAW; /* attack message will be "<foo> hits" */
312 attk->adtyp = AD_PHYS;
314 attk->damn = 1; /* relatively weak: 1d6 */
315 attk->damd = 6;
317 /* barrow wight, Nazgul, erinys have weapon attack for non-physical
318 damage; force physical damage if attacker has been cancelled or
319 if weapon is sufficiently interesting; a few unique creatures
320 have two weapon attacks where one does physical damage and other
321 doesn't--avoid forcing physical damage for those */
322 } else if (indx == 0 && magr != &youmonst
323 && attk->aatyp == AT_WEAP && attk->adtyp != AD_PHYS
324 && !(mptr->mattk[1].aatyp == AT_WEAP
325 && mptr->mattk[1].adtyp == AD_PHYS)
326 && (magr->mcan
327 || (weap && ((weap->otyp == CORPSE
328 && touch_petrifies(&mons[weap->corpsenm]))
329 || weap->oartifact == ART_STORMBRINGER
330 || weap->oartifact == ART_VORPAL_BLADE)))) {
331 *alt_attk_buf = *attk;
332 attk = alt_attk_buf;
333 attk->adtyp = AD_PHYS;
335 return attk;
339 * mattacku: monster attacks you
340 * returns 1 if monster dies (e.g. "yellow light"), 0 otherwise
341 * Note: if you're displaced or invisible the monster might attack the
342 * wrong position...
343 * Assumption: it's attacking you or an empty square; if there's another
344 * monster which it attacks by mistake, the caller had better
345 * take care of it...
348 mattacku(mtmp)
349 register struct monst *mtmp;
351 struct attack *mattk, alt_attk;
352 int i, j = 0, tmp, sum[NATTK];
353 struct permonst *mdat = mtmp->data;
354 boolean ranged = (distu(mtmp->mx, mtmp->my) > 3);
355 /* Is it near you? Affects your actions */
356 boolean range2 = !monnear(mtmp, mtmp->mux, mtmp->muy);
357 /* Does it think it's near you? Affects its actions */
358 boolean foundyou = (mtmp->mux == u.ux && mtmp->muy == u.uy);
359 /* Is it attacking you or your image? */
360 boolean youseeit = canseemon(mtmp);
361 /* Might be attacking your image around the corner, or
362 * invisible, or you might be blind....
364 boolean skipnonmagc = FALSE;
365 /* Are further physical attack attempts useless? */
367 if (!ranged)
368 nomul(0);
369 if (mtmp->mhp <= 0 || (Underwater && !is_swimmer(mtmp->data)))
370 return 0;
372 /* If swallowed, can only be affected by u.ustuck */
373 if (u.uswallow) {
374 if (mtmp != u.ustuck)
375 return 0;
376 u.ustuck->mux = u.ux;
377 u.ustuck->muy = u.uy;
378 range2 = 0;
379 foundyou = 1;
380 if (u.uinvulnerable)
381 return 0; /* stomachs can't hurt you! */
383 } else if (u.usteed) {
384 if (mtmp == u.usteed)
385 /* Your steed won't attack you */
386 return 0;
387 /* Orcs like to steal and eat horses and the like */
388 if (!rn2(is_orc(mtmp->data) ? 2 : 4)
389 && distu(mtmp->mx, mtmp->my) <= 2) {
390 /* Attack your steed instead */
391 i = mattackm(mtmp, u.usteed);
392 if ((i & MM_AGR_DIED))
393 return 1;
394 /* make sure steed is still alive and within range */
395 if ((i & MM_DEF_DIED) || !u.usteed
396 || distu(mtmp->mx, mtmp->my) > 2)
397 return 0;
398 /* Let your steed retaliate */
399 return !!(mattackm(u.usteed, mtmp) & MM_DEF_DIED);
403 if (u.uundetected && !range2 && foundyou && !u.uswallow) {
404 if (!canspotmon(mtmp))
405 map_invisible(mtmp->mx, mtmp->my);
406 u.uundetected = 0;
407 if (is_hider(youmonst.data) && u.umonnum != PM_TRAPPER) {
408 /* ceiling hider */
409 coord cc; /* maybe we need a unexto() function? */
410 struct obj *obj;
412 You("fall from the %s!", ceiling(u.ux, u.uy));
413 /* take monster off map now so that its location
414 is eligible for placing hero; we assume that a
415 removed monster remembers its old spot <mx,my> */
416 remove_monster(mtmp->mx, mtmp->my);
417 if (!enexto(&cc, u.ux, u.uy, youmonst.data)
418 /* a fish won't voluntarily swap positions
419 when it's in water and hero is over land */
420 || (mtmp->data->mlet == S_EEL
421 && is_pool(mtmp->mx, mtmp->my)
422 && !is_pool(u.ux, u.uy))) {
423 /* couldn't find any spot for hero; this used to
424 kill off attacker, but now we just give a "miss"
425 message and keep both mtmp and hero at their
426 original positions; hero has become unconcealed
427 so mtmp's next move will be a regular attack */
428 place_monster(mtmp, mtmp->mx, mtmp->my); /* put back */
429 newsym(u.ux, u.uy); /* u.uundetected was toggled */
430 pline("%s draws back as you drop!", Monnam(mtmp));
431 return 0;
434 /* put mtmp at hero's spot and move hero to <cc.x,.y> */
435 newsym(mtmp->mx, mtmp->my); /* finish removal */
436 place_monster(mtmp, u.ux, u.uy);
437 if (mtmp->wormno) {
438 worm_move(mtmp);
439 /* tail hasn't grown, so if it now occupies <cc.x,.y>
440 then one of its original spots must be free */
441 if (m_at(cc.x, cc.y))
442 (void) enexto(&cc, u.ux, u.uy, youmonst.data);
444 teleds(cc.x, cc.y, TRUE); /* move hero */
445 set_apparxy(mtmp);
446 newsym(u.ux, u.uy);
448 if (youmonst.data->mlet != S_PIERCER)
449 return 0; /* lurkers don't attack */
451 obj = which_armor(mtmp, WORN_HELMET);
452 if (obj && is_metallic(obj)) {
453 Your("blow glances off %s %s.", s_suffix(mon_nam(mtmp)),
454 helm_simple_name(obj));
455 } else {
456 if (3 + find_mac(mtmp) <= rnd(20)) {
457 pline("%s is hit by a falling piercer (you)!",
458 Monnam(mtmp));
459 if ((mtmp->mhp -= d(3, 6)) < 1)
460 killed(mtmp);
461 } else
462 pline("%s is almost hit by a falling piercer (you)!",
463 Monnam(mtmp));
466 } else {
467 /* surface hider */
468 if (!youseeit) {
469 pline("It tries to move where you are hiding.");
470 } else {
471 /* Ugly kludge for eggs. The message is phrased so as
472 * to be directed at the monster, not the player,
473 * which makes "laid by you" wrong. For the
474 * parallelism to work, we can't rephrase it, so we
475 * zap the "laid by you" momentarily instead.
477 struct obj *obj = level.objects[u.ux][u.uy];
479 if (obj || u.umonnum == PM_TRAPPER
480 || (youmonst.data->mlet == S_EEL
481 && is_pool(u.ux, u.uy))) {
482 int save_spe = 0; /* suppress warning */
484 if (obj) {
485 save_spe = obj->spe;
486 if (obj->otyp == EGG)
487 obj->spe = 0;
489 if (youmonst.data->mlet == S_EEL
490 || u.umonnum == PM_TRAPPER)
491 pline(
492 "Wait, %s! There's a hidden %s named %s there!",
493 m_monnam(mtmp), youmonst.data->mname, plname);
494 else
495 pline(
496 "Wait, %s! There's a %s named %s hiding under %s!",
497 m_monnam(mtmp), youmonst.data->mname, plname,
498 doname(level.objects[u.ux][u.uy]));
499 if (obj)
500 obj->spe = save_spe;
501 } else
502 impossible("hiding under nothing?");
504 newsym(u.ux, u.uy);
506 return 0;
509 /* hero might be a mimic, concealed via #monster */
510 if (youmonst.data->mlet == S_MIMIC && youmonst.m_ap_type && !range2
511 && foundyou && !u.uswallow) {
512 boolean sticky = sticks(youmonst.data);
514 if (!canspotmon(mtmp))
515 map_invisible(mtmp->mx, mtmp->my);
516 if (sticky && !youseeit)
517 pline("It gets stuck on you.");
518 else
519 pline("Wait, %s! That's a %s named %s!", m_monnam(mtmp),
520 youmonst.data->mname, plname);
521 if (sticky)
522 u.ustuck = mtmp;
523 youmonst.m_ap_type = M_AP_NOTHING;
524 youmonst.mappearance = 0;
525 newsym(u.ux, u.uy);
526 return 0;
529 /* non-mimic hero might be mimicking an object after eating m corpse */
530 if (youmonst.m_ap_type == M_AP_OBJECT && !range2 && foundyou
531 && !u.uswallow) {
532 if (!canspotmon(mtmp))
533 map_invisible(mtmp->mx, mtmp->my);
534 if (!youseeit)
535 pline("%s %s!", Something, (likes_gold(mtmp->data)
536 && youmonst.mappearance == GOLD_PIECE)
537 ? "tries to pick you up"
538 : "disturbs you");
539 else
540 pline("Wait, %s! That %s is really %s named %s!", m_monnam(mtmp),
541 mimic_obj_name(&youmonst), an(mons[u.umonnum].mname),
542 plname);
543 if (multi < 0) { /* this should always be the case */
544 char buf[BUFSZ];
546 Sprintf(buf, "You appear to be %s again.",
547 Upolyd ? (const char *) an(youmonst.data->mname)
548 : (const char *) "yourself");
549 unmul(buf); /* immediately stop mimicking */
551 return 0;
554 /* Work out the armor class differential */
555 tmp = AC_VALUE(u.uac) + 10; /* tmp ~= 0 - 20 */
556 tmp += mtmp->m_lev;
557 if (multi < 0)
558 tmp += 4;
559 if ((Invis && !perceives(mdat)) || !mtmp->mcansee)
560 tmp -= 2;
561 if (mtmp->mtrapped)
562 tmp -= 2;
563 if (tmp <= 0)
564 tmp = 1;
566 /* make eels visible the moment they hit/miss us */
567 if (mdat->mlet == S_EEL && mtmp->minvis && cansee(mtmp->mx, mtmp->my)) {
568 mtmp->minvis = 0;
569 newsym(mtmp->mx, mtmp->my);
572 /* Special demon handling code */
573 if ((mtmp->cham == NON_PM) && is_demon(mdat) && !range2
574 && mtmp->data != &mons[PM_BALROG] && mtmp->data != &mons[PM_SUCCUBUS]
575 && mtmp->data != &mons[PM_INCUBUS])
576 if (!mtmp->mcan && !rn2(13))
577 (void) msummon(mtmp);
579 /* Special lycanthrope handling code */
580 if ((mtmp->cham == NON_PM) && is_were(mdat) && !range2) {
581 if (is_human(mdat)) {
582 if (!rn2(5 - (night() * 2)) && !mtmp->mcan)
583 new_were(mtmp);
584 } else if (!rn2(30) && !mtmp->mcan)
585 new_were(mtmp);
586 mdat = mtmp->data;
588 if (!rn2(10) && !mtmp->mcan) {
589 int numseen, numhelp;
590 char buf[BUFSZ], genericwere[BUFSZ];
592 Strcpy(genericwere, "creature");
593 numhelp = were_summon(mdat, FALSE, &numseen, genericwere);
594 if (youseeit) {
595 pline("%s summons help!", Monnam(mtmp));
596 if (numhelp > 0) {
597 if (numseen == 0)
598 You_feel("hemmed in.");
599 } else
600 pline("But none comes.");
601 } else {
602 const char *from_nowhere;
604 if (!Deaf) {
605 pline("%s %s!", Something, makeplural(growl_sound(mtmp)));
606 from_nowhere = "";
607 } else
608 from_nowhere = " from nowhere";
609 if (numhelp > 0) {
610 if (numseen < 1)
611 You_feel("hemmed in.");
612 else {
613 if (numseen == 1)
614 Sprintf(buf, "%s appears", an(genericwere));
615 else
616 Sprintf(buf, "%s appear",
617 makeplural(genericwere));
618 pline("%s%s!", upstart(buf), from_nowhere);
620 } /* else no help came; but you didn't know it tried */
625 if (u.uinvulnerable) {
626 /* monsters won't attack you */
627 if (mtmp == u.ustuck)
628 pline("%s loosens its grip slightly.", Monnam(mtmp));
629 else if (!range2) {
630 if (youseeit || sensemon(mtmp))
631 pline("%s starts to attack you, but pulls back.",
632 Monnam(mtmp));
633 else
634 You_feel("%s move nearby.", something);
636 return 0;
639 /* Unlike defensive stuff, don't let them use item _and_ attack. */
640 if (find_offensive(mtmp)) {
641 int foo = use_offensive(mtmp);
643 if (foo != 0)
644 return (foo == 1);
647 for (i = 0; i < NATTK; i++) {
648 sum[i] = 0;
649 mon_currwep = (struct obj *)0;
650 mattk = getmattk(mtmp, &youmonst, i, sum, &alt_attk);
651 if ((u.uswallow && mattk->aatyp != AT_ENGL)
652 || (skipnonmagc && mattk->aatyp != AT_MAGC))
653 continue;
655 switch (mattk->aatyp) {
656 case AT_CLAW: /* "hand to hand" attacks */
657 case AT_KICK:
658 case AT_BITE:
659 case AT_STNG:
660 case AT_TUCH:
661 case AT_BUTT:
662 case AT_TENT:
663 if (!range2 && (!MON_WEP(mtmp) || mtmp->mconf || Conflict
664 || !touch_petrifies(youmonst.data))) {
665 if (foundyou) {
666 if (tmp > (j = rnd(20 + i))) {
667 if (mattk->aatyp != AT_KICK
668 || !thick_skinned(youmonst.data))
669 sum[i] = hitmu(mtmp, mattk);
670 } else
671 missmu(mtmp, (tmp == j), mattk);
672 } else {
673 wildmiss(mtmp, mattk);
674 /* skip any remaining non-spell attacks */
675 skipnonmagc = TRUE;
678 break;
680 case AT_HUGS: /* automatic if prev two attacks succeed */
681 /* Note: if displaced, prev attacks never succeeded */
682 if ((!range2 && i >= 2 && sum[i - 1] && sum[i - 2])
683 || mtmp == u.ustuck)
684 sum[i] = hitmu(mtmp, mattk);
685 break;
687 case AT_GAZE: /* can affect you either ranged or not */
688 /* Medusa gaze already operated through m_respond in
689 dochug(); don't gaze more than once per round. */
690 if (mdat != &mons[PM_MEDUSA])
691 sum[i] = gazemu(mtmp, mattk);
692 break;
694 case AT_EXPL: /* automatic hit if next to, and aimed at you */
695 if (!range2)
696 sum[i] = explmu(mtmp, mattk, foundyou);
697 break;
699 case AT_ENGL:
700 if (!range2) {
701 if (foundyou) {
702 if (u.uswallow
703 || (!mtmp->mspec_used && tmp > (j = rnd(20 + i)))) {
704 /* force swallowing monster to be displayed
705 even when hero is moving away */
706 flush_screen(1);
707 sum[i] = gulpmu(mtmp, mattk);
708 } else {
709 missmu(mtmp, (tmp == j), mattk);
711 } else if (is_animal(mtmp->data)) {
712 pline("%s gulps some air!", Monnam(mtmp));
713 } else {
714 if (youseeit)
715 pline("%s lunges forward and recoils!", Monnam(mtmp));
716 else
717 You_hear("a %s nearby.",
718 is_whirly(mtmp->data) ? "rushing noise"
719 : "splat");
722 break;
723 case AT_BREA:
724 if (range2)
725 sum[i] = breamu(mtmp, mattk);
726 /* Note: breamu takes care of displacement */
727 break;
728 case AT_SPIT:
729 if (range2)
730 sum[i] = spitmu(mtmp, mattk);
731 /* Note: spitmu takes care of displacement */
732 break;
733 case AT_WEAP:
734 if (range2) {
735 if (!Is_rogue_level(&u.uz))
736 thrwmu(mtmp);
737 } else {
738 int hittmp = 0;
740 /* Rare but not impossible. Normally the monster
741 * wields when 2 spaces away, but it can be
742 * teleported or whatever....
744 if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) {
745 mtmp->weapon_check = NEED_HTH_WEAPON;
746 /* mon_wield_item resets weapon_check as appropriate */
747 if (mon_wield_item(mtmp) != 0)
748 break;
750 if (foundyou) {
751 mon_currwep = MON_WEP(mtmp);
752 if (mon_currwep) {
753 hittmp = hitval(mon_currwep, &youmonst);
754 tmp += hittmp;
755 mswings(mtmp, mon_currwep);
757 if (tmp > (j = dieroll = rnd(20 + i)))
758 sum[i] = hitmu(mtmp, mattk);
759 else
760 missmu(mtmp, (tmp == j), mattk);
761 /* KMH -- Don't accumulate to-hit bonuses */
762 if (mon_currwep)
763 tmp -= hittmp;
764 } else {
765 wildmiss(mtmp, mattk);
766 /* skip any remaining non-spell attacks */
767 skipnonmagc = TRUE;
770 break;
771 case AT_MAGC:
772 if (range2)
773 sum[i] = buzzmu(mtmp, mattk);
774 else
775 sum[i] = castmu(mtmp, mattk, TRUE, foundyou);
776 break;
778 default: /* no attack */
779 break;
781 if (context.botl)
782 bot();
783 /* give player a chance of waking up before dying -kaa */
784 if (sum[i] == 1) { /* successful attack */
785 if (u.usleep && u.usleep < monstermoves && !rn2(10)) {
786 multi = -1;
787 nomovemsg = "The combat suddenly awakens you.";
790 if (sum[i] == 2)
791 return 1; /* attacker dead */
792 if (sum[i] == 3)
793 break; /* attacker teleported, no more attacks */
794 /* sum[i] == 0: unsuccessful attack */
796 return 0;
799 STATIC_OVL boolean
800 diseasemu(mdat)
801 struct permonst *mdat;
803 if (Sick_resistance) {
804 You_feel("a slight illness.");
805 return FALSE;
806 } else {
807 make_sick(Sick ? Sick / 3L + 1L : (long) rn1(ACURR(A_CON), 20),
808 mdat->mname, TRUE, SICK_NONVOMITABLE);
809 return TRUE;
813 /* check whether slippery clothing protects from hug or wrap attack */
814 STATIC_OVL boolean
815 u_slip_free(mtmp, mattk)
816 struct monst *mtmp;
817 struct attack *mattk;
819 struct obj *obj = (uarmc ? uarmc : uarm);
821 if (!obj)
822 obj = uarmu;
823 if (mattk->adtyp == AD_DRIN)
824 obj = uarmh;
826 /* if your cloak/armor is greased, monster slips off; this
827 protection might fail (33% chance) when the armor is cursed */
828 if (obj && (obj->greased || obj->otyp == OILSKIN_CLOAK)
829 && (!obj->cursed || rn2(3))) {
830 pline("%s %s your %s %s!", Monnam(mtmp),
831 (mattk->adtyp == AD_WRAP) ? "slips off of"
832 : "grabs you, but cannot hold onto",
833 obj->greased ? "greased" : "slippery",
834 /* avoid "slippery slippery cloak"
835 for undiscovered oilskin cloak */
836 (obj->greased || objects[obj->otyp].oc_name_known)
837 ? xname(obj)
838 : cloak_simple_name(obj));
840 if (obj->greased && !rn2(2)) {
841 pline_The("grease wears off.");
842 obj->greased = 0;
843 update_inventory();
845 return TRUE;
847 return FALSE;
850 /* armor that sufficiently covers the body might be able to block magic */
852 magic_negation(mon)
853 struct monst *mon;
855 struct obj *o;
856 long wearmask;
857 int armpro, mc = 0;
858 boolean is_you = (mon == &youmonst),
859 gotprot = is_you ? (EProtection != 0L)
860 /* high priests have innate protection */
861 : (mon->data == &mons[PM_HIGH_PRIEST]);
863 for (o = is_you ? invent : mon->minvent; o; o = o->nobj) {
864 /* a_can field is only applicable for armor (which must be worn) */
865 if ((o->owornmask & W_ARMOR) != 0L) {
866 armpro = objects[o->otyp].a_can;
867 if (armpro > mc)
868 mc = armpro;
870 /* if we've already confirmed Protection, skip additional checks */
871 if (is_you || gotprot)
872 continue;
874 /* omit W_SWAPWEP+W_QUIVER; W_ART+W_ARTI handled by protects() */
875 wearmask = W_ARMOR | W_ACCESSORY;
876 if (o->oclass == WEAPON_CLASS || is_weptool(o))
877 wearmask |= W_WEP;
878 if (protects(o, ((o->owornmask & wearmask) != 0L) ? TRUE : FALSE))
879 gotprot = TRUE;
882 if (gotprot) {
883 /* extrinsic Protection increases mc by 1 */
884 if (mc < 3)
885 mc += 1;
886 } else if (mc < 1) {
887 /* intrinsic Protection is weaker (play balance; obtaining divine
888 protection is too easy); it confers minimum mc 1 instead of 0 */
889 if ((is_you && ((HProtection && u.ublessed > 0) || u.uspellprot))
890 /* aligned priests and angels have innate intrinsic Protection */
891 || (mon->data == &mons[PM_ALIGNED_PRIEST] || is_minion(mon->data)))
892 mc = 1;
894 return mc;
898 * hitmu: monster hits you
899 * returns 2 if monster dies (e.g. "yellow light"), 1 otherwise
900 * 3 if the monster lives but teleported/paralyzed, so it can't keep
901 * attacking you
903 STATIC_OVL int
904 hitmu(mtmp, mattk)
905 register struct monst *mtmp;
906 register struct attack *mattk;
908 register struct permonst *mdat = mtmp->data;
909 register int uncancelled, ptmp;
910 int dmg, armpro, permdmg;
911 char buf[BUFSZ];
912 struct permonst *olduasmon = youmonst.data;
913 int res;
915 if (!canspotmon(mtmp))
916 map_invisible(mtmp->mx, mtmp->my);
918 /* If the monster is undetected & hits you, you should know where
919 * the attack came from.
921 if (mtmp->mundetected && (hides_under(mdat) || mdat->mlet == S_EEL)) {
922 mtmp->mundetected = 0;
923 if (!(Blind ? Blind_telepat : Unblind_telepat)) {
924 struct obj *obj;
925 const char *what;
927 if ((obj = level.objects[mtmp->mx][mtmp->my]) != 0) {
928 if (Blind && !obj->dknown)
929 what = something;
930 else if (is_pool(mtmp->mx, mtmp->my) && !Underwater)
931 what = "the water";
932 else
933 what = doname(obj);
935 pline("%s was hidden under %s!", Amonnam(mtmp), what);
937 newsym(mtmp->mx, mtmp->my);
941 /* First determine the base damage done */
942 dmg = d((int) mattk->damn, (int) mattk->damd);
943 if ((is_undead(mdat) || is_vampshifter(mtmp)) && midnight())
944 dmg += d((int) mattk->damn, (int) mattk->damd); /* extra damage */
946 /* Next a cancellation factor.
947 * Use uncancelled when cancellation factor takes into account certain
948 * armor's special magic protection. Otherwise just use !mtmp->mcan.
950 armpro = magic_negation(&youmonst);
951 uncancelled = !mtmp->mcan && (rn2(10) >= 3 * armpro);
953 permdmg = 0;
954 /* Now, adjust damages via resistances or specific attacks */
955 switch (mattk->adtyp) {
956 case AD_PHYS:
957 if (mattk->aatyp == AT_HUGS && !sticks(youmonst.data)) {
958 if (!u.ustuck && rn2(2)) {
959 if (u_slip_free(mtmp, mattk)) {
960 dmg = 0;
961 } else {
962 u.ustuck = mtmp;
963 pline("%s grabs you!", Monnam(mtmp));
965 } else if (u.ustuck == mtmp) {
966 exercise(A_STR, FALSE);
967 You("are being %s.", (mtmp->data == &mons[PM_ROPE_GOLEM])
968 ? "choked"
969 : "crushed");
971 } else { /* hand to hand weapon */
972 struct obj *otmp = mon_currwep;
973 if (mattk->aatyp == AT_WEAP && otmp) {
974 int tmp;
976 if (otmp->otyp == CORPSE
977 && touch_petrifies(&mons[otmp->corpsenm])) {
978 dmg = 1;
979 pline("%s hits you with the %s corpse.", Monnam(mtmp),
980 mons[otmp->corpsenm].mname);
981 if (!Stoned)
982 goto do_stone;
984 dmg += dmgval(otmp, &youmonst);
985 if (dmg <= 0)
986 dmg = 1;
987 if (!(otmp->oartifact
988 && artifact_hit(mtmp, &youmonst, otmp, &dmg, dieroll)))
989 hitmsg(mtmp, mattk);
990 if (!dmg)
991 break;
992 if (objects[otmp->otyp].oc_material == SILVER
993 && Hate_silver) {
994 pline_The("silver sears your flesh!");
995 exercise(A_CON, FALSE);
997 /* this redundancy necessary because you have
998 to take the damage _before_ being cloned;
999 need to have at least 2 hp left to split */
1000 tmp = dmg;
1001 if (u.uac < 0)
1002 tmp -= rnd(-u.uac);
1003 if (tmp < 1)
1004 tmp = 1;
1005 if (u.mh - tmp > 1 && objects[otmp->otyp].oc_material == IRON
1006 && (u.umonnum == PM_BLACK_PUDDING
1007 || u.umonnum == PM_BROWN_PUDDING)) {
1008 if (tmp > 1)
1009 exercise(A_STR, FALSE);
1010 /* inflict damage now; we know it can't be fatal */
1011 u.mh -= tmp;
1012 context.botl = 1;
1013 dmg = 0; /* don't inflict more damage below */
1014 if (cloneu())
1015 You("divide as %s hits you!", mon_nam(mtmp));
1017 rustm(&youmonst, otmp);
1018 } else if (mattk->aatyp != AT_TUCH || dmg != 0
1019 || mtmp != u.ustuck)
1020 hitmsg(mtmp, mattk);
1022 break;
1023 case AD_DISE:
1024 hitmsg(mtmp, mattk);
1025 if (!diseasemu(mdat))
1026 dmg = 0;
1027 break;
1028 case AD_FIRE:
1029 hitmsg(mtmp, mattk);
1030 if (uncancelled) {
1031 pline("You're %s!", on_fire(youmonst.data, mattk));
1032 if (youmonst.data == &mons[PM_STRAW_GOLEM]
1033 || youmonst.data == &mons[PM_PAPER_GOLEM]) {
1034 You("roast!");
1035 /* KMH -- this is okay with unchanging */
1036 rehumanize();
1037 break;
1038 } else if (Fire_resistance) {
1039 pline_The("fire doesn't feel hot!");
1040 dmg = 0;
1042 if ((int) mtmp->m_lev > rn2(20))
1043 destroy_item(SCROLL_CLASS, AD_FIRE);
1044 if ((int) mtmp->m_lev > rn2(20))
1045 destroy_item(POTION_CLASS, AD_FIRE);
1046 if ((int) mtmp->m_lev > rn2(25))
1047 destroy_item(SPBOOK_CLASS, AD_FIRE);
1048 burn_away_slime();
1049 } else
1050 dmg = 0;
1051 break;
1052 case AD_COLD:
1053 hitmsg(mtmp, mattk);
1054 if (uncancelled) {
1055 pline("You're covered in frost!");
1056 if (Cold_resistance) {
1057 pline_The("frost doesn't seem cold!");
1058 dmg = 0;
1060 if ((int) mtmp->m_lev > rn2(20))
1061 destroy_item(POTION_CLASS, AD_COLD);
1062 } else
1063 dmg = 0;
1064 break;
1065 case AD_ELEC:
1066 hitmsg(mtmp, mattk);
1067 if (uncancelled) {
1068 You("get zapped!");
1069 if (Shock_resistance) {
1070 pline_The("zap doesn't shock you!");
1071 dmg = 0;
1073 if ((int) mtmp->m_lev > rn2(20))
1074 destroy_item(WAND_CLASS, AD_ELEC);
1075 if ((int) mtmp->m_lev > rn2(20))
1076 destroy_item(RING_CLASS, AD_ELEC);
1077 } else
1078 dmg = 0;
1079 break;
1080 case AD_SLEE:
1081 hitmsg(mtmp, mattk);
1082 if (uncancelled && multi >= 0 && !rn2(5)) {
1083 if (Sleep_resistance)
1084 break;
1085 fall_asleep(-rnd(10), TRUE);
1086 if (Blind)
1087 You("are put to sleep!");
1088 else
1089 You("are put to sleep by %s!", mon_nam(mtmp));
1091 break;
1092 case AD_BLND:
1093 if (can_blnd(mtmp, &youmonst, mattk->aatyp, (struct obj *) 0)) {
1094 if (!Blind)
1095 pline("%s blinds you!", Monnam(mtmp));
1096 make_blinded(Blinded + (long) dmg, FALSE);
1097 if (!Blind)
1098 Your1(vision_clears);
1100 dmg = 0;
1101 break;
1102 case AD_DRST:
1103 ptmp = A_STR;
1104 goto dopois;
1105 case AD_DRDX:
1106 ptmp = A_DEX;
1107 goto dopois;
1108 case AD_DRCO:
1109 ptmp = A_CON;
1110 dopois:
1111 hitmsg(mtmp, mattk);
1112 if (uncancelled && !rn2(8)) {
1113 Sprintf(buf, "%s %s", s_suffix(Monnam(mtmp)),
1114 mpoisons_subj(mtmp, mattk));
1115 poisoned(buf, ptmp, mdat->mname, 30, FALSE);
1117 break;
1118 case AD_DRIN:
1119 hitmsg(mtmp, mattk);
1120 if (defends(AD_DRIN, uwep) || !has_head(youmonst.data)) {
1121 You("don't seem harmed.");
1122 /* Not clear what to do for green slimes */
1123 break;
1125 if (u_slip_free(mtmp, mattk))
1126 break;
1128 if (uarmh && rn2(8)) {
1129 /* not body_part(HEAD) */
1130 Your("%s blocks the attack to your head.",
1131 helm_simple_name(uarmh));
1132 break;
1134 /* negative armor class doesn't reduce this damage */
1135 if (Half_physical_damage)
1136 dmg = (dmg + 1) / 2;
1137 mdamageu(mtmp, dmg);
1138 dmg = 0; /* don't inflict a second dose below */
1140 if (!uarmh || uarmh->otyp != DUNCE_CAP) {
1141 /* eat_brains() will miss if target is mindless (won't
1142 happen here; hero is considered to retain his mind
1143 regardless of current shape) or is noncorporeal
1144 (can't happen here; no one can poly into a ghost
1145 or shade) so this check for missing is academic */
1146 if (eat_brains(mtmp, &youmonst, TRUE, (int *) 0) == MM_MISS)
1147 break;
1149 /* adjattrib gives dunce cap message when appropriate */
1150 (void) adjattrib(A_INT, -rnd(2), FALSE);
1151 forget_levels(25); /* lose memory of 25% of levels */
1152 forget_objects(25); /* lose memory of 25% of objects */
1153 break;
1154 case AD_PLYS:
1155 hitmsg(mtmp, mattk);
1156 if (uncancelled && multi >= 0 && !rn2(3)) {
1157 if (Free_action) {
1158 You("momentarily stiffen.");
1159 } else {
1160 if (Blind)
1161 You("are frozen!");
1162 else
1163 You("are frozen by %s!", mon_nam(mtmp));
1164 nomovemsg = You_can_move_again;
1165 nomul(-rnd(10));
1166 multi_reason = "paralyzed by a monster";
1167 exercise(A_DEX, FALSE);
1170 break;
1171 case AD_DRLI:
1172 hitmsg(mtmp, mattk);
1173 if (uncancelled && !rn2(3) && !Drain_resistance) {
1174 losexp("life drainage");
1176 break;
1177 case AD_LEGS: {
1178 register long side = rn2(2) ? RIGHT_SIDE : LEFT_SIDE;
1179 const char *sidestr = (side == RIGHT_SIDE) ? "right" : "left",
1180 *Monst_name = Monnam(mtmp), *leg = body_part(LEG);
1182 /* This case is too obvious to ignore, but Nethack is not in
1183 * general very good at considering height--most short monsters
1184 * still _can_ attack you when you're flying or mounted.
1185 * [FIXME: why can't a flying attacker overcome this?]
1187 if (u.usteed || Levitation || Flying) {
1188 pline("%s tries to reach your %s %s!", Monst_name, sidestr, leg);
1189 dmg = 0;
1190 } else if (mtmp->mcan) {
1191 pline("%s nuzzles against your %s %s!", Monnam(mtmp),
1192 sidestr, leg);
1193 dmg = 0;
1194 } else {
1195 if (uarmf) {
1196 if (rn2(2) && (uarmf->otyp == LOW_BOOTS
1197 || uarmf->otyp == IRON_SHOES)) {
1198 pline("%s pricks the exposed part of your %s %s!",
1199 Monst_name, sidestr, leg);
1200 } else if (!rn2(5)) {
1201 pline("%s pricks through your %s boot!", Monst_name,
1202 sidestr);
1203 } else {
1204 pline("%s scratches your %s boot!", Monst_name,
1205 sidestr);
1206 dmg = 0;
1207 break;
1209 } else
1210 pline("%s pricks your %s %s!", Monst_name, sidestr, leg);
1212 set_wounded_legs(side, rnd(60 - ACURR(A_DEX)));
1213 exercise(A_STR, FALSE);
1214 exercise(A_DEX, FALSE);
1216 break;
1218 case AD_STON: /* cockatrice */
1219 hitmsg(mtmp, mattk);
1220 if (!rn2(3)) {
1221 if (mtmp->mcan) {
1222 if (!Deaf)
1223 You_hear("a cough from %s!", mon_nam(mtmp));
1224 } else {
1225 if (!Deaf)
1226 You_hear("%s hissing!", s_suffix(mon_nam(mtmp)));
1227 if (!rn2(10)
1228 || (flags.moonphase == NEW_MOON && !have_lizard())) {
1229 do_stone:
1230 if (!Stoned && !Stone_resistance
1231 && !(poly_when_stoned(youmonst.data)
1232 && polymon(PM_STONE_GOLEM))) {
1233 int kformat = KILLED_BY_AN;
1234 const char *kname = mtmp->data->mname;
1236 if (mtmp->data->geno & G_UNIQ) {
1237 if (!type_is_pname(mtmp->data))
1238 kname = the(kname);
1239 kformat = KILLED_BY;
1241 make_stoned(5L, (char *) 0, kformat, kname);
1242 return 1;
1243 /* done_in_by(mtmp, STONING); */
1248 break;
1249 case AD_STCK:
1250 hitmsg(mtmp, mattk);
1251 if (uncancelled && !u.ustuck && !sticks(youmonst.data))
1252 u.ustuck = mtmp;
1253 break;
1254 case AD_WRAP:
1255 if ((!mtmp->mcan || u.ustuck == mtmp) && !sticks(youmonst.data)) {
1256 if (!u.ustuck && !rn2(10)) {
1257 if (u_slip_free(mtmp, mattk)) {
1258 dmg = 0;
1259 } else {
1260 pline("%s swings itself around you!", Monnam(mtmp));
1261 u.ustuck = mtmp;
1263 } else if (u.ustuck == mtmp) {
1264 if (is_pool(mtmp->mx, mtmp->my) && !Swimming && !Amphibious) {
1265 boolean moat = (levl[mtmp->mx][mtmp->my].typ != POOL)
1266 && (levl[mtmp->mx][mtmp->my].typ != WATER)
1267 && !Is_medusa_level(&u.uz)
1268 && !Is_waterlevel(&u.uz);
1270 pline("%s drowns you...", Monnam(mtmp));
1271 killer.format = KILLED_BY_AN;
1272 Sprintf(killer.name, "%s by %s",
1273 moat ? "moat" : "pool of water",
1274 an(mtmp->data->mname));
1275 done(DROWNING);
1276 } else if (mattk->aatyp == AT_HUGS)
1277 You("are being crushed.");
1278 } else {
1279 dmg = 0;
1280 if (flags.verbose)
1281 pline("%s brushes against your %s.", Monnam(mtmp),
1282 body_part(LEG));
1284 } else
1285 dmg = 0;
1286 break;
1287 case AD_WERE:
1288 hitmsg(mtmp, mattk);
1289 if (uncancelled && !rn2(4) && u.ulycn == NON_PM
1290 && !Protection_from_shape_changers && !defends(AD_WERE, uwep)) {
1291 You_feel("feverish.");
1292 exercise(A_CON, FALSE);
1293 set_ulycn(monsndx(mdat));
1294 retouch_equipment(2);
1296 break;
1297 case AD_SGLD:
1298 hitmsg(mtmp, mattk);
1299 if (youmonst.data->mlet == mdat->mlet)
1300 break;
1301 if (!mtmp->mcan)
1302 stealgold(mtmp);
1303 break;
1305 case AD_SSEX:
1306 if (SYSOPT_SEDUCE) {
1307 if (could_seduce(mtmp, &youmonst, mattk) == 1 && !mtmp->mcan)
1308 if (doseduce(mtmp))
1309 return 3;
1310 break;
1312 /* else FALLTHRU */
1313 case AD_SITM: /* for now these are the same */
1314 case AD_SEDU:
1315 if (is_animal(mtmp->data)) {
1316 hitmsg(mtmp, mattk);
1317 if (mtmp->mcan)
1318 break;
1319 /* Continue below */
1320 } else if (dmgtype(youmonst.data, AD_SEDU)
1321 || (SYSOPT_SEDUCE && dmgtype(youmonst.data, AD_SSEX))) {
1322 pline("%s %s.", Monnam(mtmp),
1323 mtmp->minvent
1324 ? "brags about the goods some dungeon explorer provided"
1325 : "makes some remarks about how difficult theft is lately");
1326 if (!tele_restrict(mtmp))
1327 (void) rloc(mtmp, TRUE);
1328 return 3;
1329 } else if (mtmp->mcan) {
1330 if (!Blind)
1331 pline("%s tries to %s you, but you seem %s.",
1332 Adjmonnam(mtmp, "plain"),
1333 flags.female ? "charm" : "seduce",
1334 flags.female ? "unaffected" : "uninterested");
1335 if (rn2(3)) {
1336 if (!tele_restrict(mtmp))
1337 (void) rloc(mtmp, TRUE);
1338 return 3;
1340 break;
1342 buf[0] = '\0';
1343 switch (steal(mtmp, buf)) {
1344 case -1:
1345 return 2;
1346 case 0:
1347 break;
1348 default:
1349 if (!is_animal(mtmp->data) && !tele_restrict(mtmp))
1350 (void) rloc(mtmp, TRUE);
1351 if (is_animal(mtmp->data) && *buf) {
1352 if (canseemon(mtmp))
1353 pline("%s tries to %s away with %s.", Monnam(mtmp),
1354 locomotion(mtmp->data, "run"), buf);
1356 monflee(mtmp, 0, FALSE, FALSE);
1357 return 3;
1359 break;
1361 case AD_SAMU:
1362 hitmsg(mtmp, mattk);
1363 /* when the Wizard or quest nemesis hits, there's a 1/20 chance
1364 to steal a quest artifact (any, not just the one for the hero's
1365 own role) or the Amulet or one of the invocation tools */
1366 if (!rn2(20))
1367 stealamulet(mtmp);
1368 break;
1370 case AD_TLPT:
1371 hitmsg(mtmp, mattk);
1372 if (uncancelled) {
1373 if (flags.verbose)
1374 Your("position suddenly seems very uncertain!");
1375 tele();
1377 break;
1378 case AD_RUST:
1379 hitmsg(mtmp, mattk);
1380 if (mtmp->mcan)
1381 break;
1382 if (u.umonnum == PM_IRON_GOLEM) {
1383 You("rust!");
1384 /* KMH -- this is okay with unchanging */
1385 rehumanize();
1386 break;
1388 erode_armor(&youmonst, ERODE_RUST);
1389 break;
1390 case AD_CORR:
1391 hitmsg(mtmp, mattk);
1392 if (mtmp->mcan)
1393 break;
1394 erode_armor(&youmonst, ERODE_CORRODE);
1395 break;
1396 case AD_DCAY:
1397 hitmsg(mtmp, mattk);
1398 if (mtmp->mcan)
1399 break;
1400 if (u.umonnum == PM_WOOD_GOLEM || u.umonnum == PM_LEATHER_GOLEM) {
1401 You("rot!");
1402 /* KMH -- this is okay with unchanging */
1403 rehumanize();
1404 break;
1406 erode_armor(&youmonst, ERODE_ROT);
1407 break;
1408 case AD_HEAL:
1409 /* a cancelled nurse is just an ordinary monster,
1410 * nurses don't heal those that cause petrification */
1411 if (mtmp->mcan || (Upolyd && touch_petrifies(youmonst.data))) {
1412 hitmsg(mtmp, mattk);
1413 break;
1415 if (!uwep && !uarmu && !uarm && !uarmc
1416 && !uarms && !uarmg && !uarmf && !uarmh) {
1417 boolean goaway = FALSE;
1419 pline("%s hits! (I hope you don't mind.)", Monnam(mtmp));
1420 if (Upolyd) {
1421 u.mh += rnd(7);
1422 if (!rn2(7)) {
1423 /* no upper limit necessary; effect is temporary */
1424 u.mhmax++;
1425 if (!rn2(13))
1426 goaway = TRUE;
1428 if (u.mh > u.mhmax)
1429 u.mh = u.mhmax;
1430 } else {
1431 u.uhp += rnd(7);
1432 if (!rn2(7)) {
1433 /* hard upper limit via nurse care: 25 * ulevel */
1434 if (u.uhpmax < 5 * u.ulevel + d(2 * u.ulevel, 10))
1435 u.uhpmax++;
1436 if (!rn2(13))
1437 goaway = TRUE;
1439 if (u.uhp > u.uhpmax)
1440 u.uhp = u.uhpmax;
1442 if (!rn2(3))
1443 exercise(A_STR, TRUE);
1444 if (!rn2(3))
1445 exercise(A_CON, TRUE);
1446 if (Sick)
1447 make_sick(0L, (char *) 0, FALSE, SICK_ALL);
1448 context.botl = 1;
1449 if (goaway) {
1450 mongone(mtmp);
1451 return 2;
1452 } else if (!rn2(33)) {
1453 if (!tele_restrict(mtmp))
1454 (void) rloc(mtmp, TRUE);
1455 monflee(mtmp, d(3, 6), TRUE, FALSE);
1456 return 3;
1458 dmg = 0;
1459 } else {
1460 if (Role_if(PM_HEALER)) {
1461 if (!Deaf && !(moves % 5))
1462 verbalize("Doc, I can't help you unless you cooperate.");
1463 dmg = 0;
1464 } else
1465 hitmsg(mtmp, mattk);
1467 break;
1468 case AD_CURS:
1469 hitmsg(mtmp, mattk);
1470 if (!night() && mdat == &mons[PM_GREMLIN])
1471 break;
1472 if (!mtmp->mcan && !rn2(10)) {
1473 if (!Deaf) {
1474 if (Blind)
1475 You_hear("laughter.");
1476 else
1477 pline("%s chuckles.", Monnam(mtmp));
1479 if (u.umonnum == PM_CLAY_GOLEM) {
1480 pline("Some writing vanishes from your head!");
1481 /* KMH -- this is okay with unchanging */
1482 rehumanize();
1483 break;
1485 attrcurse();
1487 break;
1488 case AD_STUN:
1489 hitmsg(mtmp, mattk);
1490 if (!mtmp->mcan && !rn2(4)) {
1491 make_stunned((HStun & TIMEOUT) + (long) dmg, TRUE);
1492 dmg /= 2;
1494 break;
1495 case AD_ACID:
1496 hitmsg(mtmp, mattk);
1497 if (!mtmp->mcan && !rn2(3))
1498 if (Acid_resistance) {
1499 pline("You're covered in %s, but it seems harmless.",
1500 hliquid("acid"));
1501 dmg = 0;
1502 } else {
1503 pline("You're covered in %s! It burns!", hliquid("acid"));
1504 exercise(A_STR, FALSE);
1506 else
1507 dmg = 0;
1508 break;
1509 case AD_SLOW:
1510 hitmsg(mtmp, mattk);
1511 if (uncancelled && HFast && !defends(AD_SLOW, uwep) && !rn2(4))
1512 u_slow_down();
1513 break;
1514 case AD_DREN:
1515 hitmsg(mtmp, mattk);
1516 if (uncancelled && !rn2(4)) /* 25% chance */
1517 drain_en(dmg);
1518 dmg = 0;
1519 break;
1520 case AD_CONF:
1521 hitmsg(mtmp, mattk);
1522 if (!mtmp->mcan && !rn2(4) && !mtmp->mspec_used) {
1523 mtmp->mspec_used = mtmp->mspec_used + (dmg + rn2(6));
1524 if (Confusion)
1525 You("are getting even more confused.");
1526 else
1527 You("are getting confused.");
1528 make_confused(HConfusion + dmg, FALSE);
1530 dmg = 0;
1531 break;
1532 case AD_DETH:
1533 pline("%s reaches out with its deadly touch.", Monnam(mtmp));
1534 if (is_undead(youmonst.data)) {
1535 /* Still does normal damage */
1536 pline("Was that the touch of death?");
1537 break;
1539 switch (rn2(20)) {
1540 case 19:
1541 case 18:
1542 case 17:
1543 if (!Antimagic) {
1544 killer.format = KILLED_BY_AN;
1545 Strcpy(killer.name, "touch of death");
1546 done(DIED);
1547 dmg = 0;
1548 break;
1549 } /* else FALLTHRU */
1550 default: /* case 16: ... case 5: */
1551 You_feel("your life force draining away...");
1552 permdmg = 1; /* actual damage done below */
1553 break;
1554 case 4:
1555 case 3:
1556 case 2:
1557 case 1:
1558 case 0:
1559 if (Antimagic)
1560 shieldeff(u.ux, u.uy);
1561 pline("Lucky for you, it didn't work!");
1562 dmg = 0;
1563 break;
1565 break;
1566 case AD_PEST:
1567 pline("%s reaches out, and you feel fever and chills.", Monnam(mtmp));
1568 (void) diseasemu(mdat); /* plus the normal damage */
1569 break;
1570 case AD_FAMN:
1571 pline("%s reaches out, and your body shrivels.", Monnam(mtmp));
1572 exercise(A_CON, FALSE);
1573 if (!is_fainted())
1574 morehungry(rn1(40, 40));
1575 /* plus the normal damage */
1576 break;
1577 case AD_SLIM:
1578 hitmsg(mtmp, mattk);
1579 if (!uncancelled)
1580 break;
1581 if (flaming(youmonst.data)) {
1582 pline_The("slime burns away!");
1583 dmg = 0;
1584 } else if (Unchanging || noncorporeal(youmonst.data)
1585 || youmonst.data == &mons[PM_GREEN_SLIME]) {
1586 You("are unaffected.");
1587 dmg = 0;
1588 } else if (!Slimed) {
1589 You("don't feel very well.");
1590 make_slimed(10L, (char *) 0);
1591 delayed_killer(SLIMED, KILLED_BY_AN, mtmp->data->mname);
1592 } else
1593 pline("Yuck!");
1594 break;
1595 case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */
1596 hitmsg(mtmp, mattk);
1597 /* uncancelled is sufficient enough; please
1598 don't make this attack less frequent */
1599 if (uncancelled) {
1600 struct obj *obj = some_armor(&youmonst);
1602 if (!obj) {
1603 /* some rings are susceptible;
1604 amulets and blindfolds aren't (at present) */
1605 switch (rn2(5)) {
1606 case 0:
1607 break;
1608 case 1:
1609 obj = uright;
1610 break;
1611 case 2:
1612 obj = uleft;
1613 break;
1614 case 3:
1615 obj = uamul;
1616 break;
1617 case 4:
1618 obj = ublindf;
1619 break;
1622 if (drain_item(obj, FALSE)) {
1623 pline("%s less effective.", Yobjnam2(obj, "seem"));
1626 break;
1627 default:
1628 dmg = 0;
1629 break;
1631 if (u.uhp < 1)
1632 done_in_by(mtmp, DIED);
1634 /* Negative armor class reduces damage done instead of fully protecting
1635 * against hits.
1637 if (dmg && u.uac < 0) {
1638 dmg -= rnd(-u.uac);
1639 if (dmg < 1)
1640 dmg = 1;
1643 if (dmg) {
1644 if (Half_physical_damage
1645 /* Mitre of Holiness */
1646 || (Role_if(PM_PRIEST) && uarmh && is_quest_artifact(uarmh)
1647 && (is_undead(mtmp->data) || is_demon(mtmp->data)
1648 || is_vampshifter(mtmp))))
1649 dmg = (dmg + 1) / 2;
1651 if (permdmg) { /* Death's life force drain */
1652 int lowerlimit, *hpmax_p;
1654 * Apply some of the damage to permanent hit points:
1655 * polymorphed 100% against poly'd hpmax
1656 * hpmax > 25*lvl 100% against normal hpmax
1657 * hpmax > 10*lvl 50..100%
1658 * hpmax > 5*lvl 25..75%
1659 * otherwise 0..50%
1660 * Never reduces hpmax below 1 hit point per level.
1662 permdmg = rn2(dmg / 2 + 1);
1663 if (Upolyd || u.uhpmax > 25 * u.ulevel)
1664 permdmg = dmg;
1665 else if (u.uhpmax > 10 * u.ulevel)
1666 permdmg += dmg / 2;
1667 else if (u.uhpmax > 5 * u.ulevel)
1668 permdmg += dmg / 4;
1670 if (Upolyd) {
1671 hpmax_p = &u.mhmax;
1672 /* [can't use youmonst.m_lev] */
1673 lowerlimit = min((int) youmonst.data->mlevel, u.ulevel);
1674 } else {
1675 hpmax_p = &u.uhpmax;
1676 lowerlimit = u.ulevel;
1678 if (*hpmax_p - permdmg > lowerlimit)
1679 *hpmax_p -= permdmg;
1680 else if (*hpmax_p > lowerlimit)
1681 *hpmax_p = lowerlimit;
1682 /* else unlikely...
1683 * already at or below minimum threshold; do nothing */
1684 context.botl = 1;
1687 mdamageu(mtmp, dmg);
1690 if (dmg)
1691 res = passiveum(olduasmon, mtmp, mattk);
1692 else
1693 res = 1;
1694 stop_occupation();
1695 return res;
1698 /* An interface for use when taking a blindfold off, for example,
1699 * to see if an engulfing attack should immediately take affect, like
1700 * a passive attack. TRUE if engulfing blindness occurred */
1701 boolean
1702 gulp_blnd_check()
1704 struct attack *mattk;
1706 if (!Blinded && u.uswallow
1707 && (mattk = attacktype_fordmg(u.ustuck->data, AT_ENGL, AD_BLND))
1708 && can_blnd(u.ustuck, &youmonst, mattk->aatyp, (struct obj *) 0)) {
1709 ++u.uswldtim; /* compensate for gulpmu change */
1710 (void) gulpmu(u.ustuck, mattk);
1711 return TRUE;
1713 return FALSE;
1716 /* monster swallows you, or damage if u.uswallow */
1717 STATIC_OVL int
1718 gulpmu(mtmp, mattk)
1719 register struct monst *mtmp;
1720 register struct attack *mattk;
1722 struct trap *t = t_at(u.ux, u.uy);
1723 int tmp = d((int) mattk->damn, (int) mattk->damd);
1724 int tim_tmp;
1725 register struct obj *otmp2;
1726 int i;
1727 boolean physical_damage = FALSE;
1729 if (!u.uswallow) { /* swallows you */
1730 int omx = mtmp->mx, omy = mtmp->my;
1732 if (!engulf_target(mtmp, &youmonst))
1733 return 0;
1734 if ((t && ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT)))
1735 && sobj_at(BOULDER, u.ux, u.uy))
1736 return 0;
1738 if (Punished)
1739 unplacebc(); /* ball&chain go away */
1740 remove_monster(omx, omy);
1741 mtmp->mtrapped = 0; /* no longer on old trap */
1742 place_monster(mtmp, u.ux, u.uy);
1743 u.ustuck = mtmp;
1744 newsym(mtmp->mx, mtmp->my);
1745 if (is_animal(mtmp->data) && u.usteed) {
1746 char buf[BUFSZ];
1748 /* Too many quirks presently if hero and steed
1749 * are swallowed. Pretend purple worms don't
1750 * like horses for now :-)
1752 Strcpy(buf, mon_nam(u.usteed));
1753 pline("%s lunges forward and plucks you off %s!", Monnam(mtmp),
1754 buf);
1755 dismount_steed(DISMOUNT_ENGULFED);
1756 } else
1757 pline("%s engulfs you!", Monnam(mtmp));
1758 stop_occupation();
1759 reset_occupations(); /* behave as if you had moved */
1761 if (u.utrap) {
1762 You("are released from the %s!",
1763 u.utraptype == TT_WEB ? "web" : "trap");
1764 u.utrap = 0;
1767 i = number_leashed();
1768 if (i > 0) {
1769 const char *s = (i > 1) ? "leashes" : "leash";
1770 pline_The("%s %s loose.", s, vtense(s, "snap"));
1771 unleash_all();
1774 if (touch_petrifies(youmonst.data) && !resists_ston(mtmp)) {
1775 /* put the attacker back where it started;
1776 the resulting statue will end up there */
1777 remove_monster(mtmp->mx, mtmp->my); /* u.ux,u.uy */
1778 place_monster(mtmp, omx, omy);
1779 minstapetrify(mtmp, TRUE);
1780 /* normally unstuck() would do this, but we're not
1781 fully swallowed yet so that won't work here */
1782 if (Punished)
1783 placebc();
1784 u.ustuck = 0;
1785 return (mtmp->mhp > 0) ? 0 : 2;
1788 display_nhwindow(WIN_MESSAGE, FALSE);
1789 vision_recalc(2); /* hero can't see anything */
1790 u.uswallow = 1;
1791 /* for digestion, shorter time is more dangerous;
1792 for other swallowings, longer time means more
1793 chances for the swallower to attack */
1794 if (mattk->adtyp == AD_DGST) {
1795 tim_tmp = 25 - (int) mtmp->m_lev;
1796 if (tim_tmp > 0)
1797 tim_tmp = rnd(tim_tmp) / 2;
1798 else if (tim_tmp < 0)
1799 tim_tmp = -(rnd(-tim_tmp) / 2);
1800 /* having good armor & high constitution makes
1801 it take longer for you to be digested, but
1802 you'll end up trapped inside for longer too */
1803 tim_tmp += -u.uac + 10 + (ACURR(A_CON) / 3 - 1);
1804 } else {
1805 /* higher level attacker takes longer to eject hero */
1806 tim_tmp = rnd((int) mtmp->m_lev + 10 / 2);
1808 /* u.uswldtim always set > 1 */
1809 u.uswldtim = (unsigned) ((tim_tmp < 2) ? 2 : tim_tmp);
1810 swallowed(1);
1811 for (otmp2 = invent; otmp2; otmp2 = otmp2->nobj)
1812 (void) snuff_lit(otmp2);
1815 if (mtmp != u.ustuck)
1816 return 0;
1817 if (u.uswldtim > 0)
1818 u.uswldtim -= 1;
1820 switch (mattk->adtyp) {
1821 case AD_DGST:
1822 physical_damage = TRUE;
1823 if (Slow_digestion) {
1824 /* Messages are handled below */
1825 u.uswldtim = 0;
1826 tmp = 0;
1827 } else if (u.uswldtim == 0) {
1828 pline("%s totally digests you!", Monnam(mtmp));
1829 tmp = u.uhp;
1830 if (Half_physical_damage)
1831 tmp *= 2; /* sorry */
1832 } else {
1833 pline("%s%s digests you!", Monnam(mtmp),
1834 (u.uswldtim == 2) ? " thoroughly"
1835 : (u.uswldtim == 1) ? " utterly" : "");
1836 exercise(A_STR, FALSE);
1838 break;
1839 case AD_PHYS:
1840 physical_damage = TRUE;
1841 if (mtmp->data == &mons[PM_FOG_CLOUD]) {
1842 You("are laden with moisture and %s",
1843 flaming(youmonst.data)
1844 ? "are smoldering out!"
1845 : Breathless ? "find it mildly uncomfortable."
1846 : amphibious(youmonst.data)
1847 ? "feel comforted."
1848 : "can barely breathe!");
1849 /* NB: Amphibious includes Breathless */
1850 if (Amphibious && !flaming(youmonst.data))
1851 tmp = 0;
1852 } else {
1853 You("are pummeled with debris!");
1854 exercise(A_STR, FALSE);
1856 break;
1857 case AD_ACID:
1858 if (Acid_resistance) {
1859 You("are covered with a seemingly harmless goo.");
1860 tmp = 0;
1861 } else {
1862 if (Hallucination)
1863 pline("Ouch! You've been slimed!");
1864 else
1865 You("are covered in slime! It burns!");
1866 exercise(A_STR, FALSE);
1868 break;
1869 case AD_BLND:
1870 if (can_blnd(mtmp, &youmonst, mattk->aatyp, (struct obj *) 0)) {
1871 if (!Blind) {
1872 long was_blinded = Blinded;
1873 if (!Blinded)
1874 You_cant("see in here!");
1875 make_blinded((long) tmp, FALSE);
1876 if (!was_blinded && !Blind)
1877 Your1(vision_clears);
1878 } else
1879 /* keep him blind until disgorged */
1880 make_blinded(Blinded + 1, FALSE);
1882 tmp = 0;
1883 break;
1884 case AD_ELEC:
1885 if (!mtmp->mcan && rn2(2)) {
1886 pline_The("air around you crackles with electricity.");
1887 if (Shock_resistance) {
1888 shieldeff(u.ux, u.uy);
1889 You("seem unhurt.");
1890 ugolemeffects(AD_ELEC, tmp);
1891 tmp = 0;
1893 } else
1894 tmp = 0;
1895 break;
1896 case AD_COLD:
1897 if (!mtmp->mcan && rn2(2)) {
1898 if (Cold_resistance) {
1899 shieldeff(u.ux, u.uy);
1900 You_feel("mildly chilly.");
1901 ugolemeffects(AD_COLD, tmp);
1902 tmp = 0;
1903 } else
1904 You("are freezing to death!");
1905 } else
1906 tmp = 0;
1907 break;
1908 case AD_FIRE:
1909 if (!mtmp->mcan && rn2(2)) {
1910 if (Fire_resistance) {
1911 shieldeff(u.ux, u.uy);
1912 You_feel("mildly hot.");
1913 ugolemeffects(AD_FIRE, tmp);
1914 tmp = 0;
1915 } else
1916 You("are burning to a crisp!");
1917 burn_away_slime();
1918 } else
1919 tmp = 0;
1920 break;
1921 case AD_DISE:
1922 if (!diseasemu(mtmp->data))
1923 tmp = 0;
1924 break;
1925 case AD_DREN:
1926 /* AC magic cancellation doesn't help when engulfed */
1927 if (!mtmp->mcan && rn2(4)) /* 75% chance */
1928 drain_en(tmp);
1929 tmp = 0;
1930 break;
1931 default:
1932 physical_damage = TRUE;
1933 tmp = 0;
1934 break;
1937 if (physical_damage)
1938 tmp = Maybe_Half_Phys(tmp);
1940 mdamageu(mtmp, tmp);
1941 if (tmp)
1942 stop_occupation();
1944 if (touch_petrifies(youmonst.data) && !resists_ston(mtmp)) {
1945 pline("%s very hurriedly %s you!", Monnam(mtmp),
1946 is_animal(mtmp->data) ? "regurgitates" : "expels");
1947 expels(mtmp, mtmp->data, FALSE);
1948 } else if (!u.uswldtim || youmonst.data->msize >= MZ_HUGE) {
1949 You("get %s!", is_animal(mtmp->data) ? "regurgitated" : "expelled");
1950 if (flags.verbose
1951 && (is_animal(mtmp->data)
1952 || (dmgtype(mtmp->data, AD_DGST) && Slow_digestion)))
1953 pline("Obviously %s doesn't like your taste.", mon_nam(mtmp));
1954 expels(mtmp, mtmp->data, FALSE);
1956 return 1;
1959 /* monster explodes in your face */
1960 STATIC_OVL int
1961 explmu(mtmp, mattk, ufound)
1962 register struct monst *mtmp;
1963 register struct attack *mattk;
1964 boolean ufound;
1966 boolean physical_damage = TRUE, kill_agr = TRUE;
1968 if (mtmp->mcan)
1969 return 0;
1971 if (!ufound)
1972 pline("%s explodes at a spot in %s!",
1973 canseemon(mtmp) ? Monnam(mtmp) : "It",
1974 levl[mtmp->mux][mtmp->muy].typ == WATER ? "empty water"
1975 : "thin air");
1976 else {
1977 register int tmp = d((int) mattk->damn, (int) mattk->damd);
1978 register boolean not_affected = defends((int) mattk->adtyp, uwep);
1980 hitmsg(mtmp, mattk);
1982 switch (mattk->adtyp) {
1983 case AD_COLD:
1984 physical_damage = FALSE;
1985 not_affected |= Cold_resistance;
1986 goto common;
1987 case AD_FIRE:
1988 physical_damage = FALSE;
1989 not_affected |= Fire_resistance;
1990 goto common;
1991 case AD_ELEC:
1992 physical_damage = FALSE;
1993 not_affected |= Shock_resistance;
1994 common:
1996 if (!not_affected) {
1997 if (ACURR(A_DEX) > rnd(20)) {
1998 You("duck some of the blast.");
1999 tmp = (tmp + 1) / 2;
2000 } else {
2001 if (flags.verbose)
2002 You("get blasted!");
2004 if (mattk->adtyp == AD_FIRE)
2005 burn_away_slime();
2006 if (physical_damage)
2007 tmp = Maybe_Half_Phys(tmp);
2008 mdamageu(mtmp, tmp);
2010 break;
2012 case AD_BLND:
2013 not_affected = resists_blnd(&youmonst);
2014 if (!not_affected) {
2015 /* sometimes you're affected even if it's invisible */
2016 if (mon_visible(mtmp) || (rnd(tmp /= 2) > u.ulevel)) {
2017 You("are blinded by a blast of light!");
2018 make_blinded((long) tmp, FALSE);
2019 if (!Blind)
2020 Your1(vision_clears);
2021 } else if (flags.verbose)
2022 You("get the impression it was not terribly bright.");
2024 break;
2026 case AD_HALU:
2027 not_affected |= Blind || (u.umonnum == PM_BLACK_LIGHT
2028 || u.umonnum == PM_VIOLET_FUNGUS
2029 || dmgtype(youmonst.data, AD_STUN));
2030 if (!not_affected) {
2031 boolean chg;
2032 if (!Hallucination)
2033 You("are caught in a blast of kaleidoscopic light!");
2034 /* avoid hallucinating the black light as it dies */
2035 mondead(mtmp); /* remove it from map now */
2036 kill_agr = FALSE; /* already killed (maybe lifesaved) */
2037 chg =
2038 make_hallucinated(HHallucination + (long) tmp, FALSE, 0L);
2039 You("%s.", chg ? "are freaked out" : "seem unaffected");
2041 break;
2043 default:
2044 break;
2046 if (not_affected) {
2047 You("seem unaffected by it.");
2048 ugolemeffects((int) mattk->adtyp, tmp);
2051 if (kill_agr)
2052 mondead(mtmp);
2053 wake_nearto(mtmp->mx, mtmp->my, 7 * 7);
2054 return (mtmp->mhp > 0) ? 0 : 2;
2057 /* monster gazes at you */
2059 gazemu(mtmp, mattk)
2060 register struct monst *mtmp;
2061 register struct attack *mattk;
2063 static const char *const reactions[] = {
2064 "confused", /* [0] */
2065 "stunned", /* [1] */
2066 "puzzled", "dazzled", /* [2,3] */
2067 "irritated", "inflamed", /* [4,5] */
2068 "tired", /* [6] */
2069 "dulled", /* [7] */
2071 int react = -1;
2072 boolean cancelled = (mtmp->mcan != 0), already = FALSE;
2074 /* assumes that hero has to see monster's gaze in order to be
2075 affected, rather than monster just having to look at hero;
2076 when hallucinating, hero's brain doesn't register what
2077 it's seeing correctly so the gaze is usually ineffective
2078 [this could be taken a lot farther and select a gaze effect
2079 appropriate to what's currently being displayed, giving
2080 ordinary monsters a gaze attack when hero thinks he or she
2081 is facing a gazing creature, but let's not go that far...] */
2082 if (Hallucination && rn2(4))
2083 cancelled = TRUE;
2085 switch (mattk->adtyp) {
2086 case AD_STON:
2087 if (cancelled || !mtmp->mcansee) {
2088 if (!canseemon(mtmp))
2089 break; /* silently */
2090 pline("%s %s.", Monnam(mtmp),
2091 (mtmp->data == &mons[PM_MEDUSA] && mtmp->mcan)
2092 ? "doesn't look all that ugly"
2093 : "gazes ineffectually");
2094 break;
2096 if (Reflecting && couldsee(mtmp->mx, mtmp->my)
2097 && mtmp->data == &mons[PM_MEDUSA]) {
2098 /* hero has line of sight to Medusa and she's not blind */
2099 boolean useeit = canseemon(mtmp);
2101 if (useeit)
2102 (void) ureflects("%s gaze is reflected by your %s.",
2103 s_suffix(Monnam(mtmp)));
2104 if (mon_reflects(
2105 mtmp, !useeit ? (char *) 0
2106 : "The gaze is reflected away by %s %s!"))
2107 break;
2108 if (!m_canseeu(mtmp)) { /* probably you're invisible */
2109 if (useeit)
2110 pline(
2111 "%s doesn't seem to notice that %s gaze was reflected.",
2112 Monnam(mtmp), mhis(mtmp));
2113 break;
2115 if (useeit)
2116 pline("%s is turned to stone!", Monnam(mtmp));
2117 stoned = TRUE;
2118 killed(mtmp);
2120 if (mtmp->mhp > 0)
2121 break;
2122 return 2;
2124 if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my)
2125 && !Stone_resistance) {
2126 You("meet %s gaze.", s_suffix(mon_nam(mtmp)));
2127 stop_occupation();
2128 if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
2129 break;
2130 You("turn to stone...");
2131 killer.format = KILLED_BY;
2132 Strcpy(killer.name, mtmp->data->mname);
2133 done(STONING);
2135 break;
2136 case AD_CONF:
2137 if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) && mtmp->mcansee
2138 && !mtmp->mspec_used && rn2(5)) {
2139 if (cancelled) {
2140 react = 0; /* "confused" */
2141 already = (mtmp->mconf != 0);
2142 } else {
2143 int conf = d(3, 4);
2145 mtmp->mspec_used = mtmp->mspec_used + (conf + rn2(6));
2146 if (!Confusion)
2147 pline("%s gaze confuses you!", s_suffix(Monnam(mtmp)));
2148 else
2149 You("are getting more and more confused.");
2150 make_confused(HConfusion + conf, FALSE);
2151 stop_occupation();
2154 break;
2155 case AD_STUN:
2156 if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) && mtmp->mcansee
2157 && !mtmp->mspec_used && rn2(5)) {
2158 if (cancelled) {
2159 react = 1; /* "stunned" */
2160 already = (mtmp->mstun != 0);
2161 } else {
2162 int stun = d(2, 6);
2164 mtmp->mspec_used = mtmp->mspec_used + (stun + rn2(6));
2165 pline("%s stares piercingly at you!", Monnam(mtmp));
2166 make_stunned((HStun & TIMEOUT) + (long) stun, TRUE);
2167 stop_occupation();
2170 break;
2171 case AD_BLND:
2172 if (canseemon(mtmp) && !resists_blnd(&youmonst)
2173 && distu(mtmp->mx, mtmp->my) <= BOLT_LIM * BOLT_LIM) {
2174 if (cancelled) {
2175 react = rn1(2, 2); /* "puzzled" || "dazzled" */
2176 already = (mtmp->mcansee == 0);
2177 /* Archons gaze every round; we don't want cancelled ones
2178 giving the "seems puzzled/dazzled" message that often */
2179 if (mtmp->mcan && mtmp->data == &mons[PM_ARCHON] && rn2(5))
2180 react = -1;
2181 } else {
2182 int blnd = d((int) mattk->damn, (int) mattk->damd);
2184 You("are blinded by %s radiance!", s_suffix(mon_nam(mtmp)));
2185 make_blinded((long) blnd, FALSE);
2186 stop_occupation();
2187 /* not blind at this point implies you're wearing
2188 the Eyes of the Overworld; make them block this
2189 particular stun attack too */
2190 if (!Blind) {
2191 Your1(vision_clears);
2192 } else {
2193 long oldstun = (HStun & TIMEOUT), newstun = (long) rnd(3);
2195 /* we don't want to increment stun duration every time
2196 or sighted hero will become incapacitated */
2197 make_stunned(max(oldstun, newstun), TRUE);
2201 break;
2202 case AD_FIRE:
2203 if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) && mtmp->mcansee
2204 && !mtmp->mspec_used && rn2(5)) {
2205 if (cancelled) {
2206 react = rn1(2, 4); /* "irritated" || "inflamed" */
2207 } else {
2208 int dmg = d(2, 6), lev = (int) mtmp->m_lev;
2210 pline("%s attacks you with a fiery gaze!", Monnam(mtmp));
2211 stop_occupation();
2212 if (Fire_resistance) {
2213 pline_The("fire doesn't feel hot!");
2214 dmg = 0;
2216 burn_away_slime();
2217 if (lev > rn2(20))
2218 destroy_item(SCROLL_CLASS, AD_FIRE);
2219 if (lev > rn2(20))
2220 destroy_item(POTION_CLASS, AD_FIRE);
2221 if (lev > rn2(25))
2222 destroy_item(SPBOOK_CLASS, AD_FIRE);
2223 if (dmg)
2224 mdamageu(mtmp, dmg);
2227 break;
2228 #ifdef PM_BEHOLDER /* work in progress */
2229 case AD_SLEE:
2230 if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) && mtmp->mcansee
2231 && multi >= 0 && !rn2(5) && !Sleep_resistance) {
2232 if (cancelled) {
2233 react = 6; /* "tired" */
2234 already = (mtmp->mfrozen != 0); /* can't happen... */
2235 } else {
2236 fall_asleep(-rnd(10), TRUE);
2237 pline("%s gaze makes you very sleepy...",
2238 s_suffix(Monnam(mtmp)));
2241 break;
2242 case AD_SLOW:
2243 if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) && mtmp->mcansee
2244 && (HFast & (INTRINSIC | TIMEOUT)) && !defends(AD_SLOW, uwep)
2245 && !rn2(4)) {
2246 if (cancelled) {
2247 react = 7; /* "dulled" */
2248 already = (mtmp->mspeed == MSLOW);
2249 } else {
2250 u_slow_down();
2251 stop_occupation();
2254 break;
2255 #endif /* BEHOLDER */
2256 default:
2257 impossible("Gaze attack %d?", mattk->adtyp);
2258 break;
2260 if (react >= 0) {
2261 if (Hallucination && rn2(3))
2262 react = rn2(SIZE(reactions));
2263 /* cancelled/hallucinatory feedback; monster might look "confused",
2264 "stunned",&c but we don't actually set corresponding attribute */
2265 pline("%s looks %s%s.", Monnam(mtmp),
2266 !rn2(3) ? "" : already ? "quite "
2267 : (!rn2(2) ? "a bit " : "somewhat "),
2268 reactions[react]);
2270 return 0;
2273 /* mtmp hits you for n points damage */
2274 void
2275 mdamageu(mtmp, n)
2276 register struct monst *mtmp;
2277 register int n;
2279 context.botl = 1;
2280 if (Upolyd) {
2281 u.mh -= n;
2282 if (u.mh < 1)
2283 rehumanize();
2284 } else {
2285 u.uhp -= n;
2286 if (u.uhp < 1)
2287 done_in_by(mtmp, DIED);
2291 /* returns 0 if seduction impossible,
2292 * 1 if fine,
2293 * 2 if wrong gender for nymph
2296 could_seduce(magr, mdef, mattk)
2297 struct monst *magr, *mdef;
2298 struct attack *mattk;
2300 register struct permonst *pagr;
2301 boolean agrinvis, defperc;
2302 xchar genagr, gendef;
2304 if (is_animal(magr->data))
2305 return 0;
2306 if (magr == &youmonst) {
2307 pagr = youmonst.data;
2308 agrinvis = (Invis != 0);
2309 genagr = poly_gender();
2310 } else {
2311 pagr = magr->data;
2312 agrinvis = magr->minvis;
2313 genagr = gender(magr);
2315 if (mdef == &youmonst) {
2316 defperc = (See_invisible != 0);
2317 gendef = poly_gender();
2318 } else {
2319 defperc = perceives(mdef->data);
2320 gendef = gender(mdef);
2323 if (agrinvis && !defperc
2324 && (!SYSOPT_SEDUCE || (mattk && mattk->adtyp != AD_SSEX)))
2325 return 0;
2327 if (pagr->mlet != S_NYMPH
2328 && ((pagr != &mons[PM_INCUBUS] && pagr != &mons[PM_SUCCUBUS])
2329 || (SYSOPT_SEDUCE && mattk && mattk->adtyp != AD_SSEX)))
2330 return 0;
2332 if (genagr == 1 - gendef)
2333 return 1;
2334 else
2335 return (pagr->mlet == S_NYMPH) ? 2 : 0;
2338 /* Returns 1 if monster teleported */
2340 doseduce(mon)
2341 register struct monst *mon;
2343 register struct obj *ring, *nring;
2344 boolean fem = (mon->data == &mons[PM_SUCCUBUS]); /* otherwise incubus */
2345 int attr_tot, tried_gloves = 0;
2346 char qbuf[QBUFSZ];
2348 if (mon->mcan || mon->mspec_used) {
2349 pline("%s acts as though %s has got a %sheadache.", Monnam(mon),
2350 mhe(mon), mon->mcan ? "severe " : "");
2351 return 0;
2354 if (unconscious()) {
2355 pline("%s seems dismayed at your lack of response.", Monnam(mon));
2356 return 0;
2359 if (Blind)
2360 pline("It caresses you...");
2361 else
2362 You_feel("very attracted to %s.", mon_nam(mon));
2363 /* if in the process of putting armor on or taking armor off,
2364 interrupt that activity now */
2365 (void) stop_donning((struct obj *) 0);
2366 /* don't try to take off gloves if cursed weapon blocks them */
2367 if (welded(uwep))
2368 tried_gloves = 1;
2370 for (ring = invent; ring; ring = nring) {
2371 nring = ring->nobj;
2372 if (ring->otyp != RIN_ADORNMENT)
2373 continue;
2374 if (fem) {
2375 if (ring->owornmask && uarmg) {
2376 /* don't take off worn ring if gloves are in the way */
2377 if (!tried_gloves++)
2378 mayberem(uarmg, "gloves");
2379 if (uarmg)
2380 continue; /* next ring might not be worn */
2382 if (rn2(20) < ACURR(A_CHA)) {
2383 (void) safe_qbuf(qbuf, "\"That ",
2384 " looks pretty. May I have it?\"", ring,
2385 xname, simpleonames, "ring");
2386 makeknown(RIN_ADORNMENT);
2387 if (yn(qbuf) == 'n')
2388 continue;
2389 } else
2390 pline("%s decides she'd like %s, and takes it.",
2391 Blind ? "She" : Monnam(mon), yname(ring));
2392 makeknown(RIN_ADORNMENT);
2393 if (ring == uleft || ring == uright)
2394 Ring_gone(ring);
2395 if (ring == uwep)
2396 setuwep((struct obj *) 0);
2397 if (ring == uswapwep)
2398 setuswapwep((struct obj *) 0);
2399 if (ring == uquiver)
2400 setuqwep((struct obj *) 0);
2401 freeinv(ring);
2402 (void) mpickobj(mon, ring);
2403 } else {
2404 if (uleft && uright && uleft->otyp == RIN_ADORNMENT
2405 && uright->otyp == RIN_ADORNMENT)
2406 break;
2407 if (ring == uleft || ring == uright)
2408 continue;
2409 if (uarmg) {
2410 /* don't put on ring if gloves are in the way */
2411 if (!tried_gloves++)
2412 mayberem(uarmg, "gloves");
2413 if (uarmg)
2414 break; /* no point trying further rings */
2416 if (rn2(20) < ACURR(A_CHA)) {
2417 (void) safe_qbuf(qbuf, "\"That ",
2418 " looks pretty. Would you wear it for me?\"",
2419 ring, xname, simpleonames, "ring");
2420 makeknown(RIN_ADORNMENT);
2421 if (yn(qbuf) == 'n')
2422 continue;
2423 } else {
2424 pline("%s decides you'd look prettier wearing %s,",
2425 Blind ? "He" : Monnam(mon), yname(ring));
2426 pline("and puts it on your finger.");
2428 makeknown(RIN_ADORNMENT);
2429 if (!uright) {
2430 pline("%s puts %s on your right %s.",
2431 Blind ? "He" : Monnam(mon), the(xname(ring)),
2432 body_part(HAND));
2433 setworn(ring, RIGHT_RING);
2434 } else if (!uleft) {
2435 pline("%s puts %s on your left %s.",
2436 Blind ? "He" : Monnam(mon), the(xname(ring)),
2437 body_part(HAND));
2438 setworn(ring, LEFT_RING);
2439 } else if (uright && uright->otyp != RIN_ADORNMENT) {
2440 pline("%s replaces %s with %s.", Blind ? "He" : Monnam(mon),
2441 yname(uright), yname(ring));
2442 Ring_gone(uright);
2443 setworn(ring, RIGHT_RING);
2444 } else if (uleft && uleft->otyp != RIN_ADORNMENT) {
2445 pline("%s replaces %s with %s.", Blind ? "He" : Monnam(mon),
2446 yname(uleft), yname(ring));
2447 Ring_gone(uleft);
2448 setworn(ring, LEFT_RING);
2449 } else
2450 impossible("ring replacement");
2451 Ring_on(ring);
2452 prinv((char *) 0, ring, 0L);
2456 if (!uarmc && !uarmf && !uarmg && !uarms && !uarmh && !uarmu)
2457 pline("%s murmurs sweet nothings into your ear.",
2458 Blind ? (fem ? "She" : "He") : Monnam(mon));
2459 else
2460 pline("%s murmurs in your ear, while helping you undress.",
2461 Blind ? (fem ? "She" : "He") : Monnam(mon));
2462 mayberem(uarmc, cloak_simple_name(uarmc));
2463 if (!uarmc)
2464 mayberem(uarm, "suit");
2465 mayberem(uarmf, "boots");
2466 if (!tried_gloves)
2467 mayberem(uarmg, "gloves");
2468 mayberem(uarms, "shield");
2469 mayberem(uarmh, helm_simple_name(uarmh));
2470 if (!uarmc && !uarm)
2471 mayberem(uarmu, "shirt");
2473 if (uarm || uarmc) {
2474 verbalize("You're such a %s; I wish...",
2475 flags.female ? "sweet lady" : "nice guy");
2476 if (!tele_restrict(mon))
2477 (void) rloc(mon, TRUE);
2478 return 1;
2480 if (u.ualign.type == A_CHAOTIC)
2481 adjalign(1);
2483 /* by this point you have discovered mon's identity, blind or not... */
2484 pline("Time stands still while you and %s lie in each other's arms...",
2485 noit_mon_nam(mon));
2486 /* 3.6.1: a combined total for charisma plus intelligence of 35-1
2487 used to guarantee successful outcome; now total maxes out at 32
2488 as far as deciding what will happen; chance for bad outcome when
2489 Cha+Int is 32 or more is 2/35, a bit over 5.7% */
2490 attr_tot = ACURR(A_CHA) + ACURR(A_INT);
2491 if (rn2(35) > min(attr_tot, 32)) {
2492 /* Don't bother with mspec_used here... it didn't get tired! */
2493 pline("%s seems to have enjoyed it more than you...",
2494 noit_Monnam(mon));
2495 switch (rn2(5)) {
2496 case 0:
2497 You_feel("drained of energy.");
2498 u.uen = 0;
2499 u.uenmax -= rnd(Half_physical_damage ? 5 : 10);
2500 exercise(A_CON, FALSE);
2501 if (u.uenmax < 0)
2502 u.uenmax = 0;
2503 break;
2504 case 1:
2505 You("are down in the dumps.");
2506 (void) adjattrib(A_CON, -1, TRUE);
2507 exercise(A_CON, FALSE);
2508 context.botl = 1;
2509 break;
2510 case 2:
2511 Your("senses are dulled.");
2512 (void) adjattrib(A_WIS, -1, TRUE);
2513 exercise(A_WIS, FALSE);
2514 context.botl = 1;
2515 break;
2516 case 3:
2517 if (!resists_drli(&youmonst)) {
2518 You_feel("out of shape.");
2519 losexp("overexertion");
2520 } else {
2521 You("have a curious feeling...");
2523 exercise(A_CON, FALSE);
2524 exercise(A_DEX, FALSE);
2525 exercise(A_WIS, FALSE);
2526 break;
2527 case 4: {
2528 int tmp;
2530 You_feel("exhausted.");
2531 exercise(A_STR, FALSE);
2532 tmp = rn1(10, 6);
2533 losehp(Maybe_Half_Phys(tmp), "exhaustion", KILLED_BY);
2534 break;
2535 } /* case 4 */
2536 } /* switch */
2537 } else {
2538 mon->mspec_used = rnd(100); /* monster is worn out */
2539 You("seem to have enjoyed it more than %s...", noit_mon_nam(mon));
2540 switch (rn2(5)) {
2541 case 0:
2542 You_feel("raised to your full potential.");
2543 exercise(A_CON, TRUE);
2544 u.uen = (u.uenmax += rnd(5));
2545 break;
2546 case 1:
2547 You_feel("good enough to do it again.");
2548 (void) adjattrib(A_CON, 1, TRUE);
2549 exercise(A_CON, TRUE);
2550 context.botl = 1;
2551 break;
2552 case 2:
2553 You("will always remember %s...", noit_mon_nam(mon));
2554 (void) adjattrib(A_WIS, 1, TRUE);
2555 exercise(A_WIS, TRUE);
2556 context.botl = 1;
2557 break;
2558 case 3:
2559 pline("That was a very educational experience.");
2560 pluslvl(FALSE);
2561 exercise(A_WIS, TRUE);
2562 break;
2563 case 4:
2564 You_feel("restored to health!");
2565 u.uhp = u.uhpmax;
2566 if (Upolyd)
2567 u.mh = u.mhmax;
2568 exercise(A_STR, TRUE);
2569 context.botl = 1;
2570 break;
2574 if (mon->mtame) { /* don't charge */
2576 } else if (rn2(20) < ACURR(A_CHA)) {
2577 pline("%s demands that you pay %s, but you refuse...",
2578 noit_Monnam(mon), Blind ? (fem ? "her" : "him") : mhim(mon));
2579 } else if (u.umonnum == PM_LEPRECHAUN) {
2580 pline("%s tries to take your money, but fails...", noit_Monnam(mon));
2581 } else {
2582 long cost;
2583 long umoney = money_cnt(invent);
2585 if (umoney > (long) LARGEST_INT - 10L)
2586 cost = (long) rnd(LARGEST_INT) + 500L;
2587 else
2588 cost = (long) rnd((int) umoney + 10) + 500L;
2589 if (mon->mpeaceful) {
2590 cost /= 5L;
2591 if (!cost)
2592 cost = 1L;
2594 if (cost > umoney)
2595 cost = umoney;
2596 if (!cost) {
2597 verbalize("It's on the house!");
2598 } else {
2599 pline("%s takes %ld %s for services rendered!", noit_Monnam(mon),
2600 cost, currency(cost));
2601 money2mon(mon, cost);
2602 context.botl = 1;
2605 if (!rn2(25))
2606 mon->mcan = 1; /* monster is worn out */
2607 if (!tele_restrict(mon))
2608 (void) rloc(mon, TRUE);
2609 return 1;
2612 STATIC_OVL void
2613 mayberem(obj, str)
2614 register struct obj *obj;
2615 const char *str;
2617 char qbuf[QBUFSZ];
2619 if (!obj || !obj->owornmask)
2620 return;
2622 if (rn2(20) < ACURR(A_CHA)) {
2623 Sprintf(qbuf, "\"Shall I remove your %s, %s?\"", str,
2624 (!rn2(2) ? "lover" : !rn2(2) ? "dear" : "sweetheart"));
2625 if (yn(qbuf) == 'n')
2626 return;
2627 } else {
2628 char hairbuf[BUFSZ];
2630 Sprintf(hairbuf, "let me run my fingers through your %s",
2631 body_part(HAIR));
2632 verbalize("Take off your %s; %s.", str,
2633 (obj == uarm)
2634 ? "let's get a little closer"
2635 : (obj == uarmc || obj == uarms)
2636 ? "it's in the way"
2637 : (obj == uarmf)
2638 ? "let me rub your feet"
2639 : (obj == uarmg)
2640 ? "they're too clumsy"
2641 : (obj == uarmu)
2642 ? "let me massage you"
2643 /* obj == uarmh */
2644 : hairbuf);
2646 remove_worn_item(obj, TRUE);
2649 STATIC_OVL int
2650 passiveum(olduasmon, mtmp, mattk)
2651 struct permonst *olduasmon;
2652 register struct monst *mtmp;
2653 register struct attack *mattk;
2655 int i, tmp;
2657 for (i = 0;; i++) {
2658 if (i >= NATTK)
2659 return 1;
2660 if (olduasmon->mattk[i].aatyp == AT_NONE
2661 || olduasmon->mattk[i].aatyp == AT_BOOM)
2662 break;
2664 if (olduasmon->mattk[i].damn)
2665 tmp =
2666 d((int) olduasmon->mattk[i].damn, (int) olduasmon->mattk[i].damd);
2667 else if (olduasmon->mattk[i].damd)
2668 tmp = d((int) olduasmon->mlevel + 1, (int) olduasmon->mattk[i].damd);
2669 else
2670 tmp = 0;
2672 /* These affect the enemy even if you were "killed" (rehumanized) */
2673 switch (olduasmon->mattk[i].adtyp) {
2674 case AD_ACID:
2675 if (!rn2(2)) {
2676 pline("%s is splashed by your %s!", Monnam(mtmp), hliquid("acid"));
2677 if (resists_acid(mtmp)) {
2678 pline("%s is not affected.", Monnam(mtmp));
2679 tmp = 0;
2681 } else
2682 tmp = 0;
2683 if (!rn2(30))
2684 erode_armor(mtmp, ERODE_CORRODE);
2685 if (!rn2(6))
2686 acid_damage(MON_WEP(mtmp));
2687 goto assess_dmg;
2688 case AD_STON: /* cockatrice */
2690 long protector = attk_protection((int) mattk->aatyp),
2691 wornitems = mtmp->misc_worn_check;
2693 /* wielded weapon gives same protection as gloves here */
2694 if (MON_WEP(mtmp) != 0)
2695 wornitems |= W_ARMG;
2697 if (!resists_ston(mtmp)
2698 && (protector == 0L
2699 || (protector != ~0L
2700 && (wornitems & protector) != protector))) {
2701 if (poly_when_stoned(mtmp->data)) {
2702 mon_to_stone(mtmp);
2703 return 1;
2705 pline("%s turns to stone!", Monnam(mtmp));
2706 stoned = 1;
2707 xkilled(mtmp, XKILL_NOMSG);
2708 if (mtmp->mhp > 0)
2709 return 1;
2710 return 2;
2712 return 1;
2714 case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */
2715 if (mon_currwep) {
2716 /* by_you==True: passive counterattack to hero's action
2717 is hero's fault */
2718 (void) drain_item(mon_currwep, TRUE);
2719 /* No message */
2721 return 1;
2722 default:
2723 break;
2725 if (!Upolyd)
2726 return 1;
2728 /* These affect the enemy only if you are still a monster */
2729 if (rn2(3))
2730 switch (youmonst.data->mattk[i].adtyp) {
2731 case AD_PHYS:
2732 if (youmonst.data->mattk[i].aatyp == AT_BOOM) {
2733 You("explode!");
2734 /* KMH, balance patch -- this is okay with unchanging */
2735 rehumanize();
2736 goto assess_dmg;
2738 break;
2739 case AD_PLYS: /* Floating eye */
2740 if (tmp > 127)
2741 tmp = 127;
2742 if (u.umonnum == PM_FLOATING_EYE) {
2743 if (!rn2(4))
2744 tmp = 127;
2745 if (mtmp->mcansee && haseyes(mtmp->data) && rn2(3)
2746 && (perceives(mtmp->data) || !Invis)) {
2747 if (Blind)
2748 pline("As a blind %s, you cannot defend yourself.",
2749 youmonst.data->mname);
2750 else {
2751 if (mon_reflects(mtmp,
2752 "Your gaze is reflected by %s %s."))
2753 return 1;
2754 pline("%s is frozen by your gaze!", Monnam(mtmp));
2755 paralyze_monst(mtmp, tmp);
2756 return 3;
2759 } else { /* gelatinous cube */
2760 pline("%s is frozen by you.", Monnam(mtmp));
2761 paralyze_monst(mtmp, tmp);
2762 return 3;
2764 return 1;
2765 case AD_COLD: /* Brown mold or blue jelly */
2766 if (resists_cold(mtmp)) {
2767 shieldeff(mtmp->mx, mtmp->my);
2768 pline("%s is mildly chilly.", Monnam(mtmp));
2769 golemeffects(mtmp, AD_COLD, tmp);
2770 tmp = 0;
2771 break;
2773 pline("%s is suddenly very cold!", Monnam(mtmp));
2774 u.mh += tmp / 2;
2775 if (u.mhmax < u.mh)
2776 u.mhmax = u.mh;
2777 if (u.mhmax > ((youmonst.data->mlevel + 1) * 8))
2778 (void) split_mon(&youmonst, mtmp);
2779 break;
2780 case AD_STUN: /* Yellow mold */
2781 if (!mtmp->mstun) {
2782 mtmp->mstun = 1;
2783 pline("%s %s.", Monnam(mtmp),
2784 makeplural(stagger(mtmp->data, "stagger")));
2786 tmp = 0;
2787 break;
2788 case AD_FIRE: /* Red mold */
2789 if (resists_fire(mtmp)) {
2790 shieldeff(mtmp->mx, mtmp->my);
2791 pline("%s is mildly warm.", Monnam(mtmp));
2792 golemeffects(mtmp, AD_FIRE, tmp);
2793 tmp = 0;
2794 break;
2796 pline("%s is suddenly very hot!", Monnam(mtmp));
2797 break;
2798 case AD_ELEC:
2799 if (resists_elec(mtmp)) {
2800 shieldeff(mtmp->mx, mtmp->my);
2801 pline("%s is slightly tingled.", Monnam(mtmp));
2802 golemeffects(mtmp, AD_ELEC, tmp);
2803 tmp = 0;
2804 break;
2806 pline("%s is jolted with your electricity!", Monnam(mtmp));
2807 break;
2808 default:
2809 tmp = 0;
2810 break;
2812 else
2813 tmp = 0;
2815 assess_dmg:
2816 if ((mtmp->mhp -= tmp) <= 0) {
2817 pline("%s dies!", Monnam(mtmp));
2818 xkilled(mtmp, XKILL_NOMSG);
2819 if (mtmp->mhp > 0)
2820 return 1;
2821 return 2;
2823 return 1;
2826 struct monst *
2827 cloneu()
2829 register struct monst *mon;
2830 int mndx = monsndx(youmonst.data);
2832 if (u.mh <= 1)
2833 return (struct monst *) 0;
2834 if (mvitals[mndx].mvflags & G_EXTINCT)
2835 return (struct monst *) 0;
2836 mon = makemon(youmonst.data, u.ux, u.uy, NO_MINVENT | MM_EDOG);
2837 if (!mon)
2838 return NULL;
2839 mon->mcloned = 1;
2840 mon = christen_monst(mon, plname);
2841 initedog(mon);
2842 mon->m_lev = youmonst.data->mlevel;
2843 mon->mhpmax = u.mhmax;
2844 mon->mhp = u.mh / 2;
2845 u.mh -= mon->mhp;
2846 context.botl = 1;
2847 return mon;
2850 /*mhitu.c*/