1 /* NetHack 3.6 mhitu.c $NHDT-Date: 1470819843 2016/08/10 09:04:03 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.144 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
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
*,
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. */
29 register struct monst
*mtmp
;
30 register struct attack
*mattk
;
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");
44 switch (mattk
->aatyp
) {
49 pline("%s kicks%c", Monst_name
,
50 thick_skinned(youmonst
.data
) ? '.' : '!');
59 pfmt
= "%s touches you!";
62 pfmt
= "%s tentacles suck you!";
63 Monst_name
= s_suffix(Monst_name
);
67 pfmt
= "%s explodes!";
73 pline(pfmt
, Monst_name
);
77 /* monster missed you */
79 missmu(mtmp
, nearmiss
, 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
));
90 pline("%s %smisses!", Monnam(mtmp
),
91 (nearmiss
&& flags
.verbose
) ? "just " : "");
96 /* monster swings obj */
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 */
111 mpoisons_subj(mtmp
, mattk
)
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";
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 */
134 else /* speed boots */
135 Your("quickness feels less natural.");
136 exercise(A_DEX
, FALSE
);
139 /* monster attacked your displaced image */
141 wildmiss(mtmp
, mattk
)
142 register struct monst
*mtmp
;
143 register struct attack
*mattk
;
146 const char *Monst_name
; /* Monnam(mtmp) */
148 /* no map_invisible() -- no way to tell where _this_ is coming from */
152 if (!cansee(mtmp
->mx
, mtmp
->my
))
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"
169 pline("%s tries to touch you and misses!", Monst_name
);
173 pline("%s %s wildly and misses!", Monst_name
, swings
);
176 pline("%s attacks a spot beside you.", Monst_name
);
179 pline("%s strikes at %s!", Monst_name
,
180 (levl
[mtmp
->mux
][mtmp
->muy
].typ
== WATER
)
185 pline("%s %s wildly!", Monst_name
, swings
);
189 } else if (Displaced
) {
191 pline("%s smiles %s at your %sdisplaced image...", Monst_name
,
192 (compat
== 2) ? "engagingly" : "seductively",
193 Invis
? "invisible " : "");
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
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 */
207 pline("%s reaches towards your distorted image.", Monst_name
);
209 pline("%s is fooled by water reflections and misses!",
213 impossible("%s attacks you without knowing your location?",
218 expels(mtmp
, mdat
, message
)
220 struct permonst
*mdat
; /* if mtmp is polymorphed, mdat != mtmp->data */
224 if (is_animal(mdat
)) {
225 You("get regurgitated!");
231 for (i
= 0; i
< NATTK
; i
++)
232 if (mdat
->mattk
[i
].aatyp
== AT_ENGL
)
234 if (mdat
->mattk
[i
].aatyp
!= AT_ENGL
) {
235 impossible("Swallower has no engulfing attack?");
237 if (is_whirly(mdat
)) {
238 switch (mdat
->mattk
[i
].adtyp
) {
240 Strcpy(blast
, " in a shower of sparks");
243 Strcpy(blast
, " in a blast of frost");
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() */
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 */
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
;
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
;
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
;
307 if (attk
->adtyp
== AD_ACID
|| attk
->adtyp
== AD_ELEC
308 || attk
->adtyp
== AD_COLD
|| attk
->adtyp
== AD_FIRE
) {
309 attk
->aatyp
= AT_TUCH
;
311 attk
->aatyp
= AT_CLAW
; /* attack message will be "<foo> hits" */
312 attk
->adtyp
= AD_PHYS
;
314 attk
->damn
= 1; /* relatively weak: 1d6 */
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
)
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
;
333 attk
->adtyp
= AD_PHYS
;
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
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
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? */
369 if (mtmp
->mhp
<= 0 || (Underwater
&& !is_swimmer(mtmp
->data
)))
372 /* If swallowed, can only be affected by u.ustuck */
374 if (mtmp
!= u
.ustuck
)
376 u
.ustuck
->mux
= u
.ux
;
377 u
.ustuck
->muy
= u
.uy
;
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 */
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
))
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)
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
);
407 if (is_hider(youmonst
.data
) && u
.umonnum
!= PM_TRAPPER
) {
409 coord cc
; /* maybe we need a unexto() function? */
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
));
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
);
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 */
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
));
456 if (3 + find_mac(mtmp
) <= rnd(20)) {
457 pline("%s is hit by a falling piercer (you)!",
459 if ((mtmp
->mhp
-= d(3, 6)) < 1)
462 pline("%s is almost hit by a falling piercer (you)!",
469 pline("It tries to move where you are hiding.");
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 */
486 if (obj
->otyp
== EGG
)
489 if (youmonst
.data
->mlet
== S_EEL
490 || u
.umonnum
== PM_TRAPPER
)
492 "Wait, %s! There's a hidden %s named %s there!",
493 m_monnam(mtmp
), youmonst
.data
->mname
, plname
);
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
]));
502 impossible("hiding under nothing?");
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.");
519 pline("Wait, %s! That's a %s named %s!", m_monnam(mtmp
),
520 youmonst
.data
->mname
, plname
);
523 youmonst
.m_ap_type
= M_AP_NOTHING
;
524 youmonst
.mappearance
= 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
532 if (!canspotmon(mtmp
))
533 map_invisible(mtmp
->mx
, mtmp
->my
);
535 pline("%s %s!", Something
, (likes_gold(mtmp
->data
)
536 && youmonst
.mappearance
== GOLD_PIECE
)
537 ? "tries to pick you up"
540 pline("Wait, %s! That %s is really %s named %s!", m_monnam(mtmp
),
541 mimic_obj_name(&youmonst
), an(mons
[u
.umonnum
].mname
),
543 if (multi
< 0) { /* this should always be the case */
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 */
554 /* Work out the armor class differential */
555 tmp
= AC_VALUE(u
.uac
) + 10; /* tmp ~= 0 - 20 */
559 if ((Invis
&& !perceives(mdat
)) || !mtmp
->mcansee
)
566 /* make eels visible the moment they hit/miss us */
567 if (mdat
->mlet
== S_EEL
&& mtmp
->minvis
&& cansee(mtmp
->mx
, mtmp
->my
)) {
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
)
584 } else if (!rn2(30) && !mtmp
->mcan
)
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
);
595 pline("%s summons help!", Monnam(mtmp
));
598 You_feel("hemmed in.");
600 pline("But none comes.");
602 const char *from_nowhere
;
605 pline("%s %s!", Something
, makeplural(growl_sound(mtmp
)));
608 from_nowhere
= " from nowhere";
611 You_feel("hemmed in.");
614 Sprintf(buf
, "%s appears", an(genericwere
));
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
));
630 if (youseeit
|| sensemon(mtmp
))
631 pline("%s starts to attack you, but pulls back.",
634 You_feel("%s move nearby.", something
);
639 /* Unlike defensive stuff, don't let them use item _and_ attack. */
640 if (find_offensive(mtmp
)) {
641 int foo
= use_offensive(mtmp
);
647 for (i
= 0; i
< NATTK
; i
++) {
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
))
655 switch (mattk
->aatyp
) {
656 case AT_CLAW
: /* "hand to hand" attacks */
663 if (!range2
&& (!MON_WEP(mtmp
) || mtmp
->mconf
|| Conflict
664 || !touch_petrifies(youmonst
.data
))) {
666 if (tmp
> (j
= rnd(20 + i
))) {
667 if (mattk
->aatyp
!= AT_KICK
668 || !thick_skinned(youmonst
.data
))
669 sum
[i
] = hitmu(mtmp
, mattk
);
671 missmu(mtmp
, (tmp
== j
), mattk
);
673 wildmiss(mtmp
, mattk
);
674 /* skip any remaining non-spell attacks */
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])
684 sum
[i
] = hitmu(mtmp
, mattk
);
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
);
694 case AT_EXPL
: /* automatic hit if next to, and aimed at you */
696 sum
[i
] = explmu(mtmp
, mattk
, foundyou
);
703 || (!mtmp
->mspec_used
&& tmp
> (j
= rnd(20 + i
)))) {
704 /* force swallowing monster to be displayed
705 even when hero is moving away */
707 sum
[i
] = gulpmu(mtmp
, mattk
);
709 missmu(mtmp
, (tmp
== j
), mattk
);
711 } else if (is_animal(mtmp
->data
)) {
712 pline("%s gulps some air!", Monnam(mtmp
));
715 pline("%s lunges forward and recoils!", Monnam(mtmp
));
717 You_hear("a %s nearby.",
718 is_whirly(mtmp
->data
) ? "rushing noise"
725 sum
[i
] = breamu(mtmp
, mattk
);
726 /* Note: breamu takes care of displacement */
730 sum
[i
] = spitmu(mtmp
, mattk
);
731 /* Note: spitmu takes care of displacement */
735 if (!Is_rogue_level(&u
.uz
))
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)
751 mon_currwep
= MON_WEP(mtmp
);
753 hittmp
= hitval(mon_currwep
, &youmonst
);
755 mswings(mtmp
, mon_currwep
);
757 if (tmp
> (j
= dieroll
= rnd(20 + i
)))
758 sum
[i
] = hitmu(mtmp
, mattk
);
760 missmu(mtmp
, (tmp
== j
), mattk
);
761 /* KMH -- Don't accumulate to-hit bonuses */
765 wildmiss(mtmp
, mattk
);
766 /* skip any remaining non-spell attacks */
773 sum
[i
] = buzzmu(mtmp
, mattk
);
775 sum
[i
] = castmu(mtmp
, mattk
, TRUE
, foundyou
);
778 default: /* no attack */
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)) {
787 nomovemsg
= "The combat suddenly awakens you.";
791 return 1; /* attacker dead */
793 break; /* attacker teleported, no more attacks */
794 /* sum[i] == 0: unsuccessful attack */
801 struct permonst
*mdat
;
803 if (Sick_resistance
) {
804 You_feel("a slight illness.");
807 make_sick(Sick
? Sick
/ 3L + 1L : (long) rn1(ACURR(A_CON
), 20),
808 mdat
->mname
, TRUE
, SICK_NONVOMITABLE
);
813 /* check whether slippery clothing protects from hug or wrap attack */
815 u_slip_free(mtmp
, mattk
)
817 struct attack
*mattk
;
819 struct obj
*obj
= (uarmc
? uarmc
: uarm
);
823 if (mattk
->adtyp
== AD_DRIN
)
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
)
838 : cloak_simple_name(obj
));
840 if (obj
->greased
&& !rn2(2)) {
841 pline_The("grease wears off.");
850 /* armor that sufficiently covers the body might be able to block magic */
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
;
870 /* if we've already confirmed Protection, skip additional checks */
871 if (is_you
|| gotprot
)
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
))
878 if (protects(o
, ((o
->owornmask
& wearmask
) != 0L) ? TRUE
: FALSE
))
883 /* extrinsic Protection increases mc by 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
)))
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
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
;
912 struct permonst
*olduasmon
= youmonst
.data
;
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
)) {
927 if ((obj
= level
.objects
[mtmp
->mx
][mtmp
->my
]) != 0) {
928 if (Blind
&& !obj
->dknown
)
930 else if (is_pool(mtmp
->mx
, mtmp
->my
) && !Underwater
)
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
);
954 /* Now, adjust damages via resistances or specific attacks */
955 switch (mattk
->adtyp
) {
957 if (mattk
->aatyp
== AT_HUGS
&& !sticks(youmonst
.data
)) {
958 if (!u
.ustuck
&& rn2(2)) {
959 if (u_slip_free(mtmp
, mattk
)) {
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
])
971 } else { /* hand to hand weapon */
972 struct obj
*otmp
= mon_currwep
;
973 if (mattk
->aatyp
== AT_WEAP
&& otmp
) {
976 if (otmp
->otyp
== CORPSE
977 && touch_petrifies(&mons
[otmp
->corpsenm
])) {
979 pline("%s hits you with the %s corpse.", Monnam(mtmp
),
980 mons
[otmp
->corpsenm
].mname
);
984 dmg
+= dmgval(otmp
, &youmonst
);
987 if (!(otmp
->oartifact
988 && artifact_hit(mtmp
, &youmonst
, otmp
, &dmg
, dieroll
)))
992 if (objects
[otmp
->otyp
].oc_material
== 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 */
1005 if (u
.mh
- tmp
> 1 && objects
[otmp
->otyp
].oc_material
== IRON
1006 && (u
.umonnum
== PM_BLACK_PUDDING
1007 || u
.umonnum
== PM_BROWN_PUDDING
)) {
1009 exercise(A_STR
, FALSE
);
1010 /* inflict damage now; we know it can't be fatal */
1013 dmg
= 0; /* don't inflict more damage below */
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
);
1024 hitmsg(mtmp
, mattk
);
1025 if (!diseasemu(mdat
))
1029 hitmsg(mtmp
, mattk
);
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
]) {
1035 /* KMH -- this is okay with unchanging */
1038 } else if (Fire_resistance
) {
1039 pline_The("fire doesn't feel hot!");
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
);
1053 hitmsg(mtmp
, mattk
);
1055 pline("You're covered in frost!");
1056 if (Cold_resistance
) {
1057 pline_The("frost doesn't seem cold!");
1060 if ((int) mtmp
->m_lev
> rn2(20))
1061 destroy_item(POTION_CLASS
, AD_COLD
);
1066 hitmsg(mtmp
, mattk
);
1069 if (Shock_resistance
) {
1070 pline_The("zap doesn't shock you!");
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
);
1081 hitmsg(mtmp
, mattk
);
1082 if (uncancelled
&& multi
>= 0 && !rn2(5)) {
1083 if (Sleep_resistance
)
1085 fall_asleep(-rnd(10), TRUE
);
1087 You("are put to sleep!");
1089 You("are put to sleep by %s!", mon_nam(mtmp
));
1093 if (can_blnd(mtmp
, &youmonst
, mattk
->aatyp
, (struct obj
*) 0)) {
1095 pline("%s blinds you!", Monnam(mtmp
));
1096 make_blinded(Blinded
+ (long) dmg
, FALSE
);
1098 Your1(vision_clears
);
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
);
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 */
1125 if (u_slip_free(mtmp
, mattk
))
1128 if (uarmh
&& rn2(8)) {
1129 /* not body_part(HEAD) */
1130 Your("%s blocks the attack to your head.",
1131 helm_simple_name(uarmh
));
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
)
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 */
1155 hitmsg(mtmp
, mattk
);
1156 if (uncancelled
&& multi
>= 0 && !rn2(3)) {
1158 You("momentarily stiffen.");
1163 You("are frozen by %s!", mon_nam(mtmp
));
1164 nomovemsg
= You_can_move_again
;
1166 multi_reason
= "paralyzed by a monster";
1167 exercise(A_DEX
, FALSE
);
1172 hitmsg(mtmp
, mattk
);
1173 if (uncancelled
&& !rn2(3) && !Drain_resistance
) {
1174 losexp("life drainage");
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
);
1190 } else if (mtmp
->mcan
) {
1191 pline("%s nuzzles against your %s %s!", Monnam(mtmp
),
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
,
1204 pline("%s scratches your %s boot!", Monst_name
,
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
);
1218 case AD_STON
: /* cockatrice */
1219 hitmsg(mtmp
, mattk
);
1223 You_hear("a cough from %s!", mon_nam(mtmp
));
1226 You_hear("%s hissing!", s_suffix(mon_nam(mtmp
)));
1228 || (flags
.moonphase
== NEW_MOON
&& !have_lizard())) {
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
))
1239 kformat
= KILLED_BY
;
1241 make_stoned(5L, (char *) 0, kformat
, kname
);
1243 /* done_in_by(mtmp, STONING); */
1250 hitmsg(mtmp
, mattk
);
1251 if (uncancelled
&& !u
.ustuck
&& !sticks(youmonst
.data
))
1255 if ((!mtmp
->mcan
|| u
.ustuck
== mtmp
) && !sticks(youmonst
.data
)) {
1256 if (!u
.ustuck
&& !rn2(10)) {
1257 if (u_slip_free(mtmp
, mattk
)) {
1260 pline("%s swings itself around you!", Monnam(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
));
1276 } else if (mattk
->aatyp
== AT_HUGS
)
1277 You("are being crushed.");
1281 pline("%s brushes against your %s.", Monnam(mtmp
),
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);
1298 hitmsg(mtmp
, mattk
);
1299 if (youmonst
.data
->mlet
== mdat
->mlet
)
1306 if (SYSOPT_SEDUCE
) {
1307 if (could_seduce(mtmp
, &youmonst
, mattk
) == 1 && !mtmp
->mcan
)
1313 case AD_SITM
: /* for now these are the same */
1315 if (is_animal(mtmp
->data
)) {
1316 hitmsg(mtmp
, mattk
);
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
),
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
);
1329 } else if (mtmp
->mcan
) {
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");
1336 if (!tele_restrict(mtmp
))
1337 (void) rloc(mtmp
, TRUE
);
1343 switch (steal(mtmp
, buf
)) {
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
);
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 */
1371 hitmsg(mtmp
, mattk
);
1374 Your("position suddenly seems very uncertain!");
1379 hitmsg(mtmp
, mattk
);
1382 if (u
.umonnum
== PM_IRON_GOLEM
) {
1384 /* KMH -- this is okay with unchanging */
1388 erode_armor(&youmonst
, ERODE_RUST
);
1391 hitmsg(mtmp
, mattk
);
1394 erode_armor(&youmonst
, ERODE_CORRODE
);
1397 hitmsg(mtmp
, mattk
);
1400 if (u
.umonnum
== PM_WOOD_GOLEM
|| u
.umonnum
== PM_LEATHER_GOLEM
) {
1402 /* KMH -- this is okay with unchanging */
1406 erode_armor(&youmonst
, ERODE_ROT
);
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
);
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
));
1423 /* no upper limit necessary; effect is temporary */
1433 /* hard upper limit via nurse care: 25 * ulevel */
1434 if (u
.uhpmax
< 5 * u
.ulevel
+ d(2 * u
.ulevel
, 10))
1439 if (u
.uhp
> u
.uhpmax
)
1443 exercise(A_STR
, TRUE
);
1445 exercise(A_CON
, TRUE
);
1447 make_sick(0L, (char *) 0, FALSE
, SICK_ALL
);
1452 } else if (!rn2(33)) {
1453 if (!tele_restrict(mtmp
))
1454 (void) rloc(mtmp
, TRUE
);
1455 monflee(mtmp
, d(3, 6), TRUE
, FALSE
);
1460 if (Role_if(PM_HEALER
)) {
1461 if (!Deaf
&& !(moves
% 5))
1462 verbalize("Doc, I can't help you unless you cooperate.");
1465 hitmsg(mtmp
, mattk
);
1469 hitmsg(mtmp
, mattk
);
1470 if (!night() && mdat
== &mons
[PM_GREMLIN
])
1472 if (!mtmp
->mcan
&& !rn2(10)) {
1475 You_hear("laughter.");
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 */
1489 hitmsg(mtmp
, mattk
);
1490 if (!mtmp
->mcan
&& !rn2(4)) {
1491 make_stunned((HStun
& TIMEOUT
) + (long) dmg
, TRUE
);
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.",
1503 pline("You're covered in %s! It burns!", hliquid("acid"));
1504 exercise(A_STR
, FALSE
);
1510 hitmsg(mtmp
, mattk
);
1511 if (uncancelled
&& HFast
&& !defends(AD_SLOW
, uwep
) && !rn2(4))
1515 hitmsg(mtmp
, mattk
);
1516 if (uncancelled
&& !rn2(4)) /* 25% chance */
1521 hitmsg(mtmp
, mattk
);
1522 if (!mtmp
->mcan
&& !rn2(4) && !mtmp
->mspec_used
) {
1523 mtmp
->mspec_used
= mtmp
->mspec_used
+ (dmg
+ rn2(6));
1525 You("are getting even more confused.");
1527 You("are getting confused.");
1528 make_confused(HConfusion
+ dmg
, FALSE
);
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?");
1544 killer
.format
= KILLED_BY_AN
;
1545 Strcpy(killer
.name
, "touch of death");
1549 } /* else FALLTHRU */
1550 default: /* case 16: ... case 5: */
1551 You_feel("your life force draining away...");
1552 permdmg
= 1; /* actual damage done below */
1560 shieldeff(u
.ux
, u
.uy
);
1561 pline("Lucky for you, it didn't work!");
1567 pline("%s reaches out, and you feel fever and chills.", Monnam(mtmp
));
1568 (void) diseasemu(mdat
); /* plus the normal damage */
1571 pline("%s reaches out, and your body shrivels.", Monnam(mtmp
));
1572 exercise(A_CON
, FALSE
);
1574 morehungry(rn1(40, 40));
1575 /* plus the normal damage */
1578 hitmsg(mtmp
, mattk
);
1581 if (flaming(youmonst
.data
)) {
1582 pline_The("slime burns away!");
1584 } else if (Unchanging
|| noncorporeal(youmonst
.data
)
1585 || youmonst
.data
== &mons
[PM_GREEN_SLIME
]) {
1586 You("are unaffected.");
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
);
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 */
1600 struct obj
*obj
= some_armor(&youmonst
);
1603 /* some rings are susceptible;
1604 amulets and blindfolds aren't (at present) */
1622 if (drain_item(obj
, FALSE
)) {
1623 pline("%s less effective.", Yobjnam2(obj
, "seem"));
1632 done_in_by(mtmp
, DIED
);
1634 /* Negative armor class reduces damage done instead of fully protecting
1637 if (dmg
&& u
.uac
< 0) {
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%
1660 * Never reduces hpmax below 1 hit point per level.
1662 permdmg
= rn2(dmg
/ 2 + 1);
1663 if (Upolyd
|| u
.uhpmax
> 25 * u
.ulevel
)
1665 else if (u
.uhpmax
> 10 * u
.ulevel
)
1667 else if (u
.uhpmax
> 5 * u
.ulevel
)
1672 /* [can't use youmonst.m_lev] */
1673 lowerlimit
= min((int) youmonst
.data
->mlevel
, u
.ulevel
);
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
;
1683 * already at or below minimum threshold; do nothing */
1687 mdamageu(mtmp
, dmg
);
1691 res
= passiveum(olduasmon
, mtmp
, mattk
);
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 */
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
);
1716 /* monster swallows you, or damage if u.uswallow */
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
);
1725 register struct obj
*otmp2
;
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
))
1734 if ((t
&& ((t
->ttyp
== PIT
) || (t
->ttyp
== SPIKED_PIT
)))
1735 && sobj_at(BOULDER
, u
.ux
, u
.uy
))
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
);
1744 newsym(mtmp
->mx
, mtmp
->my
);
1745 if (is_animal(mtmp
->data
) && u
.usteed
) {
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
),
1755 dismount_steed(DISMOUNT_ENGULFED
);
1757 pline("%s engulfs you!", Monnam(mtmp
));
1759 reset_occupations(); /* behave as if you had moved */
1762 You("are released from the %s!",
1763 u
.utraptype
== TT_WEB
? "web" : "trap");
1767 i
= number_leashed();
1769 const char *s
= (i
> 1) ? "leashes" : "leash";
1770 pline_The("%s %s loose.", s
, vtense(s
, "snap"));
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 */
1785 return (mtmp
->mhp
> 0) ? 0 : 2;
1788 display_nhwindow(WIN_MESSAGE
, FALSE
);
1789 vision_recalc(2); /* hero can't see anything */
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
;
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);
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
);
1811 for (otmp2
= invent
; otmp2
; otmp2
= otmp2
->nobj
)
1812 (void) snuff_lit(otmp2
);
1815 if (mtmp
!= u
.ustuck
)
1820 switch (mattk
->adtyp
) {
1822 physical_damage
= TRUE
;
1823 if (Slow_digestion
) {
1824 /* Messages are handled below */
1827 } else if (u
.uswldtim
== 0) {
1828 pline("%s totally digests you!", Monnam(mtmp
));
1830 if (Half_physical_damage
)
1831 tmp
*= 2; /* sorry */
1833 pline("%s%s digests you!", Monnam(mtmp
),
1834 (u
.uswldtim
== 2) ? " thoroughly"
1835 : (u
.uswldtim
== 1) ? " utterly" : "");
1836 exercise(A_STR
, FALSE
);
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
)
1848 : "can barely breathe!");
1849 /* NB: Amphibious includes Breathless */
1850 if (Amphibious
&& !flaming(youmonst
.data
))
1853 You("are pummeled with debris!");
1854 exercise(A_STR
, FALSE
);
1858 if (Acid_resistance
) {
1859 You("are covered with a seemingly harmless goo.");
1863 pline("Ouch! You've been slimed!");
1865 You("are covered in slime! It burns!");
1866 exercise(A_STR
, FALSE
);
1870 if (can_blnd(mtmp
, &youmonst
, mattk
->aatyp
, (struct obj
*) 0)) {
1872 long was_blinded
= Blinded
;
1874 You_cant("see in here!");
1875 make_blinded((long) tmp
, FALSE
);
1876 if (!was_blinded
&& !Blind
)
1877 Your1(vision_clears
);
1879 /* keep him blind until disgorged */
1880 make_blinded(Blinded
+ 1, FALSE
);
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
);
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
);
1904 You("are freezing to death!");
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
);
1916 You("are burning to a crisp!");
1922 if (!diseasemu(mtmp
->data
))
1926 /* AC magic cancellation doesn't help when engulfed */
1927 if (!mtmp
->mcan
&& rn2(4)) /* 75% chance */
1932 physical_damage
= TRUE
;
1937 if (physical_damage
)
1938 tmp
= Maybe_Half_Phys(tmp
);
1940 mdamageu(mtmp
, tmp
);
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");
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
);
1959 /* monster explodes in your face */
1961 explmu(mtmp
, mattk
, ufound
)
1962 register struct monst
*mtmp
;
1963 register struct attack
*mattk
;
1966 boolean physical_damage
= TRUE
, kill_agr
= TRUE
;
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"
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
) {
1984 physical_damage
= FALSE
;
1985 not_affected
|= Cold_resistance
;
1988 physical_damage
= FALSE
;
1989 not_affected
|= Fire_resistance
;
1992 physical_damage
= FALSE
;
1993 not_affected
|= Shock_resistance
;
1996 if (!not_affected
) {
1997 if (ACURR(A_DEX
) > rnd(20)) {
1998 You("duck some of the blast.");
1999 tmp
= (tmp
+ 1) / 2;
2002 You("get blasted!");
2004 if (mattk
->adtyp
== AD_FIRE
)
2006 if (physical_damage
)
2007 tmp
= Maybe_Half_Phys(tmp
);
2008 mdamageu(mtmp
, tmp
);
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
);
2020 Your1(vision_clears
);
2021 } else if (flags
.verbose
)
2022 You("get the impression it was not terribly bright.");
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
) {
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) */
2038 make_hallucinated(HHallucination
+ (long) tmp
, FALSE
, 0L);
2039 You("%s.", chg
? "are freaked out" : "seem unaffected");
2047 You("seem unaffected by it.");
2048 ugolemeffects((int) mattk
->adtyp
, tmp
);
2053 wake_nearto(mtmp
->mx
, mtmp
->my
, 7 * 7);
2054 return (mtmp
->mhp
> 0) ? 0 : 2;
2057 /* monster gazes at you */
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] */
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))
2085 switch (mattk
->adtyp
) {
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");
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
);
2102 (void) ureflects("%s gaze is reflected by your %s.",
2103 s_suffix(Monnam(mtmp
)));
2105 mtmp
, !useeit
? (char *) 0
2106 : "The gaze is reflected away by %s %s!"))
2108 if (!m_canseeu(mtmp
)) { /* probably you're invisible */
2111 "%s doesn't seem to notice that %s gaze was reflected.",
2112 Monnam(mtmp
), mhis(mtmp
));
2116 pline("%s is turned to stone!", Monnam(mtmp
));
2124 if (canseemon(mtmp
) && couldsee(mtmp
->mx
, mtmp
->my
)
2125 && !Stone_resistance
) {
2126 You("meet %s gaze.", s_suffix(mon_nam(mtmp
)));
2128 if (poly_when_stoned(youmonst
.data
) && polymon(PM_STONE_GOLEM
))
2130 You("turn to stone...");
2131 killer
.format
= KILLED_BY
;
2132 Strcpy(killer
.name
, mtmp
->data
->mname
);
2137 if (canseemon(mtmp
) && couldsee(mtmp
->mx
, mtmp
->my
) && mtmp
->mcansee
2138 && !mtmp
->mspec_used
&& rn2(5)) {
2140 react
= 0; /* "confused" */
2141 already
= (mtmp
->mconf
!= 0);
2145 mtmp
->mspec_used
= mtmp
->mspec_used
+ (conf
+ rn2(6));
2147 pline("%s gaze confuses you!", s_suffix(Monnam(mtmp
)));
2149 You("are getting more and more confused.");
2150 make_confused(HConfusion
+ conf
, FALSE
);
2156 if (canseemon(mtmp
) && couldsee(mtmp
->mx
, mtmp
->my
) && mtmp
->mcansee
2157 && !mtmp
->mspec_used
&& rn2(5)) {
2159 react
= 1; /* "stunned" */
2160 already
= (mtmp
->mstun
!= 0);
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
);
2172 if (canseemon(mtmp
) && !resists_blnd(&youmonst
)
2173 && distu(mtmp
->mx
, mtmp
->my
) <= BOLT_LIM
* BOLT_LIM
) {
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))
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
);
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 */
2191 Your1(vision_clears
);
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
);
2203 if (canseemon(mtmp
) && couldsee(mtmp
->mx
, mtmp
->my
) && mtmp
->mcansee
2204 && !mtmp
->mspec_used
&& rn2(5)) {
2206 react
= rn1(2, 4); /* "irritated" || "inflamed" */
2208 int dmg
= d(2, 6), lev
= (int) mtmp
->m_lev
;
2210 pline("%s attacks you with a fiery gaze!", Monnam(mtmp
));
2212 if (Fire_resistance
) {
2213 pline_The("fire doesn't feel hot!");
2218 destroy_item(SCROLL_CLASS
, AD_FIRE
);
2220 destroy_item(POTION_CLASS
, AD_FIRE
);
2222 destroy_item(SPBOOK_CLASS
, AD_FIRE
);
2224 mdamageu(mtmp
, dmg
);
2228 #ifdef PM_BEHOLDER /* work in progress */
2230 if (canseemon(mtmp
) && couldsee(mtmp
->mx
, mtmp
->my
) && mtmp
->mcansee
2231 && multi
>= 0 && !rn2(5) && !Sleep_resistance
) {
2233 react
= 6; /* "tired" */
2234 already
= (mtmp
->mfrozen
!= 0); /* can't happen... */
2236 fall_asleep(-rnd(10), TRUE
);
2237 pline("%s gaze makes you very sleepy...",
2238 s_suffix(Monnam(mtmp
)));
2243 if (canseemon(mtmp
) && couldsee(mtmp
->mx
, mtmp
->my
) && mtmp
->mcansee
2244 && (HFast
& (INTRINSIC
| TIMEOUT
)) && !defends(AD_SLOW
, uwep
)
2247 react
= 7; /* "dulled" */
2248 already
= (mtmp
->mspeed
== MSLOW
);
2255 #endif /* BEHOLDER */
2257 impossible("Gaze attack %d?", mattk
->adtyp
);
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 "),
2273 /* mtmp hits you for n points damage */
2276 register struct monst
*mtmp
;
2287 done_in_by(mtmp
, DIED
);
2291 /* returns 0 if seduction impossible,
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
))
2306 if (magr
== &youmonst
) {
2307 pagr
= youmonst
.data
;
2308 agrinvis
= (Invis
!= 0);
2309 genagr
= poly_gender();
2312 agrinvis
= magr
->minvis
;
2313 genagr
= gender(magr
);
2315 if (mdef
== &youmonst
) {
2316 defperc
= (See_invisible
!= 0);
2317 gendef
= poly_gender();
2319 defperc
= perceives(mdef
->data
);
2320 gendef
= gender(mdef
);
2323 if (agrinvis
&& !defperc
2324 && (!SYSOPT_SEDUCE
|| (mattk
&& mattk
->adtyp
!= AD_SSEX
)))
2327 if (pagr
->mlet
!= S_NYMPH
2328 && ((pagr
!= &mons
[PM_INCUBUS
] && pagr
!= &mons
[PM_SUCCUBUS
])
2329 || (SYSOPT_SEDUCE
&& mattk
&& mattk
->adtyp
!= AD_SSEX
)))
2332 if (genagr
== 1 - gendef
)
2335 return (pagr
->mlet
== S_NYMPH
) ? 2 : 0;
2338 /* Returns 1 if monster teleported */
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;
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 " : "");
2354 if (unconscious()) {
2355 pline("%s seems dismayed at your lack of response.", Monnam(mon
));
2360 pline("It caresses you...");
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 */
2370 for (ring
= invent
; ring
; ring
= nring
) {
2372 if (ring
->otyp
!= RIN_ADORNMENT
)
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");
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')
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
)
2396 setuwep((struct obj
*) 0);
2397 if (ring
== uswapwep
)
2398 setuswapwep((struct obj
*) 0);
2399 if (ring
== uquiver
)
2400 setuqwep((struct obj
*) 0);
2402 (void) mpickobj(mon
, ring
);
2404 if (uleft
&& uright
&& uleft
->otyp
== RIN_ADORNMENT
2405 && uright
->otyp
== RIN_ADORNMENT
)
2407 if (ring
== uleft
|| ring
== uright
)
2410 /* don't put on ring if gloves are in the way */
2411 if (!tried_gloves
++)
2412 mayberem(uarmg
, "gloves");
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')
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
);
2430 pline("%s puts %s on your right %s.",
2431 Blind
? "He" : Monnam(mon
), the(xname(ring
)),
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
)),
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
));
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
));
2448 setworn(ring
, LEFT_RING
);
2450 impossible("ring replacement");
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
));
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
));
2464 mayberem(uarm
, "suit");
2465 mayberem(uarmf
, "boots");
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
);
2480 if (u
.ualign
.type
== A_CHAOTIC
)
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...",
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...",
2497 You_feel("drained of energy.");
2499 u
.uenmax
-= rnd(Half_physical_damage
? 5 : 10);
2500 exercise(A_CON
, FALSE
);
2505 You("are down in the dumps.");
2506 (void) adjattrib(A_CON
, -1, TRUE
);
2507 exercise(A_CON
, FALSE
);
2511 Your("senses are dulled.");
2512 (void) adjattrib(A_WIS
, -1, TRUE
);
2513 exercise(A_WIS
, FALSE
);
2517 if (!resists_drli(&youmonst
)) {
2518 You_feel("out of shape.");
2519 losexp("overexertion");
2521 You("have a curious feeling...");
2523 exercise(A_CON
, FALSE
);
2524 exercise(A_DEX
, FALSE
);
2525 exercise(A_WIS
, FALSE
);
2530 You_feel("exhausted.");
2531 exercise(A_STR
, FALSE
);
2533 losehp(Maybe_Half_Phys(tmp
), "exhaustion", KILLED_BY
);
2538 mon
->mspec_used
= rnd(100); /* monster is worn out */
2539 You("seem to have enjoyed it more than %s...", noit_mon_nam(mon
));
2542 You_feel("raised to your full potential.");
2543 exercise(A_CON
, TRUE
);
2544 u
.uen
= (u
.uenmax
+= rnd(5));
2547 You_feel("good enough to do it again.");
2548 (void) adjattrib(A_CON
, 1, TRUE
);
2549 exercise(A_CON
, TRUE
);
2553 You("will always remember %s...", noit_mon_nam(mon
));
2554 (void) adjattrib(A_WIS
, 1, TRUE
);
2555 exercise(A_WIS
, TRUE
);
2559 pline("That was a very educational experience.");
2561 exercise(A_WIS
, TRUE
);
2564 You_feel("restored to health!");
2568 exercise(A_STR
, TRUE
);
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
));
2583 long umoney
= money_cnt(invent
);
2585 if (umoney
> (long) LARGEST_INT
- 10L)
2586 cost
= (long) rnd(LARGEST_INT
) + 500L;
2588 cost
= (long) rnd((int) umoney
+ 10) + 500L;
2589 if (mon
->mpeaceful
) {
2597 verbalize("It's on the house!");
2599 pline("%s takes %ld %s for services rendered!", noit_Monnam(mon
),
2600 cost
, currency(cost
));
2601 money2mon(mon
, cost
);
2606 mon
->mcan
= 1; /* monster is worn out */
2607 if (!tele_restrict(mon
))
2608 (void) rloc(mon
, TRUE
);
2614 register struct obj
*obj
;
2619 if (!obj
|| !obj
->owornmask
)
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')
2628 char hairbuf
[BUFSZ
];
2630 Sprintf(hairbuf
, "let me run my fingers through your %s",
2632 verbalize("Take off your %s; %s.", str
,
2634 ? "let's get a little closer"
2635 : (obj
== uarmc
|| obj
== uarms
)
2638 ? "let me rub your feet"
2640 ? "they're too clumsy"
2642 ? "let me massage you"
2646 remove_worn_item(obj
, TRUE
);
2650 passiveum(olduasmon
, mtmp
, mattk
)
2651 struct permonst
*olduasmon
;
2652 register struct monst
*mtmp
;
2653 register struct attack
*mattk
;
2660 if (olduasmon
->mattk
[i
].aatyp
== AT_NONE
2661 || olduasmon
->mattk
[i
].aatyp
== AT_BOOM
)
2664 if (olduasmon
->mattk
[i
].damn
)
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
);
2672 /* These affect the enemy even if you were "killed" (rehumanized) */
2673 switch (olduasmon
->mattk
[i
].adtyp
) {
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
));
2684 erode_armor(mtmp
, ERODE_CORRODE
);
2686 acid_damage(MON_WEP(mtmp
));
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
)
2699 || (protector
!= ~0L
2700 && (wornitems
& protector
) != protector
))) {
2701 if (poly_when_stoned(mtmp
->data
)) {
2705 pline("%s turns to stone!", Monnam(mtmp
));
2707 xkilled(mtmp
, XKILL_NOMSG
);
2714 case AD_ENCH
: /* KMH -- remove enchantment (disenchanter) */
2716 /* by_you==True: passive counterattack to hero's action
2718 (void) drain_item(mon_currwep
, TRUE
);
2728 /* These affect the enemy only if you are still a monster */
2730 switch (youmonst
.data
->mattk
[i
].adtyp
) {
2732 if (youmonst
.data
->mattk
[i
].aatyp
== AT_BOOM
) {
2734 /* KMH, balance patch -- this is okay with unchanging */
2739 case AD_PLYS
: /* Floating eye */
2742 if (u
.umonnum
== PM_FLOATING_EYE
) {
2745 if (mtmp
->mcansee
&& haseyes(mtmp
->data
) && rn2(3)
2746 && (perceives(mtmp
->data
) || !Invis
)) {
2748 pline("As a blind %s, you cannot defend yourself.",
2749 youmonst
.data
->mname
);
2751 if (mon_reflects(mtmp
,
2752 "Your gaze is reflected by %s %s."))
2754 pline("%s is frozen by your gaze!", Monnam(mtmp
));
2755 paralyze_monst(mtmp
, tmp
);
2759 } else { /* gelatinous cube */
2760 pline("%s is frozen by you.", Monnam(mtmp
));
2761 paralyze_monst(mtmp
, tmp
);
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
);
2773 pline("%s is suddenly very cold!", Monnam(mtmp
));
2777 if (u
.mhmax
> ((youmonst
.data
->mlevel
+ 1) * 8))
2778 (void) split_mon(&youmonst
, mtmp
);
2780 case AD_STUN
: /* Yellow mold */
2783 pline("%s %s.", Monnam(mtmp
),
2784 makeplural(stagger(mtmp
->data
, "stagger")));
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
);
2796 pline("%s is suddenly very hot!", Monnam(mtmp
));
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
);
2806 pline("%s is jolted with your electricity!", Monnam(mtmp
));
2816 if ((mtmp
->mhp
-= tmp
) <= 0) {
2817 pline("%s dies!", Monnam(mtmp
));
2818 xkilled(mtmp
, XKILL_NOMSG
);
2829 register struct monst
*mon
;
2830 int mndx
= monsndx(youmonst
.data
);
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
);
2840 mon
= christen_monst(mon
, plname
);
2842 mon
->m_lev
= youmonst
.data
->mlevel
;
2843 mon
->mhpmax
= u
.mhmax
;
2844 mon
->mhp
= u
.mh
/ 2;