1 /* aNetHack 0.0.1 uhitm.c $ANH-Date: 1470819843 2016/08/10 09:04:03 $ $ANH-Branch: master $:$ANH-Revision: 1.164 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* aNetHack may be freely redistributed. See license for details. */
7 STATIC_DCL boolean
FDECL(known_hitum
, (struct monst
*, struct obj
*, int *,
8 int, int, struct attack
*));
9 STATIC_DCL boolean
FDECL(theft_petrifies
, (struct obj
*));
10 STATIC_DCL
void FDECL(steal_it
, (struct monst
*, struct attack
*));
11 STATIC_DCL boolean
FDECL(hitum
, (struct monst
*, struct attack
*));
12 STATIC_DCL boolean
FDECL(hmon_hitmon
, (struct monst
*, struct obj
*, int));
13 STATIC_DCL
int FDECL(joust
, (struct monst
*, struct obj
*));
14 STATIC_DCL
void NDECL(demonpet
);
15 STATIC_DCL boolean
FDECL(m_slips_free
, (struct monst
* mtmp
,
16 struct attack
*mattk
));
17 STATIC_DCL
int FDECL(explum
, (struct monst
*, struct attack
*));
18 STATIC_DCL
void FDECL(start_engulf
, (struct monst
*));
19 STATIC_DCL
void NDECL(end_engulf
);
20 STATIC_DCL
int FDECL(gulpum
, (struct monst
*, struct attack
*));
21 STATIC_DCL boolean
FDECL(hmonas
, (struct monst
*));
22 STATIC_DCL
void FDECL(nohandglow
, (struct monst
*));
23 STATIC_DCL boolean
FDECL(shade_aware
, (struct obj
*));
25 extern boolean notonhead
; /* for long worms */
26 /* The below might become a parameter instead if we use it a lot */
28 /* Used to flag attacks caused by Stormbringer's maliciousness. */
29 static boolean override_confirmation
= FALSE
;
31 #define PROJECTILE(obj) ((obj) && is_ammo(obj))
34 erode_armor(mdef
, hurt
)
40 /* What the following code does: it keeps looping until it
41 * finds a target for the rust monster.
42 * Head, feet, etc... not covered by metal, or covered by
43 * rusty metal, are not targets. However, your body always
44 * is, no matter what covers it.
49 target
= which_armor(mdef
, W_ARMH
);
51 || erode_obj(target
, xname(target
), hurt
, EF_GREASE
)
56 target
= which_armor(mdef
, W_ARMC
);
58 (void) erode_obj(target
, xname(target
), hurt
,
59 EF_GREASE
| EF_VERBOSE
);
62 if ((target
= which_armor(mdef
, W_ARM
)) != (struct obj
*) 0) {
63 (void) erode_obj(target
, xname(target
), hurt
,
64 EF_GREASE
| EF_VERBOSE
);
65 } else if ((target
= which_armor(mdef
, W_ARMU
))
66 != (struct obj
*) 0) {
67 (void) erode_obj(target
, xname(target
), hurt
,
68 EF_GREASE
| EF_VERBOSE
);
72 target
= which_armor(mdef
, W_ARMS
);
74 || erode_obj(target
, xname(target
), hurt
, EF_GREASE
)
79 target
= which_armor(mdef
, W_ARMG
);
81 || erode_obj(target
, xname(target
), hurt
, EF_GREASE
)
86 target
= which_armor(mdef
, W_ARMF
);
88 || erode_obj(target
, xname(target
), hurt
, EF_GREASE
)
93 break; /* Out of while loop */
97 /* FALSE means it's OK to attack */
99 attack_checks(mtmp
, wep
)
100 register struct monst
*mtmp
;
101 struct obj
*wep
; /* uwep for attack(), null for kick_monster() */
105 /* if you're close enough to attack, alert any waiting monster */
106 mtmp
->mstrategy
&= ~STRAT_WAITMASK
;
108 if (u
.uswallow
&& mtmp
== u
.ustuck
)
111 if (context
.forcefight
) {
112 /* Do this in the caller, after we checked that the monster
113 * didn't die from the blow. Reason: putting the 'I' there
114 * causes the hero to forget the square's contents since
115 * both 'I' and remembered contents are stored in .glyph.
116 * If the monster dies immediately from the blow, the 'I' will
117 * not stay there, so the player will have suddenly forgotten
118 * the square's contents for no apparent reason.
119 if (!canspotmon(mtmp)
120 && !glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph))
121 map_invisible(bhitpos.x, bhitpos.y);
126 /* Put up an invisible monster marker, but with exceptions for
127 * monsters that hide and monsters you've been warned about.
128 * The former already prints a warning message and
129 * prevents you from hitting the monster just via the hidden monster
130 * code below; if we also did that here, similar behavior would be
131 * happening two turns in a row. The latter shows a glyph on
132 * the screen, so you know something is there.
134 if (!canspotmon(mtmp
) && !glyph_is_warning(glyph_at(bhitpos
.x
, bhitpos
.y
))
135 && !glyph_is_invisible(levl
[bhitpos
.x
][bhitpos
.y
].glyph
)
136 && !(!Blind
&& mtmp
->mundetected
&& hides_under(mtmp
->data
))) {
137 pline("Wait! There's %s there you can't see!", something
);
138 map_invisible(bhitpos
.x
, bhitpos
.y
);
139 /* if it was an invisible mimic, treat it as if we stumbled
140 * onto a visible mimic
142 if (mtmp
->m_ap_type
&& !Protection_from_shape_changers
143 /* applied pole-arm attack is too far to get stuck */
144 && distu(mtmp
->mx
, mtmp
->my
) <= 2) {
145 if (!u
.ustuck
&& !mtmp
->mflee
&& dmgtype(mtmp
->data
, AD_STCK
))
148 wakeup(mtmp
, TRUE
); /* always necessary; also un-mimics mimics */
152 if (mtmp
->m_ap_type
&& !Protection_from_shape_changers
&& !sensemon(mtmp
)
153 && !glyph_is_warning(glyph_at(bhitpos
.x
, bhitpos
.y
))) {
154 /* If a hidden mimic was in a square where a player remembers
155 * some (probably different) unseen monster, the player is in
156 * luck--he attacks it even though it's hidden.
158 if (glyph_is_invisible(levl
[mtmp
->mx
][mtmp
->my
].glyph
)) {
162 stumble_onto_mimic(mtmp
);
166 if (mtmp
->mundetected
&& !canseemon(mtmp
)
167 && !glyph_is_warning(glyph_at(bhitpos
.x
, bhitpos
.y
))
168 && (hides_under(mtmp
->data
) || mtmp
->data
->mlet
== S_EEL
)) {
169 mtmp
->mundetected
= mtmp
->msleeping
= 0;
170 newsym(mtmp
->mx
, mtmp
->my
);
171 if (glyph_is_invisible(levl
[mtmp
->mx
][mtmp
->my
].glyph
)) {
175 if (!((Blind
? Blind_telepat
: Unblind_telepat
) || Detect_monsters
)) {
178 if (Blind
|| (is_pool(mtmp
->mx
, mtmp
->my
) && !Underwater
))
179 pline("Wait! There's a hidden monster there!");
180 else if ((obj
= level
.objects
[mtmp
->mx
][mtmp
->my
]) != 0)
181 pline("Wait! There's %s hiding under %s!",
182 an(l_monnam(mtmp
)), doname(obj
));
188 * make sure to wake up a monster from the above cases if the
189 * hero can sense that the monster is there.
191 if ((mtmp
->mundetected
|| mtmp
->m_ap_type
) && sensemon(mtmp
)) {
192 mtmp
->mundetected
= 0;
196 if (flags
.confirm
&& mtmp
->mpeaceful
&& !Confusion
&& !Hallucination
198 /* Intelligent chaotic weapons (Stormbringer) want blood */
199 if (wep
&& wep
->oartifact
== ART_STORMBRINGER
) {
200 override_confirmation
= TRUE
;
203 if (canspotmon(mtmp
)) {
204 Sprintf(qbuf
, "Really attack %s?", mon_nam(mtmp
));
205 if (!paranoid_query(ParanoidHit
, qbuf
)) {
216 * It is unchivalrous for a knight to attack the defenseless or from behind.
222 if (u
.ualign
.record
<= -10)
225 if (Role_if(PM_KNIGHT
) && u
.ualign
.type
== A_LAWFUL
226 && (!mtmp
->mcanmove
|| mtmp
->msleeping
227 || (mtmp
->mflee
&& !mtmp
->mavenge
))) {
230 } else if (Role_if(PM_SAMURAI
) && mtmp
->mpeaceful
) {
231 /* attacking peaceful creatures is bad for the samurai's giri */
232 You("dishonorably attack the innocent!");
238 find_roll_to_hit(mtmp
, aatyp
, weapon
, attk_count
, role_roll_penalty
)
239 register struct monst
*mtmp
;
240 uchar aatyp
; /* usually AT_WEAP or AT_KICK */
241 struct obj
*weapon
; /* uwep or uswapwep or NULL */
242 int *attk_count
, *role_roll_penalty
;
246 *role_roll_penalty
= 0; /* default is `none' */
248 tmp
= 1 + Luck
+ abon() + find_mac(mtmp
) + u
.uhitinc
249 + maybe_polyd(youmonst
.data
->mlevel
, u
.ulevel
);
251 /* some actions should occur only once during multiple attacks */
252 if (!(*attk_count
)++) {
253 /* knight's chivalry or samurai's giri */
257 /* adjust vs. (and possibly modify) monster state */
263 if (mtmp
->msleeping
) {
267 if (!mtmp
->mcanmove
) {
275 /* role/race adjustments */
276 if (Role_if(PM_MONK
) && !Upolyd
) {
278 tmp
-= (*role_roll_penalty
= urole
.spelarmr
);
279 else if (!uwep
&& !uarms
)
280 tmp
+= (u
.ulevel
/ 3) + 2;
282 if (is_orc(mtmp
->data
)
283 && maybe_polyd(is_elf(youmonst
.data
), Race_if(PM_ELF
)))
286 /* encumbrance: with a lot of luggage, your agility diminishes */
287 if ((tmp2
= near_capacity()) != 0)
288 tmp
-= (tmp2
* 2) - 1;
293 * hitval applies if making a weapon attack while wielding a weapon;
294 * weapon_hit_bonus applies if doing a weapon attack even bare-handed
295 * or if kicking as martial artist
297 if (aatyp
== AT_WEAP
|| aatyp
== AT_CLAW
) {
299 tmp
+= hitval(weapon
, mtmp
);
300 tmp
+= weapon_hit_bonus(weapon
);
301 } else if (aatyp
== AT_KICK
&& martial_bonus()) {
302 tmp
+= weapon_hit_bonus((struct obj
*) 0);
308 /* try to attack; return False if monster evaded;
309 u.dx and u.dy must be set */
312 register struct monst
*mtmp
;
314 register struct permonst
*mdat
= mtmp
->data
;
316 /* This section of code provides protection against accidentally
317 * hitting peaceful (like '@') and tame (like 'd') monsters.
318 * Protection is provided as long as player is not: blind, confused,
319 * hallucinating or stunned.
320 * changes by wwp 5/16/85
321 * More changes 12/90, -dkh-. if its tame and safepet, (and protected
322 * 07/92) then we assume that you're not trying to attack. Instead,
323 * you'll usually just swap places if this is a movement command
325 /* Intelligent chaotic weapons (Stormbringer) want blood */
326 if (is_safepet(mtmp
) && !context
.forcefight
) {
327 if (!uwep
|| uwep
->oartifact
!= ART_STORMBRINGER
) {
328 /* there are some additional considerations: this won't work
329 * if in a shop or Punished or you miss a random roll or
330 * if you can walk thru walls and your pet cannot (KAA) or
331 * if your pet is a long worm (unless someone does better).
332 * there's also a chance of displacing a "frozen" monster.
333 * sleeping monsters might magically walk in their sleep.
335 boolean foo
= (Punished
|| !rn2(7) || is_longworm(mtmp
->data
)),
339 for (p
= in_rooms(mtmp
->mx
, mtmp
->my
, SHOPBASE
); *p
; p
++)
340 if (tended_shop(&rooms
[*p
- ROOMOFFSET
])) {
345 if (inshop
|| foo
|| (IS_ROCK(levl
[u
.ux
][u
.uy
].typ
)
346 && !passes_walls(mtmp
->data
))) {
349 monflee(mtmp
, rnd(6), FALSE
, FALSE
);
350 Strcpy(buf
, y_monnam(mtmp
));
351 buf
[0] = highc(buf
[0]);
352 You("stop. %s is in the way!", buf
);
353 context
.travel
= context
.travel1
= context
.mv
= context
.run
= 0;
355 } else if ((mtmp
->mfrozen
|| (!mtmp
->mcanmove
)
356 || (mtmp
->data
->mmove
== 0)) && rn2(6)) {
357 pline("%s doesn't seem to move!", Monnam(mtmp
));
358 context
.travel
= context
.travel1
= context
.mv
= context
.run
= 0;
365 /* possibly set in attack_checks;
366 examined in known_hitum, called via hitum or hmonas below */
367 override_confirmation
= FALSE
;
368 /* attack_checks() used to use <u.ux+u.dx,u.uy+u.dy> directly, now
369 it uses bhitpos instead; it might map an invisible monster there */
370 bhitpos
.x
= u
.ux
+ u
.dx
;
371 bhitpos
.y
= u
.uy
+ u
.dy
;
372 if (attack_checks(mtmp
, uwep
))
375 if (Upolyd
&& noattacks(youmonst
.data
)) {
376 /* certain "pacifist" monsters don't attack */
377 You("have no way to attack monsters physically.");
378 mtmp
->mstrategy
&= ~STRAT_WAITMASK
;
382 if (check_capacity("You cannot fight while so heavily loaded.")
383 /* consume extra nutrition during combat; maybe pass out */
387 if (u
.twoweap
&& !can_twoweapon())
394 You("begin bashing monsters with %s.",
395 yobjnam(uwep
, (char *) 0));
396 else if (!cantwield(youmonst
.data
))
397 You("begin %sing monsters with your %s %s.",
398 Role_if(PM_MONK
) ? "strik" : "bash",
399 uarmg
? "gloved" : "bare", /* Del Lamb */
400 makeplural(body_part(HAND
)));
403 exercise(A_STR
, TRUE
); /* you're exercising muscles */
404 /* andrew@orca: prevent unlimited pick-axe attacks */
407 /* Is the "it died" check actually correct? */
408 if (mdat
->mlet
== S_LEPRECHAUN
&& !mtmp
->mfrozen
&& !mtmp
->msleeping
409 && !mtmp
->mconf
&& mtmp
->mcansee
&& !rn2(7)
410 && (m_move(mtmp
, 0) == 2 /* it died */
411 || mtmp
->mx
!= u
.ux
+ u
.dx
412 || mtmp
->my
!= u
.uy
+ u
.dy
)) /* it moved */
418 (void) hitum(mtmp
, youmonst
.data
->mattk
);
419 mtmp
->mstrategy
&= ~STRAT_WAITMASK
;
422 /* see comment in attack_checks() */
423 /* we only need to check for this if we did an attack_checks()
424 * and it returned 0 (it's okay to attack), and the monster didn't
427 if (context
.forcefight
&& mtmp
->mhp
> 0 && !canspotmon(mtmp
)
428 && !glyph_is_invisible(levl
[u
.ux
+ u
.dx
][u
.uy
+ u
.dy
].glyph
)
429 && !(u
.uswallow
&& mtmp
== u
.ustuck
))
430 map_invisible(u
.ux
+ u
.dx
, u
.uy
+ u
.dy
);
435 /* really hit target monster; returns TRUE if it still lives */
437 known_hitum(mon
, weapon
, mhit
, rollneeded
, armorpenalty
, uattk
)
438 register struct monst
*mon
;
441 int rollneeded
, armorpenalty
; /* for monks */
442 struct attack
*uattk
;
444 register boolean malive
= TRUE
;
446 if (override_confirmation
) {
447 /* this may need to be generalized if weapons other than
448 Stormbringer acquire similar anti-social behavior... */
450 Your("bloodthirsty blade attacks!");
454 missum(mon
, uattk
, (rollneeded
+ armorpenalty
> dieroll
));
456 int oldhp
= mon
->mhp
, x
= u
.ux
+ u
.dx
, y
= u
.uy
+ u
.dy
;
457 long oldweaphit
= u
.uconduct
.weaphit
;
460 if (weapon
&& (weapon
->oclass
== WEAPON_CLASS
|| is_weptool(weapon
)))
461 u
.uconduct
.weaphit
++;
463 /* we hit the monster; be careful: it might die or
464 be knocked into a different location */
465 notonhead
= (mon
->mx
!= x
|| mon
->my
!= y
);
466 malive
= hmon(mon
, weapon
, HMON_MELEE
);
468 /* monster still alive */
469 if (!rn2(25) && mon
->mhp
< mon
->mhpmax
/ 2
470 && !(u
.uswallow
&& mon
== u
.ustuck
)) {
471 /* maybe should regurgitate if swallowed? */
472 monflee(mon
, !rn2(3) ? rnd(100) : 0, FALSE
, TRUE
);
474 if (u
.ustuck
== mon
&& !u
.uswallow
&& !sticks(youmonst
.data
))
477 /* Vorpal Blade hit converted to miss */
478 /* could be headless monster or worm tail */
479 if (mon
->mhp
== oldhp
) {
481 /* a miss does not break conduct */
482 u
.uconduct
.weaphit
= oldweaphit
;
484 if (mon
->wormno
&& *mhit
)
485 cutworm(mon
, x
, y
, weapon
);
491 /* hit target monster; returns TRUE if it still lives */
495 struct attack
*uattk
;
497 boolean malive
, wep_was_destroyed
= FALSE
;
498 struct obj
*wepbefore
= uwep
;
499 int armorpenalty
, attknum
= 0, x
= u
.ux
+ u
.dx
, y
= u
.uy
+ u
.dy
,
500 tmp
= find_roll_to_hit(mon
, uattk
->aatyp
, uwep
,
501 &attknum
, &armorpenalty
);
502 int mhit
= (tmp
> (dieroll
= rnd(20)) || u
.uswallow
);
505 exercise(A_DEX
, TRUE
);
506 malive
= known_hitum(mon
, uwep
, &mhit
, tmp
, armorpenalty
, uattk
);
507 /* second attack for two-weapon combat; won't occur if Stormbringer
508 overrode confirmation (assumes Stormbringer is primary weapon)
509 or if the monster was killed or knocked to different location */
510 if (u
.twoweap
&& !override_confirmation
&& malive
&& m_at(x
, y
) == mon
) {
511 tmp
= find_roll_to_hit(mon
, uattk
->aatyp
, uswapwep
, &attknum
,
513 mhit
= (tmp
> (dieroll
= rnd(20)) || u
.uswallow
);
514 malive
= known_hitum(mon
, uswapwep
, &mhit
, tmp
, armorpenalty
, uattk
);
516 if (wepbefore
&& !uwep
)
517 wep_was_destroyed
= TRUE
;
518 (void) passive(mon
, mhit
, malive
, AT_WEAP
, wep_was_destroyed
);
522 /* general "damage monster" routine; return True if mon still alive */
524 hmon(mon
, obj
, thrown
)
527 int thrown
; /* HMON_xxx (0 => hand-to-hand, other => ranged) */
529 boolean result
, anger_guards
;
531 anger_guards
= (mon
->mpeaceful
532 && (mon
->ispriest
|| mon
->isshk
|| is_watch(mon
->data
)));
533 result
= hmon_hitmon(mon
, obj
, thrown
);
534 if (mon
->ispriest
&& !rn2(2))
537 (void) angry_guards(!!Deaf
);
543 hmon_hitmon(mon
, obj
, thrown
)
546 int thrown
; /* HMON_xxx (0 => hand-to-hand, other => ranged) */
549 struct permonst
*mdat
= mon
->data
;
550 int barehand_silver_rings
= 0;
551 /* The basic reason we need all these booleans is that we don't want
552 * a "hit" message when a monster dies, so we have to know how much
553 * damage it did _before_ outputting a hit message, but any messages
554 * associated with the damage don't come out until _after_ outputting
557 boolean hittxt
= FALSE
, destroyed
= FALSE
, already_killed
= FALSE
;
558 boolean get_dmg_bonus
= TRUE
;
559 boolean ispoisoned
= FALSE
, needpoismsg
= FALSE
, poiskilled
= FALSE
,
561 boolean silvermsg
= FALSE
, silverobj
= FALSE
;
562 boolean valid_weapon_attack
= FALSE
;
563 boolean unarmed
= !uwep
&& !uarm
&& !uarms
;
564 boolean hand_to_hand
= (thrown
== HMON_MELEE
565 /* not grapnels; applied implies uwep */
566 || (thrown
== HMON_APPLIED
&& is_pole(uwep
)));
570 char unconventional
[BUFSZ
]; /* substituted for word "attack" in msg */
571 char saved_oname
[BUFSZ
];
573 unconventional
[0] = '\0';
574 saved_oname
[0] = '\0';
577 if (!obj
) { /* attack with bare hands */
578 if (mdat
== &mons
[PM_SHADE
])
580 else if (martial_bonus())
581 tmp
= rnd(4); /* bonus for martial arts */
584 valid_weapon_attack
= (tmp
> 1);
585 /* blessed gloves give bonuses when fighting 'bare-handed' */
586 if (uarmg
&& uarmg
->blessed
587 && (is_undead(mdat
) || is_demon(mdat
) || is_vampshifter(mon
)))
589 /* So do silver rings. Note: rings are worn under gloves, so you
590 * don't get both bonuses.
593 if (uleft
&& objects
[uleft
->otyp
].oc_material
== SILVER
)
594 barehand_silver_rings
++;
595 if (uright
&& objects
[uright
->otyp
].oc_material
== SILVER
)
596 barehand_silver_rings
++;
597 if (barehand_silver_rings
&& mon_hates_silver(mon
)) {
603 Strcpy(saved_oname
, cxname(obj
));
604 if (obj
->oclass
== WEAPON_CLASS
|| is_weptool(obj
)
605 || obj
->oclass
== GEM_CLASS
) {
606 /* is it not a melee weapon? */
607 if (/* if you strike with a bow... */
609 /* or strike with a missile in your hand... */
610 || (!thrown
&& (is_missile(obj
) || is_ammo(obj
)))
611 /* or use a pole at short range and not mounted... */
612 || (!thrown
&& !u
.usteed
&& is_pole(obj
))
613 /* or throw a missile without the proper bow... */
614 || (is_ammo(obj
) && (thrown
!= HMON_THROWN
615 || !ammo_and_launcher(obj
, uwep
)))) {
616 /* then do only 1-2 points of damage */
617 if (mdat
== &mons
[PM_SHADE
] && !shade_glare(obj
))
621 if (objects
[obj
->otyp
].oc_material
== SILVER
622 && mon_hates_silver(mon
)) {
625 /* if it will already inflict dmg, make it worse */
626 tmp
+= rnd((tmp
) ? 20 : 10);
628 if (!thrown
&& obj
== uwep
&& obj
->otyp
== BOOMERANG
629 && rnl(4) == 4 - 1) {
630 boolean more_than_1
= (obj
->quan
> 1L);
632 pline("As you hit %s, %s%s breaks into splinters.",
633 mon_nam(mon
), more_than_1
? "one of " : "",
636 uwepgone(); /* set unweapon */
639 obj
= (struct obj
*) 0;
641 if (mdat
!= &mons
[PM_SHADE
])
645 tmp
= dmgval(obj
, mon
);
646 /* a minimal hit doesn't exercise proficiency */
647 valid_weapon_attack
= (tmp
> 1);
648 if (!valid_weapon_attack
|| mon
== u
.ustuck
|| u
.twoweap
) {
649 ; /* no special bonuses */
650 } else if (mon
->mflee
&& Role_if(PM_ROGUE
) && !Upolyd
651 /* multi-shot throwing is too powerful here */
653 You("strike %s from behind!", mon_nam(mon
));
654 tmp
+= rnd(u
.ulevel
);
656 } else if (dieroll
== 2 && obj
== uwep
657 && obj
->oclass
== WEAPON_CLASS
659 || (Role_if(PM_SAMURAI
) && obj
->otyp
== KATANA
661 && ((wtype
= uwep_skill_type()) != P_NONE
662 && P_SKILL(wtype
) >= P_SKILLED
)
663 && ((monwep
= MON_WEP(mon
)) != 0
664 && !is_flimsy(monwep
)
665 && !obj_resists(monwep
,
666 50 + 15 * (greatest_erosion(obj
)
667 - greatest_erosion(monwep
)),
670 * 2.5% chance of shattering defender's weapon when
671 * using a two-handed weapon; less if uwep is rusted.
672 * [dieroll == 2 is most successful non-beheading or
673 * -bisecting hit, in case of special artifact damage;
674 * the percentage chance is (1/20)*(50/100).]
675 * If attacker's weapon is rustier than defender's,
676 * the obj_resists chance is increased so the shatter
677 * chance is decreased; if less rusty, then vice versa.
679 setmnotwielded(mon
, monwep
);
680 mon
->weapon_check
= NEED_WEAPON
;
681 pline("%s from the force of your blow!",
682 Yobjnam2(monwep
, "shatter"));
683 m_useupall(mon
, monwep
);
684 /* If someone just shattered MY weapon, I'd flee! */
686 monflee(mon
, d(2, 3), TRUE
, TRUE
);
692 && artifact_hit(&youmonst
, mon
, obj
, &tmp
, dieroll
)) {
693 if (mon
->mhp
<= 0) /* artifact killed monster */
699 if (objects
[obj
->otyp
].oc_material
== SILVER
700 && mon_hates_silver(mon
)) {
704 if (u
.usteed
&& !thrown
&& tmp
> 0
705 && weapon_type(obj
) == P_LANCE
&& mon
!= u
.ustuck
) {
706 jousting
= joust(mon
, obj
);
707 /* exercise skill even for minimal damage hits */
709 valid_weapon_attack
= TRUE
;
711 if (thrown
== HMON_THROWN
712 && (is_ammo(obj
) || is_missile(obj
))) {
713 if (ammo_and_launcher(obj
, uwep
)) {
714 /* Elves and Samurai do extra damage using
715 * their bows&arrows; they're highly trained.
717 if (Role_if(PM_SAMURAI
) && obj
->otyp
== YA
718 && uwep
->otyp
== YUMI
)
720 else if (Race_if(PM_ELF
) && obj
->otyp
== ELVEN_ARROW
721 && uwep
->otyp
== ELVEN_BOW
)
724 if (obj
->opoisoned
&& is_poisonable(obj
))
728 } else if (obj
->oclass
== POTION_CLASS
) {
730 obj
= splitobj(obj
, 1L);
732 setuwep((struct obj
*) 0);
734 potionhit(mon
, obj
, TRUE
);
736 return FALSE
; /* killed */
738 /* in case potion effect causes transformation */
740 tmp
= (mdat
== &mons
[PM_SHADE
]) ? 0 : 1;
742 if (mdat
== &mons
[PM_SHADE
] && !shade_aware(obj
)) {
744 Strcpy(unconventional
, cxname(obj
));
747 case BOULDER
: /* 1d20 */
748 case HEAVY_IRON_BALL
: /* 1d25 */
749 case IRON_CHAIN
: /* 1d4+1 */
750 tmp
= dmgval(obj
, mon
);
753 if (breaktest(obj
)) {
754 You("break %s. That's bad luck!", ysimple_name(obj
));
757 obj
= (struct obj
*) 0;
758 unarmed
= FALSE
; /* avoid obj==0 confusion */
759 get_dmg_bonus
= FALSE
;
764 case EXPENSIVE_CAMERA
:
765 You("succeed in destroying %s. Congratulations!",
767 release_camera_demon(obj
, u
.ux
, u
.uy
);
770 case CORPSE
: /* fixed by polder@cs.vu.nl */
771 if (touch_petrifies(&mons
[obj
->corpsenm
])) {
774 You("hit %s with %s.", mon_nam(mon
),
775 corpse_xname(obj
, (const char *) 0,
776 obj
->dknown
? CXN_PFX_THE
779 if (!munstone(mon
, TRUE
))
780 minstapetrify(mon
, TRUE
);
781 if (resists_ston(mon
))
783 /* note: hp may be <= 0 even if munstoned==TRUE */
784 return (boolean
) (mon
->mhp
> 0);
786 } else if (touch_petrifies(mdat
)) {
787 ; /* maybe turn the corpse into a statue? */
790 tmp
= (obj
->corpsenm
>= LOW_PM
? mons
[obj
->corpsenm
].msize
794 #define useup_eggs(o) \
797 obfree(o, (struct obj *) 0); \
800 o = (struct obj *) 0; \
803 long cnt
= obj
->quan
;
805 tmp
= 1; /* nominal physical damage */
806 get_dmg_bonus
= FALSE
;
807 hittxt
= TRUE
; /* message always given */
808 /* egg is always either used up or transformed, so next
809 hand-to-hand attack should yield a "bashing" mesg */
812 if (obj
->spe
&& obj
->corpsenm
>= LOW_PM
) {
814 change_luck((schar
) - (obj
->quan
));
819 if (touch_petrifies(&mons
[obj
->corpsenm
])) {
820 /*learn_egg_type(obj->corpsenm);*/
821 pline("Splat! You hit %s with %s %s egg%s!",
823 obj
->known
? "the" : cnt
> 1L ? "some" : "a",
824 obj
->known
? mons
[obj
->corpsenm
].mname
827 obj
->known
= 1; /* (not much point...) */
829 if (!munstone(mon
, TRUE
))
830 minstapetrify(mon
, TRUE
);
831 if (resists_ston(mon
))
833 return (boolean
) (mon
->mhp
> 0);
834 } else { /* ordinary egg(s) */
836 (obj
->corpsenm
!= NON_PM
&& obj
->known
)
837 ? the(mons
[obj
->corpsenm
].mname
)
838 : (cnt
> 1L) ? "some" : "an";
839 You("hit %s with %s egg%s.", mon_nam(mon
), eggp
,
841 if (touch_petrifies(mdat
) && !stale_egg(obj
)) {
842 pline_The("egg%s %s alive any more...", plur(cnt
),
843 (cnt
== 1L) ? "isn't" : "aren't");
845 obj_stop_timers(obj
);
847 obj
->oclass
= GEM_CLASS
;
850 obj
->known
= obj
->dknown
= obj
->bknown
= 0;
851 obj
->owt
= weight(obj
);
853 place_object(obj
, mon
->mx
, mon
->my
);
857 exercise(A_WIS
, FALSE
);
863 case CLOVE_OF_GARLIC
: /* no effect against demons */
864 if (is_undead(mdat
) || is_vampshifter(mon
)) {
865 monflee(mon
, d(2, 4), FALSE
, TRUE
);
872 if (can_blnd(&youmonst
, mon
,
873 (uchar
) (obj
->otyp
== BLINDING_VENOM
878 pline(obj
->otyp
== CREAM_PIE
? "Splat!"
880 } else if (obj
->otyp
== BLINDING_VENOM
) {
881 pline_The("venom blinds %s%s!", mon_nam(mon
),
882 mon
->mcansee
? "" : " further");
884 char *whom
= mon_nam(mon
);
885 char *what
= The(xname(obj
));
887 if (!thrown
&& obj
->quan
> 1L)
888 what
= An(singular(obj
, xname
));
889 /* note: s_suffix returns a modifiable buffer */
891 && mdat
!= &mons
[PM_FLOATING_EYE
])
892 whom
= strcat(strcat(s_suffix(whom
), " "),
893 mbodypart(mon
, FACE
));
894 pline("%s %s over %s!", what
,
895 vtense(what
, "splash"), whom
);
897 setmangry(mon
, TRUE
);
900 if (((int) mon
->mblinded
+ tmp
) > 127)
903 mon
->mblinded
+= tmp
;
905 pline(obj
->otyp
== CREAM_PIE
? "Splat!" : "Splash!");
906 setmangry(mon
, TRUE
);
909 obfree(obj
, (struct obj
*) 0);
913 get_dmg_bonus
= FALSE
;
916 case ACID_VENOM
: /* thrown (or spit) */
917 if (resists_acid(mon
)) {
918 Your("venom hits %s harmlessly.", mon_nam(mon
));
921 Your("venom burns %s!", mon_nam(mon
));
922 tmp
= dmgval(obj
, mon
);
925 obfree(obj
, (struct obj
*) 0);
929 get_dmg_bonus
= FALSE
;
932 /* non-weapons can damage because of their weight */
933 /* (but not too much) */
934 tmp
= obj
->owt
/ 100;
935 if (is_wet_towel(obj
)) {
936 /* wielded wet towel should probably use whip skill
937 (but not by setting objects[TOWEL].oc_skill==P_WHIP
938 because that would turn towel into a weptool) */
940 if (rn2(obj
->spe
+ 1)) /* usually lose some wetness */
941 dry_a_towel(obj
, -1, TRUE
);
950 * Things like silver wands can arrive here so
951 * so we need another silver check.
953 if (objects
[obj
->otyp
].oc_material
== SILVER
954 && mon_hates_silver(mon
)) {
964 /****** NOTE: perhaps obj is undefined!! (if !thrown && BOOMERANG)
965 * *OR* if attacking bare-handed!! */
967 if (get_dmg_bonus
&& tmp
> 0) {
969 /* If you throw using a propellor, you don't get a strength
970 * bonus but you do get an increase-damage bonus.
972 if (thrown
!= HMON_THROWN
|| !obj
|| !uwep
973 || !ammo_and_launcher(obj
, uwep
))
977 if (valid_weapon_attack
) {
980 /* to be valid a projectile must have had the correct projector */
981 wep
= PROJECTILE(obj
) ? uwep
: obj
;
982 tmp
+= weapon_dam_bonus(wep
);
983 /* [this assumes that `!thrown' implies wielded...] */
984 wtype
= thrown
? weapon_type(wep
) : uwep_skill_type();
989 int nopoison
= (10 - (obj
->owt
/ 10));
993 if (Role_if(PM_SAMURAI
)) {
994 You("dishonorably use a poisoned weapon!");
995 adjalign(-sgn(u
.ualign
.type
));
996 } else if (u
.ualign
.type
== A_LAWFUL
&& u
.ualign
.record
> -10) {
997 You_feel("like an evil coward for using a poisoned weapon.");
1000 if (obj
&& !rn2(nopoison
)) {
1001 /* remove poison now in case obj ends up in a bones file */
1002 obj
->opoisoned
= FALSE
;
1003 /* defer "obj is no longer poisoned" until after hit message */
1006 if (resists_poison(mon
))
1014 /* make sure that negative damage adjustment can't result
1015 in inadvertently boosting the victim's hit points */
1017 if (mdat
== &mons
[PM_SHADE
]) {
1019 const char *what
= *unconventional
? unconventional
: "attack";
1021 Your("%s %s harmlessly through %s.", what
,
1022 vtense(what
, "pass"), mon_nam(mon
));
1032 tmp
+= d(2, (obj
== uwep
) ? 10 : 2); /* [was in dmgval()] */
1033 You("joust %s%s", mon_nam(mon
), canseemon(mon
) ? exclam(tmp
) : ".");
1035 pline("%s shatters on impact!", Yname2(obj
));
1036 /* (must be either primary or secondary weapon to get here) */
1037 u
.twoweap
= FALSE
; /* untwoweapon() is too verbose here */
1039 uwepgone(); /* set unweapon */
1040 /* minor side-effect: broken lance won't split puddings */
1044 /* avoid migrating a dead monster */
1045 if (mon
->mhp
> tmp
) {
1046 mhurtle(mon
, u
.dx
, u
.dy
, 1);
1047 mdat
= mon
->data
; /* in case of a polymorph trap */
1048 if (DEADMONSTER(mon
))
1049 already_killed
= TRUE
;
1052 } else if (unarmed
&& tmp
> 1 && !thrown
&& !obj
&& !Upolyd
) {
1053 /* VERY small chance of stunning opponent if unarmed. */
1054 if (rnd(100) < P_SKILL(P_BARE_HANDED_COMBAT
) && !bigmonst(mdat
)
1055 && !thick_skinned(mdat
)) {
1056 if (canspotmon(mon
))
1057 pline("%s %s from your powerful strike!", Monnam(mon
),
1058 makeplural(stagger(mon
->data
, "stagger")));
1059 /* avoid migrating a dead monster */
1060 if (mon
->mhp
> tmp
) {
1061 mhurtle(mon
, u
.dx
, u
.dy
, 1);
1062 mdat
= mon
->data
; /* in case of a polymorph trap */
1063 if (DEADMONSTER(mon
))
1064 already_killed
= TRUE
;
1070 if (!already_killed
)
1072 /* adjustments might have made tmp become less than what
1073 a level draining artifact has already done to max HP */
1074 if (mon
->mhp
> mon
->mhpmax
)
1075 mon
->mhp
= mon
->mhpmax
;
1078 if (mon
->mtame
&& tmp
> 0) {
1079 /* do this even if the pet is being killed (affects revival) */
1080 abuse_dog(mon
); /* reduces tameness */
1081 /* flee if still alive and still tame; if already suffering from
1082 untimed fleeing, no effect, otherwise increases timed fleeing */
1083 if (mon
->mtame
&& !destroyed
)
1084 monflee(mon
, 10 * rnd(tmp
), FALSE
, FALSE
);
1086 if ((mdat
== &mons
[PM_BLACK_PUDDING
] || mdat
== &mons
[PM_BROWN_PUDDING
])
1087 /* pudding is alive and healthy enough to split */
1088 && mon
->mhp
> 1 && !mon
->mcan
1089 /* iron weapon using melee or polearm hit [3.6.1: metal weapon too] */
1090 && obj
&& obj
== uwep
1091 && ((objects
[obj
->otyp
].oc_material
== IRON
1092 /* allow scalpel and tsurugi to split puddings */
1093 || objects
[obj
->otyp
].oc_material
== METAL
)
1094 /* but not bashing with darts, arrows or ya */
1095 && !(is_ammo(obj
) || is_missile(obj
)))
1097 if (clone_mon(mon
, 0, 0)) {
1098 pline("%s divides as you hit it!", Monnam(mon
));
1103 if (!hittxt
/*( thrown => obj exists )*/
1105 || (thrown
&& m_shot
.n
> 1 && m_shot
.o
== obj
->otyp
))) {
1107 hit(mshot_xname(obj
), mon
, exclam(tmp
));
1108 else if (!flags
.verbose
)
1111 You("%s %s%s", Role_if(PM_BARBARIAN
) ? "smite" : "hit",
1112 mon_nam(mon
), canseemon(mon
) ? exclam(tmp
) : ".");
1117 char *whom
= mon_nam(mon
);
1118 char silverobjbuf
[BUFSZ
];
1120 if (canspotmon(mon
)) {
1121 if (barehand_silver_rings
== 1)
1122 fmt
= "Your silver ring sears %s!";
1123 else if (barehand_silver_rings
== 2)
1124 fmt
= "Your silver rings sear %s!";
1125 else if (silverobj
&& saved_oname
[0]) {
1126 Sprintf(silverobjbuf
, "Your %s%s %s %%s!",
1127 strstri(saved_oname
, "silver") ? "" : "silver ",
1128 saved_oname
, vtense(saved_oname
, "sear"));
1131 fmt
= "The silver sears %s!";
1133 *whom
= highc(*whom
); /* "it" -> "It" */
1134 fmt
= "%s is seared!";
1136 /* note: s_suffix returns a modifiable buffer */
1137 if (!noncorporeal(mdat
) && !amorphous(mdat
))
1138 whom
= strcat(s_suffix(whom
), " flesh");
1141 /* if a "no longer poisoned" message is coming, it will be last;
1142 obj->opoisoned was cleared above and any message referring to
1143 "poisoned <obj>" has now been given; we want just "<obj>" for
1144 last message, so reformat while obj is still accessible */
1146 Strcpy(saved_oname
, cxname(obj
));
1148 /* [note: thrown obj might go away during killed/xkilled call] */
1151 pline_The("poison doesn't seem to affect %s.", mon_nam(mon
));
1153 pline_The("poison was deadly...");
1154 if (!already_killed
)
1155 xkilled(mon
, XKILL_NOMSG
);
1156 destroyed
= TRUE
; /* return FALSE; */
1157 } else if (destroyed
) {
1158 if (!already_killed
)
1159 killed(mon
); /* takes care of most messages */
1160 } else if (u
.umconf
&& hand_to_hand
) {
1162 if (!mon
->mconf
&& !resist(mon
, SPBOOK_CLASS
, 0, NOTELL
)) {
1164 if (!mon
->mstun
&& mon
->mcanmove
&& !mon
->msleeping
1166 pline("%s appears confused.", Monnam(mon
));
1170 Your("%s %s no longer poisoned.", saved_oname
,
1171 vtense(saved_oname
, "are"));
1173 return destroyed
? FALSE
: TRUE
;
1183 * The things in this list either
1186 * 2) are dealt with properly by other routines
1187 * when it comes to shades.
1189 if (obj
->otyp
== BOULDER
1190 || obj
->otyp
== HEAVY_IRON_BALL
1191 || obj
->otyp
== IRON_CHAIN
/* dmgval handles those first three */
1192 || obj
->otyp
== MIRROR
/* silver in the reflective surface */
1193 || obj
->otyp
== CLOVE_OF_GARLIC
/* causes shades to flee */
1194 || objects
[obj
->otyp
].oc_material
== SILVER
)
1199 /* check whether slippery clothing protects from hug or wrap attack */
1200 /* [currently assumes that you are the attacker] */
1202 m_slips_free(mdef
, mattk
)
1204 struct attack
*mattk
;
1208 if (mattk
->adtyp
== AD_DRIN
) {
1209 /* intelligence drain attacks the head */
1210 obj
= which_armor(mdef
, W_ARMH
);
1212 /* grabbing attacks the body */
1213 obj
= which_armor(mdef
, W_ARMC
); /* cloak */
1215 obj
= which_armor(mdef
, W_ARM
); /* suit */
1217 obj
= which_armor(mdef
, W_ARMU
); /* shirt */
1220 /* if monster's cloak/armor is greased, your grab slips off; this
1221 protection might fail (33% chance) when the armor is cursed */
1222 if (obj
&& (obj
->greased
|| obj
->otyp
== OILSKIN_CLOAK
)
1223 && (!obj
->cursed
|| rn2(3))) {
1225 mattk
->adtyp
== AD_WRAP
? "slip off of"
1226 : "grab, but cannot hold onto",
1227 s_suffix(mon_nam(mdef
)), obj
->greased
? "greased" : "slippery",
1228 /* avoid "slippery slippery cloak"
1229 for undiscovered oilskin cloak */
1230 (obj
->greased
|| objects
[obj
->otyp
].oc_name_known
)
1232 : cloak_simple_name(obj
));
1234 if (obj
->greased
&& !rn2(2)) {
1235 pline_The("grease wears off.");
1243 /* used when hitting a monster with a lance while mounted;
1244 1: joust hit; 0: ordinary hit; -1: joust but break lance */
1247 struct monst
*mon
; /* target */
1248 struct obj
*obj
; /* weapon */
1250 int skill_rating
, joust_dieroll
;
1252 if (Fumbling
|| Stunned
)
1254 /* sanity check; lance must be wielded in order to joust */
1255 if (obj
!= uwep
&& (obj
!= uswapwep
|| !u
.twoweap
))
1258 /* if using two weapons, use worse of lance and two-weapon skills */
1259 skill_rating
= P_SKILL(weapon_type(obj
)); /* lance skill */
1260 if (u
.twoweap
&& P_SKILL(P_TWO_WEAPON_COMBAT
) < skill_rating
)
1261 skill_rating
= P_SKILL(P_TWO_WEAPON_COMBAT
);
1262 if (skill_rating
== P_ISRESTRICTED
)
1263 skill_rating
= P_UNSKILLED
; /* 0=>1 */
1265 /* odds to joust are expert:80%, skilled:60%, basic:40%, unskilled:20% */
1266 if ((joust_dieroll
= rn2(5)) < skill_rating
) {
1267 if (joust_dieroll
== 0 && rnl(50) == (50 - 1) && !unsolid(mon
->data
)
1268 && !obj_resists(obj
, 0, 100))
1269 return -1; /* hit that breaks lance */
1270 return 1; /* successful joust */
1272 return 0; /* no joust bonus; revert to ordinary attack */
1276 * Send in a demon pet for the hero. Exercise wisdom.
1278 * This function used to be inline to damageum(), but the Metrowerks compiler
1279 * (DR4 and DR4.5) screws up with an internal error 5 "Expression Too
1281 * Pulling it out makes it work.
1287 struct permonst
*pm
;
1290 pline("Some hell-p has arrived!");
1291 i
= !rn2(6) ? ndemon(u
.ualign
.type
) : NON_PM
;
1292 pm
= i
!= NON_PM
? &mons
[i
] : youmonst
.data
;
1293 if ((dtmp
= makemon(pm
, u
.ux
, u
.uy
, NO_MM_FLAGS
)) != 0)
1294 (void) tamedog(dtmp
, (struct obj
*) 0);
1295 exercise(A_WIS
, TRUE
);
1299 theft_petrifies(otmp
)
1302 if (uarmg
|| otmp
->otyp
!= CORPSE
1303 || !touch_petrifies(&mons
[otmp
->corpsenm
]) || Stone_resistance
)
1306 #if 0 /* no poly_when_stoned() critter has theft capability */
1307 if (poly_when_stoned(youmonst
.data
) && polymon(PM_STONE_GOLEM
)) {
1308 display_nhwindow(WIN_MESSAGE
, FALSE
); /* --More-- */
1313 /* stealing this corpse is fatal... */
1314 instapetrify(corpse_xname(otmp
, "stolen", CXN_ARTICLE
));
1315 /* apparently wasn't fatal after all... */
1320 * Player uses theft attack against monster.
1322 * If the target is wearing body armor, take all of its possessions;
1323 * otherwise, take one object. [Is this really the behavior we want?]
1326 steal_it(mdef
, mattk
)
1328 struct attack
*mattk
;
1330 struct obj
*otmp
, *stealoid
, **minvent_ptr
;
1334 return; /* nothing to take */
1336 /* look for worn body armor */
1337 stealoid
= (struct obj
*) 0;
1338 if (could_seduce(&youmonst
, mdef
, mattk
)) {
1339 /* find armor, and move it to end of inventory in the process */
1340 minvent_ptr
= &mdef
->minvent
;
1341 while ((otmp
= *minvent_ptr
) != 0)
1342 if (otmp
->owornmask
& W_ARM
) {
1344 panic("steal_it: multiple worn suits");
1345 *minvent_ptr
= otmp
->nobj
; /* take armor out of minvent */
1347 stealoid
->nobj
= (struct obj
*) 0;
1349 minvent_ptr
= &otmp
->nobj
;
1351 *minvent_ptr
= stealoid
; /* put armor back into minvent */
1354 if (stealoid
) { /* we will be taking everything */
1355 if (gender(mdef
) == (int) u
.mfemale
&& youmonst
.data
->mlet
== S_NYMPH
)
1356 You("charm %s. She gladly hands over her possessions.",
1359 You("seduce %s and %s starts to take off %s clothes.",
1360 mon_nam(mdef
), mhe(mdef
), mhis(mdef
));
1363 while ((otmp
= mdef
->minvent
) != 0) {
1365 break; /* no longer have ability to steal */
1366 /* take the object away from the monster */
1367 obj_extract_self(otmp
);
1368 if ((unwornmask
= otmp
->owornmask
) != 0L) {
1369 mdef
->misc_worn_check
&= ~unwornmask
;
1370 if (otmp
->owornmask
& W_WEP
)
1371 setmnotwielded(mdef
, otmp
);
1372 otmp
->owornmask
= 0L;
1373 update_mon_intrinsics(mdef
, otmp
, FALSE
, FALSE
);
1375 if (otmp
== stealoid
) /* special message for final item */
1376 pline("%s finishes taking off %s suit.", Monnam(mdef
),
1379 /* give the object to the character */
1380 otmp
= hold_another_object(otmp
, "You snatched but dropped %s.",
1381 doname(otmp
), "You steal: ");
1382 if (otmp
->where
!= OBJ_INVENT
)
1384 if (theft_petrifies(otmp
))
1385 break; /* stop thieving even though hero survived */
1386 /* more take-away handling, after theft message */
1387 if (unwornmask
& W_WEP
) { /* stole wielded weapon */
1388 possibly_unwield(mdef
, FALSE
);
1389 } else if (unwornmask
& W_ARMG
) { /* stole worn gloves */
1390 mselftouch(mdef
, (const char *) 0, TRUE
);
1391 if (mdef
->mhp
<= 0) /* it's now a statue */
1392 return; /* can't continue stealing */
1396 break; /* only taking one item */
1401 damageum(mdef
, mattk
)
1402 register struct monst
*mdef
;
1403 register struct attack
*mattk
;
1405 register struct permonst
*pd
= mdef
->data
;
1406 int armpro
, tmp
= d((int) mattk
->damn
, (int) mattk
->damd
);
1409 armpro
= magic_negation(mdef
);
1410 /* since hero can't be cancelled, only defender's armor applies */
1411 negated
= !(rn2(10) >= 3 * armpro
);
1413 if (is_demon(youmonst
.data
) && !rn2(13) && !uwep
1414 && u
.umonnum
!= PM_SUCCUBUS
&& u
.umonnum
!= PM_INCUBUS
1415 && u
.umonnum
!= PM_BALROG
) {
1419 switch (mattk
->adtyp
) {
1422 pline("%s %s for a moment.", Monnam(mdef
),
1423 makeplural(stagger(pd
, "stagger")));
1434 case AD_WERE
: /* no special effect on monsters */
1435 case AD_HEAL
: /* likewise */
1438 if (mattk
->aatyp
== AT_WEAP
) {
1441 } else if (mattk
->aatyp
== AT_KICK
) {
1442 if (thick_skinned(pd
))
1444 if (pd
== &mons
[PM_SHADE
]) {
1445 if (!(uarmf
&& uarmf
->blessed
)) {
1446 impossible("bad shade attack function flow?");
1449 tmp
= rnd(4); /* bless damage */
1451 /* add ring(s) of increase damage */
1452 if (u
.udaminc
> 0) {
1453 /* applies even if damage was 0 */
1455 } else if (tmp
> 0) {
1456 /* ring(s) might be negative; avoid converting
1457 0 to non-0 or positive to non-positive */
1470 pline("%s is %s!", Monnam(mdef
), on_fire(pd
, mattk
));
1471 if (pd
== &mons
[PM_STRAW_GOLEM
] || pd
== &mons
[PM_PAPER_GOLEM
]) {
1473 pline("%s burns completely!", Monnam(mdef
));
1474 xkilled(mdef
, XKILL_NOMSG
| XKILL_NOCORPSE
);
1477 /* Don't return yet; keep hp<1 and tmp=0 for pet msg */
1479 tmp
+= destroy_mitem(mdef
, SCROLL_CLASS
, AD_FIRE
);
1480 tmp
+= destroy_mitem(mdef
, SPBOOK_CLASS
, AD_FIRE
);
1481 if (resists_fire(mdef
)) {
1483 pline_The("fire doesn't heat %s!", mon_nam(mdef
));
1484 golemeffects(mdef
, AD_FIRE
, tmp
);
1485 shieldeff(mdef
->mx
, mdef
->my
);
1488 /* only potions damage resistant players in destroy_item */
1489 tmp
+= destroy_mitem(mdef
, POTION_CLASS
, AD_FIRE
);
1497 pline("%s is covered in frost!", Monnam(mdef
));
1498 if (resists_cold(mdef
)) {
1499 shieldeff(mdef
->mx
, mdef
->my
);
1501 pline_The("frost doesn't chill %s!", mon_nam(mdef
));
1502 golemeffects(mdef
, AD_COLD
, tmp
);
1505 tmp
+= destroy_mitem(mdef
, POTION_CLASS
, AD_COLD
);
1513 pline("%s is zapped!", Monnam(mdef
));
1514 tmp
+= destroy_mitem(mdef
, WAND_CLASS
, AD_ELEC
);
1515 if (resists_elec(mdef
)) {
1517 pline_The("zap doesn't shock %s!", mon_nam(mdef
));
1518 golemeffects(mdef
, AD_ELEC
, tmp
);
1519 shieldeff(mdef
->mx
, mdef
->my
);
1522 /* only rings damage resistant players in destroy_item */
1523 tmp
+= destroy_mitem(mdef
, RING_CLASS
, AD_ELEC
);
1526 if (resists_acid(mdef
))
1530 if (!munstone(mdef
, TRUE
))
1531 minstapetrify(mdef
, TRUE
);
1537 steal_it(mdef
, mattk
);
1541 /* This you as a leprechaun, so steal
1542 real gold only, no lesser coins */
1544 struct obj
*mongold
= findgold(mdef
->minvent
);
1546 obj_extract_self(mongold
);
1547 if (merge_choice(invent
, mongold
) || inv_cnt(FALSE
) < 52) {
1549 Your("purse feels heavier.");
1551 You("grab %s's gold, but find no room in your knapsack.",
1557 exercise(A_DEX
, TRUE
);
1563 if (!negated
&& tmp
< mdef
->mhp
) {
1566 canseemon(mdef
) || (u
.uswallow
&& u
.ustuck
== mdef
);
1567 /* record the name before losing sight of monster */
1568 Strcpy(nambuf
, Monnam(mdef
));
1569 if (u_teleport_mon(mdef
, FALSE
) && u_saw_mon
1570 && !(canseemon(mdef
) || (u
.uswallow
&& u
.ustuck
== mdef
)))
1571 pline("%s suddenly disappears!", nambuf
);
1575 if (can_blnd(&youmonst
, mdef
, mattk
->aatyp
, (struct obj
*) 0)) {
1576 if (!Blind
&& mdef
->mcansee
)
1577 pline("%s is blinded.", Monnam(mdef
));
1579 tmp
+= mdef
->mblinded
;
1582 mdef
->mblinded
= tmp
;
1587 if (night() && !rn2(10) && !mdef
->mcan
) {
1588 if (pd
== &mons
[PM_CLAY_GOLEM
]) {
1590 pline("Some writing vanishes from %s head!",
1591 s_suffix(mon_nam(mdef
)));
1592 xkilled(mdef
, XKILL_NOMSG
);
1593 /* Don't return yet; keep hp<1 and tmp=0 for pet msg */
1602 if (!negated
&& !rn2(3) && !resists_drli(mdef
)) {
1605 pline("%s suddenly seems weaker!", Monnam(mdef
));
1606 mdef
->mhpmax
-= xtmp
;
1608 /* !m_lev: level 0 monster is killed rather than drop to -1 */
1609 if (mdef
->mhp
<= 0 && !mdef
->m_lev
) {
1610 pline("%s dies!", Monnam(mdef
));
1611 xkilled(mdef
, XKILL_NOMSG
);
1618 if (pd
== &mons
[PM_IRON_GOLEM
]) {
1619 pline("%s falls to pieces!", Monnam(mdef
));
1620 xkilled(mdef
, XKILL_NOMSG
);
1622 erode_armor(mdef
, ERODE_RUST
);
1626 erode_armor(mdef
, ERODE_CORRODE
);
1630 if (pd
== &mons
[PM_WOOD_GOLEM
] || pd
== &mons
[PM_LEATHER_GOLEM
]) {
1631 pline("%s falls to pieces!", Monnam(mdef
));
1632 xkilled(mdef
, XKILL_NOMSG
);
1634 erode_armor(mdef
, ERODE_ROT
);
1638 if (!negated
&& !rn2(4))
1639 xdrainenergym(mdef
, TRUE
);
1645 if (!negated
&& !rn2(8)) {
1646 Your("%s was poisoned!", mpoisons_subj(&youmonst
, mattk
));
1647 if (resists_poison(mdef
))
1648 pline_The("poison doesn't seem to affect %s.", mon_nam(mdef
));
1651 Your("poison was deadly...");
1661 if (notonhead
|| !has_head(pd
)) {
1662 pline("%s doesn't seem harmed.", Monnam(mdef
));
1664 if (!Unchanging
&& pd
== &mons
[PM_GREEN_SLIME
]) {
1666 You("suck in some slime and don't feel very well.");
1667 make_slimed(10L, (char *) 0);
1672 if (m_slips_free(mdef
, mattk
))
1675 if ((helmet
= which_armor(mdef
, W_ARMH
)) != 0 && rn2(8)) {
1676 pline("%s %s blocks your attack to %s head.",
1677 s_suffix(Monnam(mdef
)), helm_simple_name(helmet
),
1682 (void) eat_brains(&youmonst
, mdef
, TRUE
, &tmp
);
1686 if (!negated
&& !sticks(pd
))
1687 u
.ustuck
= mdef
; /* it's now stuck to you */
1691 if (!u
.ustuck
&& !rn2(10)) {
1692 if (m_slips_free(mdef
, mattk
)) {
1695 You("swing yourself around %s!", mon_nam(mdef
));
1698 } else if (u
.ustuck
== mdef
) {
1699 /* Monsters don't wear amulets of magical breathing */
1700 if (is_pool(u
.ux
, u
.uy
) && !is_swimmer(pd
)
1701 && !amphibious(pd
)) {
1702 You("drown %s...", mon_nam(mdef
));
1704 } else if (mattk
->aatyp
== AT_HUGS
)
1705 pline("%s is being crushed.", Monnam(mdef
));
1709 You("brush against %s %s.", s_suffix(mon_nam(mdef
)),
1710 mbodypart(mdef
, LEG
));
1716 if (!negated
&& mdef
->mcanmove
&& !rn2(3) && tmp
< mdef
->mhp
) {
1718 pline("%s is frozen by you!", Monnam(mdef
));
1719 paralyze_monst(mdef
, rnd(10));
1723 if (!negated
&& !mdef
->msleeping
&& sleep_monst(mdef
, rnd(10), -1)) {
1725 pline("%s is put to sleep by you!", Monnam(mdef
));
1731 break; /* physical damage only */
1732 if (!rn2(4) && !slimeproof(pd
)) {
1733 if (!munslime(mdef
, TRUE
) && mdef
->mhp
> 0) {
1734 /* this assumes newcham() won't fail; since hero has
1735 a slime attack, green slimes haven't been geno'd */
1736 You("turn %s into slime.", mon_nam(mdef
));
1737 if (newcham(mdef
, &mons
[PM_GREEN_SLIME
], FALSE
, FALSE
))
1740 /* munslime attempt could have been fatal */
1742 return 2; /* skip death message */
1746 case AD_ENCH
: /* KMH -- remove enchantment (disenchanter) */
1747 /* there's no msomearmor() function, so just do damage */
1748 /* if (negated) break; */
1751 if (!negated
&& mdef
->mspeed
!= MSLOW
) {
1752 unsigned int oldspeed
= mdef
->mspeed
;
1754 mon_adjust_speed(mdef
, -1, (struct obj
*) 0);
1755 if (mdef
->mspeed
!= oldspeed
&& canseemon(mdef
))
1756 pline("%s slows down.", Monnam(mdef
));
1761 if (canseemon(mdef
))
1762 pline("%s looks confused.", Monnam(mdef
));
1771 mdef
->mstrategy
&= ~STRAT_WAITFORU
; /* in case player is very fast */
1773 if (mdef
->mhp
< 1) {
1774 if (mdef
->mtame
&& !cansee(mdef
->mx
, mdef
->my
)) {
1775 You_feel("embarrassed for a moment.");
1777 xkilled(mdef
, XKILL_NOMSG
); /* !tmp but hp<1: already killed */
1778 } else if (!flags
.verbose
) {
1781 xkilled(mdef
, XKILL_NOMSG
);
1791 register struct monst
*mdef
;
1792 register struct attack
*mattk
;
1794 register int tmp
= d((int) mattk
->damn
, (int) mattk
->damd
);
1797 switch (mattk
->adtyp
) {
1798 boolean resistance
; /* only for cold/fire/elec */
1801 if (!resists_blnd(mdef
)) {
1802 pline("%s is blinded by your flash of light!", Monnam(mdef
));
1803 mdef
->mblinded
= min((int) mdef
->mblinded
+ tmp
, 127);
1808 if (haseyes(mdef
->data
) && mdef
->mcansee
) {
1809 pline("%s is affected by your flash of light!", Monnam(mdef
));
1814 resistance
= resists_cold(mdef
);
1817 resistance
= resists_fire(mdef
);
1820 resistance
= resists_elec(mdef
);
1823 pline("%s gets blasted!", Monnam(mdef
));
1825 if (mdef
->mhp
<= 0) {
1830 shieldeff(mdef
->mx
, mdef
->my
);
1831 if (is_golem(mdef
->data
))
1832 golemeffects(mdef
, (int) mattk
->adtyp
, tmp
);
1834 pline_The("blast doesn't seem to affect %s.", mon_nam(mdef
));
1848 map_location(u
.ux
, u
.uy
, TRUE
);
1849 tmp_at(DISP_ALWAYS
, mon_to_glyph(&youmonst
));
1850 tmp_at(mdef
->mx
, mdef
->my
);
1852 You("engulf %s!", mon_nam(mdef
));
1861 tmp_at(DISP_END
, 0);
1868 register struct monst
*mdef
;
1869 register struct attack
*mattk
;
1871 #ifdef LINT /* static char msgbuf[BUFSZ]; */
1874 static char msgbuf
[BUFSZ
]; /* for nomovemsg */
1877 register int dam
= d((int) mattk
->damn
, (int) mattk
->damd
);
1880 struct permonst
*pd
= mdef
->data
;
1882 /* Not totally the same as for real monsters. Specifically, these
1883 * don't take multiple moves. (It's just too hard, for too little
1884 * result, to program monsters which attack from inside you, which
1885 * would be necessary if done accurately.) Instead, we arbitrarily
1886 * kill the monster immediately for AD_DGST and we regurgitate them
1887 * after exactly 1 round of attack otherwise. -KAA
1890 if (!engulf_target(&youmonst
, mdef
))
1893 if (u
.uhunger
< 1500 && !u
.uswallow
) {
1894 for (otmp
= mdef
->minvent
; otmp
; otmp
= otmp
->nobj
)
1895 (void) snuff_lit(otmp
);
1897 /* force vampire in bat, cloud, or wolf form to revert back to
1898 vampire form now instead of dealing with that when it dies */
1899 if (is_vampshifter(mdef
)
1900 && newcham(mdef
, &mons
[mdef
->cham
], FALSE
, FALSE
)) {
1901 You("engulf it, then expel it.");
1902 if (canspotmon(mdef
))
1903 pline("It turns into %s.", a_monnam(mdef
));
1905 map_invisible(mdef
->mx
, mdef
->my
);
1909 /* engulfing a cockatrice or digesting a Rider or Medusa */
1910 fatal_gulp
= (touch_petrifies(pd
) && !Stone_resistance
)
1911 || (mattk
->adtyp
== AD_DGST
1912 && (is_rider(pd
) || (pd
== &mons
[PM_MEDUSA
]
1913 && !Stone_resistance
)));
1915 if ((mattk
->adtyp
== AD_DGST
&& !Slow_digestion
) || fatal_gulp
)
1916 eating_conducts(pd
);
1918 if (fatal_gulp
&& !is_rider(pd
)) { /* petrification */
1920 const char *mname
= pd
->mname
;
1922 if (!type_is_pname(pd
))
1924 You("englut %s.", mon_nam(mdef
));
1925 Sprintf(kbuf
, "swallowing %s whole", mname
);
1929 switch (mattk
->adtyp
) {
1931 /* eating a Rider or its corpse is fatal */
1933 pline("Unfortunately, digesting any of it is fatal.");
1935 Sprintf(killer
.name
, "unwisely tried to eat %s",
1937 killer
.format
= NO_KILLER_PREFIX
;
1939 return 0; /* lifesaved */
1942 if (Slow_digestion
) {
1947 /* Use up amulet of life saving */
1948 if (!!(otmp
= mlifesaver(mdef
)))
1949 m_useup(mdef
, otmp
);
1952 /* start_engulf() issues "you engulf <mdef>" above; this
1953 used to specify XKILL_NOMSG but we need "you kill <mdef>"
1954 in case we're also going to get "welcome to level N+1";
1955 "you totally digest <mdef>" will be coming soon (after
1956 several turns) but the level-gain message seems out of
1957 order if the kill message is left implicit */
1958 xkilled(mdef
, XKILL_GIVEMSG
| XKILL_NOCORPSE
);
1959 if (mdef
->mhp
> 0) { /* monster lifesaved */
1960 You("hurriedly regurgitate the sizzling in your %s.",
1961 body_part(STOMACH
));
1963 tmp
= 1 + (pd
->cwt
>> 8);
1964 if (corpse_chance(mdef
, &youmonst
, TRUE
)
1965 && !(mvitals
[monsndx(pd
)].mvflags
& G_NOCORPSE
)) {
1966 /* nutrition only if there can be a corpse */
1967 u
.uhunger
+= (pd
->cnutrit
+ 1) / 2;
1970 Sprintf(msgbuf
, "You totally digest %s.", mon_nam(mdef
));
1972 /* setting afternmv = end_engulf is tempting,
1973 * but will cause problems if the player is
1974 * attacked (which uses his real location) or
1975 * if his See_invisible wears off
1977 You("digest %s.", mon_nam(mdef
));
1981 multi_reason
= "digesting something";
1985 if (pd
== &mons
[PM_GREEN_SLIME
]) {
1986 Sprintf(msgbuf
, "%s isn't sitting well with you.",
1989 make_slimed(5L, (char *) 0);
1992 exercise(A_CON
, TRUE
);
1997 if (youmonst
.data
== &mons
[PM_FOG_CLOUD
]) {
1998 pline("%s is laden with your moisture.", Monnam(mdef
));
1999 if (amphibious(pd
) && !flaming(pd
)) {
2001 pline("%s seems unharmed.", Monnam(mdef
));
2004 pline("%s is pummeled with your debris!", Monnam(mdef
));
2007 pline("%s is covered with your goo!", Monnam(mdef
));
2008 if (resists_acid(mdef
)) {
2009 pline("It seems harmless to %s.", mon_nam(mdef
));
2014 if (can_blnd(&youmonst
, mdef
, mattk
->aatyp
,
2015 (struct obj
*) 0)) {
2017 pline("%s can't see in there!", Monnam(mdef
));
2019 dam
+= mdef
->mblinded
;
2022 mdef
->mblinded
= dam
;
2028 pline_The("air around %s crackles with electricity.",
2030 if (resists_elec(mdef
)) {
2031 pline("%s seems unhurt.", Monnam(mdef
));
2034 golemeffects(mdef
, (int) mattk
->adtyp
, dam
);
2040 if (resists_cold(mdef
)) {
2041 pline("%s seems mildly chilly.", Monnam(mdef
));
2044 pline("%s is freezing to death!", Monnam(mdef
));
2045 golemeffects(mdef
, (int) mattk
->adtyp
, dam
);
2051 if (resists_fire(mdef
)) {
2052 pline("%s seems mildly hot.", Monnam(mdef
));
2055 pline("%s is burning to a crisp!", Monnam(mdef
));
2056 golemeffects(mdef
, (int) mattk
->adtyp
, dam
);
2062 xdrainenergym(mdef
, TRUE
);
2068 if (mdef
->mhp
<= 0) {
2070 if (mdef
->mhp
<= 0) /* not lifesaved */
2073 You("%s %s!", is_animal(youmonst
.data
) ? "regurgitate" : "expel",
2075 if (Slow_digestion
|| is_animal(youmonst
.data
)) {
2076 pline("Obviously, you didn't like %s taste.",
2077 s_suffix(mon_nam(mdef
)));
2085 missum(mdef
, mattk
, wouldhavehit
)
2086 register struct monst
*mdef
;
2087 register struct attack
*mattk
;
2088 boolean wouldhavehit
;
2090 if (wouldhavehit
) /* monk is missing due to penalty for wearing suit */
2091 Your("armor is rather cumbersome...");
2093 if (could_seduce(&youmonst
, mdef
, mattk
))
2094 You("pretend to be friendly to %s.", mon_nam(mdef
));
2095 else if (canspotmon(mdef
) && flags
.verbose
)
2096 You("miss %s.", mon_nam(mdef
));
2099 if (!mdef
->msleeping
&& mdef
->mcanmove
)
2103 /* attack monster as a monster. */
2106 register struct monst
*mon
;
2108 struct attack
*mattk
, alt_attk
;
2110 boolean altwep
= FALSE
, weapon_used
= FALSE
;
2111 int i
, tmp
, armorpenalty
, sum
[NATTK
], nsum
= 0, dhit
= 0, attknum
= 0;
2113 for (i
= 0; i
< NATTK
; i
++) {
2115 mattk
= getmattk(&youmonst
, mon
, i
, sum
, &alt_attk
);
2116 switch (mattk
->aatyp
) {
2119 /* Certain monsters don't use weapons when encountered as enemies,
2120 * but players who polymorph into them have hands or claws and
2121 * thus should be able to use weapons. This shouldn't prohibit
2122 * the use of most special abilities, either.
2123 * If monster has multiple claw attacks, only one can use weapon.
2126 /* Potential problem: if the monster gets multiple weapon attacks,
2127 * we currently allow the player to get each of these as a weapon
2128 * attack. Is this really desirable?
2130 /* approximate two-weapon mode */
2131 weapon
= (altwep
&& uswapwep
) ? uswapwep
: uwep
;
2132 altwep
= !altwep
; /* toggle for next attack */
2133 tmp
= find_roll_to_hit(mon
, AT_WEAP
, weapon
, &attknum
,
2135 dhit
= (tmp
> (dieroll
= rnd(20)) || u
.uswallow
);
2136 /* Enemy dead, before any special abilities used */
2137 if (!known_hitum(mon
, weapon
, &dhit
, tmp
, armorpenalty
, mattk
)) {
2142 /* might be a worm that gets cut in half */
2143 if (m_at(u
.ux
+ u
.dx
, u
.uy
+ u
.dy
) != mon
)
2144 return (boolean
) (nsum
!= 0);
2145 /* Do not print "You hit" message, since known_hitum
2148 if (dhit
&& mattk
->adtyp
!= AD_SPEL
&& mattk
->adtyp
!= AD_PHYS
)
2149 sum
[i
] = damageum(mon
, mattk
);
2152 if (uwep
&& !cantwield(youmonst
.data
) && !weapon_used
)
2156 if (uwep
&& youmonst
.data
->mlet
== S_LICH
&& !weapon_used
)
2164 tmp
= find_roll_to_hit(mon
, mattk
->aatyp
, (struct obj
*) 0,
2165 &attknum
, &armorpenalty
);
2166 dhit
= (tmp
> (dieroll
= rnd(20)) || u
.uswallow
);
2171 && (compat
= could_seduce(&youmonst
, mon
, mattk
))) {
2173 mon
->mcansee
&& haseyes(mon
->data
) ? "smile at"
2176 compat
== 2 ? "engagingly" : "seductively");
2177 /* doesn't anger it; no wakeup() */
2178 sum
[i
] = damageum(mon
, mattk
);
2182 /* maybe this check should be in damageum()? */
2183 if (mon
->data
== &mons
[PM_SHADE
]
2184 && !(mattk
->aatyp
== AT_KICK
&& uarmf
2185 && uarmf
->blessed
)) {
2186 Your("attack passes harmlessly through %s.",
2190 if (mattk
->aatyp
== AT_KICK
)
2191 You("kick %s.", mon_nam(mon
));
2192 else if (mattk
->aatyp
== AT_BITE
)
2193 You("bite %s.", mon_nam(mon
));
2194 else if (mattk
->aatyp
== AT_STNG
)
2195 You("sting %s.", mon_nam(mon
));
2196 else if (mattk
->aatyp
== AT_BUTT
)
2197 You("butt %s.", mon_nam(mon
));
2198 else if (mattk
->aatyp
== AT_TUCH
)
2199 You("touch %s.", mon_nam(mon
));
2200 else if (mattk
->aatyp
== AT_TENT
)
2201 Your("tentacles suck %s.", mon_nam(mon
));
2203 You("hit %s.", mon_nam(mon
));
2204 sum
[i
] = damageum(mon
, mattk
);
2206 missum(mon
, mattk
, (tmp
+ armorpenalty
> dieroll
));
2211 /* automatic if prev two attacks succeed, or if
2212 * already grabbed in a previous attack
2216 if (mon
->data
== &mons
[PM_SHADE
])
2217 Your("hug passes harmlessly through %s.", mon_nam(mon
));
2218 else if (!sticks(mon
->data
) && !u
.uswallow
) {
2219 if (mon
== u
.ustuck
) {
2220 pline("%s is being %s.", Monnam(mon
),
2221 u
.umonnum
== PM_ROPE_GOLEM
? "choked" : "crushed");
2222 sum
[i
] = damageum(mon
, mattk
);
2223 } else if (i
>= 2 && sum
[i
- 1] && sum
[i
- 2]) {
2224 You("grab %s!", mon_nam(mon
));
2226 sum
[i
] = damageum(mon
, mattk
);
2231 case AT_EXPL
: /* automatic hit if next to */
2234 sum
[i
] = explum(mon
, mattk
);
2238 tmp
= find_roll_to_hit(mon
, mattk
->aatyp
, (struct obj
*) 0,
2239 &attknum
, &armorpenalty
);
2240 if ((dhit
= (tmp
> rnd(20 + i
)))) {
2242 if (mon
->data
== &mons
[PM_SHADE
])
2243 Your("attempt to surround %s is harmless.", mon_nam(mon
));
2245 sum
[i
] = gulpum(mon
, mattk
);
2246 if (sum
[i
] == 2 && (mon
->data
->mlet
== S_ZOMBIE
2247 || mon
->data
->mlet
== S_MUMMY
)
2248 && rn2(5) && !Sick_resistance
) {
2249 You_feel("%ssick.", (Sick
) ? "very " : "");
2250 mdamageu(mon
, rnd(8));
2254 missum(mon
, mattk
, FALSE
);
2259 /* No check for uwep; if wielding nothing we want to
2260 * do the normal 1-2 points bare hand damage...
2262 if ((youmonst
.data
->mlet
== S_KOBOLD
2263 || youmonst
.data
->mlet
== S_ORC
2264 || youmonst
.data
->mlet
== S_GNOME
) && !weapon_used
)
2270 /* Not break--avoid passive attacks from enemy */
2274 case AT_GAZE
: /* all done using #monster command */
2278 default: /* Strange... */
2279 impossible("strange attack of yours (%d)", mattk
->aatyp
);
2282 u
.mh
= -1; /* dead in the current form */
2286 return (boolean
) passive(mon
, 1, 0, mattk
->aatyp
, FALSE
);
2289 (void) passive(mon
, sum
[i
], 1, mattk
->aatyp
, FALSE
);
2293 break; /* No extra attacks if no longer a monster */
2295 break; /* If paralyzed while attacking, i.e. floating eye */
2297 return (boolean
) (nsum
!= 0);
2300 /* Special (passive) attacks on you by monsters done here.
2303 passive(mon
, mhit
, malive
, aatyp
, wep_was_destroyed
)
2304 register struct monst
*mon
;
2305 register boolean mhit
;
2306 register int malive
;
2308 boolean wep_was_destroyed
;
2310 register struct permonst
*ptr
= mon
->data
;
2311 register int i
, tmp
;
2315 return (malive
| mhit
); /* no passive attacks */
2316 if (ptr
->mattk
[i
].aatyp
== AT_NONE
)
2317 break; /* try this one */
2319 /* Note: tmp not always used */
2320 if (ptr
->mattk
[i
].damn
)
2321 tmp
= d((int) ptr
->mattk
[i
].damn
, (int) ptr
->mattk
[i
].damd
);
2322 else if (ptr
->mattk
[i
].damd
)
2323 tmp
= d((int) mon
->m_lev
+ 1, (int) ptr
->mattk
[i
].damd
);
2327 /* These affect you even if they just died.
2329 switch (ptr
->mattk
[i
].adtyp
) {
2331 if (mhit
&& !mon
->mcan
) {
2332 if (aatyp
== AT_KICK
) {
2333 if (uarmf
&& !rn2(6))
2334 (void) erode_obj(uarmf
, xname(uarmf
), ERODE_BURN
,
2335 EF_GREASE
| EF_VERBOSE
);
2336 } else if (aatyp
== AT_WEAP
|| aatyp
== AT_CLAW
2337 || aatyp
== AT_MAGC
|| aatyp
== AT_TUCH
)
2338 passive_obj(mon
, (struct obj
*) 0, &(ptr
->mattk
[i
]));
2342 if (mhit
&& rn2(2)) {
2343 if (Blind
|| !flags
.verbose
)
2344 You("are splashed!");
2346 You("are splashed by %s %s!", s_suffix(mon_nam(mon
)),
2349 if (!Acid_resistance
)
2352 erode_armor(&youmonst
, ERODE_CORRODE
);
2355 if (aatyp
== AT_KICK
) {
2356 if (uarmf
&& !rn2(6))
2357 (void) erode_obj(uarmf
, xname(uarmf
), ERODE_CORRODE
,
2358 EF_GREASE
| EF_VERBOSE
);
2359 } else if (aatyp
== AT_WEAP
|| aatyp
== AT_CLAW
2360 || aatyp
== AT_MAGC
|| aatyp
== AT_TUCH
)
2361 passive_obj(mon
, (struct obj
*) 0, &(ptr
->mattk
[i
]));
2363 exercise(A_STR
, FALSE
);
2366 if (mhit
) { /* successful attack */
2367 long protector
= attk_protection((int) aatyp
);
2369 /* hero using monsters' AT_MAGC attack is hitting hand to
2370 hand rather than casting a spell */
2371 if (aatyp
== AT_MAGC
)
2374 if (protector
== 0L /* no protection */
2375 || (protector
== W_ARMG
&& !uarmg
2376 && !uwep
&& !wep_was_destroyed
)
2377 || (protector
== W_ARMF
&& !uarmf
)
2378 || (protector
== W_ARMH
&& !uarmh
)
2379 || (protector
== (W_ARMC
| W_ARMG
) && (!uarmc
|| !uarmg
))) {
2380 if (!Stone_resistance
2381 && !(poly_when_stoned(youmonst
.data
)
2382 && polymon(PM_STONE_GOLEM
))) {
2383 done_in_by(mon
, STONING
); /* "You turn to stone..." */
2390 if (mhit
&& !mon
->mcan
) {
2391 if (aatyp
== AT_KICK
) {
2393 (void) erode_obj(uarmf
, xname(uarmf
), ERODE_RUST
,
2394 EF_GREASE
| EF_VERBOSE
);
2395 } else if (aatyp
== AT_WEAP
|| aatyp
== AT_CLAW
2396 || aatyp
== AT_MAGC
|| aatyp
== AT_TUCH
)
2397 passive_obj(mon
, (struct obj
*) 0, &(ptr
->mattk
[i
]));
2401 if (mhit
&& !mon
->mcan
) {
2402 if (aatyp
== AT_KICK
) {
2404 (void) erode_obj(uarmf
, xname(uarmf
), ERODE_CORRODE
,
2405 EF_GREASE
| EF_VERBOSE
);
2406 } else if (aatyp
== AT_WEAP
|| aatyp
== AT_CLAW
2407 || aatyp
== AT_MAGC
|| aatyp
== AT_TUCH
)
2408 passive_obj(mon
, (struct obj
*) 0, &(ptr
->mattk
[i
]));
2412 /* wrath of gods for attacking Oracle */
2414 shieldeff(u
.ux
, u
.uy
);
2415 pline("A hail of magic missiles narrowly misses you!");
2417 You("are hit by magic missiles appearing from thin air!");
2421 case AD_ENCH
: /* KMH -- remove enchantment (disenchanter) */
2423 struct obj
*obj
= (struct obj
*) 0;
2425 if (aatyp
== AT_KICK
) {
2429 } else if (aatyp
== AT_BITE
|| aatyp
== AT_BUTT
2430 || (aatyp
>= AT_STNG
&& aatyp
< AT_WEAP
)) {
2431 break; /* no object involved */
2433 passive_obj(mon
, obj
, &(ptr
->mattk
[i
]));
2440 /* These only affect you if they still live.
2442 if (malive
&& !mon
->mcan
&& rn2(3)) {
2443 switch (ptr
->mattk
[i
].adtyp
) {
2445 if (ptr
== &mons
[PM_FLOATING_EYE
]) {
2446 if (!canseemon(mon
)) {
2450 if (ureflects("%s gaze is reflected by your %s.",
2451 s_suffix(Monnam(mon
)))) {
2453 } else if (Free_action
) {
2454 You("momentarily stiffen under %s gaze!",
2455 s_suffix(mon_nam(mon
)));
2456 } else if (Hallucination
&& rn2(4)) {
2457 pline("%s looks %s%s.", Monnam(mon
),
2458 !rn2(2) ? "" : "rather ",
2459 !rn2(2) ? "numb" : "stupified");
2461 You("are frozen by %s gaze!", s_suffix(mon_nam(mon
)));
2462 nomul((ACURR(A_WIS
) > 12 || rn2(4)) ? -tmp
: -127);
2463 multi_reason
= "frozen by a monster's gaze";
2467 pline("%s cannot defend itself.",
2468 Adjmonnam(mon
, "blind"));
2472 } else if (Free_action
) {
2473 You("momentarily stiffen.");
2474 } else { /* gelatinous cube */
2475 You("are frozen by %s!", mon_nam(mon
));
2476 nomovemsg
= You_can_move_again
;
2478 multi_reason
= "frozen by a monster";
2479 exercise(A_DEX
, FALSE
);
2482 case AD_COLD
: /* brown mold or blue jelly */
2483 if (monnear(mon
, u
.ux
, u
.uy
)) {
2484 if (Cold_resistance
) {
2485 shieldeff(u
.ux
, u
.uy
);
2486 You_feel("a mild chill.");
2487 ugolemeffects(AD_COLD
, tmp
);
2490 You("are suddenly very cold!");
2492 /* monster gets stronger with your heat! */
2493 mon
->mhp
+= tmp
/ 2;
2494 if (mon
->mhpmax
< mon
->mhp
)
2495 mon
->mhpmax
= mon
->mhp
;
2496 /* at a certain point, the monster will reproduce! */
2497 if (mon
->mhpmax
> ((int) (mon
->m_lev
+ 1) * 8))
2498 (void) split_mon(mon
, &youmonst
);
2501 case AD_STUN
: /* specifically yellow mold */
2503 make_stunned((long) tmp
, TRUE
);
2506 if (monnear(mon
, u
.ux
, u
.uy
)) {
2507 if (Fire_resistance
) {
2508 shieldeff(u
.ux
, u
.uy
);
2509 You_feel("mildly warm.");
2510 ugolemeffects(AD_FIRE
, tmp
);
2513 You("are suddenly very hot!");
2514 mdamageu(mon
, tmp
); /* fire damage */
2518 if (Shock_resistance
) {
2519 shieldeff(u
.ux
, u
.uy
);
2520 You_feel("a mild tingle.");
2521 ugolemeffects(AD_ELEC
, tmp
);
2524 You("are jolted with electricity!");
2531 return (malive
| mhit
);
2535 * Special (passive) attacks on an attacking object by monsters done here.
2536 * Assumes the attack was successful.
2539 passive_obj(mon
, obj
, mattk
)
2541 struct obj
*obj
; /* null means pick uwep, uswapwep or uarmg */
2542 struct attack
*mattk
; /* null means we find one internally */
2544 struct permonst
*ptr
= mon
->data
;
2547 /* if caller hasn't specified an object, use uwep, uswapwep or uarmg */
2549 obj
= (u
.twoweap
&& uswapwep
&& !rn2(2)) ? uswapwep
: uwep
;
2550 if (!obj
&& mattk
->adtyp
== AD_ENCH
)
2551 obj
= uarmg
; /* no weapon? then must be gloves */
2553 return; /* no object to affect */
2556 /* if caller hasn't specified an attack, find one */
2560 return; /* no passive attacks */
2561 if (ptr
->mattk
[i
].aatyp
== AT_NONE
)
2562 break; /* try this one */
2564 mattk
= &(ptr
->mattk
[i
]);
2567 switch (mattk
->adtyp
) {
2569 if (!rn2(6) && !mon
->mcan
2570 /* steam vortex: fire resist applies, fire damage doesn't */
2571 && mon
->data
!= &mons
[PM_STEAM_VORTEX
]) {
2572 (void) erode_obj(obj
, NULL
, ERODE_BURN
, EF_NONE
);
2577 (void) erode_obj(obj
, NULL
, ERODE_CORRODE
, EF_GREASE
);
2582 (void) erode_obj(obj
, (char *) 0, ERODE_RUST
, EF_GREASE
);
2587 (void) erode_obj(obj
, (char *) 0, ERODE_CORRODE
, EF_GREASE
);
2592 if (drain_item(obj
, TRUE
) && carried(obj
)
2593 && (obj
->known
|| obj
->oclass
== ARMOR_CLASS
)) {
2594 pline("%s less effective.", Yobjnam2(obj
, "seem"));
2606 /* Note: caller must ascertain mtmp is mimicking... */
2608 stumble_onto_mimic(mtmp
)
2611 const char *fmt
= "Wait! That's %s!", *generic
= "a monster", *what
= 0;
2613 if (!u
.ustuck
&& !mtmp
->mflee
&& dmgtype(mtmp
->data
, AD_STCK
))
2618 what
= generic
; /* with default fmt */
2619 else if (mtmp
->m_ap_type
== M_AP_MONSTER
)
2620 what
= a_monnam(mtmp
); /* differs from what was sensed */
2622 int glyph
= levl
[u
.ux
+ u
.dx
][u
.uy
+ u
.dy
].glyph
;
2624 if (glyph_is_cmap(glyph
) && (glyph_to_cmap(glyph
) == S_hcdoor
2625 || glyph_to_cmap(glyph
) == S_vcdoor
))
2626 fmt
= "The door actually was %s!";
2627 else if (glyph_is_object(glyph
) && glyph_to_obj(glyph
) == GOLD_PIECE
)
2628 fmt
= "That gold was %s!";
2630 /* cloned Wiz starts out mimicking some other monster and
2631 might make himself invisible before being revealed */
2632 if (mtmp
->minvis
&& !See_invisible
)
2635 what
= a_monnam(mtmp
);
2640 wakeup(mtmp
, FALSE
); /* clears mimicking */
2641 /* if hero is blind, wakeup() won't display the monster even though
2642 it's no longer concealed */
2643 if (!canspotmon(mtmp
)
2644 && !glyph_is_invisible(levl
[mtmp
->mx
][mtmp
->my
].glyph
))
2645 map_invisible(mtmp
->mx
, mtmp
->my
);
2652 char *hands
= makeplural(body_part(HAND
));
2654 if (!u
.umconf
|| mon
->mconf
)
2656 if (u
.umconf
== 1) {
2658 Your("%s stop tingling.", hands
);
2660 Your("%s stop glowing %s.", hands
, hcolor(NH_RED
));
2663 pline_The("tingling in your %s lessens.", hands
);
2665 Your("%s no longer glow so brightly %s.", hands
, hcolor(NH_RED
));
2671 flash_hits_mon(mtmp
, otmp
)
2673 struct obj
*otmp
; /* source of flash */
2675 int tmp
, amt
, res
= 0, useeit
= canseemon(mtmp
);
2677 if (mtmp
->msleeping
) {
2678 mtmp
->msleeping
= 0;
2680 pline_The("flash awakens %s.", mon_nam(mtmp
));
2683 } else if (mtmp
->data
->mlet
!= S_LIGHT
) {
2684 if (!resists_blnd(mtmp
)) {
2685 tmp
= dist2(otmp
->ox
, otmp
->oy
, mtmp
->mx
, mtmp
->my
);
2687 pline("%s is blinded by the flash!", Monnam(mtmp
));
2690 if (mtmp
->data
== &mons
[PM_GREMLIN
]) {
2691 /* Rule #1: Keep them out of the light. */
2692 amt
= otmp
->otyp
== WAN_LIGHT
? d(1 + otmp
->spe
, 4)
2693 : rn2(min(mtmp
->mhp
, 4));
2694 light_hits_gremlin(mtmp
, amt
);
2696 if (mtmp
->mhp
> 0) {
2697 if (!context
.mon_moving
)
2698 setmangry(mtmp
, TRUE
);
2699 if (tmp
< 9 && !mtmp
->isshk
&& rn2(4))
2700 monflee(mtmp
, rn2(4) ? rnd(100) : 0, FALSE
, TRUE
);
2702 mtmp
->mblinded
= (tmp
< 3) ? 0 : rnd(1 + 50 / tmp
);
2710 light_hits_gremlin(mon
, dmg
)
2714 pline("%s %s!", Monnam(mon
),
2715 (dmg
> mon
->mhp
/ 2) ? "wails in agony" : "cries out in pain");
2717 wake_nearto(mon
->mx
, mon
->my
, 30);
2718 if (mon
->mhp
<= 0) {
2719 if (context
.mon_moving
)
2720 monkilled(mon
, (char *) 0, AD_BLND
);
2723 } else if (cansee(mon
->mx
, mon
->my
) && !canspotmon(mon
)) {
2724 map_invisible(mon
->mx
, mon
->my
);