1 /* NetHack 3.6 zap.c $NHDT-Date: 1457570259 2016/03/10 00:37:39 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.249 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
7 /* Disintegration rays have special treatment; corpses are never left.
8 * But the routine which calculates the damage is separate from the routine
9 * which kills the monster. The damage routine returns this cookie to
10 * indicate that the monster should be disintegrated.
12 #define MAGIC_COOKIE 1000
14 static NEARDATA boolean obj_zapped
;
15 static NEARDATA
int poly_zapped
;
17 extern boolean notonhead
; /* for long worms */
19 /* kludge to use mondied instead of killed */
20 extern boolean m_using
;
22 STATIC_DCL
void FDECL(polyuse
, (struct obj
*, int, int));
23 STATIC_DCL
void FDECL(create_polymon
, (struct obj
*, int));
24 STATIC_DCL
int FDECL(stone_to_flesh_obj
, (struct obj
*));
25 STATIC_DCL boolean
FDECL(zap_updown
, (struct obj
*));
26 STATIC_DCL
void FDECL(zhitu
, (int, int, const char *, XCHAR_P
, XCHAR_P
));
27 STATIC_DCL
void FDECL(revive_egg
, (struct obj
*));
28 STATIC_DCL boolean
FDECL(zap_steed
, (struct obj
*));
29 STATIC_DCL
void FDECL(skiprange
, (int, int *, int *));
31 STATIC_DCL
int FDECL(zap_hit
, (int, int));
32 STATIC_OVL
void FDECL(disintegrate_mon
, (struct monst
*, int, const char *));
33 STATIC_DCL
void FDECL(backfire
, (struct obj
*));
34 STATIC_DCL
int FDECL(spell_hit_bonus
, (int));
36 #define ZT_MAGIC_MISSILE (AD_MAGM - 1)
37 #define ZT_FIRE (AD_FIRE - 1)
38 #define ZT_COLD (AD_COLD - 1)
39 #define ZT_SLEEP (AD_SLEE - 1)
40 #define ZT_DEATH (AD_DISN - 1) /* or disintegration */
41 #define ZT_LIGHTNING (AD_ELEC - 1)
42 #define ZT_POISON_GAS (AD_DRST - 1)
43 #define ZT_ACID (AD_ACID - 1)
44 /* 8 and 9 are currently unassigned */
46 #define ZT_WAND(x) (x)
47 #define ZT_SPELL(x) (10 + (x))
48 #define ZT_BREATH(x) (20 + (x))
50 #define is_hero_spell(type) ((type) >= 10 && (type) < 20)
52 #define M_IN_WATER(ptr) \
53 ((ptr)->mlet == S_EEL || amphibious(ptr) || is_swimmer(ptr))
55 STATIC_VAR
const char are_blinded_by_the_flash
[] =
56 "are blinded by the flash!";
58 const char *const flash_types
[] = /* also used in buzzmu(mcastu.c) */
60 "magic missile", /* Wands must be 0-9 */
61 "bolt of fire", "bolt of cold", "sleep ray", "death ray",
62 "bolt of lightning", "", "", "", "",
64 "magic missile", /* Spell equivalents must be 10-19 */
65 "fireball", "cone of cold", "sleep ray", "finger of death",
66 "bolt of lightning", /* there is no spell, used for retribution */
69 "blast of missiles", /* Dragon breath equivalents 20-29*/
70 "blast of fire", "blast of frost", "blast of sleep gas",
71 "blast of disintegration", "blast of lightning",
72 "blast of poison gas", "blast of acid", "", ""
76 * Recognizing unseen wands by zapping: in 3.4.3 and earlier, zapping
77 * most wand types while blind would add that type to the discoveries
78 * list even if it had never been seen (ie, picked up while blinded
79 * and shown in inventory as simply "a wand"). This behavior has been
80 * changed; now such wands won't be discovered. But if the type is
81 * already discovered, then the individual wand whose effect was just
82 * observed will be flagged as if seen. [You already know wands of
83 * striking; you zap "a wand" and observe striking effect (presumably
84 * by sound or touch); it'll become shown in inventory as "a wand of
87 * Unfortunately, the new behavior isn't really correct either. There
88 * should be an `eknown' bit for "effect known" added for wands (and
89 * for potions since quaffing one of a stack is similar) so that the
90 * particular wand which has been zapped would have its type become
91 * known (it would change from "a wand" to "a wand of striking", for
92 * example) without the type becoming discovered or other unknown wands
93 * of that type showing additional information. When blindness ends,
94 * all objects in inventory with the eknown bit set would be discovered
95 * and other items of the same type would become known as such.
98 /* wand discovery gets special handling when hero is blinded */
103 /* For a wand (or wand-like tool) zapped by the player, if the
104 effect was observable (determined by caller; usually seen, but
105 possibly heard or felt if the hero is blinded) then discover the
106 object type provided that the object itself is known (as more
107 than just "a wand"). If object type is already discovered and
108 we observed the effect, mark the individual wand as having been
109 seen. Suppress spells (which use fake spellbook object for `obj')
110 so that casting a spell won't re-discover its forgotten book. */
111 if (obj
->oclass
!= SPBOOK_CLASS
) {
112 /* if type already discovered, treat this item has having been seen
113 even if hero is currently blinded (skips redundant makeknown) */
114 if (objects
[obj
->otyp
].oc_name_known
) {
115 obj
->dknown
= 1; /* will usually be set already */
117 /* otherwise discover it if item itself has been or can be seen */
119 /* in case it was picked up while blind and then zapped without
120 examining inventory after regaining sight (bypassing xname) */
123 /* make the discovery iff we know what we're manipulating */
125 makeknown(obj
->otyp
);
130 /* Routines for IMMEDIATE wands and spells. */
131 /* bhitm: monster mtmp was hit by the effect of wand or spell otmp */
137 boolean wake
= TRUE
; /* Most 'zaps' should wake monster */
138 boolean reveal_invis
= FALSE
, learn_it
= FALSE
;
139 boolean dbldam
= Role_if(PM_KNIGHT
) && u
.uhave
.questart
;
140 int dmg
, otyp
= otmp
->otyp
;
141 const char *zap_type_text
= "spell";
143 boolean disguised_mimic
= (mtmp
->data
->mlet
== S_MIMIC
144 && mtmp
->m_ap_type
!= M_AP_NOTHING
);
146 if (u
.uswallow
&& mtmp
== u
.ustuck
)
147 reveal_invis
= FALSE
;
149 notonhead
= (mtmp
->mx
!= bhitpos
.x
|| mtmp
->my
!= bhitpos
.y
);
152 zap_type_text
= "wand";
158 if (resists_magm(mtmp
)) { /* match effect on player */
159 shieldeff(mtmp
->mx
, mtmp
->my
);
161 break; /* skip makeknown */
162 } else if (u
.uswallow
|| rnd(20) < 10 + find_mac(mtmp
)) {
166 if (otyp
== SPE_FORCE_BOLT
)
167 dmg
= spell_damage_bonus(dmg
);
168 hit(zap_type_text
, mtmp
, exclam(dmg
));
169 (void) resist(mtmp
, otmp
->oclass
, dmg
, TELL
);
171 miss(zap_type_text
, mtmp
);
174 case WAN_SLOW_MONSTER
:
175 case SPE_SLOW_MONSTER
:
176 if (!resist(mtmp
, otmp
->oclass
, 0, NOTELL
)) {
179 mon_adjust_speed(mtmp
, -1, otmp
);
180 m_dowear(mtmp
, FALSE
); /* might want speed boots */
181 if (u
.uswallow
&& (mtmp
== u
.ustuck
) && is_whirly(mtmp
->data
)) {
182 You("disrupt %s!", mon_nam(mtmp
));
183 pline("A huge hole opens up...");
184 expels(mtmp
, mtmp
->data
, TRUE
);
188 case WAN_SPEED_MONSTER
:
189 if (!resist(mtmp
, otmp
->oclass
, 0, NOTELL
)) {
192 mon_adjust_speed(mtmp
, 1, otmp
);
193 m_dowear(mtmp
, FALSE
); /* might want speed boots */
196 case WAN_UNDEAD_TURNING
:
197 case SPE_TURN_UNDEAD
:
199 if (unturn_dead(mtmp
))
201 if (is_undead(mtmp
->data
) || is_vampshifter(mtmp
)) {
207 if (otyp
== SPE_TURN_UNDEAD
)
208 dmg
= spell_damage_bonus(dmg
);
209 context
.bypasses
= TRUE
; /* for make_corpse() */
210 if (!resist(mtmp
, otmp
->oclass
, dmg
, NOTELL
)) {
212 monflee(mtmp
, 0, FALSE
, TRUE
);
219 if (resists_magm(mtmp
)) {
220 /* magic resistance protects from polymorph traps, so make
221 it guard against involuntary polymorph attacks too... */
222 shieldeff(mtmp
->mx
, mtmp
->my
);
223 } else if (!resist(mtmp
, otmp
->oclass
, 0, NOTELL
)) {
224 /* dropped inventory (due to death by system shock,
225 or loss of wielded weapon and/or worn armor due to
226 limitations of new shape) won't be hit by this zap */
227 for (obj
= mtmp
->minvent
; obj
; obj
= obj
->nobj
)
229 /* natural shapechangers aren't affected by system shock
230 (unless protection from shapechangers is interfering
231 with their metabolism...) */
232 if (mtmp
->cham
== NON_PM
&& !rn2(25)) {
233 if (canseemon(mtmp
)) {
234 pline("%s shudders!", Monnam(mtmp
));
237 /* context.bypasses = TRUE; ## for make_corpse() */
238 /* no corpse after system shock */
240 } else if (newcham(mtmp
, (struct permonst
*) 0,
241 (otyp
!= POT_POLYMORPH
), FALSE
)) {
242 if (!Hallucination
&& canspotmon(mtmp
))
247 case WAN_CANCELLATION
:
248 case SPE_CANCELLATION
:
251 (void) cancel_monst(mtmp
, otmp
, TRUE
, TRUE
, FALSE
);
253 case WAN_TELEPORTATION
:
254 case SPE_TELEPORT_AWAY
:
257 reveal_invis
= !u_teleport_mon(mtmp
, TRUE
);
259 case WAN_MAKE_INVISIBLE
: {
260 int oldinvis
= mtmp
->minvis
;
265 /* format monster's name before altering its visibility */
266 Strcpy(nambuf
, Monnam(mtmp
));
267 mon_set_minvis(mtmp
);
268 if (!oldinvis
&& knowninvisible(mtmp
)) {
269 pline("%s turns transparent!", nambuf
);
275 case SPE_WIZARD_LOCK
:
276 wake
= closeholdingtrap(mtmp
, &learn_it
);
286 wake
= FALSE
; /* don't want immediate counterattack */
287 if (u
.uswallow
&& mtmp
== u
.ustuck
) {
288 if (is_animal(mtmp
->data
)) {
290 You_feel("a sudden rush of air!");
292 pline("%s opens its mouth!", Monnam(mtmp
));
294 expels(mtmp
, mtmp
->data
, TRUE
);
295 /* zap which hits steed will only release saddle if it
296 doesn't hit a holding or falling trap; playability
297 here overrides the more logical target ordering */
298 } else if (openholdingtrap(mtmp
, &learn_it
)) {
300 } else if (openfallingtrap(mtmp
, TRUE
, &learn_it
)) {
301 /* mtmp might now be on the migrating monsters list */
303 } else if ((obj
= which_armor(mtmp
, W_SADDLE
)) != 0) {
306 Sprintf(buf
, "%s %s", s_suffix(Monnam(mtmp
)),
307 distant_name(obj
, xname
));
308 if (cansee(mtmp
->mx
, mtmp
->my
)) {
309 if (!canspotmon(mtmp
))
310 Strcpy(buf
, An(distant_name(obj
, xname
)));
311 pline("%s falls to the %s.", buf
,
312 surface(mtmp
->mx
, mtmp
->my
));
313 } else if (canspotmon(mtmp
)) {
314 pline("%s falls off.", buf
);
316 obj_extract_self(obj
);
317 mdrop_obj(mtmp
, obj
, FALSE
);
321 case SPE_EXTRA_HEALING
:
323 if (mtmp
->data
!= &mons
[PM_PESTILENCE
]) {
324 wake
= FALSE
; /* wakeup() makes the target angry */
325 mtmp
->mhp
+= d(6, otyp
== SPE_EXTRA_HEALING
? 8 : 4);
326 if (mtmp
->mhp
> mtmp
->mhpmax
)
327 mtmp
->mhp
= mtmp
->mhpmax
;
328 if (mtmp
->mblinded
) {
332 if (canseemon(mtmp
)) {
333 if (disguised_mimic
) {
334 if (is_obj_mappear(mtmp
,STRANGE_OBJECT
)) {
335 /* it can do better now */
337 newsym(mtmp
->mx
, mtmp
->my
);
339 mimic_hit_msg(mtmp
, otyp
);
341 pline("%s looks%s better.", Monnam(mtmp
),
342 otyp
== SPE_EXTRA_HEALING
? " much" : "");
344 if (mtmp
->mtame
|| mtmp
->mpeaceful
) {
345 adjalign(Role_if(PM_HEALER
) ? 1 : sgn(u
.ualign
.type
));
347 } else { /* Pestilence */
348 /* Pestilence will always resist; damage is half of 3d{4,8} */
349 (void) resist(mtmp
, otmp
->oclass
,
350 d(3, otyp
== SPE_EXTRA_HEALING
? 8 : 4), TELL
);
353 case WAN_LIGHT
: /* (broken wand) */
354 if (flash_hits_mon(mtmp
, otmp
)) {
359 case WAN_SLEEP
: /* (broken wand) */
360 /* [wakeup() doesn't rouse victims of temporary sleep,
361 so it's okay to leave `wake' set to TRUE here] */
363 if (sleep_monst(mtmp
, d(1 + otmp
->spe
, 12), WAND_CLASS
))
368 case SPE_STONE_TO_FLESH
:
369 if (monsndx(mtmp
->data
) == PM_STONE_GOLEM
) {
370 char *name
= Monnam(mtmp
);
372 /* turn into flesh golem */
373 if (newcham(mtmp
, &mons
[PM_FLESH_GOLEM
], FALSE
, FALSE
)) {
375 pline("%s turns to flesh!", name
);
378 pline("%s looks rather fleshy for a moment.", name
);
386 dmg
= monhp_per_lvl(mtmp
);
389 if (otyp
== SPE_DRAIN_LIFE
)
390 dmg
= spell_damage_bonus(dmg
);
391 if (resists_drli(mtmp
))
392 shieldeff(mtmp
->mx
, mtmp
->my
);
393 else if (!resist(mtmp
, otmp
->oclass
, dmg
, NOTELL
) && mtmp
->mhp
> 0) {
396 if (mtmp
->mhp
<= 0 || mtmp
->mhpmax
<= 0 || mtmp
->m_lev
< 1)
401 pline("%s suddenly seems weaker!", Monnam(mtmp
));
409 impossible("What an interesting effect (%d)", otyp
);
416 if (mtmp
->isshk
&& !*u
.ushops
)
418 } else if (mtmp
->m_ap_type
)
419 seemimic(mtmp
); /* might unblock if mimicing a boulder/door */
421 /* note: bhitpos won't be set if swallowed, but that's okay since
422 * reveal_invis will be false. We can't use mtmp->mx, my since it
423 * might be an invisible worm hit on the tail.
426 if (mtmp
->mhp
> 0 && cansee(bhitpos
.x
, bhitpos
.y
)
427 && !canspotmon(mtmp
))
428 map_invisible(bhitpos
.x
, bhitpos
.y
);
430 /* if effect was observable then discover the wand type provided
431 that the wand itself has been seen */
445 return; /* don't show minvent for long worm tail */
448 for (otmp
= mtmp
->minvent
; otmp
; otmp
= otmp
->nobj
) {
449 otmp
->dknown
= 1; /* treat as "seen" */
450 if (Is_container(otmp
) || otmp
->otyp
== STATUE
) {
452 if (!SchroedingersBox(otmp
))
456 (void) display_minventory(mtmp
, MINV_ALL
| MINV_NOLET
, (char *) 0);
458 pline("%s is not carrying anything%s.", noit_Monnam(mtmp
),
459 (u
.uswallow
&& mtmp
== u
.ustuck
) ? " besides you" : "");
464 * Return the object's physical location. This only makes sense for
465 * objects that are currently on the level (i.e. migrating objects
466 * are nowhere). By default, only things that can be seen (in hero's
467 * inventory, monster's inventory, or on the ground) are reported.
468 * By adding BURIED_TOO and/or CONTAINED_TOO flags, you can also get
469 * the location of buried and contained objects. Note that if an
470 * object is carried by a monster, its reported position may change
471 * from turn to turn. This function returns FALSE if the position
472 * is not available or subject to the constraints above.
475 get_obj_location(obj
, xp
, yp
, locflags
)
480 switch (obj
->where
) {
490 if (obj
->ocarry
->mx
) {
491 *xp
= obj
->ocarry
->mx
;
492 *yp
= obj
->ocarry
->my
;
495 break; /* !mx => migrating monster */
497 if (locflags
& BURIED_TOO
) {
504 if (locflags
& CONTAINED_TOO
)
505 return get_obj_location(obj
->ocontainer
, xp
, yp
, locflags
);
513 get_mon_location(mon
, xp
, yp
, locflags
)
516 int locflags
; /* non-zero means get location even if monster is buried */
518 if (mon
== &youmonst
) {
522 } else if (mon
->mx
> 0 && (!mon
->mburied
|| locflags
)) {
526 } else { /* migrating or buried */
532 /* used by revive() and animate_statue() */
538 struct monst
*mtmp
= (struct monst
*) 0;
539 struct monst
*mtmp2
= (struct monst
*) 0;
542 mtmp2
= get_mtraits(obj
, TRUE
);
544 /* save_mtraits() validated mtmp2->mnum */
545 mtmp2
->data
= &mons
[mtmp2
->mnum
];
546 if (mtmp2
->mhpmax
<= 0 && !is_rider(mtmp2
->data
))
547 return (struct monst
*) 0;
548 mtmp
= makemon(mtmp2
->data
, cc
->x
, cc
->y
,
549 NO_MINVENT
| MM_NOWAIT
| MM_NOCOUNTBIRTH
);
553 /* heal the monster */
554 if (mtmp
->mhpmax
> mtmp2
->mhpmax
&& is_rider(mtmp2
->data
))
555 mtmp2
->mhpmax
= mtmp
->mhpmax
;
556 mtmp2
->mhp
= mtmp2
->mhpmax
;
557 /* Get these ones from mtmp */
558 mtmp2
->minvent
= mtmp
->minvent
; /*redundant*/
559 /* monster ID is available if the monster died in the current
560 game, but will be zero if the corpse was in a bones level
561 (we cleared it when loading bones) */
563 mtmp2
->m_id
= mtmp
->m_id
;
564 /* might be bringing quest leader back to life */
565 if (quest_status
.leader_is_dead
&&
566 /* leader_is_dead implies leader_m_id is valid */
567 mtmp2
->m_id
== quest_status
.leader_m_id
)
568 quest_status
.leader_is_dead
= FALSE
;
570 mtmp2
->mx
= mtmp
->mx
;
571 mtmp2
->my
= mtmp
->my
;
572 mtmp2
->mux
= mtmp
->mux
;
573 mtmp2
->muy
= mtmp
->muy
;
574 mtmp2
->mw
= mtmp
->mw
;
575 mtmp2
->wormno
= mtmp
->wormno
;
576 mtmp2
->misc_worn_check
= mtmp
->misc_worn_check
;
577 mtmp2
->weapon_check
= mtmp
->weapon_check
;
578 mtmp2
->mtrapseen
= mtmp
->mtrapseen
;
579 mtmp2
->mflee
= mtmp
->mflee
;
580 mtmp2
->mburied
= mtmp
->mburied
;
581 mtmp2
->mundetected
= mtmp
->mundetected
;
582 mtmp2
->mfleetim
= mtmp
->mfleetim
;
583 mtmp2
->mlstmv
= mtmp
->mlstmv
;
584 mtmp2
->m_ap_type
= mtmp
->m_ap_type
;
585 /* set these ones explicitly */
591 mtmp2
->msleeping
= 0;
594 /* most cancelled monsters return to normal,
595 but some need to stay cancelled */
596 if (!dmgtype(mtmp2
->data
, AD_SEDU
)
597 && (!SYSOPT_SEDUCE
|| !dmgtype(mtmp2
->data
, AD_SSEX
)))
599 mtmp2
->mcansee
= 1; /* set like in makemon */
603 replmon(mtmp
, mtmp2
);
604 newsym(mtmp2
->mx
, mtmp2
->my
); /* Might now be invisible */
606 /* in case Protection_from_shape_changers is different
607 now than it was when the traits were stored */
614 * get_container_location() returns the following information
615 * about the outermost container:
616 * loc argument gets set to:
617 * OBJ_INVENT if in hero's inventory; return 0.
618 * OBJ_FLOOR if on the floor; return 0.
619 * OBJ_BURIED if buried; return 0.
620 * OBJ_MINVENT if in monster's inventory; return monster.
621 * container_nesting is updated with the nesting depth of the containers
625 get_container_location(obj
, loc
, container_nesting
)
628 int *container_nesting
;
633 if (container_nesting
)
634 *container_nesting
= 0;
635 while (obj
&& obj
->where
== OBJ_CONTAINED
) {
636 if (container_nesting
)
637 *container_nesting
+= 1;
638 obj
= obj
->ocontainer
;
641 *loc
= obj
->where
; /* outermost container's location */
642 if (obj
->where
== OBJ_MINVENT
)
645 return (struct monst
*) 0;
649 * Attempt to revive the given corpse, return the revived monster if
650 * successful. Note: this does NOT use up the corpse if it fails.
653 revive(corpse
, by_hero
)
657 struct monst
*mtmp
= 0;
658 struct permonst
*mptr
;
659 struct obj
*container
;
662 int montype
, container_nesting
= 0;
664 if (corpse
->otyp
!= CORPSE
) {
665 impossible("Attempting to revive %s?", xname(corpse
));
666 return (struct monst
*) 0;
670 if (corpse
->where
!= OBJ_CONTAINED
) {
671 /* only for invent, minvent, or floor */
673 (void) get_obj_location(corpse
, &x
, &y
, 0);
675 /* deal with corpses in [possibly nested] containers */
676 struct monst
*carrier
;
677 int holder
= OBJ_FREE
;
679 container
= corpse
->ocontainer
;
681 get_container_location(container
, &holder
, &container_nesting
);
684 x
= carrier
->mx
, y
= carrier
->my
;
690 (void) get_obj_location(corpse
, &x
, &y
, CONTAINED_TOO
);
693 break; /* x,y are 0 */
697 /* Rules for revival from containers:
698 - the container cannot be locked
699 - the container cannot be heavily nested (>2 is arbitrary)
700 - the container cannot be a statue or bag of holding
701 (except in very rare cases for the latter)
703 (container
&& (container
->olocked
|| container_nesting
> 2
704 || container
->otyp
== STATUE
705 || (container
->otyp
== BAG_OF_HOLDING
&& rn2(40)))))
706 return (struct monst
*) 0;
708 /* record the object's location now that we're sure where it is */
709 corpse
->ox
= x
, corpse
->oy
= y
;
711 /* prepare for the monster */
712 montype
= corpse
->corpsenm
;
713 mptr
= &mons
[montype
];
714 /* [should probably handle recorporealization first; if corpse and
715 ghost are at same location, revived creature shouldn't be bumped
716 to an adjacent spot by ghost which joins with it] */
718 if (enexto(&xy
, x
, y
, mptr
))
722 if (mons
[montype
].mlet
== S_EEL
&& !IS_POOL(levl
[x
][y
].typ
)) {
723 if (by_hero
&& cansee(x
,y
))
724 pline("%s twitches feebly.",
725 upstart(corpse_xname(corpse
, (const char *) 0, CXN_PFX_THE
)));
726 return (struct monst
*) 0;
729 if (cant_revive(&montype
, TRUE
, corpse
)) {
730 /* make a zombie or doppelganger instead */
731 /* note: montype has changed; mptr keeps old value for newcham() */
732 mtmp
= makemon(&mons
[montype
], x
, y
, NO_MINVENT
| MM_NOWAIT
);
734 /* skip ghost handling */
735 if (has_omid(corpse
))
737 if (has_omonst(corpse
))
739 if (mtmp
->cham
== PM_DOPPELGANGER
) {
740 /* change shape to match the corpse */
741 (void) newcham(mtmp
, mptr
, FALSE
, FALSE
);
742 } else if (mtmp
->data
->mlet
== S_ZOMBIE
) {
743 mtmp
->mhp
= mtmp
->mhpmax
= 100;
744 mon_adjust_speed(mtmp
, 2, (struct obj
*) 0); /* MFAST */
747 } else if (has_omonst(corpse
)) {
748 /* use saved traits */
750 mtmp
= montraits(corpse
, &xy
);
751 if (mtmp
&& mtmp
->mtame
&& !mtmp
->isminion
)
752 wary_dog(mtmp
, TRUE
);
754 /* make a new monster */
755 mtmp
= makemon(mptr
, x
, y
, NO_MINVENT
| MM_NOWAIT
| MM_NOCOUNTBIRTH
);
758 return (struct monst
*) 0;
760 /* hiders shouldn't already be re-hidden when they revive */
761 if (mtmp
->mundetected
) {
762 mtmp
->mundetected
= 0;
763 newsym(mtmp
->mx
, mtmp
->my
);
768 /* if this is caused by the hero there might be a shop charge */
770 struct monst
*shkp
= 0;
772 x
= corpse
->ox
, y
= corpse
->oy
;
773 if (costly_spot(x
, y
))
774 shkp
= shop_keeper(*in_rooms(x
, y
, SHOPBASE
));
778 unsigned pfx
= CXN_PFX_THE
;
780 Strcpy(buf
, (corpse
->quan
> 1L) ? "one of " : "");
781 if (carried(corpse
) && !corpse
->unpaid
) {
782 Strcat(buf
, "your ");
785 Strcat(buf
, corpse_xname(corpse
, (const char *) 0, pfx
));
786 pline("%s glows iridescently.", upstart(buf
));
788 /* need some prior description of the corpse since
789 stolen_value() will refer to the object as "it" */
790 pline("A corpse is resuscitated.");
792 /* don't charge for shopkeeper's own corpse if we just revived him */
793 if (shkp
&& mtmp
!= shkp
)
794 (void) stolen_value(corpse
, x
, y
, (boolean
) shkp
->mpeaceful
,
797 /* [we don't give any comparable message about the corpse for
798 the !by_hero case because caller might have already done so] */
801 /* handle recorporealization of an active ghost */
802 if (has_omid(corpse
)) {
807 (void) memcpy((genericptr_t
) &m_id
, (genericptr_t
) OMID(corpse
),
809 ghost
= find_mid(m_id
, FM_FMON
);
810 if (ghost
&& ghost
->data
== &mons
[PM_GHOST
]) {
811 if (canseemon(ghost
))
812 pline("%s is suddenly drawn into its former body!",
814 /* transfer the ghost's inventory along with it */
815 while ((otmp
= ghost
->minvent
) != 0) {
816 obj_extract_self(otmp
);
817 add_to_minv(mtmp
, otmp
);
819 /* tame the revived monster if its ghost was tame */
820 if (ghost
->mtame
&& !mtmp
->mtame
) {
821 if (tamedog(mtmp
, (struct obj
*) 0)) {
822 /* ghost's edog data is ignored */
823 mtmp
->mtame
= ghost
->mtame
;
826 /* was ghost, now alive, it's all very confusing */
828 /* separate ghost monster no longer exists */
834 /* monster retains its name */
835 if (has_oname(corpse
) && !unique_corpstat(mtmp
->data
))
836 mtmp
= christen_monst(mtmp
, ONAME(corpse
));
837 /* partially eaten corpse yields wounded monster */
839 mtmp
->mhp
= eaten_stat(mtmp
->mhp
, corpse
);
840 /* track that this monster was revived at least once */
843 /* finally, get rid of the corpse--it's gone now */
844 switch (corpse
->where
) {
849 /* in case MON_AT+enexto for invisible mon */
850 x
= corpse
->ox
, y
= corpse
->oy
;
851 /* not useupf(), which charges */
852 if (corpse
->quan
> 1L)
853 corpse
= splitobj(corpse
, 1L);
858 m_useup(corpse
->ocarry
, corpse
);
861 obj_extract_self(corpse
);
862 obfree(corpse
, (struct obj
*) 0);
876 * Note: generic eggs with corpsenm set to NON_PM will never hatch.
878 if (obj
->otyp
!= EGG
)
880 if (obj
->corpsenm
!= NON_PM
&& !dead_species(obj
->corpsenm
, TRUE
))
881 attach_egg_hatch_timeout(obj
, 0L);
884 /* try to revive all corpses and eggs carried by `mon' */
889 struct obj
*otmp
, *otmp2
;
891 char owner
[BUFSZ
], corpse
[BUFSZ
];
893 int once
= 0, res
= 0;
895 youseeit
= (mon
== &youmonst
) ? TRUE
: canseemon(mon
);
896 otmp2
= (mon
== &youmonst
) ? invent
: mon
->minvent
;
898 while ((otmp
= otmp2
) != 0) {
900 if (otmp
->otyp
== EGG
)
902 if (otmp
->otyp
!= CORPSE
)
904 /* save the name; the object is liable to go away */
907 corpse_xname(otmp
, (const char *) 0, CXN_SINGULAR
));
909 /* for a merged group, only one is revived; should this be fixed? */
910 if ((mtmp2
= revive(otmp
, !context
.mon_moving
)) != 0) {
914 Strcpy(owner
, (mon
== &youmonst
) ? "Your"
915 : s_suffix(Monnam(mon
)));
916 pline("%s %s suddenly comes alive!", owner
, corpse
);
917 } else if (canseemon(mtmp2
))
918 pline("%s suddenly appears!", Amonnam(mtmp2
));
924 /* cancel obj, possibly carried by you or a monster */
927 register struct obj
*obj
;
929 boolean u_ring
= (obj
== uleft
|| obj
== uright
);
930 int otyp
= obj
->otyp
;
933 case RIN_GAIN_STRENGTH
:
934 if ((obj
->owornmask
& W_RING
) && u_ring
) {
935 ABON(A_STR
) -= obj
->spe
;
939 case RIN_GAIN_CONSTITUTION
:
940 if ((obj
->owornmask
& W_RING
) && u_ring
) {
941 ABON(A_CON
) -= obj
->spe
;
946 if ((obj
->owornmask
& W_RING
) && u_ring
) {
947 ABON(A_CHA
) -= obj
->spe
;
951 case RIN_INCREASE_ACCURACY
:
952 if ((obj
->owornmask
& W_RING
) && u_ring
)
953 u
.uhitinc
-= obj
->spe
;
955 case RIN_INCREASE_DAMAGE
:
956 if ((obj
->owornmask
& W_RING
) && u_ring
)
957 u
.udaminc
-= obj
->spe
;
959 case GAUNTLETS_OF_DEXTERITY
:
960 if ((obj
->owornmask
& W_ARMG
) && (obj
== uarmg
)) {
961 ABON(A_DEX
) -= obj
->spe
;
965 case HELM_OF_BRILLIANCE
:
966 if ((obj
->owornmask
& W_ARMH
) && (obj
== uarmh
)) {
967 ABON(A_INT
) -= obj
->spe
;
968 ABON(A_WIS
) -= obj
->spe
;
972 /* case RIN_PROTECTION: not needed */
974 if (objects
[otyp
].oc_magic
975 || (obj
->spe
&& (obj
->oclass
== ARMOR_CLASS
976 || obj
->oclass
== WEAPON_CLASS
|| is_weptool(obj
)))
978 || otyp
== POT_SICKNESS
979 || (otyp
== POT_WATER
&& (obj
->blessed
|| obj
->cursed
))) {
980 if (obj
->spe
!= ((obj
->oclass
== WAND_CLASS
) ? -1 : 0)
981 && otyp
!= WAN_CANCELLATION
/* can't cancel cancellation */
982 && otyp
!= MAGIC_LAMP
/* cancelling doesn't remove djinni */
983 && otyp
!= CANDELABRUM_OF_INVOCATION
) {
984 costly_alteration(obj
, COST_CANCEL
);
985 obj
->spe
= (obj
->oclass
== WAND_CLASS
) ? -1 : 0;
987 switch (obj
->oclass
) {
989 costly_alteration(obj
, COST_CANCEL
);
990 obj
->otyp
= SCR_BLANK_PAPER
;
994 if (otyp
!= SPE_CANCELLATION
&& otyp
!= SPE_NOVEL
995 && otyp
!= SPE_BOOK_OF_THE_DEAD
) {
996 costly_alteration(obj
, COST_CANCEL
);
997 obj
->otyp
= SPE_BLANK_PAPER
;
1001 costly_alteration(obj
,
1004 : obj
->cursed
? COST_UNCURS
: COST_UNBLSS
);
1005 if (otyp
== POT_SICKNESS
|| otyp
== POT_SEE_INVISIBLE
) {
1006 /* sickness is "biologically contaminated" fruit juice;
1007 cancel it and it just becomes fruit juice...
1008 whereas see invisible tastes like "enchanted" fruit
1009 juice, it similarly cancels */
1010 obj
->otyp
= POT_FRUIT_JUICE
;
1012 obj
->otyp
= POT_WATER
;
1013 obj
->odiluted
= 0; /* same as any other water */
1023 /* Remove a positive enchantment or charge from obj,
1024 * possibly carried by you or a monster
1028 register struct obj
*obj
;
1032 /* Is this a charged/enchanted object? */
1034 || (!objects
[obj
->otyp
].oc_charged
&& obj
->oclass
!= WEAPON_CLASS
1035 && obj
->oclass
!= ARMOR_CLASS
&& !is_weptool(obj
))
1038 if (defends(AD_DRLI
, obj
) || defends_when_carried(AD_DRLI
, obj
)
1039 || obj_resists(obj
, 10, 90))
1042 /* Charge for the cost of the object */
1043 costly_alteration(obj
, COST_DRAIN
);
1045 /* Drain the object and any implied effects */
1047 u_ring
= (obj
== uleft
) || (obj
== uright
);
1048 switch (obj
->otyp
) {
1049 case RIN_GAIN_STRENGTH
:
1050 if ((obj
->owornmask
& W_RING
) && u_ring
) {
1055 case RIN_GAIN_CONSTITUTION
:
1056 if ((obj
->owornmask
& W_RING
) && u_ring
) {
1062 if ((obj
->owornmask
& W_RING
) && u_ring
) {
1067 case RIN_INCREASE_ACCURACY
:
1068 if ((obj
->owornmask
& W_RING
) && u_ring
)
1071 case RIN_INCREASE_DAMAGE
:
1072 if ((obj
->owornmask
& W_RING
) && u_ring
)
1075 case HELM_OF_BRILLIANCE
:
1076 if ((obj
->owornmask
& W_ARMH
) && (obj
== uarmh
)) {
1082 case GAUNTLETS_OF_DEXTERITY
:
1083 if ((obj
->owornmask
& W_ARMG
) && (obj
== uarmg
)) {
1088 case RIN_PROTECTION
:
1098 obj_resists(obj
, ochance
, achance
)
1100 int ochance
, achance
; /* percent chance for ordinary objects, artifacts */
1102 if (obj
->otyp
== AMULET_OF_YENDOR
1103 || obj
->otyp
== SPE_BOOK_OF_THE_DEAD
1104 || obj
->otyp
== CANDELABRUM_OF_INVOCATION
1105 || obj
->otyp
== BELL_OF_OPENING
1106 || (obj
->otyp
== CORPSE
&& is_rider(&mons
[obj
->corpsenm
]))) {
1109 int chance
= rn2(100);
1111 return (boolean
) (chance
< (obj
->oartifact
? achance
: ochance
));
1121 if (context
.bypasses
&& obj
->bypass
)
1124 if (obj
->oclass
== WAND_CLASS
)
1125 zap_odds
= 3; /* half-life = 2 zaps */
1126 else if (obj
->cursed
)
1127 zap_odds
= 3; /* half-life = 2 zaps */
1128 else if (obj
->blessed
)
1129 zap_odds
= 12; /* half-life = 8 zaps */
1131 zap_odds
= 8; /* half-life = 6 zaps */
1133 /* adjust for "large" quantities of identical things */
1137 return (boolean
) !rn2(zap_odds
);
1140 /* Use up at least minwt number of things made of material mat.
1141 * There's also a chance that other stuff will be used up. Finally,
1142 * there's a random factor here to keep from always using the stuff
1143 * at the top of the pile.
1146 polyuse(objhdr
, mat
, minwt
)
1150 register struct obj
*otmp
, *otmp2
;
1152 for (otmp
= objhdr
; minwt
> 0 && otmp
; otmp
= otmp2
) {
1153 otmp2
= otmp
->nexthere
;
1154 if (context
.bypasses
&& otmp
->bypass
)
1156 if (otmp
== uball
|| otmp
== uchain
)
1158 if (obj_resists(otmp
, 0, 0))
1159 continue; /* preserve unique objects */
1161 if (otmp
->otyp
== SCR_MAIL
)
1165 if (((int) objects
[otmp
->otyp
].oc_material
== mat
)
1166 == (rn2(minwt
+ 1) != 0)) {
1167 /* appropriately add damage to bill */
1168 if (costly_spot(otmp
->ox
, otmp
->oy
)) {
1170 addtobill(otmp
, FALSE
, FALSE
, FALSE
);
1172 (void) stolen_value(otmp
, otmp
->ox
, otmp
->oy
, FALSE
,
1175 if (otmp
->quan
< LARGEST_INT
)
1176 minwt
-= (int) otmp
->quan
;
1185 * Polymorph some of the stuff in this pile into a monster, preferably
1186 * a golem of the kind okind.
1189 create_polymon(obj
, okind
)
1193 struct permonst
*mdat
= (struct permonst
*) 0;
1195 const char *material
;
1198 if (context
.bypasses
) {
1199 /* this is approximate because the "no golems" !obj->nexthere
1200 check below doesn't understand bypassed objects; but it
1201 should suffice since bypassed objects always end up as a
1202 consecutive group at the top of their pile */
1203 while (obj
&& obj
->bypass
)
1204 obj
= obj
->nexthere
;
1207 /* no golems if you zap only one object -- not enough stuff */
1208 if (!obj
|| (!obj
->nexthere
&& obj
->quan
== 1L))
1211 /* some of these choices are arbitrary */
1216 pm_index
= PM_IRON_GOLEM
;
1217 material
= "metal ";
1224 pm_index
= rn2(2) ? PM_STONE_GOLEM
: PM_CLAY_GOLEM
;
1225 material
= "lithic ";
1229 /* there is no flesh type, but all food is type 0, so we use it */
1230 pm_index
= PM_FLESH_GOLEM
;
1231 material
= "organic ";
1234 pm_index
= PM_WOOD_GOLEM
;
1238 pm_index
= PM_LEATHER_GOLEM
;
1239 material
= "leather ";
1242 pm_index
= PM_ROPE_GOLEM
;
1243 material
= "cloth ";
1246 pm_index
= PM_SKELETON
; /* nearest thing to "bone golem" */
1250 pm_index
= PM_GOLD_GOLEM
;
1254 pm_index
= PM_GLASS_GOLEM
;
1255 material
= "glassy ";
1258 pm_index
= PM_PAPER_GOLEM
;
1259 material
= "paper ";
1262 /* if all else fails... */
1263 pm_index
= PM_STRAW_GOLEM
;
1268 if (!(mvitals
[pm_index
].mvflags
& G_GENOD
))
1269 mdat
= &mons
[pm_index
];
1271 mtmp
= makemon(mdat
, obj
->ox
, obj
->oy
, NO_MM_FLAGS
);
1272 polyuse(obj
, okind
, (int) mons
[pm_index
].cwt
);
1274 if (mtmp
&& cansee(mtmp
->mx
, mtmp
->my
)) {
1275 pline("Some %sobjects meld, and %s arises from the pile!", material
,
1280 /* Assumes obj is on the floor. */
1288 if (obj
->otyp
== SCR_MAIL
)
1293 if (poly_zapped
< 0) {
1294 /* some may metamorphosize */
1295 for (i
= obj
->quan
; i
; i
--)
1296 if (!rn2(Luck
+ 45)) {
1297 poly_zapped
= objects
[obj
->otyp
].oc_material
;
1302 /* if quan > 1 then some will survive intact */
1303 if (obj
->quan
> 1L) {
1304 if (obj
->quan
> LARGEST_INT
)
1305 obj
= splitobj(obj
, (long) rnd(30000));
1307 obj
= splitobj(obj
, (long) rnd((int) obj
->quan
- 1));
1310 /* appropriately add damage to bill */
1311 if (costly_spot(obj
->ox
, obj
->oy
)) {
1313 addtobill(obj
, FALSE
, FALSE
, FALSE
);
1315 (void) stolen_value(obj
, obj
->ox
, obj
->oy
, FALSE
, FALSE
);
1318 /* zap the object */
1322 /* classes of items whose current charge count carries over across polymorph
1324 static const char charged_objs
[] = { WAND_CLASS
, WEAPON_CLASS
, ARMOR_CLASS
,
1328 * Polymorph the object to the given object ID. If the ID is STRANGE_OBJECT
1329 * then pick random object from the source's class (this is the standard
1330 * "polymorph" case). If ID is set to a specific object, inhibit fusing
1331 * n objects into 1. This could have been added as a flag, but currently
1332 * it is tied to not being the standard polymorph case. The new polymorphed
1333 * object replaces obj in its link chains. Return value is a pointer to
1336 * This should be safe to call for an object anywhere.
1345 boolean can_merge
= (id
== STRANGE_OBJECT
);
1346 int obj_location
= obj
->where
;
1348 if (obj
->otyp
== BOULDER
)
1350 if (id
== STRANGE_OBJECT
) { /* preserve symbol */
1352 unsigned magic_obj
= objects
[obj
->otyp
].oc_magic
;
1354 if (obj
->otyp
== UNICORN_HORN
&& obj
->degraded_horn
)
1356 /* Try up to 3 times to make the magic-or-not status of
1357 the new item be the same as it was for the old one. */
1358 otmp
= (struct obj
*) 0;
1362 otmp
= mkobj(obj
->oclass
, FALSE
);
1363 } while (--try_limit
> 0
1364 && objects
[otmp
->otyp
].oc_magic
!= magic_obj
);
1366 /* literally replace obj with this new thing */
1367 otmp
= mksobj(id
, FALSE
, FALSE
);
1368 /* Actually more things use corpsenm but they polymorph differently */
1369 #define USES_CORPSENM(typ) \
1370 ((typ) == CORPSE || (typ) == STATUE || (typ) == FIGURINE)
1372 if (USES_CORPSENM(obj
->otyp
) && USES_CORPSENM(id
))
1373 set_corpsenm(otmp
, obj
->corpsenm
);
1374 #undef USES_CORPSENM
1377 /* preserve quantity */
1378 otmp
->quan
= obj
->quan
;
1379 /* preserve the shopkeepers (lack of) interest */
1380 otmp
->no_charge
= obj
->no_charge
;
1381 /* preserve inventory letter if in inventory */
1382 if (obj_location
== OBJ_INVENT
)
1383 otmp
->invlet
= obj
->invlet
;
1385 /* You can't send yourself 100 mail messages and then
1386 * polymorph them into useful scrolls
1388 if (obj
->otyp
== SCR_MAIL
) {
1389 otmp
->otyp
= SCR_MAIL
;
1394 /* avoid abusing eggs laid by you */
1395 if (obj
->otyp
== EGG
&& obj
->spe
) {
1396 int mnum
, tryct
= 100;
1398 /* first, turn into a generic egg */
1399 if (otmp
->otyp
== EGG
)
1403 otmp
->owt
= weight(otmp
);
1405 otmp
->corpsenm
= NON_PM
;
1408 /* now change it into something laid by the hero */
1410 mnum
= can_be_hatched(random_monster());
1411 if (mnum
!= NON_PM
&& !dead_species(mnum
, TRUE
)) {
1412 otmp
->spe
= 1; /* laid by hero */
1413 set_corpsenm(otmp
, mnum
); /* also sets hatch timer */
1419 /* keep special fields (including charges on wands) */
1420 if (index(charged_objs
, otmp
->oclass
))
1421 otmp
->spe
= obj
->spe
;
1422 otmp
->recharged
= obj
->recharged
;
1424 otmp
->cursed
= obj
->cursed
;
1425 otmp
->blessed
= obj
->blessed
;
1427 if (erosion_matters(otmp
)) {
1428 if (is_flammable(otmp
) || is_rustprone(otmp
))
1429 otmp
->oeroded
= obj
->oeroded
;
1430 if (is_corrodeable(otmp
) || is_rottable(otmp
))
1431 otmp
->oeroded2
= obj
->oeroded2
;
1432 if (is_damageable(otmp
))
1433 otmp
->oerodeproof
= obj
->oerodeproof
;
1436 /* Keep chest/box traps and poisoned ammo if we may */
1437 if (obj
->otrapped
&& Is_box(otmp
))
1438 otmp
->otrapped
= TRUE
;
1440 if (obj
->opoisoned
&& is_poisonable(otmp
))
1441 otmp
->opoisoned
= TRUE
;
1443 if (id
== STRANGE_OBJECT
&& obj
->otyp
== CORPSE
) {
1444 /* turn crocodile corpses into shoes */
1445 if (obj
->corpsenm
== PM_CROCODILE
) {
1446 otmp
->otyp
= LOW_BOOTS
;
1447 otmp
->oclass
= ARMOR_CLASS
;
1450 otmp
->oerodeproof
= TRUE
;
1452 otmp
->cursed
= FALSE
;
1456 /* no box contents --KAA */
1457 if (Has_contents(otmp
))
1458 delete_contents(otmp
);
1460 /* 'n' merged objects may be fused into 1 object */
1461 if (otmp
->quan
> 1L && (!objects
[otmp
->otyp
].oc_merge
1462 || (can_merge
&& otmp
->quan
> (long) rn2(1000))))
1465 switch (otmp
->oclass
) {
1467 if (otmp
->otyp
== MAGIC_LAMP
) {
1468 otmp
->otyp
= OIL_LAMP
;
1469 otmp
->age
= 1500L; /* "best" oil lamp possible */
1470 } else if (otmp
->otyp
== MAGIC_MARKER
) {
1471 otmp
->recharged
= 1; /* degraded quality */
1473 /* don't care about the recharge count of other tools */
1477 while (otmp
->otyp
== WAN_WISHING
|| otmp
->otyp
== WAN_POLYMORPH
)
1478 otmp
->otyp
= rnd_class(WAN_LIGHT
, WAN_LIGHTNING
);
1479 /* altering the object tends to degrade its quality
1480 (analogous to spellbook `read count' handling) */
1481 if ((int) otmp
->recharged
< rn2(7)) /* recharge_limit */
1486 while (otmp
->otyp
== POT_POLYMORPH
)
1487 otmp
->otyp
= rnd_class(POT_GAIN_ABILITY
, POT_WATER
);
1491 while (otmp
->otyp
== SPE_POLYMORPH
)
1492 otmp
->otyp
= rnd_class(SPE_DIG
, SPE_BLANK_PAPER
);
1493 /* reduce spellbook abuse; non-blank books degrade */
1494 if (otmp
->otyp
!= SPE_BLANK_PAPER
) {
1495 otmp
->spestudied
= obj
->spestudied
+ 1;
1496 if (otmp
->spestudied
> MAX_SPELL_STUDY
) {
1497 otmp
->otyp
= SPE_BLANK_PAPER
;
1498 /* writing a new book over it will yield an unstudied
1499 one; re-polymorphing this one as-is may or may not
1500 get something non-blank */
1501 otmp
->spestudied
= rn2(otmp
->spestudied
);
1507 if (otmp
->quan
> (long) rnd(4)
1508 && objects
[obj
->otyp
].oc_material
== MINERAL
1509 && objects
[otmp
->otyp
].oc_material
!= MINERAL
) {
1510 otmp
->otyp
= ROCK
; /* transmutation backfired */
1511 otmp
->quan
/= 2L; /* some material has been lost */
1516 /* update the weight */
1517 otmp
->owt
= weight(otmp
);
1519 /* handle polymorph of worn item: stone-to-flesh cast on self can
1520 affect multiple objects at once, but their new forms won't
1521 produce any side-effects; a single worn item dipped into potion
1522 of polymorph can produce side-effects but those won't yield out
1523 of sequence messages because current polymorph is finished */
1524 if (obj_location
== OBJ_INVENT
&& obj
->owornmask
) {
1525 long old_wornmask
= obj
->owornmask
& ~(W_ART
| W_ARTI
),
1526 new_wornmask
= wearslot(otmp
);
1527 boolean was_twohanded
= bimanual(obj
), was_twoweap
= u
.twoweap
;
1529 remove_worn_item(obj
, TRUE
);
1530 /* if the new form can be worn in the same slot, make it so
1531 [possible extension: if it could be worn in some other
1532 slot which is currently unfilled, wear it there instead] */
1533 if ((old_wornmask
& W_QUIVER
) != 0L) {
1535 } else if ((old_wornmask
& W_SWAPWEP
) != 0L) {
1536 if (was_twohanded
|| !bimanual(otmp
))
1538 if (was_twoweap
&& uswapwep
)
1540 } else if ((old_wornmask
& W_WEP
) != 0L) {
1541 if (was_twohanded
|| !bimanual(otmp
) || !uarms
)
1543 if (was_twoweap
&& uwep
&& !bimanual(uwep
))
1545 } else if ((old_wornmask
& new_wornmask
) != 0L) {
1546 new_wornmask
&= old_wornmask
;
1547 setworn(otmp
, new_wornmask
);
1548 set_wear(otmp
); /* Armor_on() for side-effects */
1552 /* ** we are now done adjusting the object ** */
1554 /* swap otmp for obj */
1555 replace_object(obj
, otmp
);
1556 if (obj_location
== OBJ_INVENT
) {
1558 * We may need to do extra adjustments for the hero if we're
1559 * messing with the hero's inventory. The following calls are
1560 * equivalent to calling freeinv on obj and addinv on otmp,
1561 * while doing an in-place swap of the actual objects.
1566 } else if (obj_location
== OBJ_FLOOR
) {
1567 ox
= otmp
->ox
, oy
= otmp
->oy
; /* set by replace_object() */
1568 if (obj
->otyp
== BOULDER
&& otmp
->otyp
!= BOULDER
1569 && !does_block(ox
, oy
, &levl
[ox
][oy
]))
1570 unblock_point(ox
, oy
);
1571 else if (obj
->otyp
!= BOULDER
&& otmp
->otyp
== BOULDER
)
1572 /* (checking does_block() here would be redundant) */
1573 block_point(ox
, oy
);
1576 if ((!carried(otmp
) || obj
->unpaid
)
1577 && get_obj_location(otmp
, &ox
, &oy
, BURIED_TOO
| CONTAINED_TOO
)
1578 && costly_spot(ox
, oy
)) {
1579 register struct monst
*shkp
=
1580 shop_keeper(*in_rooms(ox
, oy
, SHOPBASE
));
1582 if ((!obj
->no_charge
1583 || (Has_contents(obj
)
1584 && (contained_cost(obj
, shkp
, 0L, FALSE
, FALSE
) != 0L)))
1585 && inhishop(shkp
)) {
1586 if (shkp
->mpeaceful
) {
1588 && *in_rooms(u
.ux
, u
.uy
, 0)
1589 == *in_rooms(shkp
->mx
, shkp
->my
, 0)
1590 && !costly_spot(u
.ux
, u
.uy
))
1591 make_angry_shk(shkp
, ox
, oy
);
1593 pline("%s gets angry!", Monnam(shkp
));
1597 Norep("%s is furious!", Monnam(shkp
));
1604 /* stone-to-flesh spell hits and maybe transforms or animates obj */
1606 stone_to_flesh_obj(obj
)
1609 int res
= 1; /* affected object by default */
1610 struct permonst
*ptr
;
1614 boolean smell
= FALSE
, golem_xform
= FALSE
;
1616 if (objects
[obj
->otyp
].oc_material
!= MINERAL
1617 && objects
[obj
->otyp
].oc_material
!= GEMSTONE
)
1619 /* Heart of Ahriman usually resists; ordinary items rarely do */
1620 if (obj_resists(obj
, 2, 98))
1623 (void) get_obj_location(obj
, &oox
, &ooy
, 0);
1624 /* add more if stone objects are added.. */
1625 switch (objects
[obj
->otyp
].oc_class
) {
1626 case ROCK_CLASS
: /* boulders and statues */
1627 case TOOL_CLASS
: /* figurines */
1628 if (obj
->otyp
== BOULDER
) {
1629 obj
= poly_obj(obj
, HUGE_CHUNK_OF_MEAT
);
1631 } else if (obj
->otyp
== STATUE
|| obj
->otyp
== FIGURINE
) {
1632 ptr
= &mons
[obj
->corpsenm
];
1633 if (is_golem(ptr
)) {
1634 golem_xform
= (ptr
!= &mons
[PM_FLESH_GOLEM
]);
1635 } else if (vegetarian(ptr
)) {
1636 /* Don't animate monsters that aren't flesh */
1637 obj
= poly_obj(obj
, MEATBALL
);
1641 if (obj
->otyp
== STATUE
) {
1642 /* animate_statue() forces all golems to become flesh golems
1644 mon
= animate_statue(obj
, oox
, ooy
, ANIMATE_SPELL
, (int *) 0);
1645 } else { /* (obj->otyp == FIGURINE) */
1647 ptr
= &mons
[PM_FLESH_GOLEM
];
1648 mon
= makemon(ptr
, oox
, ooy
, NO_MINVENT
);
1650 if (costly_spot(oox
, ooy
) && !obj
->no_charge
) {
1651 if (costly_spot(u
.ux
, u
.uy
))
1652 addtobill(obj
, carried(obj
), FALSE
, FALSE
);
1654 stolen_value(obj
, oox
, ooy
, TRUE
, FALSE
);
1657 obj_stop_timers(obj
);
1662 if (cansee(mon
->mx
, mon
->my
))
1663 pline_The("figurine %sanimates!",
1664 golem_xform
? "turns to flesh and " : "");
1669 /* this golem handling is redundant... */
1670 if (is_golem(ptr
) && ptr
!= &mons
[PM_FLESH_GOLEM
])
1671 (void) newcham(mon
, &mons
[PM_FLESH_GOLEM
], TRUE
, FALSE
);
1672 } else if ((ptr
->geno
& (G_NOCORPSE
| G_UNIQ
)) != 0) {
1673 /* didn't revive but can't leave corpse either */
1676 /* unlikely to get here since genociding monsters also
1677 sets the G_NOCORPSE flag; drop statue's contents */
1678 while ((item
= obj
->cobj
) != 0) {
1679 bypass_obj(item
); /* make stone-to-flesh miss it */
1680 obj_extract_self(item
);
1681 place_object(item
, oox
, ooy
);
1683 obj
= poly_obj(obj
, CORPSE
);
1685 } else { /* miscellaneous tool or unexpected rock... */
1689 /* maybe add weird things to become? */
1690 case RING_CLASS
: /* some of the rings are stone */
1691 obj
= poly_obj(obj
, MEAT_RING
);
1694 case WAND_CLASS
: /* marble wand */
1695 obj
= poly_obj(obj
, MEAT_STICK
);
1698 case GEM_CLASS
: /* stones & gems */
1699 obj
= poly_obj(obj
, MEATBALL
);
1702 case WEAPON_CLASS
: /* crysknife */
1710 /* non-meat eaters smell meat, meat eaters smell its flavor;
1711 monks are considered non-meat eaters regardless of behavior;
1712 other roles are non-meat eaters if they haven't broken
1713 vegetarian conduct yet (or if poly'd into non-carnivorous/
1714 non-omnivorous form, regardless of whether it's herbivorous,
1715 non-eating, or something stranger) */
1716 if (Role_if(PM_MONK
) || !u
.uconduct
.unvegetarian
1717 || !carnivorous(youmonst
.data
))
1718 Norep("You smell the odor of meat.");
1720 Norep("You smell a delicious smell.");
1727 * Object obj was hit by the effect of the wand/spell otmp. Return
1728 * non-zero if the wand/spell had any effect.
1732 struct obj
*obj
, *otmp
;
1734 int res
= 1; /* affected object by default */
1735 boolean learn_it
= FALSE
, maybelearnit
;
1737 /* fundamental: a wand effect hitting itself doesn't do anything;
1738 otherwise we need to guard against accessing otmp after something
1739 strange has happened to it (along the lines of polymorph or
1740 stone-to-flesh [which aren't good examples since polymorph wands
1741 aren't affected by polymorph zaps and stone-to-flesh isn't
1742 available in wand form, but the concept still applies...]) */
1747 /* The bypass bit is currently only used as follows:
1749 * POLYMORPH - When a monster being polymorphed drops something
1750 * from its inventory as a result of the change.
1751 * If the items fall to the floor, they are not
1752 * subject to direct subsequent polymorphing
1753 * themselves on that same zap. This makes it
1754 * consistent with items that remain in the
1755 * monster's inventory. They are not polymorphed
1757 * UNDEAD_TURNING - When an undead creature gets killed via
1758 * undead turning, prevent its corpse from being
1759 * immediately revived by the same effect.
1760 * STONE_TO_FLESH - If a statue can't be revived, its
1761 * contents get dropped before turning it into
1762 * meat; prevent those contents from being hit.
1763 * retouch_equipment() - bypass flag is used to track which
1764 * items have been handled (bhito isn't involved).
1765 * menu_drop(), askchain() - inventory traversal where multiple
1766 * Drop can alter the invent chain while traversal
1767 * is in progress (bhito isn't involved).
1769 * The bypass bit on all objects is reset each turn, whenever
1770 * context.bypasses is set.
1772 * We check the obj->bypass bit above AND context.bypasses
1773 * as a safeguard against any stray occurrence left in an obj
1774 * struct someplace, although that should never happen.
1776 if (context
.bypasses
) {
1779 debugpline1("%s for a moment.", Tobjnam(obj
, "pulsate"));
1785 * Some parts of this function expect the object to be on the floor
1786 * obj->{ox,oy} to be valid. The exception to this (so far) is
1787 * for the STONE_TO_FLESH spell.
1789 if (!(obj
->where
== OBJ_FLOOR
|| otmp
->otyp
== SPE_STONE_TO_FLESH
))
1790 impossible("bhito: obj is not floor or Stone To Flesh spell");
1794 } else if (obj
== uchain
) {
1795 if (otmp
->otyp
== WAN_OPENING
|| otmp
->otyp
== SPE_KNOCK
) {
1801 switch (otmp
->otyp
) {
1804 if (obj
->otyp
== WAN_POLYMORPH
|| obj
->otyp
== SPE_POLYMORPH
1805 || obj
->otyp
== POT_POLYMORPH
|| obj_resists(obj
, 5, 95)) {
1810 u
.uconduct
.polypiles
++;
1811 /* any saved lock context will be dangerously obsolete */
1813 (void) boxlock(obj
, otmp
);
1815 if (obj_shudders(obj
)) {
1817 ((obj
== level
.objects
[u
.ux
][u
.uy
]) && u
.uundetected
1818 && hides_under(youmonst
.data
));
1820 if (cansee(obj
->ox
, obj
->oy
))
1823 /* eek - your cover might have been blown */
1825 (void) hideunder(&youmonst
);
1828 obj
= poly_obj(obj
, STRANGE_OBJECT
);
1829 newsym(obj
->ox
, obj
->oy
);
1833 /* target object has now been "seen (up close)" */
1835 if (Is_container(obj
) || obj
->otyp
== STATUE
) {
1836 obj
->cknown
= obj
->lknown
= 1;
1838 boolean catbox
= SchroedingersBox(obj
);
1840 /* we don't want to force alive vs dead
1841 determination for Schroedinger's Cat here,
1842 so just make probing be inconclusive for it */
1845 pline("%s empty.", Tobjnam(obj
, catbox
? "seem" : "are"));
1848 /* view contents (not recursively) */
1849 for (o
= obj
->cobj
; o
; o
= o
->nobj
)
1850 o
->dknown
= 1; /* "seen", even if blind */
1851 (void) display_cinventory(obj
);
1859 case SPE_FORCE_BOLT
:
1860 /* learn the type if you see or hear something break
1861 (the sound could be implicit) */
1862 maybelearnit
= cansee(obj
->ox
, obj
->oy
) || !Deaf
;
1863 if (obj
->otyp
== BOULDER
) {
1864 if (cansee(obj
->ox
, obj
->oy
))
1865 pline_The("boulder falls apart.");
1867 You_hear("a crumbling sound.");
1869 } else if (obj
->otyp
== STATUE
) {
1870 if (break_statue(obj
)) {
1871 if (cansee(obj
->ox
, obj
->oy
)) {
1873 pline_The("%s shatters.", rndmonnam(NULL
));
1875 pline_The("statue shatters.");
1877 You_hear("a crumbling sound.");
1882 if (context
.mon_moving
1883 ? !breaks(obj
, obj
->ox
, obj
->oy
)
1884 : !hero_breaks(obj
, obj
->ox
, obj
->oy
, FALSE
))
1885 maybelearnit
= FALSE
; /* nothing broke */
1887 newsym_force(oox
,ooy
);
1893 case WAN_CANCELLATION
:
1894 case SPE_CANCELLATION
:
1897 newsym(obj
->ox
, obj
->oy
); /* might change color */
1900 case SPE_DRAIN_LIFE
:
1901 (void) drain_item(obj
);
1903 case WAN_TELEPORTATION
:
1904 case SPE_TELEPORT_AWAY
:
1907 case WAN_MAKE_INVISIBLE
:
1909 case WAN_UNDEAD_TURNING
:
1910 case SPE_TURN_UNDEAD
:
1911 if (obj
->otyp
== EGG
) {
1913 } else if (obj
->otyp
== CORPSE
) {
1914 int corpsenm
= corpse_revive_type(obj
);
1916 res
= !!revive(obj
, TRUE
);
1917 if (res
&& Role_if(PM_HEALER
)) {
1918 if (Hallucination
&& !Deaf
) {
1919 You_hear("the sound of a defibrillator.");
1921 } else if (!Blind
) {
1922 You("observe %s %s change dramatically.",
1923 s_suffix(an(mons
[corpsenm
].mname
)),
1924 nonliving(&mons
[corpsenm
]) ? "motility"
1929 exercise(A_WIS
, TRUE
);
1936 case SPE_WIZARD_LOCK
:
1938 res
= boxlock(obj
, otmp
);
1944 case WAN_SLOW_MONSTER
: /* no effect on objects */
1945 case SPE_SLOW_MONSTER
:
1946 case WAN_SPEED_MONSTER
:
1949 case SPE_EXTRA_HEALING
:
1952 case SPE_STONE_TO_FLESH
:
1953 res
= stone_to_flesh_obj(obj
);
1956 impossible("What an interesting effect (%d)", otmp
->otyp
);
1959 /* if effect was observable then discover the wand type provided
1960 that the wand itself has been seen */
1966 /* returns nonzero if something was hit */
1968 bhitpile(obj
, fhito
, tx
, ty
, zz
)
1970 int FDECL((*fhito
), (OBJ_P
, OBJ_P
));
1974 int hitanything
= 0;
1975 register struct obj
*otmp
, *next_obj
;
1977 if (obj
->otyp
== SPE_FORCE_BOLT
|| obj
->otyp
== WAN_STRIKING
) {
1978 struct trap
*t
= t_at(tx
, ty
);
1980 /* We can't settle for the default calling sequence of
1981 bhito(otmp) -> break_statue(otmp) -> activate_statue_trap(ox,oy)
1982 because that last call might end up operating on our `next_obj'
1983 (below), rather than on the current object, if it happens to
1984 encounter a statue which mustn't become animated. */
1985 if (t
&& t
->ttyp
== STATUE_TRAP
1986 && activate_statue_trap(t
, tx
, ty
, TRUE
))
1991 for (otmp
= level
.objects
[tx
][ty
]; otmp
; otmp
= next_obj
) {
1992 next_obj
= otmp
->nexthere
;
1993 /* for zap downwards, don't hit object poly'd hero is hiding under */
1994 if (zz
> 0 && u
.uundetected
&& otmp
== level
.objects
[u
.ux
][u
.uy
]
1995 && hides_under(youmonst
.data
))
1998 hitanything
+= (*fhito
)(otmp
, obj
);
2000 if (poly_zapped
>= 0)
2001 create_polymon(level
.objects
[tx
][ty
], poly_zapped
);
2007 * zappable - returns 1 if zap is available, 0 otherwise.
2008 * it removes a charge from the wand if zappable.
2009 * added by GAN 11/03/86
2013 register struct obj
*wand
;
2015 if (wand
->spe
< 0 || (wand
->spe
== 0 && rn2(121)))
2018 You("wrest one last charge from the worn-out wand.");
2024 * zapnodir - zaps a NODIR wand/spell.
2025 * added by GAN 11/03/86
2029 register struct obj
*obj
;
2031 boolean known
= FALSE
;
2033 switch (obj
->otyp
) {
2039 if (lightdamage(obj
, TRUE
, 5))
2042 case WAN_SECRET_DOOR_DETECTION
:
2043 case SPE_DETECT_UNSEEN
:
2049 case WAN_CREATE_MONSTER
:
2050 known
= create_critters(rn2(23) ? 1 : rn1(7, 2),
2051 (struct permonst
*) 0, FALSE
);
2055 if (Luck
+ rn2(5) < 0) {
2056 pline("Unfortunately, nothing happens.");
2061 case WAN_ENLIGHTENMENT
:
2063 You_feel("self-knowledgeable...");
2064 display_nhwindow(WIN_MESSAGE
, FALSE
);
2065 enlightenment(MAGICENLIGHTENMENT
, ENL_GAMEINPROGRESS
);
2066 pline_The("feeling subsides.");
2067 exercise(A_WIS
, TRUE
);
2071 if (!objects
[obj
->otyp
].oc_name_known
)
2072 more_experienced(0, 10);
2073 /* effect was observable; discover the wand type provided
2074 that the wand itself has been seen */
2084 otmp
->in_use
= TRUE
; /* in case losehp() is fatal */
2085 pline("%s suddenly explodes!", The(xname(otmp
)));
2086 dmg
= d(otmp
->spe
+ 2, 6);
2087 losehp(Maybe_Half_Phys(dmg
), "exploding wand", KILLED_BY_AN
);
2091 static NEARDATA
const char zap_syms
[] = { WAND_CLASS
, 0 };
2093 /* 'z' command (or 'y' if numbed_pad==-1) */
2097 register struct obj
*obj
;
2100 if (check_capacity((char *) 0))
2102 obj
= getobj(zap_syms
, "zap");
2108 /* zappable addition done by GAN 11/03/86 */
2110 pline1(nothing_happens
);
2111 else if (obj
->cursed
&& !rn2(WAND_BACKFIRE_CHANCE
)) {
2112 backfire(obj
); /* the wand blows up in your face! */
2113 exercise(A_STR
, FALSE
);
2115 } else if (!(objects
[obj
->otyp
].oc_dir
== NODIR
) && !getdir((char *) 0)) {
2117 pline("%s glows and fades.", The(xname(obj
)));
2118 /* make him pay for knowing !NODIR */
2119 } else if (!u
.dx
&& !u
.dy
&& !u
.dz
2120 && !(objects
[obj
->otyp
].oc_dir
== NODIR
)) {
2121 if ((damage
= zapyourself(obj
, TRUE
)) != 0) {
2124 Sprintf(buf
, "zapped %sself with a wand", uhim());
2125 losehp(Maybe_Half_Phys(damage
), buf
, NO_KILLER_PREFIX
);
2128 /* Are we having fun yet?
2129 * weffects -> buzz(obj->otyp) -> zhitm (temple priest) ->
2130 * attack -> hitum -> known_hitum -> ghod_hitsu ->
2131 * buzz(AD_ELEC) -> destroy_item(WAND_CLASS) ->
2132 * useup -> obfree -> dealloc_obj -> free(obj)
2139 if (obj
&& obj
->spe
< 0) {
2140 pline("%s to dust.", Tobjnam(obj
, "turn"));
2143 update_inventory(); /* maybe used a charge */
2148 zapyourself(obj
, ordinary
)
2152 boolean learn_it
= FALSE
;
2155 switch (obj
->otyp
) {
2157 case SPE_FORCE_BOLT
:
2160 shieldeff(u
.ux
, u
.uy
);
2164 You("bash yourself!");
2167 damage
= d(1 + obj
->spe
, 6);
2168 exercise(A_STR
, FALSE
);
2174 if (!Shock_resistance
) {
2175 You("shock yourself!");
2177 exercise(A_CON
, FALSE
);
2179 shieldeff(u
.ux
, u
.uy
);
2180 You("zap yourself, but seem unharmed.");
2181 ugolemeffects(AD_ELEC
, d(12, 6));
2183 destroy_item(WAND_CLASS
, AD_ELEC
);
2184 destroy_item(RING_CLASS
, AD_ELEC
);
2185 (void) flashburn((long) rnd(100));
2189 You("explode a fireball on top of yourself!");
2190 explode(u
.ux
, u
.uy
, 11, d(6, 6), WAND_CLASS
, EXPL_FIERY
);
2195 if (Fire_resistance
) {
2196 shieldeff(u
.ux
, u
.uy
);
2197 You_feel("rather warm.");
2198 ugolemeffects(AD_FIRE
, d(12, 6));
2200 pline("You've set yourself afire!");
2204 (void) burnarmor(&youmonst
);
2205 destroy_item(SCROLL_CLASS
, AD_FIRE
);
2206 destroy_item(POTION_CLASS
, AD_FIRE
);
2207 destroy_item(SPBOOK_CLASS
, AD_FIRE
);
2208 destroy_item(FOOD_CLASS
, AD_FIRE
); /* only slime for now */
2212 case SPE_CONE_OF_COLD
:
2215 if (Cold_resistance
) {
2216 shieldeff(u
.ux
, u
.uy
);
2217 You_feel("a little chill.");
2218 ugolemeffects(AD_COLD
, d(12, 6));
2220 You("imitate a popsicle!");
2223 destroy_item(POTION_CLASS
, AD_COLD
);
2226 case WAN_MAGIC_MISSILE
:
2227 case SPE_MAGIC_MISSILE
:
2230 shieldeff(u
.ux
, u
.uy
);
2231 pline_The("missiles bounce!");
2234 pline("Idiot! You've shot yourself!");
2246 case WAN_CANCELLATION
:
2247 case SPE_CANCELLATION
:
2248 (void) cancel_monst(&youmonst
, obj
, TRUE
, FALSE
, TRUE
);
2251 case SPE_DRAIN_LIFE
:
2252 if (!Drain_resistance
) {
2253 learn_it
= TRUE
; /* (no effect for spells...) */
2254 losexp("life drainage");
2256 damage
= 0; /* No additional damage */
2259 case WAN_MAKE_INVISIBLE
: {
2260 /* have to test before changing HInvis but must change
2261 * HInvis before doing newsym().
2263 int msg
= !Invis
&& !Blind
&& !BInvis
;
2265 if (BInvis
&& uarmc
->otyp
== MUMMY_WRAPPING
) {
2266 /* A mummy wrapping absorbs it and protects you */
2267 You_feel("rather itchy under %s.", yname(uarmc
));
2270 if (ordinary
|| !rn2(10)) { /* permanent */
2271 HInvis
|= FROMOUTSIDE
;
2272 } else { /* temporary */
2273 incr_itimeout(&HInvis
, d(obj
->spe
, 250));
2278 self_invis_message();
2283 case WAN_SPEED_MONSTER
:
2284 if (!(HFast
& INTRINSIC
)) {
2289 Your("quickness feels more natural.");
2290 exercise(A_DEX
, TRUE
);
2292 HFast
|= FROMOUTSIDE
;
2298 if (Sleep_resistance
) {
2299 shieldeff(u
.ux
, u
.uy
);
2300 You("don't feel sleepy!");
2302 pline_The("sleep ray hits you!");
2303 fall_asleep(-rnd(50), TRUE
);
2307 case WAN_SLOW_MONSTER
:
2308 case SPE_SLOW_MONSTER
:
2309 if (HFast
& (TIMEOUT
| INTRINSIC
)) {
2315 case WAN_TELEPORTATION
:
2316 case SPE_TELEPORT_AWAY
:
2318 /* same criteria as when mounted (zap_steed) */
2319 if ((Teleport_control
&& !Stunned
) || !couldsee(u
.ux0
, u
.uy0
)
2320 || distu(u
.ux0
, u
.uy0
) >= 16)
2325 case SPE_FINGER_OF_DEATH
:
2326 if (nonliving(youmonst
.data
) || is_demon(youmonst
.data
)) {
2327 pline((obj
->otyp
== WAN_DEATH
)
2328 ? "The wand shoots an apparently harmless beam at you."
2329 : "You seem no deader than before.");
2333 Sprintf(killer
.name
, "shot %sself with a death ray", uhim());
2334 killer
.format
= NO_KILLER_PREFIX
;
2335 You("irradiate yourself with pure energy!");
2337 /* They might survive with an amulet of life saving */
2340 case WAN_UNDEAD_TURNING
:
2341 case SPE_TURN_UNDEAD
:
2343 (void) unturn_dead(&youmonst
);
2344 if (is_undead(youmonst
.data
)) {
2345 You_feel("frightened and %sstunned.",
2346 Stunned
? "even more " : "");
2347 make_stunned((HStun
& TIMEOUT
) + (long) rnd(30), FALSE
);
2349 You("shudder in dread.");
2352 case SPE_EXTRA_HEALING
:
2353 learn_it
= TRUE
; /* (no effect for spells...) */
2354 healup(d(6, obj
->otyp
== SPE_EXTRA_HEALING
? 8 : 4), 0, FALSE
,
2355 (obj
->otyp
== SPE_EXTRA_HEALING
));
2356 You_feel("%sbetter.", obj
->otyp
== SPE_EXTRA_HEALING
? "much " : "");
2358 case WAN_LIGHT
: /* (broken wand) */
2359 /* assert( !ordinary ); */
2360 damage
= d(obj
->spe
, 25);
2361 case EXPENSIVE_CAMERA
:
2364 damage
= lightdamage(obj
, ordinary
, damage
);
2366 if (flashburn((long) damage
))
2368 damage
= 0; /* reset */
2376 if (u
.utrap
) { /* escape web or bear trap */
2377 (void) openholdingtrap(&youmonst
, &learn_it
);
2380 /* unlock carried boxes */
2381 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
2383 (void) boxlock(otmp
, obj
);
2384 /* trigger previously escaped trapdoor */
2385 (void) openfallingtrap(&youmonst
, TRUE
, &learn_it
);
2389 case SPE_WIZARD_LOCK
:
2391 (void) closeholdingtrap(&youmonst
, &learn_it
);
2396 case SPE_DETECT_UNSEEN
:
2402 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
) {
2404 if (Is_container(otmp
) || otmp
->otyp
== STATUE
) {
2406 if (!SchroedingersBox(otmp
))
2414 case SPE_STONE_TO_FLESH
: {
2415 struct obj
*otmp
, *onxt
;
2418 if (u
.umonnum
== PM_STONE_GOLEM
) {
2420 (void) polymon(PM_FLESH_GOLEM
);
2424 fix_petrification(); /* saved! */
2426 /* but at a cost.. */
2427 for (otmp
= invent
; otmp
; otmp
= onxt
) {
2429 if (bhito(otmp
, obj
))
2433 * It is possible that we can now merge some inventory.
2434 * Do a highly paranoid merge. Restart from the beginning
2439 for (otmp
= invent
; !didmerge
&& otmp
; otmp
= otmp
->nobj
)
2440 for (onxt
= otmp
->nobj
; onxt
; onxt
= onxt
->nobj
)
2441 if (merged(&otmp
, &onxt
)) {
2449 impossible("zapyourself: object %d used?", obj
->otyp
);
2452 /* if effect was observable then discover the wand type provided
2453 that the wand itself has been seen */
2459 /* called when poly'd hero uses breath attack against self */
2462 struct attack
*mattk
;
2464 int dtyp
= 20 + mattk
->adtyp
- 1; /* breath by hero */
2465 const char *fltxt
= flash_types
[dtyp
]; /* blast of <something> */
2467 zhitu(dtyp
, mattk
->damn
, fltxt
, u
.ux
, u
.uy
);
2470 /* light damages hero in gremlin form */
2472 lightdamage(obj
, ordinary
, amt
)
2473 struct obj
*obj
; /* item making light (fake book if spell) */
2474 boolean ordinary
; /* wand/camera zap vs wand destruction */
2475 int amt
; /* pseudo-damage used to determine blindness duration */
2481 if (dmg
&& youmonst
.data
== &mons
[PM_GREMLIN
]) {
2482 /* reduce high values (from destruction of wand with many charges) */
2485 dmg
= 10 + rnd(dmg
- 10);
2488 pline("Ow, that light hurts%c", (dmg
> 2 || u
.mh
<= 5) ? '!' : '.');
2489 /* [composing killer/reason is superfluous here; if fatal, cause
2490 of death will always be "killed while stuck in creature form"] */
2491 if (obj
->oclass
== SCROLL_CLASS
|| obj
->oclass
== SPBOOK_CLASS
)
2492 ordinary
= FALSE
; /* say blasted rather than zapped */
2493 how
= (obj
->oclass
!= SPBOOK_CLASS
)
2494 ? (const char *) ansimpleoname(obj
)
2496 Sprintf(buf
, "%s %sself with %s", ordinary
? "zapped" : "blasted",
2498 /* might rehumanize(); could be fatal, but only for Unchanging */
2499 losehp(Maybe_Half_Phys(dmg
), buf
, NO_KILLER_PREFIX
);
2504 /* light[ning] causes blindness */
2509 if (!resists_blnd(&youmonst
)) {
2510 You(are_blinded_by_the_flash
);
2511 make_blinded(duration
, FALSE
);
2513 Your1(vision_clears
);
2519 /* you've zapped a wand downwards while riding
2520 * Return TRUE if the steed was hit by the wand.
2521 * Return FALSE if the steed was not hit by the wand.
2525 struct obj
*obj
; /* wand or spell */
2527 int steedhit
= FALSE
;
2529 bhitpos
.x
= u
.usteed
->mx
, bhitpos
.y
= u
.usteed
->my
;
2531 switch (obj
->otyp
) {
2533 * Wands that are allowed to hit the steed
2534 * Carefully test the results of any that are
2535 * moved here from the bottom section.
2538 probe_monster(u
.usteed
);
2542 case WAN_TELEPORTATION
:
2543 case SPE_TELEPORT_AWAY
:
2544 /* you go together */
2546 /* same criteria as when unmounted (zapyourself) */
2547 if ((Teleport_control
&& !Stunned
) || !couldsee(u
.ux0
, u
.uy0
)
2548 || distu(u
.ux0
, u
.uy0
) >= 16)
2553 /* Default processing via bhitm() for these */
2554 case SPE_CURE_SICKNESS
:
2555 case WAN_MAKE_INVISIBLE
:
2556 case WAN_CANCELLATION
:
2557 case SPE_CANCELLATION
:
2561 case SPE_FORCE_BOLT
:
2562 case WAN_SLOW_MONSTER
:
2563 case SPE_SLOW_MONSTER
:
2564 case WAN_SPEED_MONSTER
:
2566 case SPE_EXTRA_HEALING
:
2567 case SPE_DRAIN_LIFE
:
2570 (void) bhitm(u
.usteed
, obj
);
2582 * cancel a monster (possibly the hero). inventory is cancelled only
2583 * if the monster is zapping itself directly, since otherwise the
2584 * effect is too strong. currently non-hero monsters do not zap
2585 * themselves with cancellation.
2588 cancel_monst(mdef
, obj
, youattack
, allow_cancel_kill
, self_cancel
)
2589 register struct monst
*mdef
;
2590 register struct obj
*obj
;
2591 boolean youattack
, allow_cancel_kill
, self_cancel
;
2593 boolean youdefend
= (mdef
== &youmonst
);
2594 static const char writing_vanishes
[] =
2595 "Some writing vanishes from %s head!";
2596 static const char your
[] = "your"; /* should be extern */
2598 if (youdefend
? (!youattack
&& Antimagic
)
2599 : resist(mdef
, obj
->oclass
, 0, NOTELL
))
2600 return FALSE
; /* resisted cancellation */
2602 if (self_cancel
) { /* 1st cancel inventory */
2605 for (otmp
= (youdefend
? invent
: mdef
->minvent
); otmp
;
2609 context
.botl
= 1; /* potential AC change */
2614 /* now handle special cases */
2617 if ((u
.umonnum
== PM_CLAY_GOLEM
) && !Blind
)
2618 pline(writing_vanishes
, your
);
2621 Your("amulet grows hot for a moment, then cools.");
2628 if (is_were(mdef
->data
) && mdef
->data
->mlet
!= S_HUMAN
)
2631 if (mdef
->data
== &mons
[PM_CLAY_GOLEM
]) {
2632 if (canseemon(mdef
))
2633 pline(writing_vanishes
, s_suffix(mon_nam(mdef
)));
2635 if (allow_cancel_kill
) {
2639 monkilled(mdef
, "", AD_SPEL
);
2646 /* you've zapped an immediate type wand up or down */
2649 struct obj
*obj
; /* wand or spell */
2651 boolean striking
= FALSE
, disclose
= FALSE
;
2652 int x
, y
, xx
, yy
, ptmp
;
2658 /* some wands have special effects other than normal bhitpile */
2659 /* drawbridge might change <u.ux,u.uy> */
2660 x
= xx
= u
.ux
; /* <x,y> is zap location */
2661 y
= yy
= u
.uy
; /* <xx,yy> is drawbridge (portcullis) position */
2662 ttmp
= t_at(x
, y
); /* trap if there is one */
2664 switch (obj
->otyp
) {
2668 You("probe towards the %s.", ceiling(x
, y
));
2670 ptmp
+= bhitpile(obj
, bhito
, x
, y
, u
.dz
);
2671 You("probe beneath the %s.", surface(x
, y
));
2672 ptmp
+= display_binventory(x
, y
, TRUE
);
2675 Your("probe reveals nothing.");
2676 return TRUE
; /* we've done our own bhitpile */
2679 /* up or down, but at closed portcullis only */
2680 if (is_db_wall(x
, y
) && find_drawbridge(&xx
, &yy
)) {
2681 open_drawbridge(xx
, yy
);
2683 } else if (u
.dz
> 0 && (x
== xdnstair
&& y
== ydnstair
) &&
2684 /* can't use the stairs down to quest level 2 until
2685 leader "unlocks" them; give feedback if you try */
2686 on_level(&u
.uz
, &qstart_level
) && !ok_to_quest()) {
2687 pline_The("stairs seem to ripple momentarily.");
2690 /* down will release you from bear trap or web */
2691 if (u
.dz
> 0 && u
.utrap
) {
2692 (void) openholdingtrap(&youmonst
, &disclose
);
2693 /* down will trigger trapdoor, hole, or [spiked-] pit */
2694 } else if (u
.dz
> 0 && !u
.utrap
) {
2695 (void) openfallingtrap(&youmonst
, FALSE
, &disclose
);
2699 case SPE_FORCE_BOLT
:
2703 case SPE_WIZARD_LOCK
:
2704 /* down at open bridge or up or down at open portcullis */
2705 if (((levl
[x
][y
].typ
== DRAWBRIDGE_DOWN
)
2707 : (is_drawbridge_wall(x
, y
) >= 0 && !is_db_wall(x
, y
)))
2708 && find_drawbridge(&xx
, &yy
)) {
2710 close_drawbridge(xx
, yy
);
2712 destroy_drawbridge(xx
, yy
);
2714 } else if (striking
&& u
.dz
< 0 && rn2(3) && !Is_airlevel(&u
.uz
)
2715 && !Is_waterlevel(&u
.uz
) && !Underwater
2716 && !Is_qstart(&u
.uz
)) {
2718 /* similar to zap_dig() */
2719 pline("A rock is dislodged from the %s and falls on your %s.",
2720 ceiling(x
, y
), body_part(HEAD
));
2721 dmg
= rnd((uarmh
&& is_metallic(uarmh
)) ? 2 : 6);
2722 losehp(Maybe_Half_Phys(dmg
), "falling rock", KILLED_BY_AN
);
2723 if ((otmp
= mksobj_at(ROCK
, x
, y
, FALSE
, FALSE
)) != 0) {
2724 (void) xname(otmp
); /* set dknown, maybe bknown */
2728 } else if (u
.dz
> 0 && ttmp
) {
2729 if (!striking
&& closeholdingtrap(&youmonst
, &disclose
)) {
2730 ; /* now stuck in web or bear trap */
2731 } else if (striking
&& ttmp
->ttyp
== TRAPDOOR
) {
2732 /* striking transforms trapdoor into hole */
2733 if (Blind
&& !ttmp
->tseen
) {
2734 pline("%s beneath you shatters.", Something
);
2735 } else if (!ttmp
->tseen
) { /* => !Blind */
2736 pline("There's a trapdoor beneath you; it shatters.");
2738 pline("The trapdoor beneath you shatters.");
2744 /* might fall down hole */
2746 } else if (!striking
&& ttmp
->ttyp
== HOLE
) {
2747 /* locking transforms hole into trapdoor */
2748 ttmp
->ttyp
= TRAPDOOR
;
2749 if (Blind
|| !ttmp
->tseen
) {
2750 pline("Some %s swirls beneath you.",
2751 is_ice(x
, y
) ? "frost" : "dust");
2755 pline("A trapdoor appears beneath you.");
2758 /* hadn't fallen down hole; won't fall now */
2762 case SPE_STONE_TO_FLESH
:
2763 if (Is_airlevel(&u
.uz
) || Is_waterlevel(&u
.uz
) || Underwater
2764 || (Is_qstart(&u
.uz
) && u
.dz
< 0)) {
2765 pline1(nothing_happens
);
2766 } else if (u
.dz
< 0) { /* we should do more... */
2767 pline("Blood drips on your %s.", body_part(FACE
));
2768 } else if (u
.dz
> 0 && !OBJ_AT(u
.ux
, u
.uy
)) {
2770 Print this message only if there wasn't an engraving
2771 affected here. If water or ice, act like waterlevel case.
2773 e
= engr_at(u
.ux
, u
.uy
);
2774 if (!(e
&& e
->engr_type
== ENGRAVE
)) {
2775 if (is_pool(u
.ux
, u
.uy
) || is_ice(u
.ux
, u
.uy
))
2776 pline1(nothing_happens
);
2778 pline("Blood %ss %s your %s.",
2779 is_lava(u
.ux
, u
.uy
) ? "boil" : "pool",
2780 Levitation
? "beneath" : "at",
2781 makeplural(body_part(FOOT
)));
2790 /* zapping downward */
2791 (void) bhitpile(obj
, bhito
, x
, y
, u
.dz
);
2793 /* subset of engraving effects; none sets `disclose' */
2794 if ((e
= engr_at(x
, y
)) != 0 && e
->engr_type
!= HEADSTONE
) {
2795 switch (obj
->otyp
) {
2799 make_engr_at(x
, y
, random_engraving(buf
), moves
, (xchar
) 0);
2801 case WAN_CANCELLATION
:
2802 case SPE_CANCELLATION
:
2803 case WAN_MAKE_INVISIBLE
:
2806 case WAN_TELEPORTATION
:
2807 case SPE_TELEPORT_AWAY
:
2810 case SPE_STONE_TO_FLESH
:
2811 if (e
->engr_type
== ENGRAVE
) {
2812 /* only affects things in stone */
2813 pline_The(Hallucination
2814 ? "floor runs like butter!"
2815 : "edges on the floor get smoother.");
2816 wipe_engr_at(x
, y
, d(2, 4), TRUE
);
2820 case SPE_FORCE_BOLT
:
2821 wipe_engr_at(x
, y
, d(2, 4), TRUE
);
2827 } else if (u
.dz
< 0) {
2828 /* zapping upward */
2830 /* game flavor: if you're hiding under "something"
2831 * a zap upward should hit that "something".
2833 if (u
.uundetected
&& hides_under(youmonst
.data
)) {
2835 otmp
= level
.objects
[u
.ux
][u
.uy
];
2838 hitit
= bhito(otmp
, obj
);
2840 (void) hideunder(&youmonst
);
2849 /* used by do_break_wand() was well as by weffects() */
2859 /* if do_osshock() set obj_zapped while polying, give a message now */
2861 You_feel("shuddering vibrations.");
2865 /* called for various wand and spell effects - M. Stephenson */
2870 int otyp
= obj
->otyp
;
2871 boolean disclose
= FALSE
, was_unkn
= !objects
[otyp
].oc_name_known
;
2873 exercise(A_WIS
, TRUE
);
2874 if (u
.usteed
&& (objects
[otyp
].oc_dir
!= NODIR
) && !u
.dx
&& !u
.dy
2875 && (u
.dz
> 0) && zap_steed(obj
)) {
2877 } else if (objects
[otyp
].oc_dir
== IMMEDIATE
) {
2878 zapsetup(); /* reset obj_zapped */
2880 (void) bhitm(u
.ustuck
, obj
);
2881 /* [how about `bhitpile(u.ustuck->minvent)' effect?] */
2883 disclose
= zap_updown(obj
);
2885 (void) bhit(u
.dx
, u
.dy
, rn1(8, 6), ZAPPED_WAND
, bhitm
, bhito
,
2888 zapwrapup(); /* give feedback for obj_zapped */
2890 } else if (objects
[otyp
].oc_dir
== NODIR
) {
2894 /* neither immediate nor directionless */
2896 if (otyp
== WAN_DIGGING
|| otyp
== SPE_DIG
)
2898 else if (otyp
>= SPE_MAGIC_MISSILE
&& otyp
<= SPE_FINGER_OF_DEATH
)
2899 buzz(otyp
- SPE_MAGIC_MISSILE
+ 10, u
.ulevel
/ 2 + 1, u
.ux
, u
.uy
,
2901 else if (otyp
>= WAN_MAGIC_MISSILE
&& otyp
<= WAN_LIGHTNING
)
2902 buzz(otyp
- WAN_MAGIC_MISSILE
,
2903 (otyp
== WAN_MAGIC_MISSILE
) ? 2 : 6, u
.ux
, u
.uy
, u
.dx
, u
.dy
);
2905 impossible("weffects: unexpected spell or wand");
2911 more_experienced(0, 10);
2916 /* augment damage for a spell dased on the hero's intelligence (and level) */
2918 spell_damage_bonus(dmg
)
2919 int dmg
; /* base amount to be adjusted by bonus or penalty */
2921 int intell
= ACURR(A_INT
);
2923 /* Punish low intelligence before low level else low intelligence
2924 gets punished only when high level */
2926 /* -3 penalty, but never reduce combined amount below 1
2927 (if dmg is 0 for some reason, we're careful to leave it there) */
2929 dmg
= (dmg
<= 3) ? 1 : dmg
- 3;
2930 } else if (intell
<= 13 || u
.ulevel
< 5)
2931 ; /* no bonus or penalty; dmg remains same */
2932 else if (intell
<= 18)
2934 else if (intell
<= 24 || u
.ulevel
< 14)
2937 dmg
+= 3; /* Int 25 */
2943 * Generate the to hit bonus for a spell. Based on the hero's skill in
2944 * spell class and dexterity.
2947 spell_hit_bonus(skill
)
2951 int dex
= ACURR(A_DEX
);
2953 switch (P_SKILL(spell_skilltype(skill
))) {
2954 case P_ISRESTRICTED
:
2976 /* Will change when print stuff below removed */
2979 /* Even increment for dextrous heroes (see weapon.c abon) */
2980 hit_bon
+= dex
- 14;
2989 /* force == 0 occurs e.g. with sleep ray */
2990 /* note that large force is usual with wands so that !! would
2991 require information about hand/weapon/wand */
2992 return (const char *) ((force
< 0) ? "?" : (force
<= 4) ? "." : "!");
2996 hit(str
, mtmp
, force
)
2999 const char *force
; /* usually either "." or "!" */
3001 if ((!cansee(bhitpos
.x
, bhitpos
.y
) && !canspotmon(mtmp
)
3002 && !(u
.uswallow
&& mtmp
== u
.ustuck
)) || !flags
.verbose
)
3003 pline("%s %s it.", The(str
), vtense(str
, "hit"));
3005 pline("%s %s %s%s", The(str
), vtense(str
, "hit"),
3006 mon_nam(mtmp
), force
);
3011 register const char *str
;
3012 register struct monst
*mtmp
;
3015 "%s %s %s.", The(str
), vtense(str
, "miss"),
3016 ((cansee(bhitpos
.x
, bhitpos
.y
) || canspotmon(mtmp
)) && flags
.verbose
)
3022 skiprange(range
, skipstart
, skipend
)
3023 int range
, *skipstart
, *skipend
;
3025 int tr
= (range
/ 4);
3026 int tmp
= range
- ((tr
> 0) ? rnd(tr
) : 0);
3028 *skipend
= tmp
- ((tmp
/ 4) * rnd(3));
3029 if (*skipend
>= tmp
)
3034 * Called for the following distance effects:
3035 * when a weapon is thrown (weapon == THROWN_WEAPON)
3036 * when an object is kicked (KICKED_WEAPON)
3037 * when an IMMEDIATE wand is zapped (ZAPPED_WAND)
3038 * when a light beam is flashed (FLASHED_LIGHT)
3039 * when a mirror is applied (INVIS_BEAM)
3040 * A thrown/kicked object falls down at end of its range or when a monster
3041 * is hit. The variable 'bhitpos' is set to the final position of the weapon
3042 * thrown/zapped. The ray of a wand may affect (by calling a provided
3043 * function) several objects and monsters on its path. The return value
3044 * is the monster hit (weapon != ZAPPED_WAND), or a null monster pointer.
3046 * Thrown and kicked objects (THROWN_WEAPON or KICKED_WEAPON) may be
3047 * destroyed and *pobj set to NULL to indicate this.
3049 * Check !u.uswallow before calling bhit().
3050 * This function reveals the absence of a remembered invisible monster in
3051 * necessary cases (throwing or kicking weapons). The presence of a real
3052 * one is revealed for a weapon, but if not a weapon is left up to fhitm().
3055 bhit(ddx
, ddy
, range
, weapon
, fhitm
, fhito
, pobj
)
3056 register int ddx
, ddy
, range
; /* direction and range */
3057 int weapon
; /* see values in hack.h */
3058 int FDECL((*fhitm
), (MONST_P
, OBJ_P
)), /* fns called when mon/obj hit */
3059 FDECL((*fhito
), (OBJ_P
, OBJ_P
));
3060 struct obj
**pobj
; /* object tossed/used, set to NULL
3061 * if object is destroyed */
3064 struct obj
*obj
= *pobj
;
3066 boolean shopdoor
= FALSE
, point_blank
= TRUE
;
3067 boolean in_skip
= FALSE
, allow_skip
= FALSE
;
3068 int skiprange_start
= 0, skiprange_end
= 0, skipcount
= 0;
3070 if (weapon
== KICKED_WEAPON
) {
3071 /* object starts one square in front of player */
3072 bhitpos
.x
= u
.ux
+ ddx
;
3073 bhitpos
.y
= u
.uy
+ ddy
;
3080 if (weapon
== THROWN_WEAPON
&& obj
&& obj
->otyp
== ROCK
) {
3081 skiprange(range
, &skiprange_start
, &skiprange_end
);
3082 allow_skip
= !rn2(3);
3085 if (weapon
== FLASHED_LIGHT
) {
3086 tmp_at(DISP_BEAM
, cmap_to_glyph(S_flashbeam
));
3087 } else if (weapon
!= ZAPPED_WAND
&& weapon
!= INVIS_BEAM
)
3088 tmp_at(DISP_FLASH
, obj_to_glyph(obj
));
3090 while (range
-- > 0) {
3104 if (is_pick(obj
) && inside_shop(x
, y
)
3105 && (mtmp
= shkcatch(obj
, x
, y
)) != 0) {
3106 tmp_at(DISP_END
, 0);
3110 typ
= levl
[bhitpos
.x
][bhitpos
.y
].typ
;
3112 /* iron bars will block anything big enough */
3113 if ((weapon
== THROWN_WEAPON
|| weapon
== KICKED_WEAPON
)
3115 && hits_bars(pobj
, x
- ddx
, y
- ddy
, bhitpos
.x
, bhitpos
.y
,
3116 point_blank
? 0 : !rn2(5), 1)) {
3117 /* caveat: obj might now be null... */
3124 if (weapon
== ZAPPED_WAND
&& find_drawbridge(&x
, &y
)) {
3125 boolean learn_it
= FALSE
;
3127 switch (obj
->otyp
) {
3130 if (is_db_wall(bhitpos
.x
, bhitpos
.y
)) {
3131 if (cansee(x
, y
) || cansee(bhitpos
.x
, bhitpos
.y
))
3133 open_drawbridge(x
, y
);
3137 case SPE_WIZARD_LOCK
:
3138 if ((cansee(x
, y
) || cansee(bhitpos
.x
, bhitpos
.y
))
3139 && levl
[x
][y
].typ
== DRAWBRIDGE_DOWN
)
3141 close_drawbridge(x
, y
);
3144 case SPE_FORCE_BOLT
:
3145 if (typ
!= DRAWBRIDGE_UP
)
3146 destroy_drawbridge(x
, y
);
3154 mtmp
= m_at(bhitpos
.x
, bhitpos
.y
);
3159 * skiprange_start is only set if this is a thrown rock
3161 if (skiprange_start
&& (range
== skiprange_start
) && allow_skip
) {
3162 if (is_pool(bhitpos
.x
, bhitpos
.y
) && !mtmp
) {
3165 pline("%s %s%s.", Yname2(obj
), otense(obj
, "skip"),
3166 skipcount
? " again" : "");
3168 You_hear("%s skip.", yname(obj
));
3170 } else if (skiprange_start
> skiprange_end
+ 1) {
3175 if (range
<= skiprange_end
) {
3177 if (range
> 3) /* another bounce? */
3178 skiprange(range
, &skiprange_start
, &skiprange_end
);
3179 } else if (mtmp
&& M_IN_WATER(mtmp
->data
)) {
3180 if ((!Blind
&& canseemon(mtmp
)) || sensemon(mtmp
))
3181 pline("%s %s over %s.", Yname2(obj
), otense(obj
, "pass"),
3186 if (mtmp
&& !(in_skip
&& M_IN_WATER(mtmp
->data
))) {
3187 notonhead
= (bhitpos
.x
!= mtmp
->mx
|| bhitpos
.y
!= mtmp
->my
);
3188 if (weapon
== FLASHED_LIGHT
) {
3189 /* FLASHED_LIGHT hitting invisible monster should
3190 pass through instead of stop so we call
3191 flash_hits_mon() directly rather than returning
3192 mtmp back to caller. That allows the flash to
3193 keep on going. Note that we use mtmp->minvis
3194 not canspotmon() because it makes no difference
3195 whether the hero can see the monster or not. */
3197 obj
->ox
= u
.ux
, obj
->oy
= u
.uy
;
3198 (void) flash_hits_mon(mtmp
, obj
);
3200 tmp_at(DISP_END
, 0);
3201 return mtmp
; /* caller will call flash_hits_mon */
3203 } else if (weapon
== INVIS_BEAM
) {
3204 /* Like FLASHED_LIGHT, INVIS_BEAM should continue
3205 through invisible targets; unlike it, we aren't
3206 prepared for multiple hits so just get first one
3207 that's either visible or could see its invisible
3208 self. [No tmp_at() cleanup is needed here.] */
3209 if (!mtmp
->minvis
|| perceives(mtmp
->data
))
3211 } else if (weapon
!= ZAPPED_WAND
) {
3212 /* THROWN_WEAPON, KICKED_WEAPON */
3213 tmp_at(DISP_END
, 0);
3214 if (cansee(bhitpos
.x
, bhitpos
.y
) && !canspotmon(mtmp
))
3215 map_invisible(bhitpos
.x
, bhitpos
.y
);
3219 (*fhitm
)(mtmp
, obj
);
3223 if (weapon
== ZAPPED_WAND
&& obj
->otyp
== WAN_PROBING
3224 && glyph_is_invisible(levl
[bhitpos
.x
][bhitpos
.y
].glyph
)) {
3225 unmap_object(bhitpos
.x
, bhitpos
.y
);
3230 if (bhitpile(obj
, fhito
, bhitpos
.x
, bhitpos
.y
, 0))
3233 if (weapon
== KICKED_WEAPON
3234 && ((obj
->oclass
== COIN_CLASS
3235 && OBJ_AT(bhitpos
.x
, bhitpos
.y
))
3236 || ship_object(obj
, bhitpos
.x
, bhitpos
.y
,
3237 costly_spot(bhitpos
.x
, bhitpos
.y
)))) {
3238 tmp_at(DISP_END
, 0);
3239 return (struct monst
*) 0;
3242 if (weapon
== ZAPPED_WAND
&& (IS_DOOR(typ
) || typ
== SDOOR
)) {
3243 switch (obj
->otyp
) {
3248 case SPE_WIZARD_LOCK
:
3249 case SPE_FORCE_BOLT
:
3250 if (doorlock(obj
, bhitpos
.x
, bhitpos
.y
)) {
3251 if (cansee(bhitpos
.x
, bhitpos
.y
)
3252 || (obj
->otyp
== WAN_STRIKING
&& !Deaf
))
3254 if (levl
[bhitpos
.x
][bhitpos
.y
].doormask
== D_BROKEN
3255 && *in_rooms(bhitpos
.x
, bhitpos
.y
, SHOPBASE
)) {
3257 add_damage(bhitpos
.x
, bhitpos
.y
, 400L);
3263 if (!ZAP_POS(typ
) || closed_door(bhitpos
.x
, bhitpos
.y
)) {
3268 if (weapon
!= ZAPPED_WAND
&& weapon
!= INVIS_BEAM
) {
3269 /* 'I' present but no monster: erase */
3270 /* do this before the tmp_at() */
3271 if (glyph_is_invisible(levl
[bhitpos
.x
][bhitpos
.y
].glyph
)
3273 unmap_object(bhitpos
.x
, bhitpos
.y
);
3276 tmp_at(bhitpos
.x
, bhitpos
.y
);
3278 /* kicked objects fall in pools */
3279 if ((weapon
== KICKED_WEAPON
)
3280 && (is_pool(bhitpos
.x
, bhitpos
.y
)
3281 || is_lava(bhitpos
.x
, bhitpos
.y
)))
3283 if (IS_SINK(typ
) && weapon
!= FLASHED_LIGHT
)
3284 break; /* physical objects fall onto sink */
3286 /* limit range of ball so hero won't make an invalid move */
3287 if (weapon
== THROWN_WEAPON
&& range
> 0
3288 && obj
->otyp
== HEAVY_IRON_BALL
) {
3292 if ((bobj
= sobj_at(BOULDER
, x
, y
)) != 0) {
3294 pline("%s hits %s.", The(distant_name(obj
, xname
)),
3297 } else if (obj
== uball
) {
3298 if (!test_move(x
- ddx
, y
- ddy
, ddx
, ddy
, TEST_MOVE
)) {
3299 /* nb: it didn't hit anything directly */
3301 pline("%s jerks to an abrupt halt.",
3302 The(distant_name(obj
, xname
))); /* lame */
3304 } else if (Sokoban
&& (t
= t_at(x
, y
)) != 0
3305 && (t
->ttyp
== PIT
|| t
->ttyp
== SPIKED_PIT
3306 || t
->ttyp
== HOLE
|| t
->ttyp
== TRAPDOOR
)) {
3307 /* hero falls into the trap, so ball stops */
3313 /* thrown/kicked missile has moved away from its starting spot */
3314 point_blank
= FALSE
; /* affects passing through iron bars */
3317 if (weapon
!= ZAPPED_WAND
&& weapon
!= INVIS_BEAM
)
3318 tmp_at(DISP_END
, 0);
3321 pay_for_damage("destroy", FALSE
);
3323 return (struct monst
*) 0;
3326 /* process thrown boomerang, which travels a curving path...
3327 * A multi-shot volley ought to have all missiles in flight at once,
3328 * but we're called separately for each one. We terminate the volley
3329 * early on a failed catch since continuing to throw after being hit
3330 * is too obviously silly.
3333 boomhit(obj
, dx
, dy
)
3338 int boom
; /* showsym[] index */
3340 boolean counterclockwise
= TRUE
; /* right-handed throw */
3342 /* counterclockwise traversal patterns:
3343 * ..........................54.................................
3344 * ..................43.....6..3....765.........................
3345 * ..........32.....5..2...7...2...8...4....87..................
3346 * .........4..1....6..1...8..1....9...3...9..6.....98..........
3347 * ..21@....5...@...7..@....9@......@12....@...5...@..7.....@9..
3348 * .3...9....6..9....89.....................1..4...1..6....1..8.
3349 * .4...8.....78.............................23....2..5...2...7.
3350 * ..567............................................34....3..6..
3351 * ........................................................45...
3352 * (invert rows for corresponding clockwise patterns)
3357 boom
= counterclockwise
? S_boomleft
: S_boomright
;
3358 for (i
= 0; i
< 8; i
++)
3359 if (xdir
[i
] == dx
&& ydir
[i
] == dy
)
3361 tmp_at(DISP_FLASH
, cmap_to_glyph(boom
));
3362 for (ct
= 0; ct
< 10; ct
++) {
3363 i
= (i
+ 8) % 8; /* 0..7 (8 -> 0, -1 -> 7) */
3364 boom
= (S_boomleft
+ S_boomright
- boom
); /* toggle */
3365 tmp_at(DISP_CHANGE
, cmap_to_glyph(boom
)); /* change glyph */
3370 if ((mtmp
= m_at(bhitpos
.x
, bhitpos
.y
)) != 0) {
3372 tmp_at(DISP_END
, 0);
3375 if (!ZAP_POS(levl
[bhitpos
.x
][bhitpos
.y
].typ
)
3376 || closed_door(bhitpos
.x
, bhitpos
.y
)) {
3381 if (bhitpos
.x
== u
.ux
&& bhitpos
.y
== u
.uy
) { /* ct == 9 */
3382 if (Fumbling
|| rn2(20) >= ACURR(A_DEX
)) {
3383 /* we hit ourselves */
3384 (void) thitu(10 + obj
->spe
, dmgval(obj
, &youmonst
), obj
,
3388 } else { /* we catch it */
3389 tmp_at(DISP_END
, 0);
3390 You("skillfully catch the boomerang.");
3394 tmp_at(bhitpos
.x
, bhitpos
.y
);
3396 if (IS_SINK(levl
[bhitpos
.x
][bhitpos
.y
].typ
)) {
3399 break; /* boomerang falls on sink */
3401 /* ct==0, initial position, we want next delta to be same;
3402 ct==5, opposite position, repeat delta undoes first one */
3404 i
+= (counterclockwise
? -1 : 1);
3406 tmp_at(DISP_END
, 0); /* do not leave last symbol */
3407 return (struct monst
*) 0;
3410 /* used by buzz(); also used by munslime(muse.c); returns damage to mon */
3412 zhitm(mon
, type
, nd
, ootmp
)
3413 register struct monst
*mon
;
3414 register int type
, nd
;
3415 struct obj
**ootmp
; /* to return worn armor for caller to disintegrate */
3417 register int tmp
= 0;
3418 register int abstype
= abs(type
) % 10;
3419 boolean sho_shieldeff
= FALSE
;
3420 boolean spellcaster
= is_hero_spell(type
); /* maybe get a bonus! */
3422 *ootmp
= (struct obj
*) 0;
3424 case ZT_MAGIC_MISSILE
:
3425 if (resists_magm(mon
)) {
3426 sho_shieldeff
= TRUE
;
3431 tmp
= spell_damage_bonus(tmp
);
3434 if (resists_fire(mon
)) {
3435 sho_shieldeff
= TRUE
;
3439 if (resists_cold(mon
))
3442 tmp
= spell_damage_bonus(tmp
);
3443 if (burnarmor(mon
)) {
3445 (void) destroy_mitem(mon
, POTION_CLASS
, AD_FIRE
);
3447 (void) destroy_mitem(mon
, SCROLL_CLASS
, AD_FIRE
);
3449 (void) destroy_mitem(mon
, SPBOOK_CLASS
, AD_FIRE
);
3450 destroy_mitem(mon
, FOOD_CLASS
, AD_FIRE
); /* carried slime */
3454 if (resists_cold(mon
)) {
3455 sho_shieldeff
= TRUE
;
3459 if (resists_fire(mon
))
3462 tmp
= spell_damage_bonus(tmp
);
3464 (void) destroy_mitem(mon
, POTION_CLASS
, AD_COLD
);
3468 (void) sleep_monst(mon
, d(nd
, 25),
3469 type
== ZT_WAND(ZT_SLEEP
) ? WAND_CLASS
: '\0');
3471 case ZT_DEATH
: /* death/disintegration */
3472 if (abs(type
) != ZT_BREATH(ZT_DEATH
)) { /* death */
3473 if (mon
->data
== &mons
[PM_DEATH
]) {
3474 mon
->mhpmax
+= mon
->mhpmax
/ 2;
3475 if (mon
->mhpmax
>= MAGIC_COOKIE
)
3476 mon
->mhpmax
= MAGIC_COOKIE
- 1;
3477 mon
->mhp
= mon
->mhpmax
;
3481 if (nonliving(mon
->data
) || is_demon(mon
->data
)
3482 || is_vampshifter(mon
) || resists_magm(mon
)) {
3483 /* similar to player */
3484 sho_shieldeff
= TRUE
;
3487 type
= -1; /* so they don't get saving throws */
3491 if (resists_disint(mon
)) {
3492 sho_shieldeff
= TRUE
;
3493 } else if (mon
->misc_worn_check
& W_ARMS
) {
3494 /* destroy shield; victim survives */
3495 *ootmp
= which_armor(mon
, W_ARMS
);
3496 } else if (mon
->misc_worn_check
& W_ARM
) {
3497 /* destroy body armor, also cloak if present */
3498 *ootmp
= which_armor(mon
, W_ARM
);
3499 if ((otmp2
= which_armor(mon
, W_ARMC
)) != 0)
3500 m_useup(mon
, otmp2
);
3502 /* no body armor, victim dies; destroy cloak
3503 and shirt now in case target gets life-saved */
3505 if ((otmp2
= which_armor(mon
, W_ARMC
)) != 0)
3506 m_useup(mon
, otmp2
);
3507 if ((otmp2
= which_armor(mon
, W_ARMU
)) != 0)
3508 m_useup(mon
, otmp2
);
3510 type
= -1; /* no saving throw wanted */
3511 break; /* not ordinary damage */
3516 if (resists_elec(mon
)) {
3517 sho_shieldeff
= TRUE
;
3519 /* can still blind the monster */
3523 tmp
= spell_damage_bonus(tmp
);
3524 if (!resists_blnd(mon
)
3525 && !(type
> 0 && u
.uswallow
&& mon
== u
.ustuck
)) {
3526 register unsigned rnd_tmp
= rnd(50);
3528 if ((mon
->mblinded
+ rnd_tmp
) > 127)
3529 mon
->mblinded
= 127;
3531 mon
->mblinded
+= rnd_tmp
;
3534 (void) destroy_mitem(mon
, WAND_CLASS
, AD_ELEC
);
3535 /* not actually possible yet */
3537 (void) destroy_mitem(mon
, RING_CLASS
, AD_ELEC
);
3540 if (resists_poison(mon
)) {
3541 sho_shieldeff
= TRUE
;
3547 if (resists_acid(mon
)) {
3548 sho_shieldeff
= TRUE
;
3553 acid_damage(MON_WEP(mon
));
3555 erode_armor(mon
, ERODE_CORRODE
);
3559 shieldeff(mon
->mx
, mon
->my
);
3560 if (is_hero_spell(type
) && (Role_if(PM_KNIGHT
) && u
.uhave
.questart
))
3562 if (tmp
> 0 && type
>= 0
3563 && resist(mon
, type
< ZT_SPELL(0) ? WAND_CLASS
: '\0', 0, NOTELL
))
3566 tmp
= 0; /* don't allow negative damage */
3567 debugpline3("zapped monster hp = %d (= %d - %d)", mon
->mhp
- tmp
,
3574 zhitu(type
, nd
, fltxt
, sx
, sy
)
3579 int dam
= 0, abstyp
= abs(type
);
3581 switch (abstyp
% 10) {
3582 case ZT_MAGIC_MISSILE
:
3585 pline_The("missiles bounce off!");
3588 exercise(A_STR
, FALSE
);
3592 if (Fire_resistance
) {
3594 You("don't feel hot!");
3595 ugolemeffects(AD_FIRE
, d(nd
, 6));
3600 if (burnarmor(&youmonst
)) { /* "body hit" */
3602 destroy_item(POTION_CLASS
, AD_FIRE
);
3604 destroy_item(SCROLL_CLASS
, AD_FIRE
);
3606 destroy_item(SPBOOK_CLASS
, AD_FIRE
);
3607 destroy_item(FOOD_CLASS
, AD_FIRE
);
3611 if (Cold_resistance
) {
3613 You("don't feel cold.");
3614 ugolemeffects(AD_COLD
, d(nd
, 6));
3619 destroy_item(POTION_CLASS
, AD_COLD
);
3622 if (Sleep_resistance
) {
3623 shieldeff(u
.ux
, u
.uy
);
3624 You("don't feel sleepy.");
3626 fall_asleep(-d(nd
, 25), TRUE
); /* sleep ray */
3630 if (abstyp
== ZT_BREATH(ZT_DEATH
)) {
3631 if (Disint_resistance
) {
3632 You("are not disintegrated.");
3635 /* destroy shield; other possessions are safe */
3636 (void) destroy_arm(uarms
);
3639 /* destroy suit; if present, cloak goes too */
3641 (void) destroy_arm(uarmc
);
3642 (void) destroy_arm(uarm
);
3645 /* no shield or suit, you're dead; wipe out cloak
3646 and/or shirt in case of life-saving or bones */
3648 (void) destroy_arm(uarmc
);
3650 (void) destroy_arm(uarmu
);
3651 } else if (nonliving(youmonst
.data
) || is_demon(youmonst
.data
)) {
3653 You("seem unaffected.");
3655 } else if (Antimagic
) {
3657 You("aren't affected.");
3660 killer
.format
= KILLED_BY_AN
;
3661 Strcpy(killer
.name
, fltxt
? fltxt
: "");
3662 /* when killed by disintegration breath, don't leave corpse */
3663 u
.ugrave_arise
= (type
== -ZT_BREATH(ZT_DEATH
)) ? -3 : NON_PM
;
3665 return; /* lifesaved */
3667 if (Shock_resistance
) {
3669 You("aren't affected.");
3670 ugolemeffects(AD_ELEC
, d(nd
, 6));
3673 exercise(A_CON
, FALSE
);
3676 destroy_item(WAND_CLASS
, AD_ELEC
);
3678 destroy_item(RING_CLASS
, AD_ELEC
);
3681 poisoned("blast", A_DEX
, "poisoned blast", 15, FALSE
);
3684 if (Acid_resistance
) {
3685 pline_The("acid doesn't hurt.");
3688 pline_The("acid burns!");
3690 exercise(A_STR
, FALSE
);
3692 /* using two weapons at once makes both of them more vulnerable */
3693 if (!rn2(u
.twoweap
? 3 : 6))
3695 if (u
.twoweap
&& !rn2(3))
3696 acid_damage(uswapwep
);
3698 erode_armor(&youmonst
, ERODE_CORRODE
);
3702 /* Half_spell_damage protection yields half-damage for wands & spells,
3703 including hero's own ricochets; breath attacks do full damage */
3704 if (dam
&& Half_spell_damage
&& !(abstyp
>= 20 && abstyp
<= 29))
3705 dam
= (dam
+ 1) / 2;
3706 losehp(dam
, fltxt
, KILLED_BY_AN
);
3711 * burn objects (such as scrolls and spellbooks) on floor
3712 * at position x,y; return the number of objects burned
3715 burn_floor_objects(x
, y
, give_feedback
, u_caused
)
3717 boolean give_feedback
; /* caller needs to decide about visibility checks */
3720 struct obj
*obj
, *obj2
;
3721 long i
, scrquan
, delquan
;
3722 char buf1
[BUFSZ
], buf2
[BUFSZ
];
3725 for (obj
= level
.objects
[x
][y
]; obj
; obj
= obj2
) {
3726 obj2
= obj
->nexthere
;
3727 if (obj
->oclass
== SCROLL_CLASS
|| obj
->oclass
== SPBOOK_CLASS
3728 || (obj
->oclass
== FOOD_CLASS
3729 && obj
->otyp
== GLOB_OF_GREEN_SLIME
)) {
3730 if (obj
->otyp
== SCR_FIRE
|| obj
->otyp
== SPE_FIREBALL
3731 || obj_resists(obj
, 2, 100))
3733 scrquan
= obj
->quan
; /* number present */
3734 delquan
= 0L; /* number to destroy */
3735 for (i
= scrquan
; i
> 0L; i
--)
3739 /* save name before potential delobj() */
3740 if (give_feedback
) {
3742 Strcpy(buf1
, (x
== u
.ux
&& y
== u
.uy
)
3744 : distant_name(obj
, xname
));
3746 Strcpy(buf2
, (x
== u
.ux
&& y
== u
.uy
)
3748 : distant_name(obj
, xname
));
3749 obj
->quan
= scrquan
;
3751 /* useupf(), which charges, only if hero caused damage */
3753 useupf(obj
, delquan
);
3754 else if (delquan
< scrquan
)
3755 obj
->quan
-= delquan
;
3759 if (give_feedback
) {
3761 pline("%ld %s burn.", delquan
, buf2
);
3763 pline("%s burns.", An(buf1
));
3771 /* will zap/spell/breath attack score a hit against armor class `ac'? */
3775 int type
; /* either hero cast spell type or 0 */
3777 int chance
= rn2(20);
3778 int spell_bonus
= type
? spell_hit_bonus(type
) : 0;
3780 /* small chance for naked target to avoid being hit */
3782 return rnd(10) < ac
+ spell_bonus
;
3784 /* very high armor protection does not achieve invulnerability */
3787 return (3 - chance
< ac
+ spell_bonus
);
3791 disintegrate_mon(mon
, type
, fltxt
)
3793 int type
; /* hero vs other */
3796 struct obj
*otmp
, *otmp2
, *m_amulet
= mlifesaver(mon
);
3798 if (canseemon(mon
)) {
3800 pline("%s is disintegrated!", Monnam(mon
));
3802 hit(fltxt
, mon
, "!");
3805 /* note: worn amulet of life saving must be preserved in order to operate */
3806 #define oresist_disintegration(obj) \
3807 (objects[obj->otyp].oc_oprop == DISINT_RES || obj_resists(obj, 5, 50) \
3808 || is_quest_artifact(obj) || obj == m_amulet)
3810 for (otmp
= mon
->minvent
; otmp
; otmp
= otmp2
) {
3812 if (!oresist_disintegration(otmp
)) {
3813 if (otmp
->owornmask
) {
3814 /* in case monster's life gets saved */
3815 mon
->misc_worn_check
&= ~otmp
->owornmask
;
3816 if (otmp
->owornmask
& W_WEP
)
3817 setmnotwielded(mon
, otmp
);
3818 /* also dismounts hero if this object is steed's saddle */
3819 update_mon_intrinsics(mon
, otmp
, FALSE
, TRUE
);
3820 otmp
->owornmask
= 0L;
3822 obj_extract_self(otmp
);
3823 obfree(otmp
, (struct obj
*) 0);
3827 #undef oresist_disintegration
3830 monkilled(mon
, (char *) 0, -AD_RBRE
);
3836 * type == 0 to 9 : you shooting a wand
3837 * type == 10 to 19 : you casting a spell
3838 * type == 20 to 29 : you breathing as a monster
3839 * type == -10 to -19 : monster casting spell
3840 * type == -20 to -29 : monster breathing at you
3841 * type == -30 to -39 : monster shooting a wand
3842 * called with dx = dy = 0 with vertical bolts
3845 buzz(type
, nd
, sx
, sy
, dx
, dy
)
3846 register int type
, nd
;
3847 register xchar sx
, sy
;
3848 register int dx
, dy
;
3850 int range
, abstype
= abs(type
) % 10;
3851 register xchar lsx
, lsy
;
3854 boolean shopdamage
= FALSE
;
3859 /* if its a Hero Spell then get its SPE_TYPE */
3860 spell_type
= is_hero_spell(type
) ? SPE_MAGIC_MISSILE
+ abstype
: 0;
3862 fltxt
= flash_types
[(type
<= -30) ? abstype
: abs(type
)];
3868 tmp
= zhitm(u
.ustuck
, type
, nd
, &otmp
);
3872 pline("%s rips into %s%s", The(fltxt
), mon_nam(u
.ustuck
),
3874 /* Using disintegration from the inside only makes a hole... */
3875 if (tmp
== MAGIC_COOKIE
)
3877 if (u
.ustuck
->mhp
< 1)
3884 if (dx
== 0 && dy
== 0)
3886 save_bhitpos
= bhitpos
;
3888 tmp_at(DISP_BEAM
, zapdir_to_glyph(dx
, dy
, abstype
));
3889 while (range
-- > 0) {
3894 if (!isok(sx
, sy
) || levl
[sx
][sy
].typ
== STONE
)
3898 if (cansee(sx
, sy
)) {
3899 /* reveal/unreveal invisible monsters before tmp_at() */
3900 if (mon
&& !canspotmon(mon
))
3901 map_invisible(sx
, sy
);
3902 else if (!mon
&& glyph_is_invisible(levl
[sx
][sy
].glyph
)) {
3903 unmap_object(sx
, sy
);
3906 if (ZAP_POS(levl
[sx
][sy
].typ
)
3907 || (isok(lsx
, lsy
) && cansee(lsx
, lsy
)))
3909 delay_output(); /* wait a little */
3912 /* hit() and miss() need bhitpos to match the target */
3913 bhitpos
.x
= sx
, bhitpos
.y
= sy
;
3914 /* Fireballs only damage when they explode */
3915 if (type
!= ZT_SPELL(ZT_FIRE
))
3916 range
+= zap_over_floor(sx
, sy
, type
, &shopdamage
, 0);
3919 if (type
== ZT_SPELL(ZT_FIRE
))
3922 mon
->mstrategy
&= ~STRAT_WAITMASK
;
3924 notonhead
= (mon
->mx
!= bhitpos
.x
|| mon
->my
!= bhitpos
.y
);
3925 if (zap_hit(find_mac(mon
), spell_type
)) {
3926 if (mon_reflects(mon
, (char *) 0)) {
3927 if (cansee(mon
->mx
, mon
->my
)) {
3928 hit(fltxt
, mon
, exclam(0));
3929 shieldeff(mon
->mx
, mon
->my
);
3930 (void) mon_reflects(mon
,
3931 "But it reflects from %s %s!");
3936 boolean mon_could_move
= mon
->mcanmove
;
3937 int tmp
= zhitm(mon
, type
, nd
, &otmp
);
3939 if (is_rider(mon
->data
)
3940 && abs(type
) == ZT_BREATH(ZT_DEATH
)) {
3941 if (canseemon(mon
)) {
3942 hit(fltxt
, mon
, ".");
3943 pline("%s disintegrates.", Monnam(mon
));
3944 pline("%s body reintegrates before your %s!",
3945 s_suffix(Monnam(mon
)),
3946 (eyecount(youmonst
.data
) == 1)
3948 : makeplural(body_part(EYE
)));
3949 pline("%s resurrects!", Monnam(mon
));
3951 mon
->mhp
= mon
->mhpmax
;
3952 break; /* Out of while loop */
3954 if (mon
->data
== &mons
[PM_DEATH
] && abstype
== ZT_DEATH
) {
3955 if (canseemon(mon
)) {
3956 hit(fltxt
, mon
, ".");
3957 pline("%s absorbs the deadly %s!", Monnam(mon
),
3958 type
== ZT_BREATH(ZT_DEATH
) ? "blast"
3960 pline("It seems even stronger than before.");
3962 break; /* Out of while loop */
3965 if (tmp
== MAGIC_COOKIE
) { /* disintegration */
3966 disintegrate_mon(mon
, type
, fltxt
);
3967 } else if (mon
->mhp
< 1) {
3969 monkilled(mon
, fltxt
, AD_RBRE
);
3974 /* normal non-fatal hit */
3975 hit(fltxt
, mon
, exclam(tmp
));
3977 /* some armor was destroyed; no damage done */
3979 pline("%s %s is disintegrated!",
3980 s_suffix(Monnam(mon
)),
3981 distant_name(otmp
, xname
));
3984 if (mon_could_move
&& !mon
->mcanmove
) /* ZT_SLEEP */
3992 } else if (sx
== u
.ux
&& sy
== u
.uy
&& range
>= 0) {
3994 if (u
.usteed
&& !rn2(3) && !mon_reflects(u
.usteed
, (char *) 0)) {
3997 } else if (zap_hit((int) u
.uac
, 0)) {
3999 pline("%s hits you!", The(fltxt
));
4002 (void) ureflects("But %s reflects from your %s!",
4005 pline("For some reason you are not affected.");
4010 zhitu(type
, nd
, fltxt
, sx
, sy
);
4012 } else if (!Blind
) {
4013 pline("%s whizzes by you!", The(fltxt
));
4014 } else if (abstype
== ZT_LIGHTNING
) {
4015 Your("%s tingles.", body_part(ARM
));
4017 if (abstype
== ZT_LIGHTNING
)
4018 (void) flashburn((long) d(nd
, 50));
4023 if (!ZAP_POS(levl
[sx
][sy
].typ
)
4024 || (closed_door(sx
, sy
) && range
>= 0)) {
4031 fireball
= (type
== ZT_SPELL(ZT_FIRE
));
4032 if ((--range
> 0 && isok(lsx
, lsy
) && cansee(lsx
, lsy
))
4034 if (Is_airlevel(&u
.uz
)) { /* nothing to bounce off of */
4035 pline_The("%s vanishes into the aether!", fltxt
);
4037 type
= ZT_WAND(ZT_FIRE
); /* skip pending fireball */
4039 } else if (fireball
) {
4042 break; /* fireballs explode before the obstacle */
4044 pline_The("%s bounces!", fltxt
);
4046 if (!dx
|| !dy
|| !rn2(20)) {
4050 if (isok(sx
, lsy
) && ZAP_POS(rmn
= levl
[sx
][lsy
].typ
)
4051 && !closed_door(sx
, lsy
)
4052 && (IS_ROOM(rmn
) || (isok(sx
+ dx
, lsy
)
4053 && ZAP_POS(levl
[sx
+ dx
][lsy
].typ
))))
4055 if (isok(lsx
, sy
) && ZAP_POS(rmn
= levl
[lsx
][sy
].typ
)
4056 && !closed_door(lsx
, sy
)
4057 && (IS_ROOM(rmn
) || (isok(lsx
, sy
+ dy
)
4058 && ZAP_POS(levl
[lsx
][sy
+ dy
].typ
))))
4059 if (!bounce
|| rn2(2))
4064 dx
= -dx
; /* fall into... */
4072 tmp_at(DISP_CHANGE
, zapdir_to_glyph(dx
, dy
, abstype
));
4076 tmp_at(DISP_END
, 0);
4077 if (type
== ZT_SPELL(ZT_FIRE
))
4078 explode(sx
, sy
, type
, d(12, 6), 0, EXPL_FIERY
);
4080 pay_for_damage(abstype
== ZT_FIRE
4082 : abstype
== ZT_COLD
4084 /* "damage" indicates wall rather than door */
4085 : abstype
== ZT_ACID
4087 : abstype
== ZT_DEATH
4091 bhitpos
= save_bhitpos
;
4099 struct rm
*lev
= &levl
[x
][y
];
4103 msg
= "The ice crackles and melts.";
4104 if (lev
->typ
== DRAWBRIDGE_UP
) {
4105 lev
->drawbridgemask
&= ~DB_ICE
; /* revert to DB_MOAT */
4106 } else { /* lev->typ == ICE */
4108 if (lev
->icedpool
== ICED_POOL
)
4113 lev
->typ
= (lev
->icedpool
== ICED_POOL
? POOL
: MOAT
);
4117 spot_stop_timers(x
, y
, MELT_ICE_AWAY
); /* no more ice to melt away */
4118 obj_ice_effects(x
, y
, FALSE
);
4125 if ((otmp
= sobj_at(BOULDER
, x
, y
)) != 0) {
4127 pline("%s settles...", An(xname(otmp
)));
4129 obj_extract_self(otmp
); /* boulder isn't being pushed */
4130 if (!boulder_hits_pool(otmp
, x
, y
, FALSE
))
4131 impossible("melt_ice: no pool?");
4132 /* try again if there's another boulder and pool didn't fill */
4133 } while (is_pool(x
, y
) && (otmp
= sobj_at(BOULDER
, x
, y
)) != 0);
4136 if (x
== u
.ux
&& y
== u
.uy
)
4137 spoteffects(TRUE
); /* possibly drown, notice objects */
4140 #define MIN_ICE_TIME 50
4141 #define MAX_ICE_TIME 2000
4143 * Usually start a melt_ice timer; sometimes the ice will become
4144 * permanent instead.
4147 start_melt_ice_timeout(x
, y
, min_time
)
4149 long min_time
; /* <x,y>'s old melt timeout (deleted by time we get here) */
4154 when
= (int) min_time
;
4155 if (when
< MIN_ICE_TIME
- 1)
4156 when
= MIN_ICE_TIME
- 1;
4158 /* random timeout; surrounding ice locations ought to be a factor... */
4159 while (++when
<= MAX_ICE_TIME
)
4160 if (!rn2((MAX_ICE_TIME
- when
) + MIN_ICE_TIME
))
4163 /* if we're within MAX_ICE_TIME, install a melt timer;
4164 otherwise, omit it to leave this ice permanent */
4165 if (when
<= MAX_ICE_TIME
) {
4166 where
= ((long) x
<< 16) | (long) y
;
4167 (void) start_timer((long) when
, TIMER_LEVEL
, MELT_ICE_AWAY
,
4168 long_to_any(where
));
4175 * Called when ice has melted completely away.
4178 melt_ice_away(arg
, timeout
)
4180 long timeout UNUSED
;
4183 long where
= arg
->a_long
;
4185 y
= (xchar
) (where
& 0xFFFF);
4186 x
= (xchar
) ((where
>> 16) & 0xFFFF);
4187 /* melt_ice does newsym when appropriate */
4188 melt_ice(x
, y
, "Some ice melts away.");
4191 /* Burn floor scrolls, evaporate pools, etc... in a single square.
4192 * Used both for normal bolts of fire, cold, etc... and for fireballs.
4193 * Sets shopdamage to TRUE if a shop door is destroyed, and returns the
4194 * amount by which range is reduced (the latter is just ignored by fireballs)
4197 zap_over_floor(x
, y
, type
, shopdamage
, exploding_wand_typ
)
4200 boolean
*shopdamage
;
4201 short exploding_wand_typ
;
4203 const char *zapverb
;
4206 struct rm
*lev
= &levl
[x
][y
];
4207 boolean see_it
= cansee(x
, y
), yourzap
;
4208 int rangemod
= 0, abstype
= abs(type
) % 10;
4213 if (t
&& t
->ttyp
== WEB
) {
4214 /* a burning web is too flimsy to notice if you can't see it */
4216 Norep("A web bursts into flames!");
4217 (void) delfloortrap(t
);
4222 melt_ice(x
, y
, (char *) 0);
4223 } else if (is_pool(x
, y
)) {
4224 const char *msgtxt
= "You hear hissing gas.";
4226 if (lev
->typ
!= POOL
) { /* MOAT or DRAWBRIDGE_UP */
4228 msgtxt
= "Some water evaporates.";
4232 t
= maketrap(x
, y
, PIT
);
4236 msgtxt
= "The water evaporates.";
4238 Norep("%s", msgtxt
);
4239 if (lev
->typ
== ROOM
)
4241 } else if (IS_FOUNTAIN(lev
->typ
)) {
4243 pline("Steam billows from the fountain.");
4245 dryup(x
, y
, type
> 0);
4247 break; /* ZT_FIRE */
4250 if (is_pool(x
, y
) || is_lava(x
, y
)) {
4251 boolean lava
= is_lava(x
, y
),
4252 moat
= is_moat(x
, y
);
4254 if (lev
->typ
== WATER
) {
4255 /* For now, don't let WATER freeze. */
4257 pline_The("water freezes for a moment.");
4259 You_hear("a soft crackling.");
4260 rangemod
-= 1000; /* stop */
4264 Strcpy(buf
, waterbody_name(x
, y
)); /* for MOAT */
4266 if (lev
->typ
== DRAWBRIDGE_UP
) {
4267 lev
->drawbridgemask
&= ~DB_UNDER
; /* clear lava */
4268 lev
->drawbridgemask
|= (lava
? DB_FLOOR
: DB_ICE
);
4271 lev
->icedpool
= (lev
->typ
== POOL
) ? ICED_POOL
4273 lev
->typ
= lava
? ROOM
: ICE
;
4278 Norep("The lava cools and solidifies.");
4280 Norep("The %s is bridged with ice!", buf
);
4282 Norep("The water freezes.");
4285 You_hear("a crackling sound.");
4287 if (x
== u
.ux
&& y
== u
.uy
) {
4288 if (u
.uinwater
) { /* not just `if (Underwater)' */
4289 /* leave the no longer existent water */
4293 vision_full_recalc
= 1;
4294 } else if (u
.utrap
&& u
.utraptype
== TT_LAVA
) {
4297 You("pass through the now-solid rock.");
4299 u
.utrap
= rn1(50, 20);
4300 u
.utraptype
= TT_INFLOOR
;
4301 You("are firmly stuck in the cooling rock.");
4304 } else if ((mon
= m_at(x
, y
)) != 0) {
4305 /* probably ought to do some hefty damage to any
4306 non-ice creature caught in freezing water;
4307 at a minimum, eels are forced out of hiding */
4308 if (is_swimmer(mon
->data
) && mon
->mundetected
) {
4309 mon
->mundetected
= 0;
4314 start_melt_ice_timeout(x
, y
, 0L);
4315 obj_ice_effects(x
, y
, TRUE
);
4319 } else if (is_ice(x
, y
)) {
4322 /* Already ice here, so just firm it up. */
4323 /* Now ensure that only ice that is already timed is affected */
4324 if ((melt_time
= spot_time_left(x
, y
, MELT_ICE_AWAY
)) != 0L) {
4325 spot_stop_timers(x
, y
, MELT_ICE_AWAY
);
4326 start_melt_ice_timeout(x
, y
, melt_time
);
4329 break; /* ZT_COLD */
4332 (void) create_gas_cloud(x
, y
, 1, 8);
4336 if (lev
->typ
== IRONBARS
) {
4337 if ((lev
->wall_info
& W_NONDIGGABLE
) != 0) {
4339 Norep("The %s corrode somewhat but remain intact.",
4340 defsyms
[S_bars
].explanation
);
4341 /* but nothing actually happens... */
4345 Norep("The %s melt.", defsyms
[S_bars
].explanation
);
4346 if (*in_rooms(x
, y
, SHOPBASE
)) {
4347 /* in case we ever have a shop bounded by bars */
4351 add_damage(x
, y
, (type
>= 0) ? 300L : 0L);
4356 lev
->doormask
= D_NODOOR
;
4362 break; /* ZT_ACID */
4368 /* set up zap text for possible door feedback; for exploding wand, we
4369 want "the blast" rather than "your blast" even if hero caused it */
4370 yourzap
= (type
>= 0 && !exploding_wand_typ
);
4371 zapverb
= "blast"; /* breath attack or wand explosion */
4372 if (!exploding_wand_typ
) {
4373 if (abs(type
) < ZT_SPELL(0))
4374 zapverb
= "bolt"; /* wand zap */
4375 else if (abs(type
) < ZT_BREATH(0))
4379 /* secret door gets revealed, converted into regular door */
4380 if (levl
[x
][y
].typ
== SDOOR
) {
4381 cvt_sdoor_to_door(&levl
[x
][y
]); /* .typ = DOOR */
4382 /* target spot will now pass closed_door() test below
4383 (except on rogue level) */
4386 pline("%s %s reveals a secret door.",
4387 yourzap
? "Your" : "The", zapverb
);
4388 else if (Is_rogue_level(&u
.uz
))
4389 draft_message(FALSE
); /* "You feel a draft." (open doorway) */
4392 /* regular door absorbs remaining zap range, possibly gets destroyed */
4393 if (closed_door(x
, y
)) {
4394 int new_doormask
= -1;
4395 const char *see_txt
= 0, *sense_txt
= 0, *hear_txt
= 0;
4400 new_doormask
= D_NODOOR
;
4401 see_txt
= "The door is consumed in flames!";
4402 sense_txt
= "smell smoke.";
4405 new_doormask
= D_NODOOR
;
4406 see_txt
= "The door freezes and shatters!";
4407 sense_txt
= "feel cold.";
4410 /* death spells/wands don't disintegrate */
4411 if (abs(type
) != ZT_BREATH(ZT_DEATH
))
4413 new_doormask
= D_NODOOR
;
4414 see_txt
= "The door disintegrates!";
4415 hear_txt
= "crashing wood.";
4418 new_doormask
= D_BROKEN
;
4419 see_txt
= "The door splinters!";
4420 hear_txt
= "crackling.";
4424 if (exploding_wand_typ
> 0) {
4425 /* Magical explosion from misc exploding wand */
4426 if (exploding_wand_typ
== WAN_STRIKING
) {
4427 new_doormask
= D_BROKEN
;
4428 see_txt
= "The door crashes open!";
4429 sense_txt
= "feel a burst of cool air.";
4434 /* "the door absorbs the blast" would be
4435 inaccurate for an exploding wand since
4436 other adjacent locations still get hit */
4437 if (exploding_wand_typ
)
4438 pline_The("door remains intact.");
4440 pline_The("door absorbs %s %s!", yourzap
? "your" : "the",
4443 You_feel("vibrations.");
4446 if (new_doormask
>= 0) { /* door gets broken */
4447 if (*in_rooms(x
, y
, SHOPBASE
)) {
4449 add_damage(x
, y
, 400L);
4451 } else /* caused by monster */
4452 add_damage(x
, y
, 0L);
4454 lev
->doormask
= new_doormask
;
4455 unblock_point(x
, y
); /* vision */
4459 } else if (sense_txt
) {
4461 } else if (hear_txt
)
4462 You_hear1(hear_txt
);
4463 if (picking_at(x
, y
)) {
4470 if (OBJ_AT(x
, y
) && abstype
== ZT_FIRE
)
4471 if (burn_floor_objects(x
, y
, FALSE
, type
> 0) && couldsee(x
, y
)) {
4473 You("%s of smoke.", !Blind
? "see a puff" : "smell a whiff");
4475 if ((mon
= m_at(x
, y
)) != 0) {
4476 /* Cannot use wakeup() which also angers the monster */
4482 if (mon
->ispriest
&& *in_rooms(mon
->mx
, mon
->my
, TEMPLE
))
4484 if (mon
->isshk
&& !*u
.ushops
)
4491 /* fractured by pick-axe or wand of striking */
4494 register struct obj
*obj
; /* no texts here! */
4497 boolean by_you
= !context
.mon_moving
;
4499 if (by_you
&& get_obj_location(obj
, &x
, &y
, 0) && costly_spot(x
, y
)) {
4500 struct monst
*shkp
= 0;
4501 char objroom
= *in_rooms(x
, y
, SHOPBASE
);
4503 if (billable(&shkp
, obj
, objroom
, FALSE
)) {
4504 /* shop message says "you owe <shk> <$> for it!" so we need
4505 to precede that with a message explaining what "it" is */
4506 You("fracture %s %s.", s_suffix(shkname(shkp
)), xname(obj
));
4507 breakobj(obj
, x
, y
, TRUE
, FALSE
); /* charges for shop goods */
4510 if (by_you
&& obj
->otyp
== BOULDER
)
4514 obj
->oclass
= GEM_CLASS
;
4515 obj
->quan
= (long) rn1(60, 7);
4516 obj
->owt
= weight(obj
);
4517 obj
->dknown
= obj
->bknown
= obj
->rknown
= 0;
4518 obj
->known
= objects
[obj
->otyp
].oc_uses_known
? 0 : 1;
4519 dealloc_oextra(obj
);
4521 if (obj
->where
== OBJ_FLOOR
) {
4522 obj_extract_self(obj
); /* move rocks back on top */
4523 place_object(obj
, obj
->ox
, obj
->oy
);
4524 if (!does_block(obj
->ox
, obj
->oy
, &levl
[obj
->ox
][obj
->oy
]))
4525 unblock_point(obj
->ox
, obj
->oy
);
4526 if (cansee(obj
->ox
, obj
->oy
))
4527 newsym(obj
->ox
, obj
->oy
);
4531 /* handle statue hit by striking/force bolt/pick-axe */
4534 register struct obj
*obj
;
4536 /* [obj is assumed to be on floor, so no get_obj_location() needed] */
4537 struct trap
*trap
= t_at(obj
->ox
, obj
->oy
);
4539 boolean by_you
= !context
.mon_moving
;
4541 if (trap
&& trap
->ttyp
== STATUE_TRAP
4542 && activate_statue_trap(trap
, obj
->ox
, obj
->oy
, TRUE
))
4544 /* drop any objects contained inside the statue */
4545 while ((item
= obj
->cobj
) != 0) {
4546 obj_extract_self(item
);
4547 place_object(item
, obj
->ox
, obj
->oy
);
4549 if (by_you
&& Role_if(PM_ARCHEOLOGIST
) && (obj
->spe
& STATUE_HISTORIC
)) {
4550 You_feel("guilty about damaging such a historic statue.");
4559 * destroy_strings[dindx][0:singular,1:plural,2:killer_reason]
4560 * [0] freezing potion
4561 * [1] boiling potion other than oil
4562 * [2] boiling potion of oil
4563 * [3] burning scroll
4564 * [4] burning spellbook
4567 * (books, rings, and wands don't stack so don't need plural form;
4568 * crumbling ring doesn't do damage so doesn't need killer reason)
4570 const char *const destroy_strings
[][3] = {
4571 /* also used in trap.c */
4572 { "freezes and shatters", "freeze and shatter", "shattered potion" },
4573 { "boils and explodes", "boil and explode", "boiling potion" },
4574 { "ignites and explodes", "ignite and explode", "exploding potion" },
4575 { "catches fire and burns", "catch fire and burn", "burning scroll" },
4576 { "catches fire and burns", "", "burning book" },
4577 { "turns to dust and vanishes", "", "" },
4578 { "breaks apart and explodes", "", "exploding wand" },
4582 destroy_item(osym
, dmgtyp
)
4583 register int osym
, dmgtyp
;
4585 register struct obj
*obj
, *obj2
;
4586 int dmg
, xresist
, skip
;
4590 boolean physical_damage
;
4592 for (obj
= invent
; obj
; obj
= obj2
) {
4594 physical_damage
= FALSE
;
4595 if (obj
->oclass
!= osym
)
4596 continue; /* test only objs of type osym */
4598 continue; /* don't destroy artifacts */
4599 if (obj
->in_use
&& obj
->quan
== 1L)
4600 continue; /* not available */
4602 /* lint suppression */
4608 if (osym
== POTION_CLASS
&& obj
->otyp
!= POT_OIL
) {
4616 xresist
= (Fire_resistance
&& obj
->oclass
!= POTION_CLASS
4617 && obj
->otyp
!= GLOB_OF_GREEN_SLIME
);
4619 if (obj
->otyp
== SCR_FIRE
|| obj
->otyp
== SPE_FIREBALL
)
4621 if (obj
->otyp
== SPE_BOOK_OF_THE_DEAD
) {
4624 pline("%s glows a strange %s, but remains intact.",
4625 The(xname(obj
)), hcolor("dark red"));
4630 dindx
= (obj
->otyp
!= POT_OIL
) ? 1 : 2;
4642 if (obj
->otyp
== GLOB_OF_GREEN_SLIME
) {
4643 dindx
= 1; /* boil and explode */
4644 dmg
= (obj
->owt
+ 19) / 20;
4655 xresist
= (Shock_resistance
&& obj
->oclass
!= RING_CLASS
);
4659 if (obj
->otyp
== RIN_SHOCK_RESISTANCE
) {
4667 if (obj
->otyp
== WAN_LIGHTNING
) {
4672 if (obj
== current_wand
) { skip
++; break; }
4688 --quan
; /* one will be used up elsewhere */
4689 for (i
= cnt
= 0L; i
< quan
; i
++)
4695 mult
= (cnt
== quan
)
4696 ? (quan
> 1) ? "All of your " : "Your"
4697 : (cnt
== 1L) ? "One of your" : "Some of your";
4698 pline("%s %s %s!", mult
, xname(obj
),
4699 destroy_strings
[dindx
][(cnt
> 1L)]);
4700 if (osym
== POTION_CLASS
&& dmgtyp
!= AD_COLD
) {
4701 if (!breathless(youmonst
.data
) || haseyes(youmonst
.data
))
4704 if (obj
->owornmask
) {
4705 if (obj
->owornmask
& W_RING
) /* ring being worn */
4710 if (obj
== current_wand
)
4711 current_wand
= 0; /* destroyed */
4712 for (i
= 0; i
< cnt
; i
++)
4716 You("aren't hurt!");
4718 const char *how
= destroy_strings
[dindx
][2];
4719 boolean one
= (cnt
== 1L);
4721 if (dmgtyp
== AD_FIRE
&& osym
== FOOD_CLASS
)
4722 how
= "exploding glob of slime";
4723 if (physical_damage
)
4724 dmg
= Maybe_Half_Phys(dmg
);
4725 losehp(dmg
, one
? how
: (const char *) makeplural(how
),
4726 one
? KILLED_BY_AN
: KILLED_BY
);
4727 exercise(A_STR
, FALSE
);
4736 destroy_mitem(mtmp
, osym
, dmgtyp
)
4740 struct obj
*obj
, *obj2
;
4746 if (mtmp
== &youmonst
) { /* this simplifies artifact_hit() */
4747 destroy_item(osym
, dmgtyp
);
4748 return 0; /* arbitrary; value doesn't matter to artifact_hit() */
4751 vis
= canseemon(mtmp
);
4752 for (obj
= mtmp
->minvent
; obj
; obj
= obj2
) {
4754 if (obj
->oclass
!= osym
)
4755 continue; /* test only objs of type osym */
4762 if (osym
== POTION_CLASS
&& obj
->otyp
!= POT_OIL
) {
4770 if (obj
->otyp
== SCR_FIRE
|| obj
->otyp
== SPE_FIREBALL
)
4772 if (obj
->otyp
== SPE_BOOK_OF_THE_DEAD
) {
4775 pline("%s glows a strange %s, but remains intact.",
4776 The(distant_name(obj
, xname
)), hcolor("dark red"));
4781 dindx
= (obj
->otyp
!= POT_OIL
) ? 1 : 2;
4793 if (obj
->otyp
== GLOB_OF_GREEN_SLIME
) {
4794 dindx
= 1; /* boil and explode */
4795 tmp
+= (obj
->owt
+ 19) / 20;
4809 if (obj
->otyp
== RIN_SHOCK_RESISTANCE
) {
4816 if (obj
->otyp
== WAN_LIGHTNING
) {
4833 for (i
= cnt
= 0L; i
< quan
; i
++)
4841 (cnt
== obj
->quan
) ? "" : (cnt
> 1L) ? "Some of "
4843 (cnt
== obj
->quan
) ? Yname2(obj
) : yname(obj
),
4844 destroy_strings
[dindx
][(cnt
> 1L)]);
4845 for (i
= 0; i
< cnt
; i
++)
4853 resist(mtmp
, oclass
, damage
, tell
)
4868 break; /* instrument */
4871 break; /* artifact */
4886 dlev
= (int) mtmp
->m_lev
;
4890 dlev
= is_mplayer(mtmp
->data
) ? u
.ulevel
: 1;
4892 resisted
= rn2(100 + alev
- dlev
) < mtmp
->data
->mr
;
4895 shieldeff(mtmp
->mx
, mtmp
->my
);
4896 pline("%s resists!", Monnam(mtmp
));
4898 damage
= (damage
+ 1) / 2;
4902 mtmp
->mhp
-= damage
;
4903 if (mtmp
->mhp
< 1) {
4905 monkilled(mtmp
, "", AD_RBRE
);
4913 #define MAXWISHTRY 5
4916 wishcmdassist(triesleft
)
4919 static NEARDATA
const char *
4923 "Enter the name of an object, such as \"potion of monster detection\",",
4924 "\"scroll labeled README\", \"elven mithril-coat\", or \"Grimtooth\"",
4925 "(without the quotes).",
4927 "For object types which come in stacks, you may specify a plural name",
4928 "such as \"potions of healing\", or specify a count, such as \"1000 gold",
4929 "pieces\", although that aspect of your wish might not be granted.",
4931 "You may also specify various prefix values which might be used to",
4932 "modify the item, such as \"uncursed\" or \"rustproof\" or \"+1\".",
4933 "Most modifiers shown when viewing your inventory can be specified.",
4935 "You may specify 'nothing' to explicitly decline this wish.",
4938 preserve_wishless
[] = "Doing so will preserve 'wishless' conduct.",
4940 "If you specify an unrecognized object name %s%s time%s,",
4941 retry_too
[] = "a randomly chosen item will be granted.",
4942 suppress_cmdassist
[] =
4943 "(Suppress this assistance with !cmdassist in your config file.)",
4944 *cardinals
[] = { "zero", "one", "two", "three", "four", "five" },
4945 too_many
[] = "too many";
4950 win
= create_nhwindow(NHW_TEXT
);
4953 for (i
= 0; i
< SIZE(wishinfo
) - 1; ++i
)
4954 putstr(win
, 0, wishinfo
[i
]);
4955 if (!u
.uconduct
.wishes
)
4956 putstr(win
, 0, preserve_wishless
);
4958 Sprintf(buf
, retry_info
,
4959 (triesleft
>= 0 && triesleft
< SIZE(cardinals
))
4960 ? cardinals
[triesleft
]
4962 (triesleft
< MAXWISHTRY
) ? " more" : "",
4964 putstr(win
, 0, buf
);
4965 putstr(win
, 0, retry_too
);
4967 if (iflags
.cmdassist
)
4968 putstr(win
, 0, suppress_cmdassist
);
4969 display_nhwindow(win
, FALSE
);
4970 destroy_nhwindow(win
);
4976 char buf
[BUFSZ
], promptbuf
[BUFSZ
];
4977 struct obj
*otmp
, nothing
;
4980 promptbuf
[0] = '\0';
4981 nothing
= zeroobj
; /* lint suppression; only its address matters */
4983 You("may wish for an object.");
4985 Strcpy(promptbuf
, "For what do you wish");
4986 if (iflags
.cmdassist
&& tries
> 0)
4987 Strcat(promptbuf
, " (enter 'help' for assistance)");
4988 Strcat(promptbuf
, "?");
4989 getlin(promptbuf
, buf
);
4990 (void) mungspaces(buf
);
4991 if (buf
[0] == '\033') {
4993 } else if (!strcmpi(buf
, "help")) {
4994 wishcmdassist(MAXWISHTRY
- tries
);
4998 * Note: if they wished for and got a non-object successfully,
4999 * otmp == &zeroobj. That includes gold, or an artifact that
5000 * has been denied. Wishing for "nothing" requires a separate
5001 * value to remain distinct.
5003 otmp
= readobjnam(buf
, ¬hing
);
5005 pline("Nothing fitting that description exists in the game.");
5006 if (++tries
< MAXWISHTRY
)
5008 pline1(thats_enough_tries
);
5009 otmp
= readobjnam((char *) 0, (struct obj
*) 0);
5011 return; /* for safety; should never happen */
5012 } else if (otmp
== ¬hing
) {
5013 /* explicitly wished for "nothing", presumably attempting
5014 to retain wishless conduct */
5019 u
.uconduct
.wishes
++;
5021 if (otmp
!= &zeroobj
) {
5023 *verb
= ((Is_airlevel(&u
.uz
) || u
.uinwater
) ? "slip" : "drop"),
5024 *oops_msg
= (u
.uswallow
5025 ? "Oops! %s out of your reach!"
5026 : (Is_airlevel(&u
.uz
) || Is_waterlevel(&u
.uz
)
5027 || levl
[u
.ux
][u
.uy
].typ
< IRONBARS
5028 || levl
[u
.ux
][u
.uy
].typ
>= ICE
)
5029 ? "Oops! %s away from you!"
5030 : "Oops! %s to the floor!");
5032 /* The(aobjnam()) is safe since otmp is unidentified -dlc */
5033 (void) hold_another_object(otmp
, oops_msg
,
5034 The(aobjnam(otmp
, verb
)),
5036 u
.ublesscnt
+= rn1(100, 50); /* the gods take notice */