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
*otmp
;
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 mattk
= getmattk(mtmp
, &youmonst
, i
, sum
, &alt_attk
);
650 if ((u
.uswallow
&& mattk
->aatyp
!= AT_ENGL
)
651 || (skipnonmagc
&& mattk
->aatyp
!= AT_MAGC
))
654 switch (mattk
->aatyp
) {
655 case AT_CLAW
: /* "hand to hand" attacks */
662 if (!range2
&& (!MON_WEP(mtmp
) || mtmp
->mconf
|| Conflict
663 || !touch_petrifies(youmonst
.data
))) {
665 if (tmp
> (j
= rnd(20 + i
))) {
666 if (mattk
->aatyp
!= AT_KICK
667 || !thick_skinned(youmonst
.data
))
668 sum
[i
] = hitmu(mtmp
, mattk
);
670 missmu(mtmp
, (tmp
== j
), mattk
);
672 wildmiss(mtmp
, mattk
);
673 /* skip any remaining non-spell attacks */
679 case AT_HUGS
: /* automatic if prev two attacks succeed */
680 /* Note: if displaced, prev attacks never succeeded */
681 if ((!range2
&& i
>= 2 && sum
[i
- 1] && sum
[i
- 2])
683 sum
[i
] = hitmu(mtmp
, mattk
);
686 case AT_GAZE
: /* can affect you either ranged or not */
687 /* Medusa gaze already operated through m_respond in
688 dochug(); don't gaze more than once per round. */
689 if (mdat
!= &mons
[PM_MEDUSA
])
690 sum
[i
] = gazemu(mtmp
, mattk
);
693 case AT_EXPL
: /* automatic hit if next to, and aimed at you */
695 sum
[i
] = explmu(mtmp
, mattk
, foundyou
);
702 || (!mtmp
->mspec_used
&& tmp
> (j
= rnd(20 + i
)))) {
703 /* force swallowing monster to be displayed
704 even when hero is moving away */
706 sum
[i
] = gulpmu(mtmp
, mattk
);
708 missmu(mtmp
, (tmp
== j
), mattk
);
710 } else if (is_animal(mtmp
->data
)) {
711 pline("%s gulps some air!", Monnam(mtmp
));
714 pline("%s lunges forward and recoils!", Monnam(mtmp
));
716 You_hear("a %s nearby.",
717 is_whirly(mtmp
->data
) ? "rushing noise"
724 sum
[i
] = breamu(mtmp
, mattk
);
725 /* Note: breamu takes care of displacement */
729 sum
[i
] = spitmu(mtmp
, mattk
);
730 /* Note: spitmu takes care of displacement */
734 if (!Is_rogue_level(&u
.uz
))
739 /* Rare but not impossible. Normally the monster
740 * wields when 2 spaces away, but it can be
741 * teleported or whatever....
743 if (mtmp
->weapon_check
== NEED_WEAPON
|| !MON_WEP(mtmp
)) {
744 mtmp
->weapon_check
= NEED_HTH_WEAPON
;
745 /* mon_wield_item resets weapon_check as appropriate */
746 if (mon_wield_item(mtmp
) != 0)
750 otmp
= MON_WEP(mtmp
);
752 hittmp
= hitval(otmp
, &youmonst
);
756 if (tmp
> (j
= dieroll
= rnd(20 + i
)))
757 sum
[i
] = hitmu(mtmp
, mattk
);
759 missmu(mtmp
, (tmp
== j
), mattk
);
760 /* KMH -- Don't accumulate to-hit bonuses */
764 wildmiss(mtmp
, mattk
);
765 /* skip any remaining non-spell attacks */
772 sum
[i
] = buzzmu(mtmp
, mattk
);
774 sum
[i
] = castmu(mtmp
, mattk
, TRUE
, foundyou
);
777 default: /* no attack */
782 /* give player a chance of waking up before dying -kaa */
783 if (sum
[i
] == 1) { /* successful attack */
784 if (u
.usleep
&& u
.usleep
< monstermoves
&& !rn2(10)) {
786 nomovemsg
= "The combat suddenly awakens you.";
790 return 1; /* attacker dead */
792 break; /* attacker teleported, no more attacks */
793 /* sum[i] == 0: unsuccessful attack */
800 struct permonst
*mdat
;
802 if (Sick_resistance
) {
803 You_feel("a slight illness.");
806 make_sick(Sick
? Sick
/ 3L + 1L : (long) rn1(ACURR(A_CON
), 20),
807 mdat
->mname
, TRUE
, SICK_NONVOMITABLE
);
812 /* check whether slippery clothing protects from hug or wrap attack */
814 u_slip_free(mtmp
, mattk
)
816 struct attack
*mattk
;
818 struct obj
*obj
= (uarmc
? uarmc
: uarm
);
822 if (mattk
->adtyp
== AD_DRIN
)
825 /* if your cloak/armor is greased, monster slips off; this
826 protection might fail (33% chance) when the armor is cursed */
827 if (obj
&& (obj
->greased
|| obj
->otyp
== OILSKIN_CLOAK
)
828 && (!obj
->cursed
|| rn2(3))) {
829 pline("%s %s your %s %s!", Monnam(mtmp
),
830 (mattk
->adtyp
== AD_WRAP
) ? "slips off of"
831 : "grabs you, but cannot hold onto",
832 obj
->greased
? "greased" : "slippery",
833 /* avoid "slippery slippery cloak"
834 for undiscovered oilskin cloak */
835 (obj
->greased
|| objects
[obj
->otyp
].oc_name_known
)
837 : cloak_simple_name(obj
));
839 if (obj
->greased
&& !rn2(2)) {
840 pline_The("grease wears off.");
849 /* armor that sufficiently covers the body might be able to block magic */
857 boolean is_you
= (mon
== &youmonst
),
858 gotprot
= is_you
? (EProtection
!= 0L)
859 /* high priests have innate protection */
860 : (mon
->data
== &mons
[PM_HIGH_PRIEST
]);
862 for (o
= is_you
? invent
: mon
->minvent
; o
; o
= o
->nobj
) {
863 /* a_can field is only applicable for armor (which must be worn) */
864 if ((o
->owornmask
& W_ARMOR
) != 0L) {
865 armpro
= objects
[o
->otyp
].a_can
;
869 /* if we've already confirmed Protection, skip additional checks */
870 if (is_you
|| gotprot
)
873 /* omit W_SWAPWEP+W_QUIVER; W_ART+W_ARTI handled by protects() */
874 wearmask
= W_ARMOR
| W_ACCESSORY
;
875 if (o
->oclass
== WEAPON_CLASS
|| is_weptool(o
))
877 if (protects(o
, ((o
->owornmask
& wearmask
) != 0L) ? TRUE
: FALSE
))
882 /* extrinsic Protection increases mc by 1 */
886 /* intrinsic Protection is weaker (play balance; obtaining divine
887 protection is too easy); it confers minimum mc 1 instead of 0 */
888 if ((is_you
&& ((HProtection
&& u
.ublessed
> 0) || u
.uspellprot
))
889 /* aligned priests and angels have innate intrinsic Protection */
890 || (mon
->data
== &mons
[PM_ALIGNED_PRIEST
] || is_minion(mon
->data
)))
897 * hitmu: monster hits you
898 * returns 2 if monster dies (e.g. "yellow light"), 1 otherwise
899 * 3 if the monster lives but teleported/paralyzed, so it can't keep
904 register struct monst
*mtmp
;
905 register struct attack
*mattk
;
907 register struct permonst
*mdat
= mtmp
->data
;
908 register int uncancelled
, ptmp
;
909 int dmg
, armpro
, permdmg
;
911 struct permonst
*olduasmon
= youmonst
.data
;
914 if (!canspotmon(mtmp
))
915 map_invisible(mtmp
->mx
, mtmp
->my
);
917 /* If the monster is undetected & hits you, you should know where
918 * the attack came from.
920 if (mtmp
->mundetected
&& (hides_under(mdat
) || mdat
->mlet
== S_EEL
)) {
921 mtmp
->mundetected
= 0;
922 if (!(Blind
? Blind_telepat
: Unblind_telepat
)) {
926 if ((obj
= level
.objects
[mtmp
->mx
][mtmp
->my
]) != 0) {
927 if (Blind
&& !obj
->dknown
)
929 else if (is_pool(mtmp
->mx
, mtmp
->my
) && !Underwater
)
934 pline("%s was hidden under %s!", Amonnam(mtmp
), what
);
936 newsym(mtmp
->mx
, mtmp
->my
);
940 /* First determine the base damage done */
941 dmg
= d((int) mattk
->damn
, (int) mattk
->damd
);
942 if ((is_undead(mdat
) || is_vampshifter(mtmp
)) && midnight())
943 dmg
+= d((int) mattk
->damn
, (int) mattk
->damd
); /* extra damage */
945 /* Next a cancellation factor.
946 * Use uncancelled when cancellation factor takes into account certain
947 * armor's special magic protection. Otherwise just use !mtmp->mcan.
949 armpro
= magic_negation(&youmonst
);
950 uncancelled
= !mtmp
->mcan
&& (rn2(10) >= 3 * armpro
);
953 /* Now, adjust damages via resistances or specific attacks */
954 switch (mattk
->adtyp
) {
956 if (mattk
->aatyp
== AT_HUGS
&& !sticks(youmonst
.data
)) {
957 if (!u
.ustuck
&& rn2(2)) {
958 if (u_slip_free(mtmp
, mattk
)) {
962 pline("%s grabs you!", Monnam(mtmp
));
964 } else if (u
.ustuck
== mtmp
) {
965 exercise(A_STR
, FALSE
);
966 You("are being %s.", (mtmp
->data
== &mons
[PM_ROPE_GOLEM
])
970 } else { /* hand to hand weapon */
971 if (mattk
->aatyp
== AT_WEAP
&& otmp
) {
974 if (otmp
->otyp
== CORPSE
975 && touch_petrifies(&mons
[otmp
->corpsenm
])) {
977 pline("%s hits you with the %s corpse.", Monnam(mtmp
),
978 mons
[otmp
->corpsenm
].mname
);
982 dmg
+= dmgval(otmp
, &youmonst
);
985 if (!(otmp
->oartifact
986 && artifact_hit(mtmp
, &youmonst
, otmp
, &dmg
, dieroll
)))
990 if (objects
[otmp
->otyp
].oc_material
== SILVER
992 pline_The("silver sears your flesh!");
993 exercise(A_CON
, FALSE
);
995 /* this redundancy necessary because you have
996 to take the damage _before_ being cloned;
997 need to have at least 2 hp left to split */
1003 if (u
.mh
- tmp
> 1 && objects
[otmp
->otyp
].oc_material
== IRON
1004 && (u
.umonnum
== PM_BLACK_PUDDING
1005 || u
.umonnum
== PM_BROWN_PUDDING
)) {
1007 exercise(A_STR
, FALSE
);
1008 /* inflict damage now; we know it can't be fatal */
1011 dmg
= 0; /* don't inflict more damage below */
1013 You("divide as %s hits you!", mon_nam(mtmp
));
1015 rustm(&youmonst
, otmp
);
1016 } else if (mattk
->aatyp
!= AT_TUCH
|| dmg
!= 0
1017 || mtmp
!= u
.ustuck
)
1018 hitmsg(mtmp
, mattk
);
1022 hitmsg(mtmp
, mattk
);
1023 if (!diseasemu(mdat
))
1027 hitmsg(mtmp
, mattk
);
1029 pline("You're %s!", on_fire(youmonst
.data
, mattk
));
1030 if (youmonst
.data
== &mons
[PM_STRAW_GOLEM
]
1031 || youmonst
.data
== &mons
[PM_PAPER_GOLEM
]) {
1033 /* KMH -- this is okay with unchanging */
1036 } else if (Fire_resistance
) {
1037 pline_The("fire doesn't feel hot!");
1040 if ((int) mtmp
->m_lev
> rn2(20))
1041 destroy_item(SCROLL_CLASS
, AD_FIRE
);
1042 if ((int) mtmp
->m_lev
> rn2(20))
1043 destroy_item(POTION_CLASS
, AD_FIRE
);
1044 if ((int) mtmp
->m_lev
> rn2(25))
1045 destroy_item(SPBOOK_CLASS
, AD_FIRE
);
1051 hitmsg(mtmp
, mattk
);
1053 pline("You're covered in frost!");
1054 if (Cold_resistance
) {
1055 pline_The("frost doesn't seem cold!");
1058 if ((int) mtmp
->m_lev
> rn2(20))
1059 destroy_item(POTION_CLASS
, AD_COLD
);
1064 hitmsg(mtmp
, mattk
);
1067 if (Shock_resistance
) {
1068 pline_The("zap doesn't shock you!");
1071 if ((int) mtmp
->m_lev
> rn2(20))
1072 destroy_item(WAND_CLASS
, AD_ELEC
);
1073 if ((int) mtmp
->m_lev
> rn2(20))
1074 destroy_item(RING_CLASS
, AD_ELEC
);
1079 hitmsg(mtmp
, mattk
);
1080 if (uncancelled
&& multi
>= 0 && !rn2(5)) {
1081 if (Sleep_resistance
)
1083 fall_asleep(-rnd(10), TRUE
);
1085 You("are put to sleep!");
1087 You("are put to sleep by %s!", mon_nam(mtmp
));
1091 if (can_blnd(mtmp
, &youmonst
, mattk
->aatyp
, (struct obj
*) 0)) {
1093 pline("%s blinds you!", Monnam(mtmp
));
1094 make_blinded(Blinded
+ (long) dmg
, FALSE
);
1096 Your1(vision_clears
);
1109 hitmsg(mtmp
, mattk
);
1110 if (uncancelled
&& !rn2(8)) {
1111 Sprintf(buf
, "%s %s", s_suffix(Monnam(mtmp
)),
1112 mpoisons_subj(mtmp
, mattk
));
1113 poisoned(buf
, ptmp
, mdat
->mname
, 30, FALSE
);
1117 hitmsg(mtmp
, mattk
);
1118 if (defends(AD_DRIN
, uwep
) || !has_head(youmonst
.data
)) {
1119 You("don't seem harmed.");
1120 /* Not clear what to do for green slimes */
1123 if (u_slip_free(mtmp
, mattk
))
1126 if (uarmh
&& rn2(8)) {
1127 /* not body_part(HEAD) */
1128 Your("%s blocks the attack to your head.",
1129 helm_simple_name(uarmh
));
1132 /* negative armor class doesn't reduce this damage */
1133 if (Half_physical_damage
)
1134 dmg
= (dmg
+ 1) / 2;
1135 mdamageu(mtmp
, dmg
);
1136 dmg
= 0; /* don't inflict a second dose below */
1138 if (!uarmh
|| uarmh
->otyp
!= DUNCE_CAP
) {
1139 /* eat_brains() will miss if target is mindless (won't
1140 happen here; hero is considered to retain his mind
1141 regardless of current shape) or is noncorporeal
1142 (can't happen here; no one can poly into a ghost
1143 or shade) so this check for missing is academic */
1144 if (eat_brains(mtmp
, &youmonst
, TRUE
, (int *) 0) == MM_MISS
)
1147 /* adjattrib gives dunce cap message when appropriate */
1148 (void) adjattrib(A_INT
, -rnd(2), FALSE
);
1149 forget_levels(25); /* lose memory of 25% of levels */
1150 forget_objects(25); /* lose memory of 25% of objects */
1153 hitmsg(mtmp
, mattk
);
1154 if (uncancelled
&& multi
>= 0 && !rn2(3)) {
1156 You("momentarily stiffen.");
1161 You("are frozen by %s!", mon_nam(mtmp
));
1162 nomovemsg
= You_can_move_again
;
1164 multi_reason
= "paralyzed by a monster";
1165 exercise(A_DEX
, FALSE
);
1170 hitmsg(mtmp
, mattk
);
1171 if (uncancelled
&& !rn2(3) && !Drain_resistance
) {
1172 losexp("life drainage");
1176 register long side
= rn2(2) ? RIGHT_SIDE
: LEFT_SIDE
;
1177 const char *sidestr
= (side
== RIGHT_SIDE
) ? "right" : "left",
1178 *Monst_name
= Monnam(mtmp
), *leg
= body_part(LEG
);
1180 /* This case is too obvious to ignore, but Nethack is not in
1181 * general very good at considering height--most short monsters
1182 * still _can_ attack you when you're flying or mounted.
1183 * [FIXME: why can't a flying attacker overcome this?]
1185 if (u
.usteed
|| Levitation
|| Flying
) {
1186 pline("%s tries to reach your %s %s!", Monst_name
, sidestr
, leg
);
1188 } else if (mtmp
->mcan
) {
1189 pline("%s nuzzles against your %s %s!", Monnam(mtmp
),
1194 if (rn2(2) && (uarmf
->otyp
== LOW_BOOTS
1195 || uarmf
->otyp
== IRON_SHOES
)) {
1196 pline("%s pricks the exposed part of your %s %s!",
1197 Monst_name
, sidestr
, leg
);
1198 } else if (!rn2(5)) {
1199 pline("%s pricks through your %s boot!", Monst_name
,
1202 pline("%s scratches your %s boot!", Monst_name
,
1208 pline("%s pricks your %s %s!", Monst_name
, sidestr
, leg
);
1210 set_wounded_legs(side
, rnd(60 - ACURR(A_DEX
)));
1211 exercise(A_STR
, FALSE
);
1212 exercise(A_DEX
, FALSE
);
1216 case AD_STON
: /* cockatrice */
1217 hitmsg(mtmp
, mattk
);
1221 You_hear("a cough from %s!", mon_nam(mtmp
));
1224 You_hear("%s hissing!", s_suffix(mon_nam(mtmp
)));
1226 || (flags
.moonphase
== NEW_MOON
&& !have_lizard())) {
1228 if (!Stoned
&& !Stone_resistance
1229 && !(poly_when_stoned(youmonst
.data
)
1230 && polymon(PM_STONE_GOLEM
))) {
1231 int kformat
= KILLED_BY_AN
;
1232 const char *kname
= mtmp
->data
->mname
;
1234 if (mtmp
->data
->geno
& G_UNIQ
) {
1235 if (!type_is_pname(mtmp
->data
))
1237 kformat
= KILLED_BY
;
1239 make_stoned(5L, (char *) 0, kformat
, kname
);
1241 /* done_in_by(mtmp, STONING); */
1248 hitmsg(mtmp
, mattk
);
1249 if (uncancelled
&& !u
.ustuck
&& !sticks(youmonst
.data
))
1253 if ((!mtmp
->mcan
|| u
.ustuck
== mtmp
) && !sticks(youmonst
.data
)) {
1254 if (!u
.ustuck
&& !rn2(10)) {
1255 if (u_slip_free(mtmp
, mattk
)) {
1258 pline("%s swings itself around you!", Monnam(mtmp
));
1261 } else if (u
.ustuck
== mtmp
) {
1262 if (is_pool(mtmp
->mx
, mtmp
->my
) && !Swimming
&& !Amphibious
) {
1263 boolean moat
= (levl
[mtmp
->mx
][mtmp
->my
].typ
!= POOL
)
1264 && (levl
[mtmp
->mx
][mtmp
->my
].typ
!= WATER
)
1265 && !Is_medusa_level(&u
.uz
)
1266 && !Is_waterlevel(&u
.uz
);
1268 pline("%s drowns you...", Monnam(mtmp
));
1269 killer
.format
= KILLED_BY_AN
;
1270 Sprintf(killer
.name
, "%s by %s",
1271 moat
? "moat" : "pool of water",
1272 an(mtmp
->data
->mname
));
1274 } else if (mattk
->aatyp
== AT_HUGS
)
1275 You("are being crushed.");
1279 pline("%s brushes against your %s.", Monnam(mtmp
),
1286 hitmsg(mtmp
, mattk
);
1287 if (uncancelled
&& !rn2(4) && u
.ulycn
== NON_PM
1288 && !Protection_from_shape_changers
&& !defends(AD_WERE
, uwep
)) {
1289 You_feel("feverish.");
1290 exercise(A_CON
, FALSE
);
1291 set_ulycn(monsndx(mdat
));
1292 retouch_equipment(2);
1296 hitmsg(mtmp
, mattk
);
1297 if (youmonst
.data
->mlet
== mdat
->mlet
)
1304 if (SYSOPT_SEDUCE
) {
1305 if (could_seduce(mtmp
, &youmonst
, mattk
) == 1 && !mtmp
->mcan
)
1311 case AD_SITM
: /* for now these are the same */
1313 if (is_animal(mtmp
->data
)) {
1314 hitmsg(mtmp
, mattk
);
1317 /* Continue below */
1318 } else if (dmgtype(youmonst
.data
, AD_SEDU
)
1319 || (SYSOPT_SEDUCE
&& dmgtype(youmonst
.data
, AD_SSEX
))) {
1320 pline("%s %s.", Monnam(mtmp
),
1322 ? "brags about the goods some dungeon explorer provided"
1323 : "makes some remarks about how difficult theft is lately");
1324 if (!tele_restrict(mtmp
))
1325 (void) rloc(mtmp
, TRUE
);
1327 } else if (mtmp
->mcan
) {
1329 pline("%s tries to %s you, but you seem %s.",
1330 Adjmonnam(mtmp
, "plain"),
1331 flags
.female
? "charm" : "seduce",
1332 flags
.female
? "unaffected" : "uninterested");
1334 if (!tele_restrict(mtmp
))
1335 (void) rloc(mtmp
, TRUE
);
1341 switch (steal(mtmp
, buf
)) {
1347 if (!is_animal(mtmp
->data
) && !tele_restrict(mtmp
))
1348 (void) rloc(mtmp
, TRUE
);
1349 if (is_animal(mtmp
->data
) && *buf
) {
1350 if (canseemon(mtmp
))
1351 pline("%s tries to %s away with %s.", Monnam(mtmp
),
1352 locomotion(mtmp
->data
, "run"), buf
);
1354 monflee(mtmp
, 0, FALSE
, FALSE
);
1360 hitmsg(mtmp
, mattk
);
1361 /* when the Wizard or quest nemesis hits, there's a 1/20 chance
1362 to steal a quest artifact (any, not just the one for the hero's
1363 own role) or the Amulet or one of the invocation tools */
1369 hitmsg(mtmp
, mattk
);
1372 Your("position suddenly seems very uncertain!");
1377 hitmsg(mtmp
, mattk
);
1380 if (u
.umonnum
== PM_IRON_GOLEM
) {
1382 /* KMH -- this is okay with unchanging */
1386 erode_armor(&youmonst
, ERODE_RUST
);
1389 hitmsg(mtmp
, mattk
);
1392 erode_armor(&youmonst
, ERODE_CORRODE
);
1395 hitmsg(mtmp
, mattk
);
1398 if (u
.umonnum
== PM_WOOD_GOLEM
|| u
.umonnum
== PM_LEATHER_GOLEM
) {
1400 /* KMH -- this is okay with unchanging */
1404 erode_armor(&youmonst
, ERODE_ROT
);
1407 /* a cancelled nurse is just an ordinary monster,
1408 * nurses don't heal those that cause petrification */
1409 if (mtmp
->mcan
|| (Upolyd
&& touch_petrifies(youmonst
.data
))) {
1410 hitmsg(mtmp
, mattk
);
1413 if (!uwep
&& !uarmu
&& !uarm
&& !uarmc
1414 && !uarms
&& !uarmg
&& !uarmf
&& !uarmh
) {
1415 boolean goaway
= FALSE
;
1417 pline("%s hits! (I hope you don't mind.)", Monnam(mtmp
));
1421 /* no upper limit necessary; effect is temporary */
1431 /* hard upper limit via nurse care: 25 * ulevel */
1432 if (u
.uhpmax
< 5 * u
.ulevel
+ d(2 * u
.ulevel
, 10))
1437 if (u
.uhp
> u
.uhpmax
)
1441 exercise(A_STR
, TRUE
);
1443 exercise(A_CON
, TRUE
);
1445 make_sick(0L, (char *) 0, FALSE
, SICK_ALL
);
1450 } else if (!rn2(33)) {
1451 if (!tele_restrict(mtmp
))
1452 (void) rloc(mtmp
, TRUE
);
1453 monflee(mtmp
, d(3, 6), TRUE
, FALSE
);
1458 if (Role_if(PM_HEALER
)) {
1459 if (!Deaf
&& !(moves
% 5))
1460 verbalize("Doc, I can't help you unless you cooperate.");
1463 hitmsg(mtmp
, mattk
);
1467 hitmsg(mtmp
, mattk
);
1468 if (!night() && mdat
== &mons
[PM_GREMLIN
])
1470 if (!mtmp
->mcan
&& !rn2(10)) {
1473 You_hear("laughter.");
1475 pline("%s chuckles.", Monnam(mtmp
));
1477 if (u
.umonnum
== PM_CLAY_GOLEM
) {
1478 pline("Some writing vanishes from your head!");
1479 /* KMH -- this is okay with unchanging */
1487 hitmsg(mtmp
, mattk
);
1488 if (!mtmp
->mcan
&& !rn2(4)) {
1489 make_stunned((HStun
& TIMEOUT
) + (long) dmg
, TRUE
);
1494 hitmsg(mtmp
, mattk
);
1495 if (!mtmp
->mcan
&& !rn2(3))
1496 if (Acid_resistance
) {
1497 pline("You're covered in %s, but it seems harmless.",
1501 pline("You're covered in %s! It burns!", hliquid("acid"));
1502 exercise(A_STR
, FALSE
);
1508 hitmsg(mtmp
, mattk
);
1509 if (uncancelled
&& HFast
&& !defends(AD_SLOW
, uwep
) && !rn2(4))
1513 hitmsg(mtmp
, mattk
);
1514 if (uncancelled
&& !rn2(4)) /* 25% chance */
1519 hitmsg(mtmp
, mattk
);
1520 if (!mtmp
->mcan
&& !rn2(4) && !mtmp
->mspec_used
) {
1521 mtmp
->mspec_used
= mtmp
->mspec_used
+ (dmg
+ rn2(6));
1523 You("are getting even more confused.");
1525 You("are getting confused.");
1526 make_confused(HConfusion
+ dmg
, FALSE
);
1531 pline("%s reaches out with its deadly touch.", Monnam(mtmp
));
1532 if (is_undead(youmonst
.data
)) {
1533 /* Still does normal damage */
1534 pline("Was that the touch of death?");
1542 killer
.format
= KILLED_BY_AN
;
1543 Strcpy(killer
.name
, "touch of death");
1547 } /* else FALLTHRU */
1548 default: /* case 16: ... case 5: */
1549 You_feel("your life force draining away...");
1550 permdmg
= 1; /* actual damage done below */
1558 shieldeff(u
.ux
, u
.uy
);
1559 pline("Lucky for you, it didn't work!");
1565 pline("%s reaches out, and you feel fever and chills.", Monnam(mtmp
));
1566 (void) diseasemu(mdat
); /* plus the normal damage */
1569 pline("%s reaches out, and your body shrivels.", Monnam(mtmp
));
1570 exercise(A_CON
, FALSE
);
1572 morehungry(rn1(40, 40));
1573 /* plus the normal damage */
1576 hitmsg(mtmp
, mattk
);
1579 if (flaming(youmonst
.data
)) {
1580 pline_The("slime burns away!");
1582 } else if (Unchanging
|| noncorporeal(youmonst
.data
)
1583 || youmonst
.data
== &mons
[PM_GREEN_SLIME
]) {
1584 You("are unaffected.");
1586 } else if (!Slimed
) {
1587 You("don't feel very well.");
1588 make_slimed(10L, (char *) 0);
1589 delayed_killer(SLIMED
, KILLED_BY_AN
, mtmp
->data
->mname
);
1593 case AD_ENCH
: /* KMH -- remove enchantment (disenchanter) */
1594 hitmsg(mtmp
, mattk
);
1595 /* uncancelled is sufficient enough; please
1596 don't make this attack less frequent */
1598 struct obj
*obj
= some_armor(&youmonst
);
1601 /* some rings are susceptible;
1602 amulets and blindfolds aren't (at present) */
1620 if (drain_item(obj
, FALSE
)) {
1621 pline("%s less effective.", Yobjnam2(obj
, "seem"));
1630 done_in_by(mtmp
, DIED
);
1632 /* Negative armor class reduces damage done instead of fully protecting
1635 if (dmg
&& u
.uac
< 0) {
1642 if (Half_physical_damage
1643 /* Mitre of Holiness */
1644 || (Role_if(PM_PRIEST
) && uarmh
&& is_quest_artifact(uarmh
)
1645 && (is_undead(mtmp
->data
) || is_demon(mtmp
->data
)
1646 || is_vampshifter(mtmp
))))
1647 dmg
= (dmg
+ 1) / 2;
1649 if (permdmg
) { /* Death's life force drain */
1650 int lowerlimit
, *hpmax_p
;
1652 * Apply some of the damage to permanent hit points:
1653 * polymorphed 100% against poly'd hpmax
1654 * hpmax > 25*lvl 100% against normal hpmax
1655 * hpmax > 10*lvl 50..100%
1656 * hpmax > 5*lvl 25..75%
1658 * Never reduces hpmax below 1 hit point per level.
1660 permdmg
= rn2(dmg
/ 2 + 1);
1661 if (Upolyd
|| u
.uhpmax
> 25 * u
.ulevel
)
1663 else if (u
.uhpmax
> 10 * u
.ulevel
)
1665 else if (u
.uhpmax
> 5 * u
.ulevel
)
1670 /* [can't use youmonst.m_lev] */
1671 lowerlimit
= min((int) youmonst
.data
->mlevel
, u
.ulevel
);
1673 hpmax_p
= &u
.uhpmax
;
1674 lowerlimit
= u
.ulevel
;
1676 if (*hpmax_p
- permdmg
> lowerlimit
)
1677 *hpmax_p
-= permdmg
;
1678 else if (*hpmax_p
> lowerlimit
)
1679 *hpmax_p
= lowerlimit
;
1681 * already at or below minimum threshold; do nothing */
1685 mdamageu(mtmp
, dmg
);
1689 res
= passiveum(olduasmon
, mtmp
, mattk
);
1696 /* An interface for use when taking a blindfold off, for example,
1697 * to see if an engulfing attack should immediately take affect, like
1698 * a passive attack. TRUE if engulfing blindness occurred */
1702 struct attack
*mattk
;
1704 if (!Blinded
&& u
.uswallow
1705 && (mattk
= attacktype_fordmg(u
.ustuck
->data
, AT_ENGL
, AD_BLND
))
1706 && can_blnd(u
.ustuck
, &youmonst
, mattk
->aatyp
, (struct obj
*) 0)) {
1707 ++u
.uswldtim
; /* compensate for gulpmu change */
1708 (void) gulpmu(u
.ustuck
, mattk
);
1714 /* monster swallows you, or damage if u.uswallow */
1717 register struct monst
*mtmp
;
1718 register struct attack
*mattk
;
1720 struct trap
*t
= t_at(u
.ux
, u
.uy
);
1721 int tmp
= d((int) mattk
->damn
, (int) mattk
->damd
);
1723 register struct obj
*otmp2
;
1725 boolean physical_damage
= FALSE
;
1727 if (!u
.uswallow
) { /* swallows you */
1728 int omx
= mtmp
->mx
, omy
= mtmp
->my
;
1730 if (!engulf_target(mtmp
, &youmonst
))
1732 if ((t
&& ((t
->ttyp
== PIT
) || (t
->ttyp
== SPIKED_PIT
)))
1733 && sobj_at(BOULDER
, u
.ux
, u
.uy
))
1737 unplacebc(); /* ball&chain go away */
1738 remove_monster(omx
, omy
);
1739 mtmp
->mtrapped
= 0; /* no longer on old trap */
1740 place_monster(mtmp
, u
.ux
, u
.uy
);
1742 newsym(mtmp
->mx
, mtmp
->my
);
1743 if (is_animal(mtmp
->data
) && u
.usteed
) {
1746 /* Too many quirks presently if hero and steed
1747 * are swallowed. Pretend purple worms don't
1748 * like horses for now :-)
1750 Strcpy(buf
, mon_nam(u
.usteed
));
1751 pline("%s lunges forward and plucks you off %s!", Monnam(mtmp
),
1753 dismount_steed(DISMOUNT_ENGULFED
);
1755 pline("%s engulfs you!", Monnam(mtmp
));
1757 reset_occupations(); /* behave as if you had moved */
1760 You("are released from the %s!",
1761 u
.utraptype
== TT_WEB
? "web" : "trap");
1765 i
= number_leashed();
1767 const char *s
= (i
> 1) ? "leashes" : "leash";
1768 pline_The("%s %s loose.", s
, vtense(s
, "snap"));
1772 if (touch_petrifies(youmonst
.data
) && !resists_ston(mtmp
)) {
1773 /* put the attacker back where it started;
1774 the resulting statue will end up there */
1775 remove_monster(mtmp
->mx
, mtmp
->my
); /* u.ux,u.uy */
1776 place_monster(mtmp
, omx
, omy
);
1777 minstapetrify(mtmp
, TRUE
);
1778 /* normally unstuck() would do this, but we're not
1779 fully swallowed yet so that won't work here */
1783 return (mtmp
->mhp
> 0) ? 0 : 2;
1786 display_nhwindow(WIN_MESSAGE
, FALSE
);
1787 vision_recalc(2); /* hero can't see anything */
1789 /* for digestion, shorter time is more dangerous;
1790 for other swallowings, longer time means more
1791 chances for the swallower to attack */
1792 if (mattk
->adtyp
== AD_DGST
) {
1793 tim_tmp
= 25 - (int) mtmp
->m_lev
;
1795 tim_tmp
= rnd(tim_tmp
) / 2;
1796 else if (tim_tmp
< 0)
1797 tim_tmp
= -(rnd(-tim_tmp
) / 2);
1798 /* having good armor & high constitution makes
1799 it take longer for you to be digested, but
1800 you'll end up trapped inside for longer too */
1801 tim_tmp
+= -u
.uac
+ 10 + (ACURR(A_CON
) / 3 - 1);
1803 /* higher level attacker takes longer to eject hero */
1804 tim_tmp
= rnd((int) mtmp
->m_lev
+ 10 / 2);
1806 /* u.uswldtim always set > 1 */
1807 u
.uswldtim
= (unsigned) ((tim_tmp
< 2) ? 2 : tim_tmp
);
1809 for (otmp2
= invent
; otmp2
; otmp2
= otmp2
->nobj
)
1810 (void) snuff_lit(otmp2
);
1813 if (mtmp
!= u
.ustuck
)
1818 switch (mattk
->adtyp
) {
1820 physical_damage
= TRUE
;
1821 if (Slow_digestion
) {
1822 /* Messages are handled below */
1825 } else if (u
.uswldtim
== 0) {
1826 pline("%s totally digests you!", Monnam(mtmp
));
1828 if (Half_physical_damage
)
1829 tmp
*= 2; /* sorry */
1831 pline("%s%s digests you!", Monnam(mtmp
),
1832 (u
.uswldtim
== 2) ? " thoroughly"
1833 : (u
.uswldtim
== 1) ? " utterly" : "");
1834 exercise(A_STR
, FALSE
);
1838 physical_damage
= TRUE
;
1839 if (mtmp
->data
== &mons
[PM_FOG_CLOUD
]) {
1840 You("are laden with moisture and %s",
1841 flaming(youmonst
.data
)
1842 ? "are smoldering out!"
1843 : Breathless
? "find it mildly uncomfortable."
1844 : amphibious(youmonst
.data
)
1846 : "can barely breathe!");
1847 /* NB: Amphibious includes Breathless */
1848 if (Amphibious
&& !flaming(youmonst
.data
))
1851 You("are pummeled with debris!");
1852 exercise(A_STR
, FALSE
);
1856 if (Acid_resistance
) {
1857 You("are covered with a seemingly harmless goo.");
1861 pline("Ouch! You've been slimed!");
1863 You("are covered in slime! It burns!");
1864 exercise(A_STR
, FALSE
);
1868 if (can_blnd(mtmp
, &youmonst
, mattk
->aatyp
, (struct obj
*) 0)) {
1870 long was_blinded
= Blinded
;
1872 You_cant("see in here!");
1873 make_blinded((long) tmp
, FALSE
);
1874 if (!was_blinded
&& !Blind
)
1875 Your1(vision_clears
);
1877 /* keep him blind until disgorged */
1878 make_blinded(Blinded
+ 1, FALSE
);
1883 if (!mtmp
->mcan
&& rn2(2)) {
1884 pline_The("air around you crackles with electricity.");
1885 if (Shock_resistance
) {
1886 shieldeff(u
.ux
, u
.uy
);
1887 You("seem unhurt.");
1888 ugolemeffects(AD_ELEC
, tmp
);
1895 if (!mtmp
->mcan
&& rn2(2)) {
1896 if (Cold_resistance
) {
1897 shieldeff(u
.ux
, u
.uy
);
1898 You_feel("mildly chilly.");
1899 ugolemeffects(AD_COLD
, tmp
);
1902 You("are freezing to death!");
1907 if (!mtmp
->mcan
&& rn2(2)) {
1908 if (Fire_resistance
) {
1909 shieldeff(u
.ux
, u
.uy
);
1910 You_feel("mildly hot.");
1911 ugolemeffects(AD_FIRE
, tmp
);
1914 You("are burning to a crisp!");
1920 if (!diseasemu(mtmp
->data
))
1924 /* AC magic cancellation doesn't help when engulfed */
1925 if (!mtmp
->mcan
&& rn2(4)) /* 75% chance */
1930 physical_damage
= TRUE
;
1935 if (physical_damage
)
1936 tmp
= Maybe_Half_Phys(tmp
);
1938 mdamageu(mtmp
, tmp
);
1942 if (touch_petrifies(youmonst
.data
) && !resists_ston(mtmp
)) {
1943 pline("%s very hurriedly %s you!", Monnam(mtmp
),
1944 is_animal(mtmp
->data
) ? "regurgitates" : "expels");
1945 expels(mtmp
, mtmp
->data
, FALSE
);
1946 } else if (!u
.uswldtim
|| youmonst
.data
->msize
>= MZ_HUGE
) {
1947 You("get %s!", is_animal(mtmp
->data
) ? "regurgitated" : "expelled");
1949 && (is_animal(mtmp
->data
)
1950 || (dmgtype(mtmp
->data
, AD_DGST
) && Slow_digestion
)))
1951 pline("Obviously %s doesn't like your taste.", mon_nam(mtmp
));
1952 expels(mtmp
, mtmp
->data
, FALSE
);
1957 /* monster explodes in your face */
1959 explmu(mtmp
, mattk
, ufound
)
1960 register struct monst
*mtmp
;
1961 register struct attack
*mattk
;
1964 boolean physical_damage
= TRUE
, kill_agr
= TRUE
;
1970 pline("%s explodes at a spot in %s!",
1971 canseemon(mtmp
) ? Monnam(mtmp
) : "It",
1972 levl
[mtmp
->mux
][mtmp
->muy
].typ
== WATER
? "empty water"
1975 register int tmp
= d((int) mattk
->damn
, (int) mattk
->damd
);
1976 register boolean not_affected
= defends((int) mattk
->adtyp
, uwep
);
1978 hitmsg(mtmp
, mattk
);
1980 switch (mattk
->adtyp
) {
1982 physical_damage
= FALSE
;
1983 not_affected
|= Cold_resistance
;
1986 physical_damage
= FALSE
;
1987 not_affected
|= Fire_resistance
;
1990 physical_damage
= FALSE
;
1991 not_affected
|= Shock_resistance
;
1994 if (!not_affected
) {
1995 if (ACURR(A_DEX
) > rnd(20)) {
1996 You("duck some of the blast.");
1997 tmp
= (tmp
+ 1) / 2;
2000 You("get blasted!");
2002 if (mattk
->adtyp
== AD_FIRE
)
2004 if (physical_damage
)
2005 tmp
= Maybe_Half_Phys(tmp
);
2006 mdamageu(mtmp
, tmp
);
2011 not_affected
= resists_blnd(&youmonst
);
2012 if (!not_affected
) {
2013 /* sometimes you're affected even if it's invisible */
2014 if (mon_visible(mtmp
) || (rnd(tmp
/= 2) > u
.ulevel
)) {
2015 You("are blinded by a blast of light!");
2016 make_blinded((long) tmp
, FALSE
);
2018 Your1(vision_clears
);
2019 } else if (flags
.verbose
)
2020 You("get the impression it was not terribly bright.");
2025 not_affected
|= Blind
|| (u
.umonnum
== PM_BLACK_LIGHT
2026 || u
.umonnum
== PM_VIOLET_FUNGUS
2027 || dmgtype(youmonst
.data
, AD_STUN
));
2028 if (!not_affected
) {
2031 You("are caught in a blast of kaleidoscopic light!");
2032 /* avoid hallucinating the black light as it dies */
2033 mondead(mtmp
); /* remove it from map now */
2034 kill_agr
= FALSE
; /* already killed (maybe lifesaved) */
2036 make_hallucinated(HHallucination
+ (long) tmp
, FALSE
, 0L);
2037 You("%s.", chg
? "are freaked out" : "seem unaffected");
2045 You("seem unaffected by it.");
2046 ugolemeffects((int) mattk
->adtyp
, tmp
);
2051 wake_nearto(mtmp
->mx
, mtmp
->my
, 7 * 7);
2052 return (mtmp
->mhp
> 0) ? 0 : 2;
2055 /* monster gazes at you */
2058 register struct monst
*mtmp
;
2059 register struct attack
*mattk
;
2061 static const char *const reactions
[] = {
2062 "confused", /* [0] */
2063 "stunned", /* [1] */
2064 "puzzled", "dazzled", /* [2,3] */
2065 "irritated", "inflamed", /* [4,5] */
2070 boolean cancelled
= (mtmp
->mcan
!= 0), already
= FALSE
;
2072 /* assumes that hero has to see monster's gaze in order to be
2073 affected, rather than monster just having to look at hero;
2074 when hallucinating, hero's brain doesn't register what
2075 it's seeing correctly so the gaze is usually ineffective
2076 [this could be taken a lot farther and select a gaze effect
2077 appropriate to what's currently being displayed, giving
2078 ordinary monsters a gaze attack when hero thinks he or she
2079 is facing a gazing creature, but let's not go that far...] */
2080 if (Hallucination
&& rn2(4))
2083 switch (mattk
->adtyp
) {
2085 if (cancelled
|| !mtmp
->mcansee
) {
2086 if (!canseemon(mtmp
))
2087 break; /* silently */
2088 pline("%s %s.", Monnam(mtmp
),
2089 (mtmp
->data
== &mons
[PM_MEDUSA
] && mtmp
->mcan
)
2090 ? "doesn't look all that ugly"
2091 : "gazes ineffectually");
2094 if (Reflecting
&& couldsee(mtmp
->mx
, mtmp
->my
)
2095 && mtmp
->data
== &mons
[PM_MEDUSA
]) {
2096 /* hero has line of sight to Medusa and she's not blind */
2097 boolean useeit
= canseemon(mtmp
);
2100 (void) ureflects("%s gaze is reflected by your %s.",
2101 s_suffix(Monnam(mtmp
)));
2103 mtmp
, !useeit
? (char *) 0
2104 : "The gaze is reflected away by %s %s!"))
2106 if (!m_canseeu(mtmp
)) { /* probably you're invisible */
2109 "%s doesn't seem to notice that %s gaze was reflected.",
2110 Monnam(mtmp
), mhis(mtmp
));
2114 pline("%s is turned to stone!", Monnam(mtmp
));
2122 if (canseemon(mtmp
) && couldsee(mtmp
->mx
, mtmp
->my
)
2123 && !Stone_resistance
) {
2124 You("meet %s gaze.", s_suffix(mon_nam(mtmp
)));
2126 if (poly_when_stoned(youmonst
.data
) && polymon(PM_STONE_GOLEM
))
2128 You("turn to stone...");
2129 killer
.format
= KILLED_BY
;
2130 Strcpy(killer
.name
, mtmp
->data
->mname
);
2135 if (canseemon(mtmp
) && couldsee(mtmp
->mx
, mtmp
->my
) && mtmp
->mcansee
2136 && !mtmp
->mspec_used
&& rn2(5)) {
2138 react
= 0; /* "confused" */
2139 already
= (mtmp
->mconf
!= 0);
2143 mtmp
->mspec_used
= mtmp
->mspec_used
+ (conf
+ rn2(6));
2145 pline("%s gaze confuses you!", s_suffix(Monnam(mtmp
)));
2147 You("are getting more and more confused.");
2148 make_confused(HConfusion
+ conf
, FALSE
);
2154 if (canseemon(mtmp
) && couldsee(mtmp
->mx
, mtmp
->my
) && mtmp
->mcansee
2155 && !mtmp
->mspec_used
&& rn2(5)) {
2157 react
= 1; /* "stunned" */
2158 already
= (mtmp
->mstun
!= 0);
2162 mtmp
->mspec_used
= mtmp
->mspec_used
+ (stun
+ rn2(6));
2163 pline("%s stares piercingly at you!", Monnam(mtmp
));
2164 make_stunned((HStun
& TIMEOUT
) + (long) stun
, TRUE
);
2170 if (canseemon(mtmp
) && !resists_blnd(&youmonst
)
2171 && distu(mtmp
->mx
, mtmp
->my
) <= BOLT_LIM
* BOLT_LIM
) {
2173 react
= rn1(2, 2); /* "puzzled" || "dazzled" */
2174 already
= (mtmp
->mcansee
== 0);
2175 /* Archons gaze every round; we don't want cancelled ones
2176 giving the "seems puzzled/dazzled" message that often */
2177 if (mtmp
->mcan
&& mtmp
->data
== &mons
[PM_ARCHON
] && rn2(5))
2180 int blnd
= d((int) mattk
->damn
, (int) mattk
->damd
);
2182 You("are blinded by %s radiance!", s_suffix(mon_nam(mtmp
)));
2183 make_blinded((long) blnd
, FALSE
);
2185 /* not blind at this point implies you're wearing
2186 the Eyes of the Overworld; make them block this
2187 particular stun attack too */
2189 Your1(vision_clears
);
2191 long oldstun
= (HStun
& TIMEOUT
), newstun
= (long) rnd(3);
2193 /* we don't want to increment stun duration every time
2194 or sighted hero will become incapacitated */
2195 make_stunned(max(oldstun
, newstun
), TRUE
);
2201 if (canseemon(mtmp
) && couldsee(mtmp
->mx
, mtmp
->my
) && mtmp
->mcansee
2202 && !mtmp
->mspec_used
&& rn2(5)) {
2204 react
= rn1(2, 4); /* "irritated" || "inflamed" */
2206 int dmg
= d(2, 6), lev
= (int) mtmp
->m_lev
;
2208 pline("%s attacks you with a fiery gaze!", Monnam(mtmp
));
2210 if (Fire_resistance
) {
2211 pline_The("fire doesn't feel hot!");
2216 destroy_item(SCROLL_CLASS
, AD_FIRE
);
2218 destroy_item(POTION_CLASS
, AD_FIRE
);
2220 destroy_item(SPBOOK_CLASS
, AD_FIRE
);
2222 mdamageu(mtmp
, dmg
);
2226 #ifdef PM_BEHOLDER /* work in progress */
2228 if (canseemon(mtmp
) && couldsee(mtmp
->mx
, mtmp
->my
) && mtmp
->mcansee
2229 && multi
>= 0 && !rn2(5) && !Sleep_resistance
) {
2231 react
= 6; /* "tired" */
2232 already
= (mtmp
->mfrozen
!= 0); /* can't happen... */
2234 fall_asleep(-rnd(10), TRUE
);
2235 pline("%s gaze makes you very sleepy...",
2236 s_suffix(Monnam(mtmp
)));
2241 if (canseemon(mtmp
) && couldsee(mtmp
->mx
, mtmp
->my
) && mtmp
->mcansee
2242 && (HFast
& (INTRINSIC
| TIMEOUT
)) && !defends(AD_SLOW
, uwep
)
2245 react
= 7; /* "dulled" */
2246 already
= (mtmp
->mspeed
== MSLOW
);
2253 #endif /* BEHOLDER */
2255 impossible("Gaze attack %d?", mattk
->adtyp
);
2259 if (Hallucination
&& rn2(3))
2260 react
= rn2(SIZE(reactions
));
2261 /* cancelled/hallucinatory feedback; monster might look "confused",
2262 "stunned",&c but we don't actually set corresponding attribute */
2263 pline("%s looks %s%s.", Monnam(mtmp
),
2264 !rn2(3) ? "" : already
? "quite "
2265 : (!rn2(2) ? "a bit " : "somewhat "),
2271 /* mtmp hits you for n points damage */
2274 register struct monst
*mtmp
;
2285 done_in_by(mtmp
, DIED
);
2289 /* returns 0 if seduction impossible,
2291 * 2 if wrong gender for nymph
2294 could_seduce(magr
, mdef
, mattk
)
2295 struct monst
*magr
, *mdef
;
2296 struct attack
*mattk
;
2298 register struct permonst
*pagr
;
2299 boolean agrinvis
, defperc
;
2300 xchar genagr
, gendef
;
2302 if (is_animal(magr
->data
))
2304 if (magr
== &youmonst
) {
2305 pagr
= youmonst
.data
;
2306 agrinvis
= (Invis
!= 0);
2307 genagr
= poly_gender();
2310 agrinvis
= magr
->minvis
;
2311 genagr
= gender(magr
);
2313 if (mdef
== &youmonst
) {
2314 defperc
= (See_invisible
!= 0);
2315 gendef
= poly_gender();
2317 defperc
= perceives(mdef
->data
);
2318 gendef
= gender(mdef
);
2321 if (agrinvis
&& !defperc
2322 && (!SYSOPT_SEDUCE
|| (mattk
&& mattk
->adtyp
!= AD_SSEX
)))
2325 if (pagr
->mlet
!= S_NYMPH
2326 && ((pagr
!= &mons
[PM_INCUBUS
] && pagr
!= &mons
[PM_SUCCUBUS
])
2327 || (SYSOPT_SEDUCE
&& mattk
&& mattk
->adtyp
!= AD_SSEX
)))
2330 if (genagr
== 1 - gendef
)
2333 return (pagr
->mlet
== S_NYMPH
) ? 2 : 0;
2336 /* Returns 1 if monster teleported */
2339 register struct monst
*mon
;
2341 register struct obj
*ring
, *nring
;
2342 boolean fem
= (mon
->data
== &mons
[PM_SUCCUBUS
]); /* otherwise incubus */
2343 int attr_tot
, tried_gloves
= 0;
2346 if (mon
->mcan
|| mon
->mspec_used
) {
2347 pline("%s acts as though %s has got a %sheadache.", Monnam(mon
),
2348 mhe(mon
), mon
->mcan
? "severe " : "");
2352 if (unconscious()) {
2353 pline("%s seems dismayed at your lack of response.", Monnam(mon
));
2358 pline("It caresses you...");
2360 You_feel("very attracted to %s.", mon_nam(mon
));
2361 /* if in the process of putting armor on or taking armor off,
2362 interrupt that activity now */
2363 (void) stop_donning((struct obj
*) 0);
2364 /* don't try to take off gloves if cursed weapon blocks them */
2368 for (ring
= invent
; ring
; ring
= nring
) {
2370 if (ring
->otyp
!= RIN_ADORNMENT
)
2373 if (ring
->owornmask
&& uarmg
) {
2374 /* don't take off worn ring if gloves are in the way */
2375 if (!tried_gloves
++)
2376 mayberem(uarmg
, "gloves");
2378 continue; /* next ring might not be worn */
2380 if (rn2(20) < ACURR(A_CHA
)) {
2381 (void) safe_qbuf(qbuf
, "\"That ",
2382 " looks pretty. May I have it?\"", ring
,
2383 xname
, simpleonames
, "ring");
2384 makeknown(RIN_ADORNMENT
);
2385 if (yn(qbuf
) == 'n')
2388 pline("%s decides she'd like %s, and takes it.",
2389 Blind
? "She" : Monnam(mon
), yname(ring
));
2390 makeknown(RIN_ADORNMENT
);
2391 if (ring
== uleft
|| ring
== uright
)
2394 setuwep((struct obj
*) 0);
2395 if (ring
== uswapwep
)
2396 setuswapwep((struct obj
*) 0);
2397 if (ring
== uquiver
)
2398 setuqwep((struct obj
*) 0);
2400 (void) mpickobj(mon
, ring
);
2402 if (uleft
&& uright
&& uleft
->otyp
== RIN_ADORNMENT
2403 && uright
->otyp
== RIN_ADORNMENT
)
2405 if (ring
== uleft
|| ring
== uright
)
2408 /* don't put on ring if gloves are in the way */
2409 if (!tried_gloves
++)
2410 mayberem(uarmg
, "gloves");
2412 break; /* no point trying further rings */
2414 if (rn2(20) < ACURR(A_CHA
)) {
2415 (void) safe_qbuf(qbuf
, "\"That ",
2416 " looks pretty. Would you wear it for me?\"",
2417 ring
, xname
, simpleonames
, "ring");
2418 makeknown(RIN_ADORNMENT
);
2419 if (yn(qbuf
) == 'n')
2422 pline("%s decides you'd look prettier wearing %s,",
2423 Blind
? "He" : Monnam(mon
), yname(ring
));
2424 pline("and puts it on your finger.");
2426 makeknown(RIN_ADORNMENT
);
2428 pline("%s puts %s on your right %s.",
2429 Blind
? "He" : Monnam(mon
), the(xname(ring
)),
2431 setworn(ring
, RIGHT_RING
);
2432 } else if (!uleft
) {
2433 pline("%s puts %s on your left %s.",
2434 Blind
? "He" : Monnam(mon
), the(xname(ring
)),
2436 setworn(ring
, LEFT_RING
);
2437 } else if (uright
&& uright
->otyp
!= RIN_ADORNMENT
) {
2438 pline("%s replaces %s with %s.", Blind
? "He" : Monnam(mon
),
2439 yname(uright
), yname(ring
));
2441 setworn(ring
, RIGHT_RING
);
2442 } else if (uleft
&& uleft
->otyp
!= RIN_ADORNMENT
) {
2443 pline("%s replaces %s with %s.", Blind
? "He" : Monnam(mon
),
2444 yname(uleft
), yname(ring
));
2446 setworn(ring
, LEFT_RING
);
2448 impossible("ring replacement");
2450 prinv((char *) 0, ring
, 0L);
2454 if (!uarmc
&& !uarmf
&& !uarmg
&& !uarms
&& !uarmh
&& !uarmu
)
2455 pline("%s murmurs sweet nothings into your ear.",
2456 Blind
? (fem
? "She" : "He") : Monnam(mon
));
2458 pline("%s murmurs in your ear, while helping you undress.",
2459 Blind
? (fem
? "She" : "He") : Monnam(mon
));
2460 mayberem(uarmc
, cloak_simple_name(uarmc
));
2462 mayberem(uarm
, "suit");
2463 mayberem(uarmf
, "boots");
2465 mayberem(uarmg
, "gloves");
2466 mayberem(uarms
, "shield");
2467 mayberem(uarmh
, helm_simple_name(uarmh
));
2468 if (!uarmc
&& !uarm
)
2469 mayberem(uarmu
, "shirt");
2471 if (uarm
|| uarmc
) {
2472 verbalize("You're such a %s; I wish...",
2473 flags
.female
? "sweet lady" : "nice guy");
2474 if (!tele_restrict(mon
))
2475 (void) rloc(mon
, TRUE
);
2478 if (u
.ualign
.type
== A_CHAOTIC
)
2481 /* by this point you have discovered mon's identity, blind or not... */
2482 pline("Time stands still while you and %s lie in each other's arms...",
2484 /* 3.6.1: a combined total for charisma plus intelligence of 35-1
2485 used to guarantee successful outcome; now total maxes out at 32
2486 as far as deciding what will happen; chance for bad outcome when
2487 Cha+Int is 32 or more is 2/35, a bit over 5.7% */
2488 attr_tot
= ACURR(A_CHA
) + ACURR(A_INT
);
2489 if (rn2(35) > min(attr_tot
, 32)) {
2490 /* Don't bother with mspec_used here... it didn't get tired! */
2491 pline("%s seems to have enjoyed it more than you...",
2495 You_feel("drained of energy.");
2497 u
.uenmax
-= rnd(Half_physical_damage
? 5 : 10);
2498 exercise(A_CON
, FALSE
);
2503 You("are down in the dumps.");
2504 (void) adjattrib(A_CON
, -1, TRUE
);
2505 exercise(A_CON
, FALSE
);
2509 Your("senses are dulled.");
2510 (void) adjattrib(A_WIS
, -1, TRUE
);
2511 exercise(A_WIS
, FALSE
);
2515 if (!resists_drli(&youmonst
)) {
2516 You_feel("out of shape.");
2517 losexp("overexertion");
2519 You("have a curious feeling...");
2521 exercise(A_CON
, FALSE
);
2522 exercise(A_DEX
, FALSE
);
2523 exercise(A_WIS
, FALSE
);
2528 You_feel("exhausted.");
2529 exercise(A_STR
, FALSE
);
2531 losehp(Maybe_Half_Phys(tmp
), "exhaustion", KILLED_BY
);
2536 mon
->mspec_used
= rnd(100); /* monster is worn out */
2537 You("seem to have enjoyed it more than %s...", noit_mon_nam(mon
));
2540 You_feel("raised to your full potential.");
2541 exercise(A_CON
, TRUE
);
2542 u
.uen
= (u
.uenmax
+= rnd(5));
2545 You_feel("good enough to do it again.");
2546 (void) adjattrib(A_CON
, 1, TRUE
);
2547 exercise(A_CON
, TRUE
);
2551 You("will always remember %s...", noit_mon_nam(mon
));
2552 (void) adjattrib(A_WIS
, 1, TRUE
);
2553 exercise(A_WIS
, TRUE
);
2557 pline("That was a very educational experience.");
2559 exercise(A_WIS
, TRUE
);
2562 You_feel("restored to health!");
2566 exercise(A_STR
, TRUE
);
2572 if (mon
->mtame
) { /* don't charge */
2574 } else if (rn2(20) < ACURR(A_CHA
)) {
2575 pline("%s demands that you pay %s, but you refuse...",
2576 noit_Monnam(mon
), Blind
? (fem
? "her" : "him") : mhim(mon
));
2577 } else if (u
.umonnum
== PM_LEPRECHAUN
) {
2578 pline("%s tries to take your money, but fails...", noit_Monnam(mon
));
2581 long umoney
= money_cnt(invent
);
2583 if (umoney
> (long) LARGEST_INT
- 10L)
2584 cost
= (long) rnd(LARGEST_INT
) + 500L;
2586 cost
= (long) rnd((int) umoney
+ 10) + 500L;
2587 if (mon
->mpeaceful
) {
2595 verbalize("It's on the house!");
2597 pline("%s takes %ld %s for services rendered!", noit_Monnam(mon
),
2598 cost
, currency(cost
));
2599 money2mon(mon
, cost
);
2604 mon
->mcan
= 1; /* monster is worn out */
2605 if (!tele_restrict(mon
))
2606 (void) rloc(mon
, TRUE
);
2612 register struct obj
*obj
;
2617 if (!obj
|| !obj
->owornmask
)
2620 if (rn2(20) < ACURR(A_CHA
)) {
2621 Sprintf(qbuf
, "\"Shall I remove your %s, %s?\"", str
,
2622 (!rn2(2) ? "lover" : !rn2(2) ? "dear" : "sweetheart"));
2623 if (yn(qbuf
) == 'n')
2626 char hairbuf
[BUFSZ
];
2628 Sprintf(hairbuf
, "let me run my fingers through your %s",
2630 verbalize("Take off your %s; %s.", str
,
2632 ? "let's get a little closer"
2633 : (obj
== uarmc
|| obj
== uarms
)
2636 ? "let me rub your feet"
2638 ? "they're too clumsy"
2640 ? "let me massage you"
2644 remove_worn_item(obj
, TRUE
);
2648 passiveum(olduasmon
, mtmp
, mattk
)
2649 struct permonst
*olduasmon
;
2650 register struct monst
*mtmp
;
2651 register struct attack
*mattk
;
2658 if (olduasmon
->mattk
[i
].aatyp
== AT_NONE
2659 || olduasmon
->mattk
[i
].aatyp
== AT_BOOM
)
2662 if (olduasmon
->mattk
[i
].damn
)
2664 d((int) olduasmon
->mattk
[i
].damn
, (int) olduasmon
->mattk
[i
].damd
);
2665 else if (olduasmon
->mattk
[i
].damd
)
2666 tmp
= d((int) olduasmon
->mlevel
+ 1, (int) olduasmon
->mattk
[i
].damd
);
2670 /* These affect the enemy even if you were "killed" (rehumanized) */
2671 switch (olduasmon
->mattk
[i
].adtyp
) {
2674 pline("%s is splashed by your %s!", Monnam(mtmp
), hliquid("acid"));
2675 if (resists_acid(mtmp
)) {
2676 pline("%s is not affected.", Monnam(mtmp
));
2682 erode_armor(mtmp
, ERODE_CORRODE
);
2684 acid_damage(MON_WEP(mtmp
));
2686 case AD_STON
: /* cockatrice */
2688 long protector
= attk_protection((int) mattk
->aatyp
),
2689 wornitems
= mtmp
->misc_worn_check
;
2691 /* wielded weapon gives same protection as gloves here */
2692 if (MON_WEP(mtmp
) != 0)
2693 wornitems
|= W_ARMG
;
2695 if (!resists_ston(mtmp
)
2697 || (protector
!= ~0L
2698 && (wornitems
& protector
) != protector
))) {
2699 if (poly_when_stoned(mtmp
->data
)) {
2703 pline("%s turns to stone!", Monnam(mtmp
));
2705 xkilled(mtmp
, XKILL_NOMSG
);
2712 case AD_ENCH
: /* KMH -- remove enchantment (disenchanter) */
2714 /* by_you==True: passive counterattack to hero's action
2716 (void) drain_item(otmp
, TRUE
);
2726 /* These affect the enemy only if you are still a monster */
2728 switch (youmonst
.data
->mattk
[i
].adtyp
) {
2730 if (youmonst
.data
->mattk
[i
].aatyp
== AT_BOOM
) {
2732 /* KMH, balance patch -- this is okay with unchanging */
2737 case AD_PLYS
: /* Floating eye */
2740 if (u
.umonnum
== PM_FLOATING_EYE
) {
2743 if (mtmp
->mcansee
&& haseyes(mtmp
->data
) && rn2(3)
2744 && (perceives(mtmp
->data
) || !Invis
)) {
2746 pline("As a blind %s, you cannot defend yourself.",
2747 youmonst
.data
->mname
);
2749 if (mon_reflects(mtmp
,
2750 "Your gaze is reflected by %s %s."))
2752 pline("%s is frozen by your gaze!", Monnam(mtmp
));
2753 paralyze_monst(mtmp
, tmp
);
2757 } else { /* gelatinous cube */
2758 pline("%s is frozen by you.", Monnam(mtmp
));
2759 paralyze_monst(mtmp
, tmp
);
2763 case AD_COLD
: /* Brown mold or blue jelly */
2764 if (resists_cold(mtmp
)) {
2765 shieldeff(mtmp
->mx
, mtmp
->my
);
2766 pline("%s is mildly chilly.", Monnam(mtmp
));
2767 golemeffects(mtmp
, AD_COLD
, tmp
);
2771 pline("%s is suddenly very cold!", Monnam(mtmp
));
2775 if (u
.mhmax
> ((youmonst
.data
->mlevel
+ 1) * 8))
2776 (void) split_mon(&youmonst
, mtmp
);
2778 case AD_STUN
: /* Yellow mold */
2781 pline("%s %s.", Monnam(mtmp
),
2782 makeplural(stagger(mtmp
->data
, "stagger")));
2786 case AD_FIRE
: /* Red mold */
2787 if (resists_fire(mtmp
)) {
2788 shieldeff(mtmp
->mx
, mtmp
->my
);
2789 pline("%s is mildly warm.", Monnam(mtmp
));
2790 golemeffects(mtmp
, AD_FIRE
, tmp
);
2794 pline("%s is suddenly very hot!", Monnam(mtmp
));
2797 if (resists_elec(mtmp
)) {
2798 shieldeff(mtmp
->mx
, mtmp
->my
);
2799 pline("%s is slightly tingled.", Monnam(mtmp
));
2800 golemeffects(mtmp
, AD_ELEC
, tmp
);
2804 pline("%s is jolted with your electricity!", Monnam(mtmp
));
2814 if ((mtmp
->mhp
-= tmp
) <= 0) {
2815 pline("%s dies!", Monnam(mtmp
));
2816 xkilled(mtmp
, XKILL_NOMSG
);
2827 register struct monst
*mon
;
2828 int mndx
= monsndx(youmonst
.data
);
2831 return (struct monst
*) 0;
2832 if (mvitals
[mndx
].mvflags
& G_EXTINCT
)
2833 return (struct monst
*) 0;
2834 mon
= makemon(youmonst
.data
, u
.ux
, u
.uy
, NO_MINVENT
| MM_EDOG
);
2838 mon
= christen_monst(mon
, plname
);
2840 mon
->m_lev
= youmonst
.data
->mlevel
;
2841 mon
->mhpmax
= u
.mhmax
;
2842 mon
->mhp
= u
.mh
/ 2;