1 /* NetHack 3.6 uhitm.c $NHDT-Date: 1460103141 2016/04/08 08:12:21 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.156 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack 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
); /* 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
);
900 if (((int) mon
->mblinded
+ tmp
) > 127)
903 mon
->mblinded
+= tmp
;
905 pline(obj
->otyp
== CREAM_PIE
? "Splat!" : "Splash!");
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
;
1607 if ((mdef
->mhp
-= xtmp
) <= 0 || !mdef
->m_lev
) {
1608 pline("%s dies!", Monnam(mdef
));
1609 xkilled(mdef
, XKILL_NOMSG
);
1616 if (pd
== &mons
[PM_IRON_GOLEM
]) {
1617 pline("%s falls to pieces!", Monnam(mdef
));
1618 xkilled(mdef
, XKILL_NOMSG
);
1620 erode_armor(mdef
, ERODE_RUST
);
1624 erode_armor(mdef
, ERODE_CORRODE
);
1628 if (pd
== &mons
[PM_WOOD_GOLEM
] || pd
== &mons
[PM_LEATHER_GOLEM
]) {
1629 pline("%s falls to pieces!", Monnam(mdef
));
1630 xkilled(mdef
, XKILL_NOMSG
);
1632 erode_armor(mdef
, ERODE_ROT
);
1636 if (!negated
&& !rn2(4))
1637 xdrainenergym(mdef
, TRUE
);
1643 if (!negated
&& !rn2(8)) {
1644 Your("%s was poisoned!", mpoisons_subj(&youmonst
, mattk
));
1645 if (resists_poison(mdef
))
1646 pline_The("poison doesn't seem to affect %s.", mon_nam(mdef
));
1649 Your("poison was deadly...");
1659 if (notonhead
|| !has_head(pd
)) {
1660 pline("%s doesn't seem harmed.", Monnam(mdef
));
1662 if (!Unchanging
&& pd
== &mons
[PM_GREEN_SLIME
]) {
1664 You("suck in some slime and don't feel very well.");
1665 make_slimed(10L, (char *) 0);
1670 if (m_slips_free(mdef
, mattk
))
1673 if ((helmet
= which_armor(mdef
, W_ARMH
)) != 0 && rn2(8)) {
1674 pline("%s %s blocks your attack to %s head.",
1675 s_suffix(Monnam(mdef
)), helm_simple_name(helmet
),
1680 (void) eat_brains(&youmonst
, mdef
, TRUE
, &tmp
);
1684 if (!negated
&& !sticks(pd
))
1685 u
.ustuck
= mdef
; /* it's now stuck to you */
1689 if (!u
.ustuck
&& !rn2(10)) {
1690 if (m_slips_free(mdef
, mattk
)) {
1693 You("swing yourself around %s!", mon_nam(mdef
));
1696 } else if (u
.ustuck
== mdef
) {
1697 /* Monsters don't wear amulets of magical breathing */
1698 if (is_pool(u
.ux
, u
.uy
) && !is_swimmer(pd
)
1699 && !amphibious(pd
)) {
1700 You("drown %s...", mon_nam(mdef
));
1702 } else if (mattk
->aatyp
== AT_HUGS
)
1703 pline("%s is being crushed.", Monnam(mdef
));
1707 You("brush against %s %s.", s_suffix(mon_nam(mdef
)),
1708 mbodypart(mdef
, LEG
));
1714 if (!negated
&& mdef
->mcanmove
&& !rn2(3) && tmp
< mdef
->mhp
) {
1716 pline("%s is frozen by you!", Monnam(mdef
));
1717 paralyze_monst(mdef
, rnd(10));
1721 if (!negated
&& !mdef
->msleeping
&& sleep_monst(mdef
, rnd(10), -1)) {
1723 pline("%s is put to sleep by you!", Monnam(mdef
));
1729 break; /* physical damage only */
1730 if (!rn2(4) && !slimeproof(pd
)) {
1731 if (!munslime(mdef
, TRUE
) && mdef
->mhp
> 0) {
1732 /* this assumes newcham() won't fail; since hero has
1733 a slime attack, green slimes haven't been geno'd */
1734 You("turn %s into slime.", mon_nam(mdef
));
1735 if (newcham(mdef
, &mons
[PM_GREEN_SLIME
], FALSE
, FALSE
))
1738 /* munslime attempt could have been fatal */
1740 return 2; /* skip death message */
1744 case AD_ENCH
: /* KMH -- remove enchantment (disenchanter) */
1745 /* there's no msomearmor() function, so just do damage */
1746 /* if (negated) break; */
1749 if (!negated
&& mdef
->mspeed
!= MSLOW
) {
1750 unsigned int oldspeed
= mdef
->mspeed
;
1752 mon_adjust_speed(mdef
, -1, (struct obj
*) 0);
1753 if (mdef
->mspeed
!= oldspeed
&& canseemon(mdef
))
1754 pline("%s slows down.", Monnam(mdef
));
1759 if (canseemon(mdef
))
1760 pline("%s looks confused.", Monnam(mdef
));
1769 mdef
->mstrategy
&= ~STRAT_WAITFORU
; /* in case player is very fast */
1770 if ((mdef
->mhp
-= tmp
) < 1) {
1771 if (mdef
->mtame
&& !cansee(mdef
->mx
, mdef
->my
)) {
1772 You_feel("embarrassed for a moment.");
1774 xkilled(mdef
, XKILL_NOMSG
); /* !tmp but hp<1: already killed */
1775 } else if (!flags
.verbose
) {
1778 xkilled(mdef
, XKILL_NOMSG
);
1788 register struct monst
*mdef
;
1789 register struct attack
*mattk
;
1791 register int tmp
= d((int) mattk
->damn
, (int) mattk
->damd
);
1794 switch (mattk
->adtyp
) {
1795 boolean resistance
; /* only for cold/fire/elec */
1798 if (!resists_blnd(mdef
)) {
1799 pline("%s is blinded by your flash of light!", Monnam(mdef
));
1800 mdef
->mblinded
= min((int) mdef
->mblinded
+ tmp
, 127);
1805 if (haseyes(mdef
->data
) && mdef
->mcansee
) {
1806 pline("%s is affected by your flash of light!", Monnam(mdef
));
1811 resistance
= resists_cold(mdef
);
1814 resistance
= resists_fire(mdef
);
1817 resistance
= resists_elec(mdef
);
1820 pline("%s gets blasted!", Monnam(mdef
));
1822 if (mdef
->mhp
<= 0) {
1827 shieldeff(mdef
->mx
, mdef
->my
);
1828 if (is_golem(mdef
->data
))
1829 golemeffects(mdef
, (int) mattk
->adtyp
, tmp
);
1831 pline_The("blast doesn't seem to affect %s.", mon_nam(mdef
));
1845 map_location(u
.ux
, u
.uy
, TRUE
);
1846 tmp_at(DISP_ALWAYS
, mon_to_glyph(&youmonst
));
1847 tmp_at(mdef
->mx
, mdef
->my
);
1849 You("engulf %s!", mon_nam(mdef
));
1858 tmp_at(DISP_END
, 0);
1865 register struct monst
*mdef
;
1866 register struct attack
*mattk
;
1868 #ifdef LINT /* static char msgbuf[BUFSZ]; */
1871 static char msgbuf
[BUFSZ
]; /* for nomovemsg */
1874 register int dam
= d((int) mattk
->damn
, (int) mattk
->damd
);
1877 struct permonst
*pd
= mdef
->data
;
1879 /* Not totally the same as for real monsters. Specifically, these
1880 * don't take multiple moves. (It's just too hard, for too little
1881 * result, to program monsters which attack from inside you, which
1882 * would be necessary if done accurately.) Instead, we arbitrarily
1883 * kill the monster immediately for AD_DGST and we regurgitate them
1884 * after exactly 1 round of attack otherwise. -KAA
1887 if (!engulf_target(&youmonst
, mdef
))
1890 if (u
.uhunger
< 1500 && !u
.uswallow
) {
1891 for (otmp
= mdef
->minvent
; otmp
; otmp
= otmp
->nobj
)
1892 (void) snuff_lit(otmp
);
1894 /* engulfing a cockatrice or digesting a Rider or Medusa */
1895 fatal_gulp
= (touch_petrifies(pd
) && !Stone_resistance
)
1896 || (mattk
->adtyp
== AD_DGST
1897 && (is_rider(pd
) || (pd
== &mons
[PM_MEDUSA
]
1898 && !Stone_resistance
)));
1900 if ((mattk
->adtyp
== AD_DGST
&& !Slow_digestion
) || fatal_gulp
)
1901 eating_conducts(pd
);
1903 if (fatal_gulp
&& !is_rider(pd
)) { /* petrification */
1905 const char *mname
= pd
->mname
;
1907 if (!type_is_pname(pd
))
1909 You("englut %s.", mon_nam(mdef
));
1910 Sprintf(kbuf
, "swallowing %s whole", mname
);
1914 switch (mattk
->adtyp
) {
1916 /* eating a Rider or its corpse is fatal */
1918 pline("Unfortunately, digesting any of it is fatal.");
1920 Sprintf(killer
.name
, "unwisely tried to eat %s",
1922 killer
.format
= NO_KILLER_PREFIX
;
1924 return 0; /* lifesaved */
1927 if (Slow_digestion
) {
1932 /* Use up amulet of life saving */
1933 if (!!(otmp
= mlifesaver(mdef
)))
1934 m_useup(mdef
, otmp
);
1937 xkilled(mdef
, XKILL_NOMSG
| XKILL_NOCORPSE
);
1938 if (mdef
->mhp
> 0) { /* monster lifesaved */
1939 You("hurriedly regurgitate the sizzling in your %s.",
1940 body_part(STOMACH
));
1942 tmp
= 1 + (pd
->cwt
>> 8);
1943 if (corpse_chance(mdef
, &youmonst
, TRUE
)
1944 && !(mvitals
[monsndx(pd
)].mvflags
& G_NOCORPSE
)) {
1945 /* nutrition only if there can be a corpse */
1946 u
.uhunger
+= (pd
->cnutrit
+ 1) / 2;
1949 Sprintf(msgbuf
, "You totally digest %s.", mon_nam(mdef
));
1951 /* setting afternmv = end_engulf is tempting,
1952 * but will cause problems if the player is
1953 * attacked (which uses his real location) or
1954 * if his See_invisible wears off
1956 You("digest %s.", mon_nam(mdef
));
1960 multi_reason
= "digesting something";
1964 if (pd
== &mons
[PM_GREEN_SLIME
]) {
1965 Sprintf(msgbuf
, "%s isn't sitting well with you.",
1968 make_slimed(5L, (char *) 0);
1971 exercise(A_CON
, TRUE
);
1976 if (youmonst
.data
== &mons
[PM_FOG_CLOUD
]) {
1977 pline("%s is laden with your moisture.", Monnam(mdef
));
1978 if (amphibious(pd
) && !flaming(pd
)) {
1980 pline("%s seems unharmed.", Monnam(mdef
));
1983 pline("%s is pummeled with your debris!", Monnam(mdef
));
1986 pline("%s is covered with your goo!", Monnam(mdef
));
1987 if (resists_acid(mdef
)) {
1988 pline("It seems harmless to %s.", mon_nam(mdef
));
1993 if (can_blnd(&youmonst
, mdef
, mattk
->aatyp
,
1994 (struct obj
*) 0)) {
1996 pline("%s can't see in there!", Monnam(mdef
));
1998 dam
+= mdef
->mblinded
;
2001 mdef
->mblinded
= dam
;
2007 pline_The("air around %s crackles with electricity.",
2009 if (resists_elec(mdef
)) {
2010 pline("%s seems unhurt.", Monnam(mdef
));
2013 golemeffects(mdef
, (int) mattk
->adtyp
, dam
);
2019 if (resists_cold(mdef
)) {
2020 pline("%s seems mildly chilly.", Monnam(mdef
));
2023 pline("%s is freezing to death!", Monnam(mdef
));
2024 golemeffects(mdef
, (int) mattk
->adtyp
, dam
);
2030 if (resists_fire(mdef
)) {
2031 pline("%s seems mildly hot.", Monnam(mdef
));
2034 pline("%s is burning to a crisp!", Monnam(mdef
));
2035 golemeffects(mdef
, (int) mattk
->adtyp
, dam
);
2041 xdrainenergym(mdef
, TRUE
);
2046 if ((mdef
->mhp
-= dam
) <= 0) {
2048 if (mdef
->mhp
<= 0) /* not lifesaved */
2051 You("%s %s!", is_animal(youmonst
.data
) ? "regurgitate" : "expel",
2053 if (Slow_digestion
|| is_animal(youmonst
.data
)) {
2054 pline("Obviously, you didn't like %s taste.",
2055 s_suffix(mon_nam(mdef
)));
2063 missum(mdef
, mattk
, wouldhavehit
)
2064 register struct monst
*mdef
;
2065 register struct attack
*mattk
;
2066 boolean wouldhavehit
;
2068 if (wouldhavehit
) /* monk is missing due to penalty for wearing suit */
2069 Your("armor is rather cumbersome...");
2071 if (could_seduce(&youmonst
, mdef
, mattk
))
2072 You("pretend to be friendly to %s.", mon_nam(mdef
));
2073 else if (canspotmon(mdef
) && flags
.verbose
)
2074 You("miss %s.", mon_nam(mdef
));
2077 if (!mdef
->msleeping
&& mdef
->mcanmove
)
2081 /* attack monster as a monster. */
2084 register struct monst
*mon
;
2086 struct attack
*mattk
, alt_attk
;
2088 boolean altwep
= FALSE
, weapon_used
= FALSE
;
2089 int i
, tmp
, armorpenalty
, sum
[NATTK
], nsum
= 0, dhit
= 0, attknum
= 0;
2091 for (i
= 0; i
< NATTK
; i
++) {
2093 mattk
= getmattk(&youmonst
, mon
, i
, sum
, &alt_attk
);
2094 switch (mattk
->aatyp
) {
2097 /* Certain monsters don't use weapons when encountered as enemies,
2098 * but players who polymorph into them have hands or claws and
2099 * thus should be able to use weapons. This shouldn't prohibit
2100 * the use of most special abilities, either.
2101 * If monster has multiple claw attacks, only one can use weapon.
2104 /* Potential problem: if the monster gets multiple weapon attacks,
2105 * we currently allow the player to get each of these as a weapon
2106 * attack. Is this really desirable?
2108 /* approximate two-weapon mode */
2109 weapon
= (altwep
&& uswapwep
) ? uswapwep
: uwep
;
2110 altwep
= !altwep
; /* toggle for next attack */
2111 tmp
= find_roll_to_hit(mon
, AT_WEAP
, weapon
, &attknum
,
2113 dhit
= (tmp
> (dieroll
= rnd(20)) || u
.uswallow
);
2114 /* Enemy dead, before any special abilities used */
2115 if (!known_hitum(mon
, weapon
, &dhit
, tmp
, armorpenalty
, mattk
)) {
2120 /* might be a worm that gets cut in half */
2121 if (m_at(u
.ux
+ u
.dx
, u
.uy
+ u
.dy
) != mon
)
2122 return (boolean
) (nsum
!= 0);
2123 /* Do not print "You hit" message, since known_hitum
2126 if (dhit
&& mattk
->adtyp
!= AD_SPEL
&& mattk
->adtyp
!= AD_PHYS
)
2127 sum
[i
] = damageum(mon
, mattk
);
2130 if (uwep
&& !cantwield(youmonst
.data
) && !weapon_used
)
2134 if (uwep
&& youmonst
.data
->mlet
== S_LICH
&& !weapon_used
)
2142 tmp
= find_roll_to_hit(mon
, mattk
->aatyp
, (struct obj
*) 0,
2143 &attknum
, &armorpenalty
);
2144 dhit
= (tmp
> (dieroll
= rnd(20)) || u
.uswallow
);
2149 && (compat
= could_seduce(&youmonst
, mon
, mattk
))) {
2151 mon
->mcansee
&& haseyes(mon
->data
) ? "smile at"
2154 compat
== 2 ? "engagingly" : "seductively");
2155 /* doesn't anger it; no wakeup() */
2156 sum
[i
] = damageum(mon
, mattk
);
2160 /* maybe this check should be in damageum()? */
2161 if (mon
->data
== &mons
[PM_SHADE
]
2162 && !(mattk
->aatyp
== AT_KICK
&& uarmf
2163 && uarmf
->blessed
)) {
2164 Your("attack passes harmlessly through %s.",
2168 if (mattk
->aatyp
== AT_KICK
)
2169 You("kick %s.", mon_nam(mon
));
2170 else if (mattk
->aatyp
== AT_BITE
)
2171 You("bite %s.", mon_nam(mon
));
2172 else if (mattk
->aatyp
== AT_STNG
)
2173 You("sting %s.", mon_nam(mon
));
2174 else if (mattk
->aatyp
== AT_BUTT
)
2175 You("butt %s.", mon_nam(mon
));
2176 else if (mattk
->aatyp
== AT_TUCH
)
2177 You("touch %s.", mon_nam(mon
));
2178 else if (mattk
->aatyp
== AT_TENT
)
2179 Your("tentacles suck %s.", mon_nam(mon
));
2181 You("hit %s.", mon_nam(mon
));
2182 sum
[i
] = damageum(mon
, mattk
);
2184 missum(mon
, mattk
, (tmp
+ armorpenalty
> dieroll
));
2189 /* automatic if prev two attacks succeed, or if
2190 * already grabbed in a previous attack
2194 if (mon
->data
== &mons
[PM_SHADE
])
2195 Your("hug passes harmlessly through %s.", mon_nam(mon
));
2196 else if (!sticks(mon
->data
) && !u
.uswallow
) {
2197 if (mon
== u
.ustuck
) {
2198 pline("%s is being %s.", Monnam(mon
),
2199 u
.umonnum
== PM_ROPE_GOLEM
? "choked" : "crushed");
2200 sum
[i
] = damageum(mon
, mattk
);
2201 } else if (i
>= 2 && sum
[i
- 1] && sum
[i
- 2]) {
2202 You("grab %s!", mon_nam(mon
));
2204 sum
[i
] = damageum(mon
, mattk
);
2209 case AT_EXPL
: /* automatic hit if next to */
2212 sum
[i
] = explum(mon
, mattk
);
2216 tmp
= find_roll_to_hit(mon
, mattk
->aatyp
, (struct obj
*) 0,
2217 &attknum
, &armorpenalty
);
2218 if ((dhit
= (tmp
> rnd(20 + i
)))) {
2220 if (mon
->data
== &mons
[PM_SHADE
])
2221 Your("attempt to surround %s is harmless.", mon_nam(mon
));
2223 sum
[i
] = gulpum(mon
, mattk
);
2224 if (sum
[i
] == 2 && (mon
->data
->mlet
== S_ZOMBIE
2225 || mon
->data
->mlet
== S_MUMMY
)
2226 && rn2(5) && !Sick_resistance
) {
2227 You_feel("%ssick.", (Sick
) ? "very " : "");
2228 mdamageu(mon
, rnd(8));
2232 missum(mon
, mattk
, FALSE
);
2237 /* No check for uwep; if wielding nothing we want to
2238 * do the normal 1-2 points bare hand damage...
2240 if ((youmonst
.data
->mlet
== S_KOBOLD
2241 || youmonst
.data
->mlet
== S_ORC
2242 || youmonst
.data
->mlet
== S_GNOME
) && !weapon_used
)
2248 /* Not break--avoid passive attacks from enemy */
2252 case AT_GAZE
: /* all done using #monster command */
2256 default: /* Strange... */
2257 impossible("strange attack of yours (%d)", mattk
->aatyp
);
2260 u
.mh
= -1; /* dead in the current form */
2264 return (boolean
) passive(mon
, 1, 0, mattk
->aatyp
, FALSE
);
2267 (void) passive(mon
, sum
[i
], 1, mattk
->aatyp
, FALSE
);
2271 break; /* No extra attacks if no longer a monster */
2273 break; /* If paralyzed while attacking, i.e. floating eye */
2275 return (boolean
) (nsum
!= 0);
2278 /* Special (passive) attacks on you by monsters done here.
2281 passive(mon
, mhit
, malive
, aatyp
, wep_was_destroyed
)
2282 register struct monst
*mon
;
2283 register boolean mhit
;
2284 register int malive
;
2286 boolean wep_was_destroyed
;
2288 register struct permonst
*ptr
= mon
->data
;
2289 register int i
, tmp
;
2293 return (malive
| mhit
); /* no passive attacks */
2294 if (ptr
->mattk
[i
].aatyp
== AT_NONE
)
2295 break; /* try this one */
2297 /* Note: tmp not always used */
2298 if (ptr
->mattk
[i
].damn
)
2299 tmp
= d((int) ptr
->mattk
[i
].damn
, (int) ptr
->mattk
[i
].damd
);
2300 else if (ptr
->mattk
[i
].damd
)
2301 tmp
= d((int) mon
->m_lev
+ 1, (int) ptr
->mattk
[i
].damd
);
2305 /* These affect you even if they just died.
2307 switch (ptr
->mattk
[i
].adtyp
) {
2309 if (mhit
&& !mon
->mcan
) {
2310 if (aatyp
== AT_KICK
) {
2311 if (uarmf
&& !rn2(6))
2312 (void) erode_obj(uarmf
, xname(uarmf
), ERODE_BURN
,
2313 EF_GREASE
| EF_VERBOSE
);
2314 } else if (aatyp
== AT_WEAP
|| aatyp
== AT_CLAW
2315 || aatyp
== AT_MAGC
|| aatyp
== AT_TUCH
)
2316 passive_obj(mon
, (struct obj
*) 0, &(ptr
->mattk
[i
]));
2320 if (mhit
&& rn2(2)) {
2321 if (Blind
|| !flags
.verbose
)
2322 You("are splashed!");
2324 You("are splashed by %s acid!", s_suffix(mon_nam(mon
)));
2326 if (!Acid_resistance
)
2329 erode_armor(&youmonst
, ERODE_CORRODE
);
2332 if (aatyp
== AT_KICK
) {
2333 if (uarmf
&& !rn2(6))
2334 (void) erode_obj(uarmf
, xname(uarmf
), ERODE_CORRODE
,
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
]));
2340 exercise(A_STR
, FALSE
);
2343 if (mhit
) { /* successful attack */
2344 long protector
= attk_protection((int) aatyp
);
2346 /* hero using monsters' AT_MAGC attack is hitting hand to
2347 hand rather than casting a spell */
2348 if (aatyp
== AT_MAGC
)
2351 if (protector
== 0L /* no protection */
2352 || (protector
== W_ARMG
&& !uarmg
2353 && !uwep
&& !wep_was_destroyed
)
2354 || (protector
== W_ARMF
&& !uarmf
)
2355 || (protector
== W_ARMH
&& !uarmh
)
2356 || (protector
== (W_ARMC
| W_ARMG
) && (!uarmc
|| !uarmg
))) {
2357 if (!Stone_resistance
2358 && !(poly_when_stoned(youmonst
.data
)
2359 && polymon(PM_STONE_GOLEM
))) {
2360 done_in_by(mon
, STONING
); /* "You turn to stone..." */
2367 if (mhit
&& !mon
->mcan
) {
2368 if (aatyp
== AT_KICK
) {
2370 (void) erode_obj(uarmf
, xname(uarmf
), ERODE_RUST
,
2371 EF_GREASE
| EF_VERBOSE
);
2372 } else if (aatyp
== AT_WEAP
|| aatyp
== AT_CLAW
2373 || aatyp
== AT_MAGC
|| aatyp
== AT_TUCH
)
2374 passive_obj(mon
, (struct obj
*) 0, &(ptr
->mattk
[i
]));
2378 if (mhit
&& !mon
->mcan
) {
2379 if (aatyp
== AT_KICK
) {
2381 (void) erode_obj(uarmf
, xname(uarmf
), ERODE_CORRODE
,
2382 EF_GREASE
| EF_VERBOSE
);
2383 } else if (aatyp
== AT_WEAP
|| aatyp
== AT_CLAW
2384 || aatyp
== AT_MAGC
|| aatyp
== AT_TUCH
)
2385 passive_obj(mon
, (struct obj
*) 0, &(ptr
->mattk
[i
]));
2389 /* wrath of gods for attacking Oracle */
2391 shieldeff(u
.ux
, u
.uy
);
2392 pline("A hail of magic missiles narrowly misses you!");
2394 You("are hit by magic missiles appearing from thin air!");
2398 case AD_ENCH
: /* KMH -- remove enchantment (disenchanter) */
2400 struct obj
*obj
= (struct obj
*) 0;
2402 if (aatyp
== AT_KICK
) {
2406 } else if (aatyp
== AT_BITE
|| aatyp
== AT_BUTT
2407 || (aatyp
>= AT_STNG
&& aatyp
< AT_WEAP
)) {
2408 break; /* no object involved */
2410 passive_obj(mon
, obj
, &(ptr
->mattk
[i
]));
2417 /* These only affect you if they still live.
2419 if (malive
&& !mon
->mcan
&& rn2(3)) {
2420 switch (ptr
->mattk
[i
].adtyp
) {
2422 if (ptr
== &mons
[PM_FLOATING_EYE
]) {
2423 if (!canseemon(mon
)) {
2427 if (ureflects("%s gaze is reflected by your %s.",
2428 s_suffix(Monnam(mon
)))) {
2430 } else if (Free_action
) {
2431 You("momentarily stiffen under %s gaze!",
2432 s_suffix(mon_nam(mon
)));
2433 } else if (Hallucination
&& rn2(4)) {
2434 pline("%s looks %s%s.", Monnam(mon
),
2435 !rn2(2) ? "" : "rather ",
2436 !rn2(2) ? "numb" : "stupified");
2438 You("are frozen by %s gaze!", s_suffix(mon_nam(mon
)));
2439 nomul((ACURR(A_WIS
) > 12 || rn2(4)) ? -tmp
: -127);
2440 multi_reason
= "frozen by a monster's gaze";
2444 pline("%s cannot defend itself.",
2445 Adjmonnam(mon
, "blind"));
2449 } else if (Free_action
) {
2450 You("momentarily stiffen.");
2451 } else { /* gelatinous cube */
2452 You("are frozen by %s!", mon_nam(mon
));
2453 nomovemsg
= You_can_move_again
;
2455 multi_reason
= "frozen by a monster";
2456 exercise(A_DEX
, FALSE
);
2459 case AD_COLD
: /* brown mold or blue jelly */
2460 if (monnear(mon
, u
.ux
, u
.uy
)) {
2461 if (Cold_resistance
) {
2462 shieldeff(u
.ux
, u
.uy
);
2463 You_feel("a mild chill.");
2464 ugolemeffects(AD_COLD
, tmp
);
2467 You("are suddenly very cold!");
2469 /* monster gets stronger with your heat! */
2470 mon
->mhp
+= tmp
/ 2;
2471 if (mon
->mhpmax
< mon
->mhp
)
2472 mon
->mhpmax
= mon
->mhp
;
2473 /* at a certain point, the monster will reproduce! */
2474 if (mon
->mhpmax
> ((int) (mon
->m_lev
+ 1) * 8))
2475 (void) split_mon(mon
, &youmonst
);
2478 case AD_STUN
: /* specifically yellow mold */
2480 make_stunned((long) tmp
, TRUE
);
2483 if (monnear(mon
, u
.ux
, u
.uy
)) {
2484 if (Fire_resistance
) {
2485 shieldeff(u
.ux
, u
.uy
);
2486 You_feel("mildly warm.");
2487 ugolemeffects(AD_FIRE
, tmp
);
2490 You("are suddenly very hot!");
2491 mdamageu(mon
, tmp
); /* fire damage */
2495 if (Shock_resistance
) {
2496 shieldeff(u
.ux
, u
.uy
);
2497 You_feel("a mild tingle.");
2498 ugolemeffects(AD_ELEC
, tmp
);
2501 You("are jolted with electricity!");
2508 return (malive
| mhit
);
2512 * Special (passive) attacks on an attacking object by monsters done here.
2513 * Assumes the attack was successful.
2516 passive_obj(mon
, obj
, mattk
)
2517 register struct monst
*mon
;
2518 register struct obj
*obj
; /* null means pick uwep, uswapwep or uarmg */
2519 struct attack
*mattk
; /* null means we find one internally */
2521 struct permonst
*ptr
= mon
->data
;
2524 /* if caller hasn't specified an object, use uwep, uswapwep or uarmg */
2526 obj
= (u
.twoweap
&& uswapwep
&& !rn2(2)) ? uswapwep
: uwep
;
2527 if (!obj
&& mattk
->adtyp
== AD_ENCH
)
2528 obj
= uarmg
; /* no weapon? then must be gloves */
2530 return; /* no object to affect */
2533 /* if caller hasn't specified an attack, find one */
2537 return; /* no passive attacks */
2538 if (ptr
->mattk
[i
].aatyp
== AT_NONE
)
2539 break; /* try this one */
2541 mattk
= &(ptr
->mattk
[i
]);
2544 switch (mattk
->adtyp
) {
2546 if (!rn2(6) && !mon
->mcan
2547 /* steam vortex: fire resist applies, fire damage doesn't */
2548 && mon
->data
!= &mons
[PM_STEAM_VORTEX
]) {
2549 (void) erode_obj(obj
, NULL
, ERODE_BURN
, EF_NONE
);
2554 (void) erode_obj(obj
, NULL
, ERODE_CORRODE
, EF_GREASE
);
2559 (void) erode_obj(obj
, (char *) 0, ERODE_RUST
, EF_GREASE
);
2564 (void) erode_obj(obj
, (char *) 0, ERODE_CORRODE
, EF_GREASE
);
2569 if (drain_item(obj
) && carried(obj
)
2570 && (obj
->known
|| obj
->oclass
== ARMOR_CLASS
)) {
2571 pline("%s less effective.", Yobjnam2(obj
, "seem"));
2583 /* Note: caller must ascertain mtmp is mimicking... */
2585 stumble_onto_mimic(mtmp
)
2588 const char *fmt
= "Wait! That's %s!", *generic
= "a monster", *what
= 0;
2590 if (!u
.ustuck
&& !mtmp
->mflee
&& dmgtype(mtmp
->data
, AD_STCK
))
2595 what
= generic
; /* with default fmt */
2596 else if (mtmp
->m_ap_type
== M_AP_MONSTER
)
2597 what
= a_monnam(mtmp
); /* differs from what was sensed */
2599 int glyph
= levl
[u
.ux
+ u
.dx
][u
.uy
+ u
.dy
].glyph
;
2601 if (glyph_is_cmap(glyph
) && (glyph_to_cmap(glyph
) == S_hcdoor
2602 || glyph_to_cmap(glyph
) == S_vcdoor
))
2603 fmt
= "The door actually was %s!";
2604 else if (glyph_is_object(glyph
) && glyph_to_obj(glyph
) == GOLD_PIECE
)
2605 fmt
= "That gold was %s!";
2607 /* cloned Wiz starts out mimicking some other monster and
2608 might make himself invisible before being revealed */
2609 if (mtmp
->minvis
&& !See_invisible
)
2612 what
= a_monnam(mtmp
);
2617 wakeup(mtmp
); /* clears mimicking */
2618 /* if hero is blind, wakeup() won't display the monster even though
2619 it's no longer concealed */
2620 if (!canspotmon(mtmp
)
2621 && !glyph_is_invisible(levl
[mtmp
->mx
][mtmp
->my
].glyph
))
2622 map_invisible(mtmp
->mx
, mtmp
->my
);
2629 char *hands
= makeplural(body_part(HAND
));
2631 if (!u
.umconf
|| mon
->mconf
)
2633 if (u
.umconf
== 1) {
2635 Your("%s stop tingling.", hands
);
2637 Your("%s stop glowing %s.", hands
, hcolor(NH_RED
));
2640 pline_The("tingling in your %s lessens.", hands
);
2642 Your("%s no longer glow so brightly %s.", hands
, hcolor(NH_RED
));
2648 flash_hits_mon(mtmp
, otmp
)
2650 struct obj
*otmp
; /* source of flash */
2652 int tmp
, amt
, res
= 0, useeit
= canseemon(mtmp
);
2654 if (mtmp
->msleeping
) {
2655 mtmp
->msleeping
= 0;
2657 pline_The("flash awakens %s.", mon_nam(mtmp
));
2660 } else if (mtmp
->data
->mlet
!= S_LIGHT
) {
2661 if (!resists_blnd(mtmp
)) {
2662 tmp
= dist2(otmp
->ox
, otmp
->oy
, mtmp
->mx
, mtmp
->my
);
2664 pline("%s is blinded by the flash!", Monnam(mtmp
));
2667 if (mtmp
->data
== &mons
[PM_GREMLIN
]) {
2668 /* Rule #1: Keep them out of the light. */
2669 amt
= otmp
->otyp
== WAN_LIGHT
? d(1 + otmp
->spe
, 4)
2670 : rn2(min(mtmp
->mhp
, 4));
2671 light_hits_gremlin(mtmp
, amt
);
2673 if (mtmp
->mhp
> 0) {
2674 if (!context
.mon_moving
)
2676 if (tmp
< 9 && !mtmp
->isshk
&& rn2(4))
2677 monflee(mtmp
, rn2(4) ? rnd(100) : 0, FALSE
, TRUE
);
2679 mtmp
->mblinded
= (tmp
< 3) ? 0 : rnd(1 + 50 / tmp
);
2687 light_hits_gremlin(mon
, dmg
)
2691 pline("%s %s!", Monnam(mon
),
2692 (dmg
> mon
->mhp
/ 2) ? "wails in agony" : "cries out in pain");
2693 if ((mon
->mhp
-= dmg
) <= 0) {
2694 if (context
.mon_moving
)
2695 monkilled(mon
, (char *) 0, AD_BLND
);
2698 } else if (cansee(mon
->mx
, mon
->my
) && !canspotmon(mon
)) {
2699 map_invisible(mon
->mx
, mon
->my
);