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 boolean polyspot
= (otyp
!= POT_POLYMORPH
),
225 give_msg
= (!Hallucination
227 || (u
.uswallow
&& mtmp
== u
.ustuck
)));
229 /* dropped inventory (due to death by system shock,
230 or loss of wielded weapon and/or worn armor due to
231 limitations of new shape) won't be hit by this zap */
233 for (obj
= mtmp
->minvent
; obj
; obj
= obj
->nobj
)
235 /* natural shapechangers aren't affected by system shock
236 (unless protection from shapechangers is interfering
237 with their metabolism...) */
238 if (mtmp
->cham
== NON_PM
&& !rn2(25)) {
239 if (canseemon(mtmp
)) {
240 pline("%s shudders!", Monnam(mtmp
));
243 /* context.bypasses = TRUE; ## for make_corpse() */
244 /* no corpse after system shock */
246 } else if (newcham(mtmp
, (struct permonst
*) 0,
247 polyspot
, give_msg
) != 0
248 /* if shapechange failed because there aren't
249 enough eligible candidates (most likely for
250 vampshifter), try reverting to original form */
251 || (mtmp
->cham
>= LOW_PM
252 && newcham(mtmp
, &mons
[mtmp
->cham
],
253 polyspot
, give_msg
) != 0)) {
254 if (give_msg
&& (canspotmon(mtmp
)
255 || (u
.uswallow
&& mtmp
== u
.ustuck
)))
260 case WAN_CANCELLATION
:
261 case SPE_CANCELLATION
:
264 (void) cancel_monst(mtmp
, otmp
, TRUE
, TRUE
, FALSE
);
266 case WAN_TELEPORTATION
:
267 case SPE_TELEPORT_AWAY
:
270 reveal_invis
= !u_teleport_mon(mtmp
, TRUE
);
272 case WAN_MAKE_INVISIBLE
: {
273 int oldinvis
= mtmp
->minvis
;
278 /* format monster's name before altering its visibility */
279 Strcpy(nambuf
, Monnam(mtmp
));
280 mon_set_minvis(mtmp
);
281 if (!oldinvis
&& knowninvisible(mtmp
)) {
282 pline("%s turns transparent!", nambuf
);
288 case SPE_WIZARD_LOCK
:
289 wake
= closeholdingtrap(mtmp
, &learn_it
);
299 wake
= FALSE
; /* don't want immediate counterattack */
300 if (u
.uswallow
&& mtmp
== u
.ustuck
) {
301 if (is_animal(mtmp
->data
)) {
303 You_feel("a sudden rush of air!");
305 pline("%s opens its mouth!", Monnam(mtmp
));
307 expels(mtmp
, mtmp
->data
, TRUE
);
308 /* zap which hits steed will only release saddle if it
309 doesn't hit a holding or falling trap; playability
310 here overrides the more logical target ordering */
311 } else if (openholdingtrap(mtmp
, &learn_it
)) {
313 } else if (openfallingtrap(mtmp
, TRUE
, &learn_it
)) {
314 /* mtmp might now be on the migrating monsters list */
316 } else if ((obj
= which_armor(mtmp
, W_SADDLE
)) != 0) {
319 Sprintf(buf
, "%s %s", s_suffix(Monnam(mtmp
)),
320 distant_name(obj
, xname
));
321 if (cansee(mtmp
->mx
, mtmp
->my
)) {
322 if (!canspotmon(mtmp
))
323 Strcpy(buf
, An(distant_name(obj
, xname
)));
324 pline("%s falls to the %s.", buf
,
325 surface(mtmp
->mx
, mtmp
->my
));
326 } else if (canspotmon(mtmp
)) {
327 pline("%s falls off.", buf
);
329 obj_extract_self(obj
);
330 mdrop_obj(mtmp
, obj
, FALSE
);
334 case SPE_EXTRA_HEALING
:
336 if (mtmp
->data
!= &mons
[PM_PESTILENCE
]) {
337 wake
= FALSE
; /* wakeup() makes the target angry */
338 mtmp
->mhp
+= d(6, otyp
== SPE_EXTRA_HEALING
? 8 : 4);
339 if (mtmp
->mhp
> mtmp
->mhpmax
)
340 mtmp
->mhp
= mtmp
->mhpmax
;
341 if (mtmp
->mblinded
) {
345 if (canseemon(mtmp
)) {
346 if (disguised_mimic
) {
347 if (is_obj_mappear(mtmp
,STRANGE_OBJECT
)) {
348 /* it can do better now */
350 newsym(mtmp
->mx
, mtmp
->my
);
352 mimic_hit_msg(mtmp
, otyp
);
354 pline("%s looks%s better.", Monnam(mtmp
),
355 otyp
== SPE_EXTRA_HEALING
? " much" : "");
357 if (mtmp
->mtame
|| mtmp
->mpeaceful
) {
358 adjalign(Role_if(PM_HEALER
) ? 1 : sgn(u
.ualign
.type
));
360 } else { /* Pestilence */
361 /* Pestilence will always resist; damage is half of 3d{4,8} */
362 (void) resist(mtmp
, otmp
->oclass
,
363 d(3, otyp
== SPE_EXTRA_HEALING
? 8 : 4), TELL
);
366 case WAN_LIGHT
: /* (broken wand) */
367 if (flash_hits_mon(mtmp
, otmp
)) {
372 case WAN_SLEEP
: /* (broken wand) */
373 /* [wakeup() doesn't rouse victims of temporary sleep,
374 so it's okay to leave `wake' set to TRUE here] */
376 if (sleep_monst(mtmp
, d(1 + otmp
->spe
, 12), WAND_CLASS
))
381 case SPE_STONE_TO_FLESH
:
382 if (monsndx(mtmp
->data
) == PM_STONE_GOLEM
) {
383 char *name
= Monnam(mtmp
);
385 /* turn into flesh golem */
386 if (newcham(mtmp
, &mons
[PM_FLESH_GOLEM
], FALSE
, FALSE
)) {
388 pline("%s turns to flesh!", name
);
391 pline("%s looks rather fleshy for a moment.", name
);
399 dmg
= monhp_per_lvl(mtmp
);
402 if (otyp
== SPE_DRAIN_LIFE
)
403 dmg
= spell_damage_bonus(dmg
);
404 if (resists_drli(mtmp
))
405 shieldeff(mtmp
->mx
, mtmp
->my
);
406 else if (!resist(mtmp
, otmp
->oclass
, dmg
, NOTELL
) && mtmp
->mhp
> 0) {
409 if (mtmp
->mhp
<= 0 || mtmp
->mhpmax
<= 0 || mtmp
->m_lev
< 1)
414 pline("%s suddenly seems weaker!", Monnam(mtmp
));
422 impossible("What an interesting effect (%d)", otyp
);
429 if (mtmp
->isshk
&& !*u
.ushops
)
431 } else if (mtmp
->m_ap_type
)
432 seemimic(mtmp
); /* might unblock if mimicing a boulder/door */
434 /* note: bhitpos won't be set if swallowed, but that's okay since
435 * reveal_invis will be false. We can't use mtmp->mx, my since it
436 * might be an invisible worm hit on the tail.
439 if (mtmp
->mhp
> 0 && cansee(bhitpos
.x
, bhitpos
.y
)
440 && !canspotmon(mtmp
))
441 map_invisible(bhitpos
.x
, bhitpos
.y
);
443 /* if effect was observable then discover the wand type provided
444 that the wand itself has been seen */
458 return; /* don't show minvent for long worm tail */
461 for (otmp
= mtmp
->minvent
; otmp
; otmp
= otmp
->nobj
) {
462 otmp
->dknown
= 1; /* treat as "seen" */
463 if (Is_container(otmp
) || otmp
->otyp
== STATUE
) {
465 if (!SchroedingersBox(otmp
))
469 (void) display_minventory(mtmp
, MINV_ALL
| MINV_NOLET
, (char *) 0);
471 pline("%s is not carrying anything%s.", noit_Monnam(mtmp
),
472 (u
.uswallow
&& mtmp
== u
.ustuck
) ? " besides you" : "");
477 * Return the object's physical location. This only makes sense for
478 * objects that are currently on the level (i.e. migrating objects
479 * are nowhere). By default, only things that can be seen (in hero's
480 * inventory, monster's inventory, or on the ground) are reported.
481 * By adding BURIED_TOO and/or CONTAINED_TOO flags, you can also get
482 * the location of buried and contained objects. Note that if an
483 * object is carried by a monster, its reported position may change
484 * from turn to turn. This function returns FALSE if the position
485 * is not available or subject to the constraints above.
488 get_obj_location(obj
, xp
, yp
, locflags
)
493 switch (obj
->where
) {
503 if (obj
->ocarry
->mx
) {
504 *xp
= obj
->ocarry
->mx
;
505 *yp
= obj
->ocarry
->my
;
508 break; /* !mx => migrating monster */
510 if (locflags
& BURIED_TOO
) {
517 if (locflags
& CONTAINED_TOO
)
518 return get_obj_location(obj
->ocontainer
, xp
, yp
, locflags
);
526 get_mon_location(mon
, xp
, yp
, locflags
)
529 int locflags
; /* non-zero means get location even if monster is buried */
531 if (mon
== &youmonst
) {
535 } else if (mon
->mx
> 0 && (!mon
->mburied
|| locflags
)) {
539 } else { /* migrating or buried */
545 /* used by revive() and animate_statue() */
551 struct monst
*mtmp
= (struct monst
*) 0;
552 struct monst
*mtmp2
= (struct monst
*) 0;
555 mtmp2
= get_mtraits(obj
, TRUE
);
557 /* save_mtraits() validated mtmp2->mnum */
558 mtmp2
->data
= &mons
[mtmp2
->mnum
];
559 if (mtmp2
->mhpmax
<= 0 && !is_rider(mtmp2
->data
))
560 return (struct monst
*) 0;
561 mtmp
= makemon(mtmp2
->data
, cc
->x
, cc
->y
,
562 NO_MINVENT
| MM_NOWAIT
| MM_NOCOUNTBIRTH
);
566 /* heal the monster */
567 if (mtmp
->mhpmax
> mtmp2
->mhpmax
&& is_rider(mtmp2
->data
))
568 mtmp2
->mhpmax
= mtmp
->mhpmax
;
569 mtmp2
->mhp
= mtmp2
->mhpmax
;
570 /* Get these ones from mtmp */
571 mtmp2
->minvent
= mtmp
->minvent
; /*redundant*/
572 /* monster ID is available if the monster died in the current
573 game, but will be zero if the corpse was in a bones level
574 (we cleared it when loading bones) */
576 mtmp2
->m_id
= mtmp
->m_id
;
577 /* might be bringing quest leader back to life */
578 if (quest_status
.leader_is_dead
&&
579 /* leader_is_dead implies leader_m_id is valid */
580 mtmp2
->m_id
== quest_status
.leader_m_id
)
581 quest_status
.leader_is_dead
= FALSE
;
583 mtmp2
->mx
= mtmp
->mx
;
584 mtmp2
->my
= mtmp
->my
;
585 mtmp2
->mux
= mtmp
->mux
;
586 mtmp2
->muy
= mtmp
->muy
;
587 mtmp2
->mw
= mtmp
->mw
;
588 mtmp2
->wormno
= mtmp
->wormno
;
589 mtmp2
->misc_worn_check
= mtmp
->misc_worn_check
;
590 mtmp2
->weapon_check
= mtmp
->weapon_check
;
591 mtmp2
->mtrapseen
= mtmp
->mtrapseen
;
592 mtmp2
->mflee
= mtmp
->mflee
;
593 mtmp2
->mburied
= mtmp
->mburied
;
594 mtmp2
->mundetected
= mtmp
->mundetected
;
595 mtmp2
->mfleetim
= mtmp
->mfleetim
;
596 mtmp2
->mlstmv
= mtmp
->mlstmv
;
597 mtmp2
->m_ap_type
= mtmp
->m_ap_type
;
598 /* set these ones explicitly */
604 mtmp2
->msleeping
= 0;
607 /* most cancelled monsters return to normal,
608 but some need to stay cancelled */
609 if (!dmgtype(mtmp2
->data
, AD_SEDU
)
610 && (!SYSOPT_SEDUCE
|| !dmgtype(mtmp2
->data
, AD_SSEX
)))
612 mtmp2
->mcansee
= 1; /* set like in makemon */
616 replmon(mtmp
, mtmp2
);
617 newsym(mtmp2
->mx
, mtmp2
->my
); /* Might now be invisible */
619 /* in case Protection_from_shape_changers is different
620 now than it was when the traits were stored */
627 * get_container_location() returns the following information
628 * about the outermost container:
629 * loc argument gets set to:
630 * OBJ_INVENT if in hero's inventory; return 0.
631 * OBJ_FLOOR if on the floor; return 0.
632 * OBJ_BURIED if buried; return 0.
633 * OBJ_MINVENT if in monster's inventory; return monster.
634 * container_nesting is updated with the nesting depth of the containers
638 get_container_location(obj
, loc
, container_nesting
)
641 int *container_nesting
;
646 if (container_nesting
)
647 *container_nesting
= 0;
648 while (obj
&& obj
->where
== OBJ_CONTAINED
) {
649 if (container_nesting
)
650 *container_nesting
+= 1;
651 obj
= obj
->ocontainer
;
654 *loc
= obj
->where
; /* outermost container's location */
655 if (obj
->where
== OBJ_MINVENT
)
658 return (struct monst
*) 0;
662 * Attempt to revive the given corpse, return the revived monster if
663 * successful. Note: this does NOT use up the corpse if it fails.
666 revive(corpse
, by_hero
)
670 struct monst
*mtmp
= 0;
671 struct permonst
*mptr
;
672 struct obj
*container
;
675 int montype
, container_nesting
= 0;
677 if (corpse
->otyp
!= CORPSE
) {
678 impossible("Attempting to revive %s?", xname(corpse
));
679 return (struct monst
*) 0;
683 if (corpse
->where
!= OBJ_CONTAINED
) {
684 /* only for invent, minvent, or floor */
686 (void) get_obj_location(corpse
, &x
, &y
, 0);
688 /* deal with corpses in [possibly nested] containers */
689 struct monst
*carrier
;
690 int holder
= OBJ_FREE
;
692 container
= corpse
->ocontainer
;
694 get_container_location(container
, &holder
, &container_nesting
);
697 x
= carrier
->mx
, y
= carrier
->my
;
703 (void) get_obj_location(corpse
, &x
, &y
, CONTAINED_TOO
);
706 break; /* x,y are 0 */
710 /* Rules for revival from containers:
711 - the container cannot be locked
712 - the container cannot be heavily nested (>2 is arbitrary)
713 - the container cannot be a statue or bag of holding
714 (except in very rare cases for the latter)
716 (container
&& (container
->olocked
|| container_nesting
> 2
717 || container
->otyp
== STATUE
718 || (container
->otyp
== BAG_OF_HOLDING
&& rn2(40)))))
719 return (struct monst
*) 0;
721 /* record the object's location now that we're sure where it is */
722 corpse
->ox
= x
, corpse
->oy
= y
;
724 /* prepare for the monster */
725 montype
= corpse
->corpsenm
;
726 mptr
= &mons
[montype
];
727 /* [should probably handle recorporealization first; if corpse and
728 ghost are at same location, revived creature shouldn't be bumped
729 to an adjacent spot by ghost which joins with it] */
731 if (enexto(&xy
, x
, y
, mptr
))
735 if (mons
[montype
].mlet
== S_EEL
&& !IS_POOL(levl
[x
][y
].typ
)) {
736 if (by_hero
&& cansee(x
,y
))
737 pline("%s twitches feebly.",
738 upstart(corpse_xname(corpse
, (const char *) 0, CXN_PFX_THE
)));
739 return (struct monst
*) 0;
742 if (cant_revive(&montype
, TRUE
, corpse
)) {
743 /* make a zombie or doppelganger instead */
744 /* note: montype has changed; mptr keeps old value for newcham() */
745 mtmp
= makemon(&mons
[montype
], x
, y
, NO_MINVENT
| MM_NOWAIT
);
747 /* skip ghost handling */
748 if (has_omid(corpse
))
750 if (has_omonst(corpse
))
752 if (mtmp
->cham
== PM_DOPPELGANGER
) {
753 /* change shape to match the corpse */
754 (void) newcham(mtmp
, mptr
, FALSE
, FALSE
);
755 } else if (mtmp
->data
->mlet
== S_ZOMBIE
) {
756 mtmp
->mhp
= mtmp
->mhpmax
= 100;
757 mon_adjust_speed(mtmp
, 2, (struct obj
*) 0); /* MFAST */
760 } else if (has_omonst(corpse
)) {
761 /* use saved traits */
763 mtmp
= montraits(corpse
, &xy
);
764 if (mtmp
&& mtmp
->mtame
&& !mtmp
->isminion
)
765 wary_dog(mtmp
, TRUE
);
767 /* make a new monster */
768 mtmp
= makemon(mptr
, x
, y
, NO_MINVENT
| MM_NOWAIT
| MM_NOCOUNTBIRTH
);
771 return (struct monst
*) 0;
773 /* hiders shouldn't already be re-hidden when they revive */
774 if (mtmp
->mundetected
) {
775 mtmp
->mundetected
= 0;
776 newsym(mtmp
->mx
, mtmp
->my
);
781 /* if this is caused by the hero there might be a shop charge */
783 struct monst
*shkp
= 0;
785 x
= corpse
->ox
, y
= corpse
->oy
;
786 if (costly_spot(x
, y
))
787 shkp
= shop_keeper(*in_rooms(x
, y
, SHOPBASE
));
791 unsigned pfx
= CXN_PFX_THE
;
793 Strcpy(buf
, (corpse
->quan
> 1L) ? "one of " : "");
794 if (carried(corpse
) && !corpse
->unpaid
) {
795 Strcat(buf
, "your ");
798 Strcat(buf
, corpse_xname(corpse
, (const char *) 0, pfx
));
799 pline("%s glows iridescently.", upstart(buf
));
801 /* need some prior description of the corpse since
802 stolen_value() will refer to the object as "it" */
803 pline("A corpse is resuscitated.");
805 /* don't charge for shopkeeper's own corpse if we just revived him */
806 if (shkp
&& mtmp
!= shkp
)
807 (void) stolen_value(corpse
, x
, y
, (boolean
) shkp
->mpeaceful
,
810 /* [we don't give any comparable message about the corpse for
811 the !by_hero case because caller might have already done so] */
814 /* handle recorporealization of an active ghost */
815 if (has_omid(corpse
)) {
820 (void) memcpy((genericptr_t
) &m_id
, (genericptr_t
) OMID(corpse
),
822 ghost
= find_mid(m_id
, FM_FMON
);
823 if (ghost
&& ghost
->data
== &mons
[PM_GHOST
]) {
824 if (canseemon(ghost
))
825 pline("%s is suddenly drawn into its former body!",
827 /* transfer the ghost's inventory along with it */
828 while ((otmp
= ghost
->minvent
) != 0) {
829 obj_extract_self(otmp
);
830 add_to_minv(mtmp
, otmp
);
832 /* tame the revived monster if its ghost was tame */
833 if (ghost
->mtame
&& !mtmp
->mtame
) {
834 if (tamedog(mtmp
, (struct obj
*) 0)) {
835 /* ghost's edog data is ignored */
836 mtmp
->mtame
= ghost
->mtame
;
839 /* was ghost, now alive, it's all very confusing */
841 /* separate ghost monster no longer exists */
847 /* monster retains its name */
848 if (has_oname(corpse
) && !unique_corpstat(mtmp
->data
))
849 mtmp
= christen_monst(mtmp
, ONAME(corpse
));
850 /* partially eaten corpse yields wounded monster */
852 mtmp
->mhp
= eaten_stat(mtmp
->mhp
, corpse
);
853 /* track that this monster was revived at least once */
856 /* finally, get rid of the corpse--it's gone now */
857 switch (corpse
->where
) {
862 /* in case MON_AT+enexto for invisible mon */
863 x
= corpse
->ox
, y
= corpse
->oy
;
864 /* not useupf(), which charges */
865 if (corpse
->quan
> 1L)
866 corpse
= splitobj(corpse
, 1L);
871 m_useup(corpse
->ocarry
, corpse
);
874 obj_extract_self(corpse
);
875 obfree(corpse
, (struct obj
*) 0);
889 * Note: generic eggs with corpsenm set to NON_PM will never hatch.
891 if (obj
->otyp
!= EGG
)
893 if (obj
->corpsenm
!= NON_PM
&& !dead_species(obj
->corpsenm
, TRUE
))
894 attach_egg_hatch_timeout(obj
, 0L);
897 /* try to revive all corpses and eggs carried by `mon' */
902 struct obj
*otmp
, *otmp2
;
904 char owner
[BUFSZ
], corpse
[BUFSZ
];
906 int once
= 0, res
= 0;
908 youseeit
= (mon
== &youmonst
) ? TRUE
: canseemon(mon
);
909 otmp2
= (mon
== &youmonst
) ? invent
: mon
->minvent
;
911 while ((otmp
= otmp2
) != 0) {
913 if (otmp
->otyp
== EGG
)
915 if (otmp
->otyp
!= CORPSE
)
917 /* save the name; the object is liable to go away */
920 corpse_xname(otmp
, (const char *) 0, CXN_SINGULAR
));
922 /* for a merged group, only one is revived; should this be fixed? */
923 if ((mtmp2
= revive(otmp
, !context
.mon_moving
)) != 0) {
927 Strcpy(owner
, (mon
== &youmonst
) ? "Your"
928 : s_suffix(Monnam(mon
)));
929 pline("%s %s suddenly comes alive!", owner
, corpse
);
930 } else if (canseemon(mtmp2
))
931 pline("%s suddenly appears!", Amonnam(mtmp2
));
937 /* cancel obj, possibly carried by you or a monster */
940 register struct obj
*obj
;
942 boolean u_ring
= (obj
== uleft
|| obj
== uright
);
943 int otyp
= obj
->otyp
;
946 case RIN_GAIN_STRENGTH
:
947 if ((obj
->owornmask
& W_RING
) && u_ring
) {
948 ABON(A_STR
) -= obj
->spe
;
952 case RIN_GAIN_CONSTITUTION
:
953 if ((obj
->owornmask
& W_RING
) && u_ring
) {
954 ABON(A_CON
) -= obj
->spe
;
959 if ((obj
->owornmask
& W_RING
) && u_ring
) {
960 ABON(A_CHA
) -= obj
->spe
;
964 case RIN_INCREASE_ACCURACY
:
965 if ((obj
->owornmask
& W_RING
) && u_ring
)
966 u
.uhitinc
-= obj
->spe
;
968 case RIN_INCREASE_DAMAGE
:
969 if ((obj
->owornmask
& W_RING
) && u_ring
)
970 u
.udaminc
-= obj
->spe
;
972 case GAUNTLETS_OF_DEXTERITY
:
973 if ((obj
->owornmask
& W_ARMG
) && (obj
== uarmg
)) {
974 ABON(A_DEX
) -= obj
->spe
;
978 case HELM_OF_BRILLIANCE
:
979 if ((obj
->owornmask
& W_ARMH
) && (obj
== uarmh
)) {
980 ABON(A_INT
) -= obj
->spe
;
981 ABON(A_WIS
) -= obj
->spe
;
985 /* case RIN_PROTECTION: not needed */
987 if (objects
[otyp
].oc_magic
988 || (obj
->spe
&& (obj
->oclass
== ARMOR_CLASS
989 || obj
->oclass
== WEAPON_CLASS
|| is_weptool(obj
)))
991 || otyp
== POT_SICKNESS
992 || (otyp
== POT_WATER
&& (obj
->blessed
|| obj
->cursed
))) {
993 if (obj
->spe
!= ((obj
->oclass
== WAND_CLASS
) ? -1 : 0)
994 && otyp
!= WAN_CANCELLATION
/* can't cancel cancellation */
995 && otyp
!= MAGIC_LAMP
/* cancelling doesn't remove djinni */
996 && otyp
!= CANDELABRUM_OF_INVOCATION
) {
997 costly_alteration(obj
, COST_CANCEL
);
998 obj
->spe
= (obj
->oclass
== WAND_CLASS
) ? -1 : 0;
1000 switch (obj
->oclass
) {
1002 costly_alteration(obj
, COST_CANCEL
);
1003 obj
->otyp
= SCR_BLANK_PAPER
;
1007 if (otyp
!= SPE_CANCELLATION
&& otyp
!= SPE_NOVEL
1008 && otyp
!= SPE_BOOK_OF_THE_DEAD
) {
1009 costly_alteration(obj
, COST_CANCEL
);
1010 obj
->otyp
= SPE_BLANK_PAPER
;
1014 costly_alteration(obj
,
1017 : obj
->cursed
? COST_UNCURS
: COST_UNBLSS
);
1018 if (otyp
== POT_SICKNESS
|| otyp
== POT_SEE_INVISIBLE
) {
1019 /* sickness is "biologically contaminated" fruit juice;
1020 cancel it and it just becomes fruit juice...
1021 whereas see invisible tastes like "enchanted" fruit
1022 juice, it similarly cancels */
1023 obj
->otyp
= POT_FRUIT_JUICE
;
1025 obj
->otyp
= POT_WATER
;
1026 obj
->odiluted
= 0; /* same as any other water */
1036 /* Remove a positive enchantment or charge from obj,
1037 * possibly carried by you or a monster
1041 register struct obj
*obj
;
1045 /* Is this a charged/enchanted object? */
1047 || (!objects
[obj
->otyp
].oc_charged
&& obj
->oclass
!= WEAPON_CLASS
1048 && obj
->oclass
!= ARMOR_CLASS
&& !is_weptool(obj
))
1051 if (defends(AD_DRLI
, obj
) || defends_when_carried(AD_DRLI
, obj
)
1052 || obj_resists(obj
, 10, 90))
1055 /* Charge for the cost of the object */
1056 costly_alteration(obj
, COST_DRAIN
);
1058 /* Drain the object and any implied effects */
1060 u_ring
= (obj
== uleft
) || (obj
== uright
);
1061 switch (obj
->otyp
) {
1062 case RIN_GAIN_STRENGTH
:
1063 if ((obj
->owornmask
& W_RING
) && u_ring
) {
1068 case RIN_GAIN_CONSTITUTION
:
1069 if ((obj
->owornmask
& W_RING
) && u_ring
) {
1075 if ((obj
->owornmask
& W_RING
) && u_ring
) {
1080 case RIN_INCREASE_ACCURACY
:
1081 if ((obj
->owornmask
& W_RING
) && u_ring
)
1084 case RIN_INCREASE_DAMAGE
:
1085 if ((obj
->owornmask
& W_RING
) && u_ring
)
1088 case HELM_OF_BRILLIANCE
:
1089 if ((obj
->owornmask
& W_ARMH
) && (obj
== uarmh
)) {
1095 case GAUNTLETS_OF_DEXTERITY
:
1096 if ((obj
->owornmask
& W_ARMG
) && (obj
== uarmg
)) {
1101 case RIN_PROTECTION
:
1111 obj_resists(obj
, ochance
, achance
)
1113 int ochance
, achance
; /* percent chance for ordinary objects, artifacts */
1115 if (obj
->otyp
== AMULET_OF_YENDOR
1116 || obj
->otyp
== SPE_BOOK_OF_THE_DEAD
1117 || obj
->otyp
== CANDELABRUM_OF_INVOCATION
1118 || obj
->otyp
== BELL_OF_OPENING
1119 || (obj
->otyp
== CORPSE
&& is_rider(&mons
[obj
->corpsenm
]))) {
1122 int chance
= rn2(100);
1124 return (boolean
) (chance
< (obj
->oartifact
? achance
: ochance
));
1134 if (context
.bypasses
&& obj
->bypass
)
1137 if (obj
->oclass
== WAND_CLASS
)
1138 zap_odds
= 3; /* half-life = 2 zaps */
1139 else if (obj
->cursed
)
1140 zap_odds
= 3; /* half-life = 2 zaps */
1141 else if (obj
->blessed
)
1142 zap_odds
= 12; /* half-life = 8 zaps */
1144 zap_odds
= 8; /* half-life = 6 zaps */
1146 /* adjust for "large" quantities of identical things */
1150 return (boolean
) !rn2(zap_odds
);
1153 /* Use up at least minwt number of things made of material mat.
1154 * There's also a chance that other stuff will be used up. Finally,
1155 * there's a random factor here to keep from always using the stuff
1156 * at the top of the pile.
1159 polyuse(objhdr
, mat
, minwt
)
1163 register struct obj
*otmp
, *otmp2
;
1165 for (otmp
= objhdr
; minwt
> 0 && otmp
; otmp
= otmp2
) {
1166 otmp2
= otmp
->nexthere
;
1167 if (context
.bypasses
&& otmp
->bypass
)
1169 if (otmp
== uball
|| otmp
== uchain
)
1171 if (obj_resists(otmp
, 0, 0))
1172 continue; /* preserve unique objects */
1174 if (otmp
->otyp
== SCR_MAIL
)
1178 if (((int) objects
[otmp
->otyp
].oc_material
== mat
)
1179 == (rn2(minwt
+ 1) != 0)) {
1180 /* appropriately add damage to bill */
1181 if (costly_spot(otmp
->ox
, otmp
->oy
)) {
1183 addtobill(otmp
, FALSE
, FALSE
, FALSE
);
1185 (void) stolen_value(otmp
, otmp
->ox
, otmp
->oy
, FALSE
,
1188 if (otmp
->quan
< LARGEST_INT
)
1189 minwt
-= (int) otmp
->quan
;
1198 * Polymorph some of the stuff in this pile into a monster, preferably
1199 * a golem of the kind okind.
1202 create_polymon(obj
, okind
)
1206 struct permonst
*mdat
= (struct permonst
*) 0;
1208 const char *material
;
1211 if (context
.bypasses
) {
1212 /* this is approximate because the "no golems" !obj->nexthere
1213 check below doesn't understand bypassed objects; but it
1214 should suffice since bypassed objects always end up as a
1215 consecutive group at the top of their pile */
1216 while (obj
&& obj
->bypass
)
1217 obj
= obj
->nexthere
;
1220 /* no golems if you zap only one object -- not enough stuff */
1221 if (!obj
|| (!obj
->nexthere
&& obj
->quan
== 1L))
1224 /* some of these choices are arbitrary */
1229 pm_index
= PM_IRON_GOLEM
;
1230 material
= "metal ";
1237 pm_index
= rn2(2) ? PM_STONE_GOLEM
: PM_CLAY_GOLEM
;
1238 material
= "lithic ";
1242 /* there is no flesh type, but all food is type 0, so we use it */
1243 pm_index
= PM_FLESH_GOLEM
;
1244 material
= "organic ";
1247 pm_index
= PM_WOOD_GOLEM
;
1251 pm_index
= PM_LEATHER_GOLEM
;
1252 material
= "leather ";
1255 pm_index
= PM_ROPE_GOLEM
;
1256 material
= "cloth ";
1259 pm_index
= PM_SKELETON
; /* nearest thing to "bone golem" */
1263 pm_index
= PM_GOLD_GOLEM
;
1267 pm_index
= PM_GLASS_GOLEM
;
1268 material
= "glassy ";
1271 pm_index
= PM_PAPER_GOLEM
;
1272 material
= "paper ";
1275 /* if all else fails... */
1276 pm_index
= PM_STRAW_GOLEM
;
1281 if (!(mvitals
[pm_index
].mvflags
& G_GENOD
))
1282 mdat
= &mons
[pm_index
];
1284 mtmp
= makemon(mdat
, obj
->ox
, obj
->oy
, NO_MM_FLAGS
);
1285 polyuse(obj
, okind
, (int) mons
[pm_index
].cwt
);
1287 if (mtmp
&& cansee(mtmp
->mx
, mtmp
->my
)) {
1288 pline("Some %sobjects meld, and %s arises from the pile!", material
,
1293 /* Assumes obj is on the floor. */
1301 if (obj
->otyp
== SCR_MAIL
)
1306 if (poly_zapped
< 0) {
1307 /* some may metamorphosize */
1308 for (i
= obj
->quan
; i
; i
--)
1309 if (!rn2(Luck
+ 45)) {
1310 poly_zapped
= objects
[obj
->otyp
].oc_material
;
1315 /* if quan > 1 then some will survive intact */
1316 if (obj
->quan
> 1L) {
1317 if (obj
->quan
> LARGEST_INT
)
1318 obj
= splitobj(obj
, (long) rnd(30000));
1320 obj
= splitobj(obj
, (long) rnd((int) obj
->quan
- 1));
1323 /* appropriately add damage to bill */
1324 if (costly_spot(obj
->ox
, obj
->oy
)) {
1326 addtobill(obj
, FALSE
, FALSE
, FALSE
);
1328 (void) stolen_value(obj
, obj
->ox
, obj
->oy
, FALSE
, FALSE
);
1331 /* zap the object */
1335 /* classes of items whose current charge count carries over across polymorph
1337 static const char charged_objs
[] = { WAND_CLASS
, WEAPON_CLASS
, ARMOR_CLASS
,
1341 * Polymorph the object to the given object ID. If the ID is STRANGE_OBJECT
1342 * then pick random object from the source's class (this is the standard
1343 * "polymorph" case). If ID is set to a specific object, inhibit fusing
1344 * n objects into 1. This could have been added as a flag, but currently
1345 * it is tied to not being the standard polymorph case. The new polymorphed
1346 * object replaces obj in its link chains. Return value is a pointer to
1349 * This should be safe to call for an object anywhere.
1358 boolean can_merge
= (id
== STRANGE_OBJECT
);
1359 int obj_location
= obj
->where
;
1361 if (obj
->otyp
== BOULDER
)
1363 if (id
== STRANGE_OBJECT
) { /* preserve symbol */
1365 unsigned magic_obj
= objects
[obj
->otyp
].oc_magic
;
1367 if (obj
->otyp
== UNICORN_HORN
&& obj
->degraded_horn
)
1369 /* Try up to 3 times to make the magic-or-not status of
1370 the new item be the same as it was for the old one. */
1371 otmp
= (struct obj
*) 0;
1375 otmp
= mkobj(obj
->oclass
, FALSE
);
1376 } while (--try_limit
> 0
1377 && objects
[otmp
->otyp
].oc_magic
!= magic_obj
);
1379 /* literally replace obj with this new thing */
1380 otmp
= mksobj(id
, FALSE
, FALSE
);
1381 /* Actually more things use corpsenm but they polymorph differently */
1382 #define USES_CORPSENM(typ) \
1383 ((typ) == CORPSE || (typ) == STATUE || (typ) == FIGURINE)
1385 if (USES_CORPSENM(obj
->otyp
) && USES_CORPSENM(id
))
1386 set_corpsenm(otmp
, obj
->corpsenm
);
1387 #undef USES_CORPSENM
1390 /* preserve quantity */
1391 otmp
->quan
= obj
->quan
;
1392 /* preserve the shopkeepers (lack of) interest */
1393 otmp
->no_charge
= obj
->no_charge
;
1394 /* preserve inventory letter if in inventory */
1395 if (obj_location
== OBJ_INVENT
)
1396 otmp
->invlet
= obj
->invlet
;
1398 /* You can't send yourself 100 mail messages and then
1399 * polymorph them into useful scrolls
1401 if (obj
->otyp
== SCR_MAIL
) {
1402 otmp
->otyp
= SCR_MAIL
;
1407 /* avoid abusing eggs laid by you */
1408 if (obj
->otyp
== EGG
&& obj
->spe
) {
1409 int mnum
, tryct
= 100;
1411 /* first, turn into a generic egg */
1412 if (otmp
->otyp
== EGG
)
1416 otmp
->owt
= weight(otmp
);
1418 otmp
->corpsenm
= NON_PM
;
1421 /* now change it into something laid by the hero */
1423 mnum
= can_be_hatched(random_monster());
1424 if (mnum
!= NON_PM
&& !dead_species(mnum
, TRUE
)) {
1425 otmp
->spe
= 1; /* laid by hero */
1426 set_corpsenm(otmp
, mnum
); /* also sets hatch timer */
1432 /* keep special fields (including charges on wands) */
1433 if (index(charged_objs
, otmp
->oclass
))
1434 otmp
->spe
= obj
->spe
;
1435 otmp
->recharged
= obj
->recharged
;
1437 otmp
->cursed
= obj
->cursed
;
1438 otmp
->blessed
= obj
->blessed
;
1440 if (erosion_matters(otmp
)) {
1441 if (is_flammable(otmp
) || is_rustprone(otmp
))
1442 otmp
->oeroded
= obj
->oeroded
;
1443 if (is_corrodeable(otmp
) || is_rottable(otmp
))
1444 otmp
->oeroded2
= obj
->oeroded2
;
1445 if (is_damageable(otmp
))
1446 otmp
->oerodeproof
= obj
->oerodeproof
;
1449 /* Keep chest/box traps and poisoned ammo if we may */
1450 if (obj
->otrapped
&& Is_box(otmp
))
1451 otmp
->otrapped
= TRUE
;
1453 if (obj
->opoisoned
&& is_poisonable(otmp
))
1454 otmp
->opoisoned
= TRUE
;
1456 if (id
== STRANGE_OBJECT
&& obj
->otyp
== CORPSE
) {
1457 /* turn crocodile corpses into shoes */
1458 if (obj
->corpsenm
== PM_CROCODILE
) {
1459 otmp
->otyp
= LOW_BOOTS
;
1460 otmp
->oclass
= ARMOR_CLASS
;
1463 otmp
->oerodeproof
= TRUE
;
1465 otmp
->cursed
= FALSE
;
1469 /* no box contents --KAA */
1470 if (Has_contents(otmp
))
1471 delete_contents(otmp
);
1473 /* 'n' merged objects may be fused into 1 object */
1474 if (otmp
->quan
> 1L && (!objects
[otmp
->otyp
].oc_merge
1475 || (can_merge
&& otmp
->quan
> (long) rn2(1000))))
1478 switch (otmp
->oclass
) {
1480 if (otmp
->otyp
== MAGIC_LAMP
) {
1481 otmp
->otyp
= OIL_LAMP
;
1482 otmp
->age
= 1500L; /* "best" oil lamp possible */
1483 } else if (otmp
->otyp
== MAGIC_MARKER
) {
1484 otmp
->recharged
= 1; /* degraded quality */
1486 /* don't care about the recharge count of other tools */
1490 while (otmp
->otyp
== WAN_WISHING
|| otmp
->otyp
== WAN_POLYMORPH
)
1491 otmp
->otyp
= rnd_class(WAN_LIGHT
, WAN_LIGHTNING
);
1492 /* altering the object tends to degrade its quality
1493 (analogous to spellbook `read count' handling) */
1494 if ((int) otmp
->recharged
< rn2(7)) /* recharge_limit */
1499 while (otmp
->otyp
== POT_POLYMORPH
)
1500 otmp
->otyp
= rnd_class(POT_GAIN_ABILITY
, POT_WATER
);
1504 while (otmp
->otyp
== SPE_POLYMORPH
)
1505 otmp
->otyp
= rnd_class(SPE_DIG
, SPE_BLANK_PAPER
);
1506 /* reduce spellbook abuse; non-blank books degrade */
1507 if (otmp
->otyp
!= SPE_BLANK_PAPER
) {
1508 otmp
->spestudied
= obj
->spestudied
+ 1;
1509 if (otmp
->spestudied
> MAX_SPELL_STUDY
) {
1510 otmp
->otyp
= SPE_BLANK_PAPER
;
1511 /* writing a new book over it will yield an unstudied
1512 one; re-polymorphing this one as-is may or may not
1513 get something non-blank */
1514 otmp
->spestudied
= rn2(otmp
->spestudied
);
1520 if (otmp
->quan
> (long) rnd(4)
1521 && objects
[obj
->otyp
].oc_material
== MINERAL
1522 && objects
[otmp
->otyp
].oc_material
!= MINERAL
) {
1523 otmp
->otyp
= ROCK
; /* transmutation backfired */
1524 otmp
->quan
/= 2L; /* some material has been lost */
1529 /* update the weight */
1530 otmp
->owt
= weight(otmp
);
1532 /* handle polymorph of worn item: stone-to-flesh cast on self can
1533 affect multiple objects at once, but their new forms won't
1534 produce any side-effects; a single worn item dipped into potion
1535 of polymorph can produce side-effects but those won't yield out
1536 of sequence messages because current polymorph is finished */
1537 if (obj_location
== OBJ_INVENT
&& obj
->owornmask
) {
1538 long old_wornmask
= obj
->owornmask
& ~(W_ART
| W_ARTI
),
1539 new_wornmask
= wearslot(otmp
);
1540 boolean was_twohanded
= bimanual(obj
), was_twoweap
= u
.twoweap
;
1542 remove_worn_item(obj
, TRUE
);
1543 /* if the new form can be worn in the same slot, make it so
1544 [possible extension: if it could be worn in some other
1545 slot which is currently unfilled, wear it there instead] */
1546 if ((old_wornmask
& W_QUIVER
) != 0L) {
1548 } else if ((old_wornmask
& W_SWAPWEP
) != 0L) {
1549 if (was_twohanded
|| !bimanual(otmp
))
1551 if (was_twoweap
&& uswapwep
)
1553 } else if ((old_wornmask
& W_WEP
) != 0L) {
1554 if (was_twohanded
|| !bimanual(otmp
) || !uarms
)
1556 if (was_twoweap
&& uwep
&& !bimanual(uwep
))
1558 } else if ((old_wornmask
& new_wornmask
) != 0L) {
1559 new_wornmask
&= old_wornmask
;
1560 setworn(otmp
, new_wornmask
);
1561 set_wear(otmp
); /* Armor_on() for side-effects */
1565 /* ** we are now done adjusting the object ** */
1567 /* swap otmp for obj */
1568 replace_object(obj
, otmp
);
1569 if (obj_location
== OBJ_INVENT
) {
1571 * We may need to do extra adjustments for the hero if we're
1572 * messing with the hero's inventory. The following calls are
1573 * equivalent to calling freeinv on obj and addinv on otmp,
1574 * while doing an in-place swap of the actual objects.
1579 } else if (obj_location
== OBJ_FLOOR
) {
1580 ox
= otmp
->ox
, oy
= otmp
->oy
; /* set by replace_object() */
1581 if (obj
->otyp
== BOULDER
&& otmp
->otyp
!= BOULDER
1582 && !does_block(ox
, oy
, &levl
[ox
][oy
]))
1583 unblock_point(ox
, oy
);
1584 else if (obj
->otyp
!= BOULDER
&& otmp
->otyp
== BOULDER
)
1585 /* (checking does_block() here would be redundant) */
1586 block_point(ox
, oy
);
1589 if ((!carried(otmp
) || obj
->unpaid
)
1590 && get_obj_location(otmp
, &ox
, &oy
, BURIED_TOO
| CONTAINED_TOO
)
1591 && costly_spot(ox
, oy
)) {
1592 register struct monst
*shkp
=
1593 shop_keeper(*in_rooms(ox
, oy
, SHOPBASE
));
1595 if ((!obj
->no_charge
1596 || (Has_contents(obj
)
1597 && (contained_cost(obj
, shkp
, 0L, FALSE
, FALSE
) != 0L)))
1598 && inhishop(shkp
)) {
1599 if (shkp
->mpeaceful
) {
1601 && *in_rooms(u
.ux
, u
.uy
, 0)
1602 == *in_rooms(shkp
->mx
, shkp
->my
, 0)
1603 && !costly_spot(u
.ux
, u
.uy
))
1604 make_angry_shk(shkp
, ox
, oy
);
1606 pline("%s gets angry!", Monnam(shkp
));
1610 Norep("%s is furious!", Monnam(shkp
));
1617 /* stone-to-flesh spell hits and maybe transforms or animates obj */
1619 stone_to_flesh_obj(obj
)
1622 int res
= 1; /* affected object by default */
1623 struct permonst
*ptr
;
1627 boolean smell
= FALSE
, golem_xform
= FALSE
;
1629 if (objects
[obj
->otyp
].oc_material
!= MINERAL
1630 && objects
[obj
->otyp
].oc_material
!= GEMSTONE
)
1632 /* Heart of Ahriman usually resists; ordinary items rarely do */
1633 if (obj_resists(obj
, 2, 98))
1636 (void) get_obj_location(obj
, &oox
, &ooy
, 0);
1637 /* add more if stone objects are added.. */
1638 switch (objects
[obj
->otyp
].oc_class
) {
1639 case ROCK_CLASS
: /* boulders and statues */
1640 case TOOL_CLASS
: /* figurines */
1641 if (obj
->otyp
== BOULDER
) {
1642 obj
= poly_obj(obj
, HUGE_CHUNK_OF_MEAT
);
1644 } else if (obj
->otyp
== STATUE
|| obj
->otyp
== FIGURINE
) {
1645 ptr
= &mons
[obj
->corpsenm
];
1646 if (is_golem(ptr
)) {
1647 golem_xform
= (ptr
!= &mons
[PM_FLESH_GOLEM
]);
1648 } else if (vegetarian(ptr
)) {
1649 /* Don't animate monsters that aren't flesh */
1650 obj
= poly_obj(obj
, MEATBALL
);
1654 if (obj
->otyp
== STATUE
) {
1655 /* animate_statue() forces all golems to become flesh golems
1657 mon
= animate_statue(obj
, oox
, ooy
, ANIMATE_SPELL
, (int *) 0);
1658 } else { /* (obj->otyp == FIGURINE) */
1660 ptr
= &mons
[PM_FLESH_GOLEM
];
1661 mon
= makemon(ptr
, oox
, ooy
, NO_MINVENT
);
1663 if (costly_spot(oox
, ooy
) && !obj
->no_charge
) {
1664 if (costly_spot(u
.ux
, u
.uy
))
1665 addtobill(obj
, carried(obj
), FALSE
, FALSE
);
1667 stolen_value(obj
, oox
, ooy
, TRUE
, FALSE
);
1670 obj_stop_timers(obj
);
1675 if (cansee(mon
->mx
, mon
->my
))
1676 pline_The("figurine %sanimates!",
1677 golem_xform
? "turns to flesh and " : "");
1682 /* this golem handling is redundant... */
1683 if (is_golem(ptr
) && ptr
!= &mons
[PM_FLESH_GOLEM
])
1684 (void) newcham(mon
, &mons
[PM_FLESH_GOLEM
], TRUE
, FALSE
);
1685 } else if ((ptr
->geno
& (G_NOCORPSE
| G_UNIQ
)) != 0) {
1686 /* didn't revive but can't leave corpse either */
1689 /* unlikely to get here since genociding monsters also
1690 sets the G_NOCORPSE flag; drop statue's contents */
1691 while ((item
= obj
->cobj
) != 0) {
1692 bypass_obj(item
); /* make stone-to-flesh miss it */
1693 obj_extract_self(item
);
1694 place_object(item
, oox
, ooy
);
1696 obj
= poly_obj(obj
, CORPSE
);
1698 } else { /* miscellaneous tool or unexpected rock... */
1702 /* maybe add weird things to become? */
1703 case RING_CLASS
: /* some of the rings are stone */
1704 obj
= poly_obj(obj
, MEAT_RING
);
1707 case WAND_CLASS
: /* marble wand */
1708 obj
= poly_obj(obj
, MEAT_STICK
);
1711 case GEM_CLASS
: /* stones & gems */
1712 obj
= poly_obj(obj
, MEATBALL
);
1715 case WEAPON_CLASS
: /* crysknife */
1723 /* non-meat eaters smell meat, meat eaters smell its flavor;
1724 monks are considered non-meat eaters regardless of behavior;
1725 other roles are non-meat eaters if they haven't broken
1726 vegetarian conduct yet (or if poly'd into non-carnivorous/
1727 non-omnivorous form, regardless of whether it's herbivorous,
1728 non-eating, or something stranger) */
1729 if (Role_if(PM_MONK
) || !u
.uconduct
.unvegetarian
1730 || !carnivorous(youmonst
.data
))
1731 Norep("You smell the odor of meat.");
1733 Norep("You smell a delicious smell.");
1740 * Object obj was hit by the effect of the wand/spell otmp. Return
1741 * non-zero if the wand/spell had any effect.
1745 struct obj
*obj
, *otmp
;
1747 int res
= 1; /* affected object by default */
1748 boolean learn_it
= FALSE
, maybelearnit
;
1750 /* fundamental: a wand effect hitting itself doesn't do anything;
1751 otherwise we need to guard against accessing otmp after something
1752 strange has happened to it (along the lines of polymorph or
1753 stone-to-flesh [which aren't good examples since polymorph wands
1754 aren't affected by polymorph zaps and stone-to-flesh isn't
1755 available in wand form, but the concept still applies...]) */
1760 /* The bypass bit is currently only used as follows:
1762 * POLYMORPH - When a monster being polymorphed drops something
1763 * from its inventory as a result of the change.
1764 * If the items fall to the floor, they are not
1765 * subject to direct subsequent polymorphing
1766 * themselves on that same zap. This makes it
1767 * consistent with items that remain in the
1768 * monster's inventory. They are not polymorphed
1770 * UNDEAD_TURNING - When an undead creature gets killed via
1771 * undead turning, prevent its corpse from being
1772 * immediately revived by the same effect.
1773 * STONE_TO_FLESH - If a statue can't be revived, its
1774 * contents get dropped before turning it into
1775 * meat; prevent those contents from being hit.
1776 * retouch_equipment() - bypass flag is used to track which
1777 * items have been handled (bhito isn't involved).
1778 * menu_drop(), askchain() - inventory traversal where multiple
1779 * Drop can alter the invent chain while traversal
1780 * is in progress (bhito isn't involved).
1782 * The bypass bit on all objects is reset each turn, whenever
1783 * context.bypasses is set.
1785 * We check the obj->bypass bit above AND context.bypasses
1786 * as a safeguard against any stray occurrence left in an obj
1787 * struct someplace, although that should never happen.
1789 if (context
.bypasses
) {
1792 debugpline1("%s for a moment.", Tobjnam(obj
, "pulsate"));
1798 * Some parts of this function expect the object to be on the floor
1799 * obj->{ox,oy} to be valid. The exception to this (so far) is
1800 * for the STONE_TO_FLESH spell.
1802 if (!(obj
->where
== OBJ_FLOOR
|| otmp
->otyp
== SPE_STONE_TO_FLESH
))
1803 impossible("bhito: obj is not floor or Stone To Flesh spell");
1807 } else if (obj
== uchain
) {
1808 if (otmp
->otyp
== WAN_OPENING
|| otmp
->otyp
== SPE_KNOCK
) {
1814 switch (otmp
->otyp
) {
1817 if (obj
->otyp
== WAN_POLYMORPH
|| obj
->otyp
== SPE_POLYMORPH
1818 || obj
->otyp
== POT_POLYMORPH
|| obj_resists(obj
, 5, 95)) {
1823 u
.uconduct
.polypiles
++;
1824 /* any saved lock context will be dangerously obsolete */
1826 (void) boxlock(obj
, otmp
);
1828 if (obj_shudders(obj
)) {
1830 ((obj
== level
.objects
[u
.ux
][u
.uy
]) && u
.uundetected
1831 && hides_under(youmonst
.data
));
1833 if (cansee(obj
->ox
, obj
->oy
))
1836 /* eek - your cover might have been blown */
1838 (void) hideunder(&youmonst
);
1841 obj
= poly_obj(obj
, STRANGE_OBJECT
);
1842 newsym(obj
->ox
, obj
->oy
);
1846 /* target object has now been "seen (up close)" */
1848 if (Is_container(obj
) || obj
->otyp
== STATUE
) {
1849 obj
->cknown
= obj
->lknown
= 1;
1851 boolean catbox
= SchroedingersBox(obj
);
1853 /* we don't want to force alive vs dead
1854 determination for Schroedinger's Cat here,
1855 so just make probing be inconclusive for it */
1858 pline("%s empty.", Tobjnam(obj
, catbox
? "seem" : "are"));
1861 /* view contents (not recursively) */
1862 for (o
= obj
->cobj
; o
; o
= o
->nobj
)
1863 o
->dknown
= 1; /* "seen", even if blind */
1864 (void) display_cinventory(obj
);
1872 case SPE_FORCE_BOLT
:
1873 /* learn the type if you see or hear something break
1874 (the sound could be implicit) */
1875 maybelearnit
= cansee(obj
->ox
, obj
->oy
) || !Deaf
;
1876 if (obj
->otyp
== BOULDER
) {
1877 if (cansee(obj
->ox
, obj
->oy
))
1878 pline_The("boulder falls apart.");
1880 You_hear("a crumbling sound.");
1882 } else if (obj
->otyp
== STATUE
) {
1883 if (break_statue(obj
)) {
1884 if (cansee(obj
->ox
, obj
->oy
)) {
1886 pline_The("%s shatters.", rndmonnam(NULL
));
1888 pline_The("statue shatters.");
1890 You_hear("a crumbling sound.");
1895 if (context
.mon_moving
1896 ? !breaks(obj
, obj
->ox
, obj
->oy
)
1897 : !hero_breaks(obj
, obj
->ox
, obj
->oy
, FALSE
))
1898 maybelearnit
= FALSE
; /* nothing broke */
1900 newsym_force(oox
,ooy
);
1906 case WAN_CANCELLATION
:
1907 case SPE_CANCELLATION
:
1910 newsym(obj
->ox
, obj
->oy
); /* might change color */
1913 case SPE_DRAIN_LIFE
:
1914 (void) drain_item(obj
);
1916 case WAN_TELEPORTATION
:
1917 case SPE_TELEPORT_AWAY
:
1920 case WAN_MAKE_INVISIBLE
:
1922 case WAN_UNDEAD_TURNING
:
1923 case SPE_TURN_UNDEAD
:
1924 if (obj
->otyp
== EGG
) {
1926 } else if (obj
->otyp
== CORPSE
) {
1927 int corpsenm
= corpse_revive_type(obj
);
1929 res
= !!revive(obj
, TRUE
);
1930 if (res
&& Role_if(PM_HEALER
)) {
1931 if (Hallucination
&& !Deaf
) {
1932 You_hear("the sound of a defibrillator.");
1934 } else if (!Blind
) {
1935 You("observe %s %s change dramatically.",
1936 s_suffix(an(mons
[corpsenm
].mname
)),
1937 nonliving(&mons
[corpsenm
]) ? "motility"
1942 exercise(A_WIS
, TRUE
);
1949 case SPE_WIZARD_LOCK
:
1951 res
= boxlock(obj
, otmp
);
1957 case WAN_SLOW_MONSTER
: /* no effect on objects */
1958 case SPE_SLOW_MONSTER
:
1959 case WAN_SPEED_MONSTER
:
1962 case SPE_EXTRA_HEALING
:
1965 case SPE_STONE_TO_FLESH
:
1966 res
= stone_to_flesh_obj(obj
);
1969 impossible("What an interesting effect (%d)", otmp
->otyp
);
1972 /* if effect was observable then discover the wand type provided
1973 that the wand itself has been seen */
1979 /* returns nonzero if something was hit */
1981 bhitpile(obj
, fhito
, tx
, ty
, zz
)
1983 int FDECL((*fhito
), (OBJ_P
, OBJ_P
));
1987 int hitanything
= 0;
1988 register struct obj
*otmp
, *next_obj
;
1990 if (obj
->otyp
== SPE_FORCE_BOLT
|| obj
->otyp
== WAN_STRIKING
) {
1991 struct trap
*t
= t_at(tx
, ty
);
1993 /* We can't settle for the default calling sequence of
1994 bhito(otmp) -> break_statue(otmp) -> activate_statue_trap(ox,oy)
1995 because that last call might end up operating on our `next_obj'
1996 (below), rather than on the current object, if it happens to
1997 encounter a statue which mustn't become animated. */
1998 if (t
&& t
->ttyp
== STATUE_TRAP
1999 && activate_statue_trap(t
, tx
, ty
, TRUE
))
2004 for (otmp
= level
.objects
[tx
][ty
]; otmp
; otmp
= next_obj
) {
2005 next_obj
= otmp
->nexthere
;
2006 /* for zap downwards, don't hit object poly'd hero is hiding under */
2007 if (zz
> 0 && u
.uundetected
&& otmp
== level
.objects
[u
.ux
][u
.uy
]
2008 && hides_under(youmonst
.data
))
2011 hitanything
+= (*fhito
)(otmp
, obj
);
2013 if (poly_zapped
>= 0)
2014 create_polymon(level
.objects
[tx
][ty
], poly_zapped
);
2020 * zappable - returns 1 if zap is available, 0 otherwise.
2021 * it removes a charge from the wand if zappable.
2022 * added by GAN 11/03/86
2026 register struct obj
*wand
;
2028 if (wand
->spe
< 0 || (wand
->spe
== 0 && rn2(121)))
2031 You("wrest one last charge from the worn-out wand.");
2037 * zapnodir - zaps a NODIR wand/spell.
2038 * added by GAN 11/03/86
2042 register struct obj
*obj
;
2044 boolean known
= FALSE
;
2046 switch (obj
->otyp
) {
2052 if (lightdamage(obj
, TRUE
, 5))
2055 case WAN_SECRET_DOOR_DETECTION
:
2056 case SPE_DETECT_UNSEEN
:
2062 case WAN_CREATE_MONSTER
:
2063 known
= create_critters(rn2(23) ? 1 : rn1(7, 2),
2064 (struct permonst
*) 0, FALSE
);
2068 if (Luck
+ rn2(5) < 0) {
2069 pline("Unfortunately, nothing happens.");
2074 case WAN_ENLIGHTENMENT
:
2076 You_feel("self-knowledgeable...");
2077 display_nhwindow(WIN_MESSAGE
, FALSE
);
2078 enlightenment(MAGICENLIGHTENMENT
, ENL_GAMEINPROGRESS
);
2079 pline_The("feeling subsides.");
2080 exercise(A_WIS
, TRUE
);
2084 if (!objects
[obj
->otyp
].oc_name_known
)
2085 more_experienced(0, 10);
2086 /* effect was observable; discover the wand type provided
2087 that the wand itself has been seen */
2097 otmp
->in_use
= TRUE
; /* in case losehp() is fatal */
2098 pline("%s suddenly explodes!", The(xname(otmp
)));
2099 dmg
= d(otmp
->spe
+ 2, 6);
2100 losehp(Maybe_Half_Phys(dmg
), "exploding wand", KILLED_BY_AN
);
2104 static NEARDATA
const char zap_syms
[] = { WAND_CLASS
, 0 };
2106 /* 'z' command (or 'y' if numbed_pad==-1) */
2110 register struct obj
*obj
;
2113 if (check_capacity((char *) 0))
2115 obj
= getobj(zap_syms
, "zap");
2121 /* zappable addition done by GAN 11/03/86 */
2123 pline1(nothing_happens
);
2124 else if (obj
->cursed
&& !rn2(WAND_BACKFIRE_CHANCE
)) {
2125 backfire(obj
); /* the wand blows up in your face! */
2126 exercise(A_STR
, FALSE
);
2128 } else if (!(objects
[obj
->otyp
].oc_dir
== NODIR
) && !getdir((char *) 0)) {
2130 pline("%s glows and fades.", The(xname(obj
)));
2131 /* make him pay for knowing !NODIR */
2132 } else if (!u
.dx
&& !u
.dy
&& !u
.dz
2133 && !(objects
[obj
->otyp
].oc_dir
== NODIR
)) {
2134 if ((damage
= zapyourself(obj
, TRUE
)) != 0) {
2137 Sprintf(buf
, "zapped %sself with a wand", uhim());
2138 losehp(Maybe_Half_Phys(damage
), buf
, NO_KILLER_PREFIX
);
2141 /* Are we having fun yet?
2142 * weffects -> buzz(obj->otyp) -> zhitm (temple priest) ->
2143 * attack -> hitum -> known_hitum -> ghod_hitsu ->
2144 * buzz(AD_ELEC) -> destroy_item(WAND_CLASS) ->
2145 * useup -> obfree -> dealloc_obj -> free(obj)
2152 if (obj
&& obj
->spe
< 0) {
2153 pline("%s to dust.", Tobjnam(obj
, "turn"));
2156 update_inventory(); /* maybe used a charge */
2161 zapyourself(obj
, ordinary
)
2165 boolean learn_it
= FALSE
;
2168 switch (obj
->otyp
) {
2170 case SPE_FORCE_BOLT
:
2173 shieldeff(u
.ux
, u
.uy
);
2177 You("bash yourself!");
2180 damage
= d(1 + obj
->spe
, 6);
2181 exercise(A_STR
, FALSE
);
2187 if (!Shock_resistance
) {
2188 You("shock yourself!");
2190 exercise(A_CON
, FALSE
);
2192 shieldeff(u
.ux
, u
.uy
);
2193 You("zap yourself, but seem unharmed.");
2194 ugolemeffects(AD_ELEC
, d(12, 6));
2196 destroy_item(WAND_CLASS
, AD_ELEC
);
2197 destroy_item(RING_CLASS
, AD_ELEC
);
2198 (void) flashburn((long) rnd(100));
2202 You("explode a fireball on top of yourself!");
2203 explode(u
.ux
, u
.uy
, 11, d(6, 6), WAND_CLASS
, EXPL_FIERY
);
2208 if (Fire_resistance
) {
2209 shieldeff(u
.ux
, u
.uy
);
2210 You_feel("rather warm.");
2211 ugolemeffects(AD_FIRE
, d(12, 6));
2213 pline("You've set yourself afire!");
2217 (void) burnarmor(&youmonst
);
2218 destroy_item(SCROLL_CLASS
, AD_FIRE
);
2219 destroy_item(POTION_CLASS
, AD_FIRE
);
2220 destroy_item(SPBOOK_CLASS
, AD_FIRE
);
2221 destroy_item(FOOD_CLASS
, AD_FIRE
); /* only slime for now */
2225 case SPE_CONE_OF_COLD
:
2228 if (Cold_resistance
) {
2229 shieldeff(u
.ux
, u
.uy
);
2230 You_feel("a little chill.");
2231 ugolemeffects(AD_COLD
, d(12, 6));
2233 You("imitate a popsicle!");
2236 destroy_item(POTION_CLASS
, AD_COLD
);
2239 case WAN_MAGIC_MISSILE
:
2240 case SPE_MAGIC_MISSILE
:
2243 shieldeff(u
.ux
, u
.uy
);
2244 pline_The("missiles bounce!");
2247 pline("Idiot! You've shot yourself!");
2259 case WAN_CANCELLATION
:
2260 case SPE_CANCELLATION
:
2261 (void) cancel_monst(&youmonst
, obj
, TRUE
, FALSE
, TRUE
);
2264 case SPE_DRAIN_LIFE
:
2265 if (!Drain_resistance
) {
2266 learn_it
= TRUE
; /* (no effect for spells...) */
2267 losexp("life drainage");
2269 damage
= 0; /* No additional damage */
2272 case WAN_MAKE_INVISIBLE
: {
2273 /* have to test before changing HInvis but must change
2274 * HInvis before doing newsym().
2276 int msg
= !Invis
&& !Blind
&& !BInvis
;
2278 if (BInvis
&& uarmc
->otyp
== MUMMY_WRAPPING
) {
2279 /* A mummy wrapping absorbs it and protects you */
2280 You_feel("rather itchy under %s.", yname(uarmc
));
2283 if (ordinary
|| !rn2(10)) { /* permanent */
2284 HInvis
|= FROMOUTSIDE
;
2285 } else { /* temporary */
2286 incr_itimeout(&HInvis
, d(obj
->spe
, 250));
2291 self_invis_message();
2296 case WAN_SPEED_MONSTER
:
2297 if (!(HFast
& INTRINSIC
)) {
2302 Your("quickness feels more natural.");
2303 exercise(A_DEX
, TRUE
);
2305 HFast
|= FROMOUTSIDE
;
2311 if (Sleep_resistance
) {
2312 shieldeff(u
.ux
, u
.uy
);
2313 You("don't feel sleepy!");
2315 pline_The("sleep ray hits you!");
2316 fall_asleep(-rnd(50), TRUE
);
2320 case WAN_SLOW_MONSTER
:
2321 case SPE_SLOW_MONSTER
:
2322 if (HFast
& (TIMEOUT
| INTRINSIC
)) {
2328 case WAN_TELEPORTATION
:
2329 case SPE_TELEPORT_AWAY
:
2331 /* same criteria as when mounted (zap_steed) */
2332 if ((Teleport_control
&& !Stunned
) || !couldsee(u
.ux0
, u
.uy0
)
2333 || distu(u
.ux0
, u
.uy0
) >= 16)
2338 case SPE_FINGER_OF_DEATH
:
2339 if (nonliving(youmonst
.data
) || is_demon(youmonst
.data
)) {
2340 pline((obj
->otyp
== WAN_DEATH
)
2341 ? "The wand shoots an apparently harmless beam at you."
2342 : "You seem no deader than before.");
2346 Sprintf(killer
.name
, "shot %sself with a death ray", uhim());
2347 killer
.format
= NO_KILLER_PREFIX
;
2348 You("irradiate yourself with pure energy!");
2350 /* They might survive with an amulet of life saving */
2353 case WAN_UNDEAD_TURNING
:
2354 case SPE_TURN_UNDEAD
:
2356 (void) unturn_dead(&youmonst
);
2357 if (is_undead(youmonst
.data
)) {
2358 You_feel("frightened and %sstunned.",
2359 Stunned
? "even more " : "");
2360 make_stunned((HStun
& TIMEOUT
) + (long) rnd(30), FALSE
);
2362 You("shudder in dread.");
2365 case SPE_EXTRA_HEALING
:
2366 learn_it
= TRUE
; /* (no effect for spells...) */
2367 healup(d(6, obj
->otyp
== SPE_EXTRA_HEALING
? 8 : 4), 0, FALSE
,
2368 (obj
->otyp
== SPE_EXTRA_HEALING
));
2369 You_feel("%sbetter.", obj
->otyp
== SPE_EXTRA_HEALING
? "much " : "");
2371 case WAN_LIGHT
: /* (broken wand) */
2372 /* assert( !ordinary ); */
2373 damage
= d(obj
->spe
, 25);
2374 case EXPENSIVE_CAMERA
:
2377 damage
= lightdamage(obj
, ordinary
, damage
);
2379 if (flashburn((long) damage
))
2381 damage
= 0; /* reset */
2389 if (u
.utrap
) { /* escape web or bear trap */
2390 (void) openholdingtrap(&youmonst
, &learn_it
);
2393 /* unlock carried boxes */
2394 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
2396 (void) boxlock(otmp
, obj
);
2397 /* trigger previously escaped trapdoor */
2398 (void) openfallingtrap(&youmonst
, TRUE
, &learn_it
);
2402 case SPE_WIZARD_LOCK
:
2404 (void) closeholdingtrap(&youmonst
, &learn_it
);
2409 case SPE_DETECT_UNSEEN
:
2415 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
) {
2417 if (Is_container(otmp
) || otmp
->otyp
== STATUE
) {
2419 if (!SchroedingersBox(otmp
))
2427 case SPE_STONE_TO_FLESH
: {
2428 struct obj
*otmp
, *onxt
;
2431 if (u
.umonnum
== PM_STONE_GOLEM
) {
2433 (void) polymon(PM_FLESH_GOLEM
);
2437 fix_petrification(); /* saved! */
2439 /* but at a cost.. */
2440 for (otmp
= invent
; otmp
; otmp
= onxt
) {
2442 if (bhito(otmp
, obj
))
2446 * It is possible that we can now merge some inventory.
2447 * Do a highly paranoid merge. Restart from the beginning
2452 for (otmp
= invent
; !didmerge
&& otmp
; otmp
= otmp
->nobj
)
2453 for (onxt
= otmp
->nobj
; onxt
; onxt
= onxt
->nobj
)
2454 if (merged(&otmp
, &onxt
)) {
2462 impossible("zapyourself: object %d used?", obj
->otyp
);
2465 /* if effect was observable then discover the wand type provided
2466 that the wand itself has been seen */
2472 /* called when poly'd hero uses breath attack against self */
2475 struct attack
*mattk
;
2477 int dtyp
= 20 + mattk
->adtyp
- 1; /* breath by hero */
2478 const char *fltxt
= flash_types
[dtyp
]; /* blast of <something> */
2480 zhitu(dtyp
, mattk
->damn
, fltxt
, u
.ux
, u
.uy
);
2483 /* light damages hero in gremlin form */
2485 lightdamage(obj
, ordinary
, amt
)
2486 struct obj
*obj
; /* item making light (fake book if spell) */
2487 boolean ordinary
; /* wand/camera zap vs wand destruction */
2488 int amt
; /* pseudo-damage used to determine blindness duration */
2494 if (dmg
&& youmonst
.data
== &mons
[PM_GREMLIN
]) {
2495 /* reduce high values (from destruction of wand with many charges) */
2498 dmg
= 10 + rnd(dmg
- 10);
2501 pline("Ow, that light hurts%c", (dmg
> 2 || u
.mh
<= 5) ? '!' : '.');
2502 /* [composing killer/reason is superfluous here; if fatal, cause
2503 of death will always be "killed while stuck in creature form"] */
2504 if (obj
->oclass
== SCROLL_CLASS
|| obj
->oclass
== SPBOOK_CLASS
)
2505 ordinary
= FALSE
; /* say blasted rather than zapped */
2506 how
= (obj
->oclass
!= SPBOOK_CLASS
)
2507 ? (const char *) ansimpleoname(obj
)
2509 Sprintf(buf
, "%s %sself with %s", ordinary
? "zapped" : "blasted",
2511 /* might rehumanize(); could be fatal, but only for Unchanging */
2512 losehp(Maybe_Half_Phys(dmg
), buf
, NO_KILLER_PREFIX
);
2517 /* light[ning] causes blindness */
2522 if (!resists_blnd(&youmonst
)) {
2523 You(are_blinded_by_the_flash
);
2524 make_blinded(duration
, FALSE
);
2526 Your1(vision_clears
);
2532 /* you've zapped a wand downwards while riding
2533 * Return TRUE if the steed was hit by the wand.
2534 * Return FALSE if the steed was not hit by the wand.
2538 struct obj
*obj
; /* wand or spell */
2540 int steedhit
= FALSE
;
2542 bhitpos
.x
= u
.usteed
->mx
, bhitpos
.y
= u
.usteed
->my
;
2544 switch (obj
->otyp
) {
2546 * Wands that are allowed to hit the steed
2547 * Carefully test the results of any that are
2548 * moved here from the bottom section.
2551 probe_monster(u
.usteed
);
2555 case WAN_TELEPORTATION
:
2556 case SPE_TELEPORT_AWAY
:
2557 /* you go together */
2559 /* same criteria as when unmounted (zapyourself) */
2560 if ((Teleport_control
&& !Stunned
) || !couldsee(u
.ux0
, u
.uy0
)
2561 || distu(u
.ux0
, u
.uy0
) >= 16)
2566 /* Default processing via bhitm() for these */
2567 case SPE_CURE_SICKNESS
:
2568 case WAN_MAKE_INVISIBLE
:
2569 case WAN_CANCELLATION
:
2570 case SPE_CANCELLATION
:
2574 case SPE_FORCE_BOLT
:
2575 case WAN_SLOW_MONSTER
:
2576 case SPE_SLOW_MONSTER
:
2577 case WAN_SPEED_MONSTER
:
2579 case SPE_EXTRA_HEALING
:
2580 case SPE_DRAIN_LIFE
:
2583 (void) bhitm(u
.usteed
, obj
);
2595 * cancel a monster (possibly the hero). inventory is cancelled only
2596 * if the monster is zapping itself directly, since otherwise the
2597 * effect is too strong. currently non-hero monsters do not zap
2598 * themselves with cancellation.
2601 cancel_monst(mdef
, obj
, youattack
, allow_cancel_kill
, self_cancel
)
2602 register struct monst
*mdef
;
2603 register struct obj
*obj
;
2604 boolean youattack
, allow_cancel_kill
, self_cancel
;
2606 boolean youdefend
= (mdef
== &youmonst
);
2607 static const char writing_vanishes
[] =
2608 "Some writing vanishes from %s head!";
2609 static const char your
[] = "your"; /* should be extern */
2611 if (youdefend
? (!youattack
&& Antimagic
)
2612 : resist(mdef
, obj
->oclass
, 0, NOTELL
))
2613 return FALSE
; /* resisted cancellation */
2615 if (self_cancel
) { /* 1st cancel inventory */
2618 for (otmp
= (youdefend
? invent
: mdef
->minvent
); otmp
;
2622 context
.botl
= 1; /* potential AC change */
2627 /* now handle special cases */
2630 if ((u
.umonnum
== PM_CLAY_GOLEM
) && !Blind
)
2631 pline(writing_vanishes
, your
);
2634 Your("amulet grows hot for a moment, then cools.");
2641 if (is_were(mdef
->data
) && mdef
->data
->mlet
!= S_HUMAN
)
2644 if (mdef
->data
== &mons
[PM_CLAY_GOLEM
]) {
2645 if (canseemon(mdef
))
2646 pline(writing_vanishes
, s_suffix(mon_nam(mdef
)));
2648 if (allow_cancel_kill
) {
2652 monkilled(mdef
, "", AD_SPEL
);
2659 /* you've zapped an immediate type wand up or down */
2662 struct obj
*obj
; /* wand or spell */
2664 boolean striking
= FALSE
, disclose
= FALSE
;
2665 int x
, y
, xx
, yy
, ptmp
;
2671 /* some wands have special effects other than normal bhitpile */
2672 /* drawbridge might change <u.ux,u.uy> */
2673 x
= xx
= u
.ux
; /* <x,y> is zap location */
2674 y
= yy
= u
.uy
; /* <xx,yy> is drawbridge (portcullis) position */
2675 ttmp
= t_at(x
, y
); /* trap if there is one */
2677 switch (obj
->otyp
) {
2681 You("probe towards the %s.", ceiling(x
, y
));
2683 ptmp
+= bhitpile(obj
, bhito
, x
, y
, u
.dz
);
2684 You("probe beneath the %s.", surface(x
, y
));
2685 ptmp
+= display_binventory(x
, y
, TRUE
);
2688 Your("probe reveals nothing.");
2689 return TRUE
; /* we've done our own bhitpile */
2692 /* up or down, but at closed portcullis only */
2693 if (is_db_wall(x
, y
) && find_drawbridge(&xx
, &yy
)) {
2694 open_drawbridge(xx
, yy
);
2696 } else if (u
.dz
> 0 && (x
== xdnstair
&& y
== ydnstair
) &&
2697 /* can't use the stairs down to quest level 2 until
2698 leader "unlocks" them; give feedback if you try */
2699 on_level(&u
.uz
, &qstart_level
) && !ok_to_quest()) {
2700 pline_The("stairs seem to ripple momentarily.");
2703 /* down will release you from bear trap or web */
2704 if (u
.dz
> 0 && u
.utrap
) {
2705 (void) openholdingtrap(&youmonst
, &disclose
);
2706 /* down will trigger trapdoor, hole, or [spiked-] pit */
2707 } else if (u
.dz
> 0 && !u
.utrap
) {
2708 (void) openfallingtrap(&youmonst
, FALSE
, &disclose
);
2712 case SPE_FORCE_BOLT
:
2716 case SPE_WIZARD_LOCK
:
2717 /* down at open bridge or up or down at open portcullis */
2718 if (((levl
[x
][y
].typ
== DRAWBRIDGE_DOWN
)
2720 : (is_drawbridge_wall(x
, y
) >= 0 && !is_db_wall(x
, y
)))
2721 && find_drawbridge(&xx
, &yy
)) {
2723 close_drawbridge(xx
, yy
);
2725 destroy_drawbridge(xx
, yy
);
2727 } else if (striking
&& u
.dz
< 0 && rn2(3) && !Is_airlevel(&u
.uz
)
2728 && !Is_waterlevel(&u
.uz
) && !Underwater
2729 && !Is_qstart(&u
.uz
)) {
2731 /* similar to zap_dig() */
2732 pline("A rock is dislodged from the %s and falls on your %s.",
2733 ceiling(x
, y
), body_part(HEAD
));
2734 dmg
= rnd((uarmh
&& is_metallic(uarmh
)) ? 2 : 6);
2735 losehp(Maybe_Half_Phys(dmg
), "falling rock", KILLED_BY_AN
);
2736 if ((otmp
= mksobj_at(ROCK
, x
, y
, FALSE
, FALSE
)) != 0) {
2737 (void) xname(otmp
); /* set dknown, maybe bknown */
2741 } else if (u
.dz
> 0 && ttmp
) {
2742 if (!striking
&& closeholdingtrap(&youmonst
, &disclose
)) {
2743 ; /* now stuck in web or bear trap */
2744 } else if (striking
&& ttmp
->ttyp
== TRAPDOOR
) {
2745 /* striking transforms trapdoor into hole */
2746 if (Blind
&& !ttmp
->tseen
) {
2747 pline("%s beneath you shatters.", Something
);
2748 } else if (!ttmp
->tseen
) { /* => !Blind */
2749 pline("There's a trapdoor beneath you; it shatters.");
2751 pline("The trapdoor beneath you shatters.");
2757 /* might fall down hole */
2759 } else if (!striking
&& ttmp
->ttyp
== HOLE
) {
2760 /* locking transforms hole into trapdoor */
2761 ttmp
->ttyp
= TRAPDOOR
;
2762 if (Blind
|| !ttmp
->tseen
) {
2763 pline("Some %s swirls beneath you.",
2764 is_ice(x
, y
) ? "frost" : "dust");
2768 pline("A trapdoor appears beneath you.");
2771 /* hadn't fallen down hole; won't fall now */
2775 case SPE_STONE_TO_FLESH
:
2776 if (Is_airlevel(&u
.uz
) || Is_waterlevel(&u
.uz
) || Underwater
2777 || (Is_qstart(&u
.uz
) && u
.dz
< 0)) {
2778 pline1(nothing_happens
);
2779 } else if (u
.dz
< 0) { /* we should do more... */
2780 pline("Blood drips on your %s.", body_part(FACE
));
2781 } else if (u
.dz
> 0 && !OBJ_AT(u
.ux
, u
.uy
)) {
2783 Print this message only if there wasn't an engraving
2784 affected here. If water or ice, act like waterlevel case.
2786 e
= engr_at(u
.ux
, u
.uy
);
2787 if (!(e
&& e
->engr_type
== ENGRAVE
)) {
2788 if (is_pool(u
.ux
, u
.uy
) || is_ice(u
.ux
, u
.uy
))
2789 pline1(nothing_happens
);
2791 pline("Blood %ss %s your %s.",
2792 is_lava(u
.ux
, u
.uy
) ? "boil" : "pool",
2793 Levitation
? "beneath" : "at",
2794 makeplural(body_part(FOOT
)));
2803 /* zapping downward */
2804 (void) bhitpile(obj
, bhito
, x
, y
, u
.dz
);
2806 /* subset of engraving effects; none sets `disclose' */
2807 if ((e
= engr_at(x
, y
)) != 0 && e
->engr_type
!= HEADSTONE
) {
2808 switch (obj
->otyp
) {
2812 make_engr_at(x
, y
, random_engraving(buf
), moves
, (xchar
) 0);
2814 case WAN_CANCELLATION
:
2815 case SPE_CANCELLATION
:
2816 case WAN_MAKE_INVISIBLE
:
2819 case WAN_TELEPORTATION
:
2820 case SPE_TELEPORT_AWAY
:
2823 case SPE_STONE_TO_FLESH
:
2824 if (e
->engr_type
== ENGRAVE
) {
2825 /* only affects things in stone */
2826 pline_The(Hallucination
2827 ? "floor runs like butter!"
2828 : "edges on the floor get smoother.");
2829 wipe_engr_at(x
, y
, d(2, 4), TRUE
);
2833 case SPE_FORCE_BOLT
:
2834 wipe_engr_at(x
, y
, d(2, 4), TRUE
);
2840 } else if (u
.dz
< 0) {
2841 /* zapping upward */
2843 /* game flavor: if you're hiding under "something"
2844 * a zap upward should hit that "something".
2846 if (u
.uundetected
&& hides_under(youmonst
.data
)) {
2848 otmp
= level
.objects
[u
.ux
][u
.uy
];
2851 hitit
= bhito(otmp
, obj
);
2853 (void) hideunder(&youmonst
);
2862 /* used by do_break_wand() was well as by weffects() */
2872 /* if do_osshock() set obj_zapped while polying, give a message now */
2874 You_feel("shuddering vibrations.");
2878 /* called for various wand and spell effects - M. Stephenson */
2883 int otyp
= obj
->otyp
;
2884 boolean disclose
= FALSE
, was_unkn
= !objects
[otyp
].oc_name_known
;
2886 exercise(A_WIS
, TRUE
);
2887 if (u
.usteed
&& (objects
[otyp
].oc_dir
!= NODIR
) && !u
.dx
&& !u
.dy
2888 && (u
.dz
> 0) && zap_steed(obj
)) {
2890 } else if (objects
[otyp
].oc_dir
== IMMEDIATE
) {
2891 zapsetup(); /* reset obj_zapped */
2893 (void) bhitm(u
.ustuck
, obj
);
2894 /* [how about `bhitpile(u.ustuck->minvent)' effect?] */
2896 disclose
= zap_updown(obj
);
2898 (void) bhit(u
.dx
, u
.dy
, rn1(8, 6), ZAPPED_WAND
, bhitm
, bhito
,
2901 zapwrapup(); /* give feedback for obj_zapped */
2903 } else if (objects
[otyp
].oc_dir
== NODIR
) {
2907 /* neither immediate nor directionless */
2909 if (otyp
== WAN_DIGGING
|| otyp
== SPE_DIG
)
2911 else if (otyp
>= SPE_MAGIC_MISSILE
&& otyp
<= SPE_FINGER_OF_DEATH
)
2912 buzz(otyp
- SPE_MAGIC_MISSILE
+ 10, u
.ulevel
/ 2 + 1, u
.ux
, u
.uy
,
2914 else if (otyp
>= WAN_MAGIC_MISSILE
&& otyp
<= WAN_LIGHTNING
)
2915 buzz(otyp
- WAN_MAGIC_MISSILE
,
2916 (otyp
== WAN_MAGIC_MISSILE
) ? 2 : 6, u
.ux
, u
.uy
, u
.dx
, u
.dy
);
2918 impossible("weffects: unexpected spell or wand");
2924 more_experienced(0, 10);
2929 /* augment damage for a spell dased on the hero's intelligence (and level) */
2931 spell_damage_bonus(dmg
)
2932 int dmg
; /* base amount to be adjusted by bonus or penalty */
2934 int intell
= ACURR(A_INT
);
2936 /* Punish low intelligence before low level else low intelligence
2937 gets punished only when high level */
2939 /* -3 penalty, but never reduce combined amount below 1
2940 (if dmg is 0 for some reason, we're careful to leave it there) */
2942 dmg
= (dmg
<= 3) ? 1 : dmg
- 3;
2943 } else if (intell
<= 13 || u
.ulevel
< 5)
2944 ; /* no bonus or penalty; dmg remains same */
2945 else if (intell
<= 18)
2947 else if (intell
<= 24 || u
.ulevel
< 14)
2950 dmg
+= 3; /* Int 25 */
2956 * Generate the to hit bonus for a spell. Based on the hero's skill in
2957 * spell class and dexterity.
2960 spell_hit_bonus(skill
)
2964 int dex
= ACURR(A_DEX
);
2966 switch (P_SKILL(spell_skilltype(skill
))) {
2967 case P_ISRESTRICTED
:
2989 /* Will change when print stuff below removed */
2992 /* Even increment for dextrous heroes (see weapon.c abon) */
2993 hit_bon
+= dex
- 14;
3002 /* force == 0 occurs e.g. with sleep ray */
3003 /* note that large force is usual with wands so that !! would
3004 require information about hand/weapon/wand */
3005 return (const char *) ((force
< 0) ? "?" : (force
<= 4) ? "." : "!");
3009 hit(str
, mtmp
, force
)
3012 const char *force
; /* usually either "." or "!" */
3014 if ((!cansee(bhitpos
.x
, bhitpos
.y
) && !canspotmon(mtmp
)
3015 && !(u
.uswallow
&& mtmp
== u
.ustuck
)) || !flags
.verbose
)
3016 pline("%s %s it.", The(str
), vtense(str
, "hit"));
3018 pline("%s %s %s%s", The(str
), vtense(str
, "hit"),
3019 mon_nam(mtmp
), force
);
3024 register const char *str
;
3025 register struct monst
*mtmp
;
3028 "%s %s %s.", The(str
), vtense(str
, "miss"),
3029 ((cansee(bhitpos
.x
, bhitpos
.y
) || canspotmon(mtmp
)) && flags
.verbose
)
3035 skiprange(range
, skipstart
, skipend
)
3036 int range
, *skipstart
, *skipend
;
3038 int tr
= (range
/ 4);
3039 int tmp
= range
- ((tr
> 0) ? rnd(tr
) : 0);
3041 *skipend
= tmp
- ((tmp
/ 4) * rnd(3));
3042 if (*skipend
>= tmp
)
3047 * Called for the following distance effects:
3048 * when a weapon is thrown (weapon == THROWN_WEAPON)
3049 * when an object is kicked (KICKED_WEAPON)
3050 * when an IMMEDIATE wand is zapped (ZAPPED_WAND)
3051 * when a light beam is flashed (FLASHED_LIGHT)
3052 * when a mirror is applied (INVIS_BEAM)
3053 * A thrown/kicked object falls down at end of its range or when a monster
3054 * is hit. The variable 'bhitpos' is set to the final position of the weapon
3055 * thrown/zapped. The ray of a wand may affect (by calling a provided
3056 * function) several objects and monsters on its path. The return value
3057 * is the monster hit (weapon != ZAPPED_WAND), or a null monster pointer.
3059 * Thrown and kicked objects (THROWN_WEAPON or KICKED_WEAPON) may be
3060 * destroyed and *pobj set to NULL to indicate this.
3062 * Check !u.uswallow before calling bhit().
3063 * This function reveals the absence of a remembered invisible monster in
3064 * necessary cases (throwing or kicking weapons). The presence of a real
3065 * one is revealed for a weapon, but if not a weapon is left up to fhitm().
3068 bhit(ddx
, ddy
, range
, weapon
, fhitm
, fhito
, pobj
)
3069 register int ddx
, ddy
, range
; /* direction and range */
3070 int weapon
; /* see values in hack.h */
3071 int FDECL((*fhitm
), (MONST_P
, OBJ_P
)), /* fns called when mon/obj hit */
3072 FDECL((*fhito
), (OBJ_P
, OBJ_P
));
3073 struct obj
**pobj
; /* object tossed/used, set to NULL
3074 * if object is destroyed */
3077 struct obj
*obj
= *pobj
;
3079 boolean shopdoor
= FALSE
, point_blank
= TRUE
;
3080 boolean in_skip
= FALSE
, allow_skip
= FALSE
;
3081 int skiprange_start
= 0, skiprange_end
= 0, skipcount
= 0;
3083 if (weapon
== KICKED_WEAPON
) {
3084 /* object starts one square in front of player */
3085 bhitpos
.x
= u
.ux
+ ddx
;
3086 bhitpos
.y
= u
.uy
+ ddy
;
3093 if (weapon
== THROWN_WEAPON
&& obj
&& obj
->otyp
== ROCK
) {
3094 skiprange(range
, &skiprange_start
, &skiprange_end
);
3095 allow_skip
= !rn2(3);
3098 if (weapon
== FLASHED_LIGHT
) {
3099 tmp_at(DISP_BEAM
, cmap_to_glyph(S_flashbeam
));
3100 } else if (weapon
!= ZAPPED_WAND
&& weapon
!= INVIS_BEAM
)
3101 tmp_at(DISP_FLASH
, obj_to_glyph(obj
));
3103 while (range
-- > 0) {
3117 if (is_pick(obj
) && inside_shop(x
, y
)
3118 && (mtmp
= shkcatch(obj
, x
, y
)) != 0) {
3119 tmp_at(DISP_END
, 0);
3123 typ
= levl
[bhitpos
.x
][bhitpos
.y
].typ
;
3125 /* iron bars will block anything big enough */
3126 if ((weapon
== THROWN_WEAPON
|| weapon
== KICKED_WEAPON
)
3128 && hits_bars(pobj
, x
- ddx
, y
- ddy
, bhitpos
.x
, bhitpos
.y
,
3129 point_blank
? 0 : !rn2(5), 1)) {
3130 /* caveat: obj might now be null... */
3137 if (weapon
== ZAPPED_WAND
&& find_drawbridge(&x
, &y
)) {
3138 boolean learn_it
= FALSE
;
3140 switch (obj
->otyp
) {
3143 if (is_db_wall(bhitpos
.x
, bhitpos
.y
)) {
3144 if (cansee(x
, y
) || cansee(bhitpos
.x
, bhitpos
.y
))
3146 open_drawbridge(x
, y
);
3150 case SPE_WIZARD_LOCK
:
3151 if ((cansee(x
, y
) || cansee(bhitpos
.x
, bhitpos
.y
))
3152 && levl
[x
][y
].typ
== DRAWBRIDGE_DOWN
)
3154 close_drawbridge(x
, y
);
3157 case SPE_FORCE_BOLT
:
3158 if (typ
!= DRAWBRIDGE_UP
)
3159 destroy_drawbridge(x
, y
);
3167 mtmp
= m_at(bhitpos
.x
, bhitpos
.y
);
3172 * skiprange_start is only set if this is a thrown rock
3174 if (skiprange_start
&& (range
== skiprange_start
) && allow_skip
) {
3175 if (is_pool(bhitpos
.x
, bhitpos
.y
) && !mtmp
) {
3178 pline("%s %s%s.", Yname2(obj
), otense(obj
, "skip"),
3179 skipcount
? " again" : "");
3181 You_hear("%s skip.", yname(obj
));
3183 } else if (skiprange_start
> skiprange_end
+ 1) {
3188 if (range
<= skiprange_end
) {
3190 if (range
> 3) /* another bounce? */
3191 skiprange(range
, &skiprange_start
, &skiprange_end
);
3192 } else if (mtmp
&& M_IN_WATER(mtmp
->data
)) {
3193 if ((!Blind
&& canseemon(mtmp
)) || sensemon(mtmp
))
3194 pline("%s %s over %s.", Yname2(obj
), otense(obj
, "pass"),
3199 if (mtmp
&& !(in_skip
&& M_IN_WATER(mtmp
->data
))) {
3200 notonhead
= (bhitpos
.x
!= mtmp
->mx
|| bhitpos
.y
!= mtmp
->my
);
3201 if (weapon
== FLASHED_LIGHT
) {
3202 /* FLASHED_LIGHT hitting invisible monster should
3203 pass through instead of stop so we call
3204 flash_hits_mon() directly rather than returning
3205 mtmp back to caller. That allows the flash to
3206 keep on going. Note that we use mtmp->minvis
3207 not canspotmon() because it makes no difference
3208 whether the hero can see the monster or not. */
3210 obj
->ox
= u
.ux
, obj
->oy
= u
.uy
;
3211 (void) flash_hits_mon(mtmp
, obj
);
3213 tmp_at(DISP_END
, 0);
3214 return mtmp
; /* caller will call flash_hits_mon */
3216 } else if (weapon
== INVIS_BEAM
) {
3217 /* Like FLASHED_LIGHT, INVIS_BEAM should continue
3218 through invisible targets; unlike it, we aren't
3219 prepared for multiple hits so just get first one
3220 that's either visible or could see its invisible
3221 self. [No tmp_at() cleanup is needed here.] */
3222 if (!mtmp
->minvis
|| perceives(mtmp
->data
))
3224 } else if (weapon
!= ZAPPED_WAND
) {
3225 /* THROWN_WEAPON, KICKED_WEAPON */
3226 tmp_at(DISP_END
, 0);
3227 if (cansee(bhitpos
.x
, bhitpos
.y
) && !canspotmon(mtmp
))
3228 map_invisible(bhitpos
.x
, bhitpos
.y
);
3232 (*fhitm
)(mtmp
, obj
);
3236 if (weapon
== ZAPPED_WAND
&& obj
->otyp
== WAN_PROBING
3237 && glyph_is_invisible(levl
[bhitpos
.x
][bhitpos
.y
].glyph
)) {
3238 unmap_object(bhitpos
.x
, bhitpos
.y
);
3243 if (bhitpile(obj
, fhito
, bhitpos
.x
, bhitpos
.y
, 0))
3246 if (weapon
== KICKED_WEAPON
3247 && ((obj
->oclass
== COIN_CLASS
3248 && OBJ_AT(bhitpos
.x
, bhitpos
.y
))
3249 || ship_object(obj
, bhitpos
.x
, bhitpos
.y
,
3250 costly_spot(bhitpos
.x
, bhitpos
.y
)))) {
3251 tmp_at(DISP_END
, 0);
3252 return (struct monst
*) 0;
3255 if (weapon
== ZAPPED_WAND
&& (IS_DOOR(typ
) || typ
== SDOOR
)) {
3256 switch (obj
->otyp
) {
3261 case SPE_WIZARD_LOCK
:
3262 case SPE_FORCE_BOLT
:
3263 if (doorlock(obj
, bhitpos
.x
, bhitpos
.y
)) {
3264 if (cansee(bhitpos
.x
, bhitpos
.y
)
3265 || (obj
->otyp
== WAN_STRIKING
&& !Deaf
))
3267 if (levl
[bhitpos
.x
][bhitpos
.y
].doormask
== D_BROKEN
3268 && *in_rooms(bhitpos
.x
, bhitpos
.y
, SHOPBASE
)) {
3270 add_damage(bhitpos
.x
, bhitpos
.y
, 400L);
3276 if (!ZAP_POS(typ
) || closed_door(bhitpos
.x
, bhitpos
.y
)) {
3281 if (weapon
!= ZAPPED_WAND
&& weapon
!= INVIS_BEAM
) {
3282 /* 'I' present but no monster: erase */
3283 /* do this before the tmp_at() */
3284 if (glyph_is_invisible(levl
[bhitpos
.x
][bhitpos
.y
].glyph
)
3286 unmap_object(bhitpos
.x
, bhitpos
.y
);
3289 tmp_at(bhitpos
.x
, bhitpos
.y
);
3291 /* kicked objects fall in pools */
3292 if ((weapon
== KICKED_WEAPON
)
3293 && (is_pool(bhitpos
.x
, bhitpos
.y
)
3294 || is_lava(bhitpos
.x
, bhitpos
.y
)))
3296 if (IS_SINK(typ
) && weapon
!= FLASHED_LIGHT
)
3297 break; /* physical objects fall onto sink */
3299 /* limit range of ball so hero won't make an invalid move */
3300 if (weapon
== THROWN_WEAPON
&& range
> 0
3301 && obj
->otyp
== HEAVY_IRON_BALL
) {
3305 if ((bobj
= sobj_at(BOULDER
, x
, y
)) != 0) {
3307 pline("%s hits %s.", The(distant_name(obj
, xname
)),
3310 } else if (obj
== uball
) {
3311 if (!test_move(x
- ddx
, y
- ddy
, ddx
, ddy
, TEST_MOVE
)) {
3312 /* nb: it didn't hit anything directly */
3314 pline("%s jerks to an abrupt halt.",
3315 The(distant_name(obj
, xname
))); /* lame */
3317 } else if (Sokoban
&& (t
= t_at(x
, y
)) != 0
3318 && (t
->ttyp
== PIT
|| t
->ttyp
== SPIKED_PIT
3319 || t
->ttyp
== HOLE
|| t
->ttyp
== TRAPDOOR
)) {
3320 /* hero falls into the trap, so ball stops */
3326 /* thrown/kicked missile has moved away from its starting spot */
3327 point_blank
= FALSE
; /* affects passing through iron bars */
3330 if (weapon
!= ZAPPED_WAND
&& weapon
!= INVIS_BEAM
)
3331 tmp_at(DISP_END
, 0);
3334 pay_for_damage("destroy", FALSE
);
3336 return (struct monst
*) 0;
3339 /* process thrown boomerang, which travels a curving path...
3340 * A multi-shot volley ought to have all missiles in flight at once,
3341 * but we're called separately for each one. We terminate the volley
3342 * early on a failed catch since continuing to throw after being hit
3343 * is too obviously silly.
3346 boomhit(obj
, dx
, dy
)
3351 int boom
; /* showsym[] index */
3353 boolean counterclockwise
= TRUE
; /* right-handed throw */
3355 /* counterclockwise traversal patterns:
3356 * ..........................54.................................
3357 * ..................43.....6..3....765.........................
3358 * ..........32.....5..2...7...2...8...4....87..................
3359 * .........4..1....6..1...8..1....9...3...9..6.....98..........
3360 * ..21@....5...@...7..@....9@......@12....@...5...@..7.....@9..
3361 * .3...9....6..9....89.....................1..4...1..6....1..8.
3362 * .4...8.....78.............................23....2..5...2...7.
3363 * ..567............................................34....3..6..
3364 * ........................................................45...
3365 * (invert rows for corresponding clockwise patterns)
3370 boom
= counterclockwise
? S_boomleft
: S_boomright
;
3371 for (i
= 0; i
< 8; i
++)
3372 if (xdir
[i
] == dx
&& ydir
[i
] == dy
)
3374 tmp_at(DISP_FLASH
, cmap_to_glyph(boom
));
3375 for (ct
= 0; ct
< 10; ct
++) {
3376 i
= (i
+ 8) % 8; /* 0..7 (8 -> 0, -1 -> 7) */
3377 boom
= (S_boomleft
+ S_boomright
- boom
); /* toggle */
3378 tmp_at(DISP_CHANGE
, cmap_to_glyph(boom
)); /* change glyph */
3383 if ((mtmp
= m_at(bhitpos
.x
, bhitpos
.y
)) != 0) {
3385 tmp_at(DISP_END
, 0);
3388 if (!ZAP_POS(levl
[bhitpos
.x
][bhitpos
.y
].typ
)
3389 || closed_door(bhitpos
.x
, bhitpos
.y
)) {
3394 if (bhitpos
.x
== u
.ux
&& bhitpos
.y
== u
.uy
) { /* ct == 9 */
3395 if (Fumbling
|| rn2(20) >= ACURR(A_DEX
)) {
3396 /* we hit ourselves */
3397 (void) thitu(10 + obj
->spe
, dmgval(obj
, &youmonst
), obj
,
3401 } else { /* we catch it */
3402 tmp_at(DISP_END
, 0);
3403 You("skillfully catch the boomerang.");
3407 tmp_at(bhitpos
.x
, bhitpos
.y
);
3409 if (IS_SINK(levl
[bhitpos
.x
][bhitpos
.y
].typ
)) {
3412 break; /* boomerang falls on sink */
3414 /* ct==0, initial position, we want next delta to be same;
3415 ct==5, opposite position, repeat delta undoes first one */
3417 i
+= (counterclockwise
? -1 : 1);
3419 tmp_at(DISP_END
, 0); /* do not leave last symbol */
3420 return (struct monst
*) 0;
3423 /* used by buzz(); also used by munslime(muse.c); returns damage to mon */
3425 zhitm(mon
, type
, nd
, ootmp
)
3426 register struct monst
*mon
;
3427 register int type
, nd
;
3428 struct obj
**ootmp
; /* to return worn armor for caller to disintegrate */
3430 register int tmp
= 0;
3431 register int abstype
= abs(type
) % 10;
3432 boolean sho_shieldeff
= FALSE
;
3433 boolean spellcaster
= is_hero_spell(type
); /* maybe get a bonus! */
3435 *ootmp
= (struct obj
*) 0;
3437 case ZT_MAGIC_MISSILE
:
3438 if (resists_magm(mon
)) {
3439 sho_shieldeff
= TRUE
;
3444 tmp
= spell_damage_bonus(tmp
);
3447 if (resists_fire(mon
)) {
3448 sho_shieldeff
= TRUE
;
3452 if (resists_cold(mon
))
3455 tmp
= spell_damage_bonus(tmp
);
3456 if (burnarmor(mon
)) {
3458 (void) destroy_mitem(mon
, POTION_CLASS
, AD_FIRE
);
3460 (void) destroy_mitem(mon
, SCROLL_CLASS
, AD_FIRE
);
3462 (void) destroy_mitem(mon
, SPBOOK_CLASS
, AD_FIRE
);
3463 destroy_mitem(mon
, FOOD_CLASS
, AD_FIRE
); /* carried slime */
3467 if (resists_cold(mon
)) {
3468 sho_shieldeff
= TRUE
;
3472 if (resists_fire(mon
))
3475 tmp
= spell_damage_bonus(tmp
);
3477 (void) destroy_mitem(mon
, POTION_CLASS
, AD_COLD
);
3481 (void) sleep_monst(mon
, d(nd
, 25),
3482 type
== ZT_WAND(ZT_SLEEP
) ? WAND_CLASS
: '\0');
3484 case ZT_DEATH
: /* death/disintegration */
3485 if (abs(type
) != ZT_BREATH(ZT_DEATH
)) { /* death */
3486 if (mon
->data
== &mons
[PM_DEATH
]) {
3487 mon
->mhpmax
+= mon
->mhpmax
/ 2;
3488 if (mon
->mhpmax
>= MAGIC_COOKIE
)
3489 mon
->mhpmax
= MAGIC_COOKIE
- 1;
3490 mon
->mhp
= mon
->mhpmax
;
3494 if (nonliving(mon
->data
) || is_demon(mon
->data
)
3495 || is_vampshifter(mon
) || resists_magm(mon
)) {
3496 /* similar to player */
3497 sho_shieldeff
= TRUE
;
3500 type
= -1; /* so they don't get saving throws */
3504 if (resists_disint(mon
)) {
3505 sho_shieldeff
= TRUE
;
3506 } else if (mon
->misc_worn_check
& W_ARMS
) {
3507 /* destroy shield; victim survives */
3508 *ootmp
= which_armor(mon
, W_ARMS
);
3509 } else if (mon
->misc_worn_check
& W_ARM
) {
3510 /* destroy body armor, also cloak if present */
3511 *ootmp
= which_armor(mon
, W_ARM
);
3512 if ((otmp2
= which_armor(mon
, W_ARMC
)) != 0)
3513 m_useup(mon
, otmp2
);
3515 /* no body armor, victim dies; destroy cloak
3516 and shirt now in case target gets life-saved */
3518 if ((otmp2
= which_armor(mon
, W_ARMC
)) != 0)
3519 m_useup(mon
, otmp2
);
3520 if ((otmp2
= which_armor(mon
, W_ARMU
)) != 0)
3521 m_useup(mon
, otmp2
);
3523 type
= -1; /* no saving throw wanted */
3524 break; /* not ordinary damage */
3529 if (resists_elec(mon
)) {
3530 sho_shieldeff
= TRUE
;
3532 /* can still blind the monster */
3536 tmp
= spell_damage_bonus(tmp
);
3537 if (!resists_blnd(mon
)
3538 && !(type
> 0 && u
.uswallow
&& mon
== u
.ustuck
)) {
3539 register unsigned rnd_tmp
= rnd(50);
3541 if ((mon
->mblinded
+ rnd_tmp
) > 127)
3542 mon
->mblinded
= 127;
3544 mon
->mblinded
+= rnd_tmp
;
3547 (void) destroy_mitem(mon
, WAND_CLASS
, AD_ELEC
);
3548 /* not actually possible yet */
3550 (void) destroy_mitem(mon
, RING_CLASS
, AD_ELEC
);
3553 if (resists_poison(mon
)) {
3554 sho_shieldeff
= TRUE
;
3560 if (resists_acid(mon
)) {
3561 sho_shieldeff
= TRUE
;
3566 acid_damage(MON_WEP(mon
));
3568 erode_armor(mon
, ERODE_CORRODE
);
3572 shieldeff(mon
->mx
, mon
->my
);
3573 if (is_hero_spell(type
) && (Role_if(PM_KNIGHT
) && u
.uhave
.questart
))
3575 if (tmp
> 0 && type
>= 0
3576 && resist(mon
, type
< ZT_SPELL(0) ? WAND_CLASS
: '\0', 0, NOTELL
))
3579 tmp
= 0; /* don't allow negative damage */
3580 debugpline3("zapped monster hp = %d (= %d - %d)", mon
->mhp
- tmp
,
3587 zhitu(type
, nd
, fltxt
, sx
, sy
)
3592 int dam
= 0, abstyp
= abs(type
);
3594 switch (abstyp
% 10) {
3595 case ZT_MAGIC_MISSILE
:
3598 pline_The("missiles bounce off!");
3601 exercise(A_STR
, FALSE
);
3605 if (Fire_resistance
) {
3607 You("don't feel hot!");
3608 ugolemeffects(AD_FIRE
, d(nd
, 6));
3613 if (burnarmor(&youmonst
)) { /* "body hit" */
3615 destroy_item(POTION_CLASS
, AD_FIRE
);
3617 destroy_item(SCROLL_CLASS
, AD_FIRE
);
3619 destroy_item(SPBOOK_CLASS
, AD_FIRE
);
3620 destroy_item(FOOD_CLASS
, AD_FIRE
);
3624 if (Cold_resistance
) {
3626 You("don't feel cold.");
3627 ugolemeffects(AD_COLD
, d(nd
, 6));
3632 destroy_item(POTION_CLASS
, AD_COLD
);
3635 if (Sleep_resistance
) {
3636 shieldeff(u
.ux
, u
.uy
);
3637 You("don't feel sleepy.");
3639 fall_asleep(-d(nd
, 25), TRUE
); /* sleep ray */
3643 if (abstyp
== ZT_BREATH(ZT_DEATH
)) {
3644 if (Disint_resistance
) {
3645 You("are not disintegrated.");
3648 /* destroy shield; other possessions are safe */
3649 (void) destroy_arm(uarms
);
3652 /* destroy suit; if present, cloak goes too */
3654 (void) destroy_arm(uarmc
);
3655 (void) destroy_arm(uarm
);
3658 /* no shield or suit, you're dead; wipe out cloak
3659 and/or shirt in case of life-saving or bones */
3661 (void) destroy_arm(uarmc
);
3663 (void) destroy_arm(uarmu
);
3664 } else if (nonliving(youmonst
.data
) || is_demon(youmonst
.data
)) {
3666 You("seem unaffected.");
3668 } else if (Antimagic
) {
3670 You("aren't affected.");
3673 killer
.format
= KILLED_BY_AN
;
3674 Strcpy(killer
.name
, fltxt
? fltxt
: "");
3675 /* when killed by disintegration breath, don't leave corpse */
3676 u
.ugrave_arise
= (type
== -ZT_BREATH(ZT_DEATH
)) ? -3 : NON_PM
;
3678 return; /* lifesaved */
3680 if (Shock_resistance
) {
3682 You("aren't affected.");
3683 ugolemeffects(AD_ELEC
, d(nd
, 6));
3686 exercise(A_CON
, FALSE
);
3689 destroy_item(WAND_CLASS
, AD_ELEC
);
3691 destroy_item(RING_CLASS
, AD_ELEC
);
3694 poisoned("blast", A_DEX
, "poisoned blast", 15, FALSE
);
3697 if (Acid_resistance
) {
3698 pline_The("acid doesn't hurt.");
3701 pline_The("acid burns!");
3703 exercise(A_STR
, FALSE
);
3705 /* using two weapons at once makes both of them more vulnerable */
3706 if (!rn2(u
.twoweap
? 3 : 6))
3708 if (u
.twoweap
&& !rn2(3))
3709 acid_damage(uswapwep
);
3711 erode_armor(&youmonst
, ERODE_CORRODE
);
3715 /* Half_spell_damage protection yields half-damage for wands & spells,
3716 including hero's own ricochets; breath attacks do full damage */
3717 if (dam
&& Half_spell_damage
&& !(abstyp
>= 20 && abstyp
<= 29))
3718 dam
= (dam
+ 1) / 2;
3719 losehp(dam
, fltxt
, KILLED_BY_AN
);
3724 * burn objects (such as scrolls and spellbooks) on floor
3725 * at position x,y; return the number of objects burned
3728 burn_floor_objects(x
, y
, give_feedback
, u_caused
)
3730 boolean give_feedback
; /* caller needs to decide about visibility checks */
3733 struct obj
*obj
, *obj2
;
3734 long i
, scrquan
, delquan
;
3735 char buf1
[BUFSZ
], buf2
[BUFSZ
];
3738 for (obj
= level
.objects
[x
][y
]; obj
; obj
= obj2
) {
3739 obj2
= obj
->nexthere
;
3740 if (obj
->oclass
== SCROLL_CLASS
|| obj
->oclass
== SPBOOK_CLASS
3741 || (obj
->oclass
== FOOD_CLASS
3742 && obj
->otyp
== GLOB_OF_GREEN_SLIME
)) {
3743 if (obj
->otyp
== SCR_FIRE
|| obj
->otyp
== SPE_FIREBALL
3744 || obj_resists(obj
, 2, 100))
3746 scrquan
= obj
->quan
; /* number present */
3747 delquan
= 0L; /* number to destroy */
3748 for (i
= scrquan
; i
> 0L; i
--)
3752 /* save name before potential delobj() */
3753 if (give_feedback
) {
3755 Strcpy(buf1
, (x
== u
.ux
&& y
== u
.uy
)
3757 : distant_name(obj
, xname
));
3759 Strcpy(buf2
, (x
== u
.ux
&& y
== u
.uy
)
3761 : distant_name(obj
, xname
));
3762 obj
->quan
= scrquan
;
3764 /* useupf(), which charges, only if hero caused damage */
3766 useupf(obj
, delquan
);
3767 else if (delquan
< scrquan
)
3768 obj
->quan
-= delquan
;
3772 if (give_feedback
) {
3774 pline("%ld %s burn.", delquan
, buf2
);
3776 pline("%s burns.", An(buf1
));
3784 /* will zap/spell/breath attack score a hit against armor class `ac'? */
3788 int type
; /* either hero cast spell type or 0 */
3790 int chance
= rn2(20);
3791 int spell_bonus
= type
? spell_hit_bonus(type
) : 0;
3793 /* small chance for naked target to avoid being hit */
3795 return rnd(10) < ac
+ spell_bonus
;
3797 /* very high armor protection does not achieve invulnerability */
3800 return (3 - chance
< ac
+ spell_bonus
);
3804 disintegrate_mon(mon
, type
, fltxt
)
3806 int type
; /* hero vs other */
3809 struct obj
*otmp
, *otmp2
, *m_amulet
= mlifesaver(mon
);
3811 if (canseemon(mon
)) {
3813 pline("%s is disintegrated!", Monnam(mon
));
3815 hit(fltxt
, mon
, "!");
3818 /* note: worn amulet of life saving must be preserved in order to operate */
3819 #define oresist_disintegration(obj) \
3820 (objects[obj->otyp].oc_oprop == DISINT_RES || obj_resists(obj, 5, 50) \
3821 || is_quest_artifact(obj) || obj == m_amulet)
3823 for (otmp
= mon
->minvent
; otmp
; otmp
= otmp2
) {
3825 if (!oresist_disintegration(otmp
)) {
3826 if (otmp
->owornmask
) {
3827 /* in case monster's life gets saved */
3828 mon
->misc_worn_check
&= ~otmp
->owornmask
;
3829 if (otmp
->owornmask
& W_WEP
)
3830 setmnotwielded(mon
, otmp
);
3831 /* also dismounts hero if this object is steed's saddle */
3832 update_mon_intrinsics(mon
, otmp
, FALSE
, TRUE
);
3833 otmp
->owornmask
= 0L;
3835 obj_extract_self(otmp
);
3836 obfree(otmp
, (struct obj
*) 0);
3840 #undef oresist_disintegration
3843 monkilled(mon
, (char *) 0, -AD_RBRE
);
3849 * type == 0 to 9 : you shooting a wand
3850 * type == 10 to 19 : you casting a spell
3851 * type == 20 to 29 : you breathing as a monster
3852 * type == -10 to -19 : monster casting spell
3853 * type == -20 to -29 : monster breathing at you
3854 * type == -30 to -39 : monster shooting a wand
3855 * called with dx = dy = 0 with vertical bolts
3858 buzz(type
, nd
, sx
, sy
, dx
, dy
)
3859 register int type
, nd
;
3860 register xchar sx
, sy
;
3861 register int dx
, dy
;
3863 int range
, abstype
= abs(type
) % 10;
3864 register xchar lsx
, lsy
;
3867 boolean shopdamage
= FALSE
;
3872 /* if its a Hero Spell then get its SPE_TYPE */
3873 spell_type
= is_hero_spell(type
) ? SPE_MAGIC_MISSILE
+ abstype
: 0;
3875 fltxt
= flash_types
[(type
<= -30) ? abstype
: abs(type
)];
3881 tmp
= zhitm(u
.ustuck
, type
, nd
, &otmp
);
3885 pline("%s rips into %s%s", The(fltxt
), mon_nam(u
.ustuck
),
3887 /* Using disintegration from the inside only makes a hole... */
3888 if (tmp
== MAGIC_COOKIE
)
3890 if (u
.ustuck
->mhp
< 1)
3897 if (dx
== 0 && dy
== 0)
3899 save_bhitpos
= bhitpos
;
3901 tmp_at(DISP_BEAM
, zapdir_to_glyph(dx
, dy
, abstype
));
3902 while (range
-- > 0) {
3907 if (!isok(sx
, sy
) || levl
[sx
][sy
].typ
== STONE
)
3911 if (cansee(sx
, sy
)) {
3912 /* reveal/unreveal invisible monsters before tmp_at() */
3913 if (mon
&& !canspotmon(mon
))
3914 map_invisible(sx
, sy
);
3915 else if (!mon
&& glyph_is_invisible(levl
[sx
][sy
].glyph
)) {
3916 unmap_object(sx
, sy
);
3919 if (ZAP_POS(levl
[sx
][sy
].typ
)
3920 || (isok(lsx
, lsy
) && cansee(lsx
, lsy
)))
3922 delay_output(); /* wait a little */
3925 /* hit() and miss() need bhitpos to match the target */
3926 bhitpos
.x
= sx
, bhitpos
.y
= sy
;
3927 /* Fireballs only damage when they explode */
3928 if (type
!= ZT_SPELL(ZT_FIRE
))
3929 range
+= zap_over_floor(sx
, sy
, type
, &shopdamage
, 0);
3932 if (type
== ZT_SPELL(ZT_FIRE
))
3935 mon
->mstrategy
&= ~STRAT_WAITMASK
;
3937 notonhead
= (mon
->mx
!= bhitpos
.x
|| mon
->my
!= bhitpos
.y
);
3938 if (zap_hit(find_mac(mon
), spell_type
)) {
3939 if (mon_reflects(mon
, (char *) 0)) {
3940 if (cansee(mon
->mx
, mon
->my
)) {
3941 hit(fltxt
, mon
, exclam(0));
3942 shieldeff(mon
->mx
, mon
->my
);
3943 (void) mon_reflects(mon
,
3944 "But it reflects from %s %s!");
3949 boolean mon_could_move
= mon
->mcanmove
;
3950 int tmp
= zhitm(mon
, type
, nd
, &otmp
);
3952 if (is_rider(mon
->data
)
3953 && abs(type
) == ZT_BREATH(ZT_DEATH
)) {
3954 if (canseemon(mon
)) {
3955 hit(fltxt
, mon
, ".");
3956 pline("%s disintegrates.", Monnam(mon
));
3957 pline("%s body reintegrates before your %s!",
3958 s_suffix(Monnam(mon
)),
3959 (eyecount(youmonst
.data
) == 1)
3961 : makeplural(body_part(EYE
)));
3962 pline("%s resurrects!", Monnam(mon
));
3964 mon
->mhp
= mon
->mhpmax
;
3965 break; /* Out of while loop */
3967 if (mon
->data
== &mons
[PM_DEATH
] && abstype
== ZT_DEATH
) {
3968 if (canseemon(mon
)) {
3969 hit(fltxt
, mon
, ".");
3970 pline("%s absorbs the deadly %s!", Monnam(mon
),
3971 type
== ZT_BREATH(ZT_DEATH
) ? "blast"
3973 pline("It seems even stronger than before.");
3975 break; /* Out of while loop */
3978 if (tmp
== MAGIC_COOKIE
) { /* disintegration */
3979 disintegrate_mon(mon
, type
, fltxt
);
3980 } else if (mon
->mhp
< 1) {
3982 monkilled(mon
, fltxt
, AD_RBRE
);
3987 /* normal non-fatal hit */
3988 hit(fltxt
, mon
, exclam(tmp
));
3990 /* some armor was destroyed; no damage done */
3992 pline("%s %s is disintegrated!",
3993 s_suffix(Monnam(mon
)),
3994 distant_name(otmp
, xname
));
3997 if (mon_could_move
&& !mon
->mcanmove
) /* ZT_SLEEP */
4005 } else if (sx
== u
.ux
&& sy
== u
.uy
&& range
>= 0) {
4007 if (u
.usteed
&& !rn2(3) && !mon_reflects(u
.usteed
, (char *) 0)) {
4010 } else if (zap_hit((int) u
.uac
, 0)) {
4012 pline("%s hits you!", The(fltxt
));
4015 (void) ureflects("But %s reflects from your %s!",
4018 pline("For some reason you are not affected.");
4023 zhitu(type
, nd
, fltxt
, sx
, sy
);
4025 } else if (!Blind
) {
4026 pline("%s whizzes by you!", The(fltxt
));
4027 } else if (abstype
== ZT_LIGHTNING
) {
4028 Your("%s tingles.", body_part(ARM
));
4030 if (abstype
== ZT_LIGHTNING
)
4031 (void) flashburn((long) d(nd
, 50));
4036 if (!ZAP_POS(levl
[sx
][sy
].typ
)
4037 || (closed_door(sx
, sy
) && range
>= 0)) {
4044 fireball
= (type
== ZT_SPELL(ZT_FIRE
));
4045 if ((--range
> 0 && isok(lsx
, lsy
) && cansee(lsx
, lsy
))
4047 if (Is_airlevel(&u
.uz
)) { /* nothing to bounce off of */
4048 pline_The("%s vanishes into the aether!", fltxt
);
4050 type
= ZT_WAND(ZT_FIRE
); /* skip pending fireball */
4052 } else if (fireball
) {
4055 break; /* fireballs explode before the obstacle */
4057 pline_The("%s bounces!", fltxt
);
4059 if (!dx
|| !dy
|| !rn2(20)) {
4063 if (isok(sx
, lsy
) && ZAP_POS(rmn
= levl
[sx
][lsy
].typ
)
4064 && !closed_door(sx
, lsy
)
4065 && (IS_ROOM(rmn
) || (isok(sx
+ dx
, lsy
)
4066 && ZAP_POS(levl
[sx
+ dx
][lsy
].typ
))))
4068 if (isok(lsx
, sy
) && ZAP_POS(rmn
= levl
[lsx
][sy
].typ
)
4069 && !closed_door(lsx
, sy
)
4070 && (IS_ROOM(rmn
) || (isok(lsx
, sy
+ dy
)
4071 && ZAP_POS(levl
[lsx
][sy
+ dy
].typ
))))
4072 if (!bounce
|| rn2(2))
4077 dx
= -dx
; /* fall into... */
4085 tmp_at(DISP_CHANGE
, zapdir_to_glyph(dx
, dy
, abstype
));
4089 tmp_at(DISP_END
, 0);
4090 if (type
== ZT_SPELL(ZT_FIRE
))
4091 explode(sx
, sy
, type
, d(12, 6), 0, EXPL_FIERY
);
4093 pay_for_damage(abstype
== ZT_FIRE
4095 : abstype
== ZT_COLD
4097 /* "damage" indicates wall rather than door */
4098 : abstype
== ZT_ACID
4100 : abstype
== ZT_DEATH
4104 bhitpos
= save_bhitpos
;
4112 struct rm
*lev
= &levl
[x
][y
];
4116 msg
= "The ice crackles and melts.";
4117 if (lev
->typ
== DRAWBRIDGE_UP
) {
4118 lev
->drawbridgemask
&= ~DB_ICE
; /* revert to DB_MOAT */
4119 } else { /* lev->typ == ICE */
4121 if (lev
->icedpool
== ICED_POOL
)
4126 lev
->typ
= (lev
->icedpool
== ICED_POOL
? POOL
: MOAT
);
4130 spot_stop_timers(x
, y
, MELT_ICE_AWAY
); /* no more ice to melt away */
4131 obj_ice_effects(x
, y
, FALSE
);
4138 if ((otmp
= sobj_at(BOULDER
, x
, y
)) != 0) {
4140 pline("%s settles...", An(xname(otmp
)));
4142 obj_extract_self(otmp
); /* boulder isn't being pushed */
4143 if (!boulder_hits_pool(otmp
, x
, y
, FALSE
))
4144 impossible("melt_ice: no pool?");
4145 /* try again if there's another boulder and pool didn't fill */
4146 } while (is_pool(x
, y
) && (otmp
= sobj_at(BOULDER
, x
, y
)) != 0);
4149 if (x
== u
.ux
&& y
== u
.uy
)
4150 spoteffects(TRUE
); /* possibly drown, notice objects */
4153 #define MIN_ICE_TIME 50
4154 #define MAX_ICE_TIME 2000
4156 * Usually start a melt_ice timer; sometimes the ice will become
4157 * permanent instead.
4160 start_melt_ice_timeout(x
, y
, min_time
)
4162 long min_time
; /* <x,y>'s old melt timeout (deleted by time we get here) */
4167 when
= (int) min_time
;
4168 if (when
< MIN_ICE_TIME
- 1)
4169 when
= MIN_ICE_TIME
- 1;
4171 /* random timeout; surrounding ice locations ought to be a factor... */
4172 while (++when
<= MAX_ICE_TIME
)
4173 if (!rn2((MAX_ICE_TIME
- when
) + MIN_ICE_TIME
))
4176 /* if we're within MAX_ICE_TIME, install a melt timer;
4177 otherwise, omit it to leave this ice permanent */
4178 if (when
<= MAX_ICE_TIME
) {
4179 where
= ((long) x
<< 16) | (long) y
;
4180 (void) start_timer((long) when
, TIMER_LEVEL
, MELT_ICE_AWAY
,
4181 long_to_any(where
));
4188 * Called when ice has melted completely away.
4191 melt_ice_away(arg
, timeout
)
4193 long timeout UNUSED
;
4196 long where
= arg
->a_long
;
4198 y
= (xchar
) (where
& 0xFFFF);
4199 x
= (xchar
) ((where
>> 16) & 0xFFFF);
4200 /* melt_ice does newsym when appropriate */
4201 melt_ice(x
, y
, "Some ice melts away.");
4204 /* Burn floor scrolls, evaporate pools, etc... in a single square.
4205 * Used both for normal bolts of fire, cold, etc... and for fireballs.
4206 * Sets shopdamage to TRUE if a shop door is destroyed, and returns the
4207 * amount by which range is reduced (the latter is just ignored by fireballs)
4210 zap_over_floor(x
, y
, type
, shopdamage
, exploding_wand_typ
)
4213 boolean
*shopdamage
;
4214 short exploding_wand_typ
;
4216 const char *zapverb
;
4219 struct rm
*lev
= &levl
[x
][y
];
4220 boolean see_it
= cansee(x
, y
), yourzap
;
4221 int rangemod
= 0, abstype
= abs(type
) % 10;
4226 if (t
&& t
->ttyp
== WEB
) {
4227 /* a burning web is too flimsy to notice if you can't see it */
4229 Norep("A web bursts into flames!");
4230 (void) delfloortrap(t
);
4235 melt_ice(x
, y
, (char *) 0);
4236 } else if (is_pool(x
, y
)) {
4237 const char *msgtxt
= "You hear hissing gas.";
4239 if (lev
->typ
!= POOL
) { /* MOAT or DRAWBRIDGE_UP */
4241 msgtxt
= "Some water evaporates.";
4245 t
= maketrap(x
, y
, PIT
);
4249 msgtxt
= "The water evaporates.";
4251 Norep("%s", msgtxt
);
4252 if (lev
->typ
== ROOM
)
4254 } else if (IS_FOUNTAIN(lev
->typ
)) {
4256 pline("Steam billows from the fountain.");
4258 dryup(x
, y
, type
> 0);
4260 break; /* ZT_FIRE */
4263 if (is_pool(x
, y
) || is_lava(x
, y
)) {
4264 boolean lava
= is_lava(x
, y
),
4265 moat
= is_moat(x
, y
);
4267 if (lev
->typ
== WATER
) {
4268 /* For now, don't let WATER freeze. */
4270 pline_The("water freezes for a moment.");
4272 You_hear("a soft crackling.");
4273 rangemod
-= 1000; /* stop */
4277 Strcpy(buf
, waterbody_name(x
, y
)); /* for MOAT */
4279 if (lev
->typ
== DRAWBRIDGE_UP
) {
4280 lev
->drawbridgemask
&= ~DB_UNDER
; /* clear lava */
4281 lev
->drawbridgemask
|= (lava
? DB_FLOOR
: DB_ICE
);
4284 lev
->icedpool
= (lev
->typ
== POOL
) ? ICED_POOL
4286 lev
->typ
= lava
? ROOM
: ICE
;
4291 Norep("The lava cools and solidifies.");
4293 Norep("The %s is bridged with ice!", buf
);
4295 Norep("The water freezes.");
4298 You_hear("a crackling sound.");
4300 if (x
== u
.ux
&& y
== u
.uy
) {
4301 if (u
.uinwater
) { /* not just `if (Underwater)' */
4302 /* leave the no longer existent water */
4306 vision_full_recalc
= 1;
4307 } else if (u
.utrap
&& u
.utraptype
== TT_LAVA
) {
4310 You("pass through the now-solid rock.");
4312 u
.utrap
= rn1(50, 20);
4313 u
.utraptype
= TT_INFLOOR
;
4314 You("are firmly stuck in the cooling rock.");
4317 } else if ((mon
= m_at(x
, y
)) != 0) {
4318 /* probably ought to do some hefty damage to any
4319 non-ice creature caught in freezing water;
4320 at a minimum, eels are forced out of hiding */
4321 if (is_swimmer(mon
->data
) && mon
->mundetected
) {
4322 mon
->mundetected
= 0;
4327 start_melt_ice_timeout(x
, y
, 0L);
4328 obj_ice_effects(x
, y
, TRUE
);
4332 } else if (is_ice(x
, y
)) {
4335 /* Already ice here, so just firm it up. */
4336 /* Now ensure that only ice that is already timed is affected */
4337 if ((melt_time
= spot_time_left(x
, y
, MELT_ICE_AWAY
)) != 0L) {
4338 spot_stop_timers(x
, y
, MELT_ICE_AWAY
);
4339 start_melt_ice_timeout(x
, y
, melt_time
);
4342 break; /* ZT_COLD */
4345 (void) create_gas_cloud(x
, y
, 1, 8);
4349 if (lev
->typ
== IRONBARS
) {
4350 if ((lev
->wall_info
& W_NONDIGGABLE
) != 0) {
4352 Norep("The %s corrode somewhat but remain intact.",
4353 defsyms
[S_bars
].explanation
);
4354 /* but nothing actually happens... */
4358 Norep("The %s melt.", defsyms
[S_bars
].explanation
);
4359 if (*in_rooms(x
, y
, SHOPBASE
)) {
4360 /* in case we ever have a shop bounded by bars */
4364 add_damage(x
, y
, (type
>= 0) ? 300L : 0L);
4369 lev
->doormask
= D_NODOOR
;
4375 break; /* ZT_ACID */
4381 /* set up zap text for possible door feedback; for exploding wand, we
4382 want "the blast" rather than "your blast" even if hero caused it */
4383 yourzap
= (type
>= 0 && !exploding_wand_typ
);
4384 zapverb
= "blast"; /* breath attack or wand explosion */
4385 if (!exploding_wand_typ
) {
4386 if (abs(type
) < ZT_SPELL(0))
4387 zapverb
= "bolt"; /* wand zap */
4388 else if (abs(type
) < ZT_BREATH(0))
4392 /* secret door gets revealed, converted into regular door */
4393 if (levl
[x
][y
].typ
== SDOOR
) {
4394 cvt_sdoor_to_door(&levl
[x
][y
]); /* .typ = DOOR */
4395 /* target spot will now pass closed_door() test below
4396 (except on rogue level) */
4399 pline("%s %s reveals a secret door.",
4400 yourzap
? "Your" : "The", zapverb
);
4401 else if (Is_rogue_level(&u
.uz
))
4402 draft_message(FALSE
); /* "You feel a draft." (open doorway) */
4405 /* regular door absorbs remaining zap range, possibly gets destroyed */
4406 if (closed_door(x
, y
)) {
4407 int new_doormask
= -1;
4408 const char *see_txt
= 0, *sense_txt
= 0, *hear_txt
= 0;
4413 new_doormask
= D_NODOOR
;
4414 see_txt
= "The door is consumed in flames!";
4415 sense_txt
= "smell smoke.";
4418 new_doormask
= D_NODOOR
;
4419 see_txt
= "The door freezes and shatters!";
4420 sense_txt
= "feel cold.";
4423 /* death spells/wands don't disintegrate */
4424 if (abs(type
) != ZT_BREATH(ZT_DEATH
))
4426 new_doormask
= D_NODOOR
;
4427 see_txt
= "The door disintegrates!";
4428 hear_txt
= "crashing wood.";
4431 new_doormask
= D_BROKEN
;
4432 see_txt
= "The door splinters!";
4433 hear_txt
= "crackling.";
4437 if (exploding_wand_typ
> 0) {
4438 /* Magical explosion from misc exploding wand */
4439 if (exploding_wand_typ
== WAN_STRIKING
) {
4440 new_doormask
= D_BROKEN
;
4441 see_txt
= "The door crashes open!";
4442 sense_txt
= "feel a burst of cool air.";
4447 /* "the door absorbs the blast" would be
4448 inaccurate for an exploding wand since
4449 other adjacent locations still get hit */
4450 if (exploding_wand_typ
)
4451 pline_The("door remains intact.");
4453 pline_The("door absorbs %s %s!", yourzap
? "your" : "the",
4456 You_feel("vibrations.");
4459 if (new_doormask
>= 0) { /* door gets broken */
4460 if (*in_rooms(x
, y
, SHOPBASE
)) {
4462 add_damage(x
, y
, 400L);
4464 } else /* caused by monster */
4465 add_damage(x
, y
, 0L);
4467 lev
->doormask
= new_doormask
;
4468 unblock_point(x
, y
); /* vision */
4472 } else if (sense_txt
) {
4474 } else if (hear_txt
)
4475 You_hear1(hear_txt
);
4476 if (picking_at(x
, y
)) {
4483 if (OBJ_AT(x
, y
) && abstype
== ZT_FIRE
)
4484 if (burn_floor_objects(x
, y
, FALSE
, type
> 0) && couldsee(x
, y
)) {
4486 You("%s of smoke.", !Blind
? "see a puff" : "smell a whiff");
4488 if ((mon
= m_at(x
, y
)) != 0) {
4489 /* Cannot use wakeup() which also angers the monster */
4495 if (mon
->ispriest
&& *in_rooms(mon
->mx
, mon
->my
, TEMPLE
))
4497 if (mon
->isshk
&& !*u
.ushops
)
4504 /* fractured by pick-axe or wand of striking */
4507 register struct obj
*obj
; /* no texts here! */
4510 boolean by_you
= !context
.mon_moving
;
4512 if (by_you
&& get_obj_location(obj
, &x
, &y
, 0) && costly_spot(x
, y
)) {
4513 struct monst
*shkp
= 0;
4514 char objroom
= *in_rooms(x
, y
, SHOPBASE
);
4516 if (billable(&shkp
, obj
, objroom
, FALSE
)) {
4517 /* shop message says "you owe <shk> <$> for it!" so we need
4518 to precede that with a message explaining what "it" is */
4519 You("fracture %s %s.", s_suffix(shkname(shkp
)), xname(obj
));
4520 breakobj(obj
, x
, y
, TRUE
, FALSE
); /* charges for shop goods */
4523 if (by_you
&& obj
->otyp
== BOULDER
)
4527 obj
->oclass
= GEM_CLASS
;
4528 obj
->quan
= (long) rn1(60, 7);
4529 obj
->owt
= weight(obj
);
4530 obj
->dknown
= obj
->bknown
= obj
->rknown
= 0;
4531 obj
->known
= objects
[obj
->otyp
].oc_uses_known
? 0 : 1;
4532 dealloc_oextra(obj
);
4534 if (obj
->where
== OBJ_FLOOR
) {
4535 obj_extract_self(obj
); /* move rocks back on top */
4536 place_object(obj
, obj
->ox
, obj
->oy
);
4537 if (!does_block(obj
->ox
, obj
->oy
, &levl
[obj
->ox
][obj
->oy
]))
4538 unblock_point(obj
->ox
, obj
->oy
);
4539 if (cansee(obj
->ox
, obj
->oy
))
4540 newsym(obj
->ox
, obj
->oy
);
4544 /* handle statue hit by striking/force bolt/pick-axe */
4547 register struct obj
*obj
;
4549 /* [obj is assumed to be on floor, so no get_obj_location() needed] */
4550 struct trap
*trap
= t_at(obj
->ox
, obj
->oy
);
4552 boolean by_you
= !context
.mon_moving
;
4554 if (trap
&& trap
->ttyp
== STATUE_TRAP
4555 && activate_statue_trap(trap
, obj
->ox
, obj
->oy
, TRUE
))
4557 /* drop any objects contained inside the statue */
4558 while ((item
= obj
->cobj
) != 0) {
4559 obj_extract_self(item
);
4560 place_object(item
, obj
->ox
, obj
->oy
);
4562 if (by_you
&& Role_if(PM_ARCHEOLOGIST
) && (obj
->spe
& STATUE_HISTORIC
)) {
4563 You_feel("guilty about damaging such a historic statue.");
4572 * destroy_strings[dindx][0:singular,1:plural,2:killer_reason]
4573 * [0] freezing potion
4574 * [1] boiling potion other than oil
4575 * [2] boiling potion of oil
4576 * [3] burning scroll
4577 * [4] burning spellbook
4580 * (books, rings, and wands don't stack so don't need plural form;
4581 * crumbling ring doesn't do damage so doesn't need killer reason)
4583 const char *const destroy_strings
[][3] = {
4584 /* also used in trap.c */
4585 { "freezes and shatters", "freeze and shatter", "shattered potion" },
4586 { "boils and explodes", "boil and explode", "boiling potion" },
4587 { "ignites and explodes", "ignite and explode", "exploding potion" },
4588 { "catches fire and burns", "catch fire and burn", "burning scroll" },
4589 { "catches fire and burns", "", "burning book" },
4590 { "turns to dust and vanishes", "", "" },
4591 { "breaks apart and explodes", "", "exploding wand" },
4595 destroy_item(osym
, dmgtyp
)
4596 register int osym
, dmgtyp
;
4598 register struct obj
*obj
, *obj2
;
4599 int dmg
, xresist
, skip
;
4603 boolean physical_damage
;
4605 for (obj
= invent
; obj
; obj
= obj2
) {
4607 physical_damage
= FALSE
;
4608 if (obj
->oclass
!= osym
)
4609 continue; /* test only objs of type osym */
4611 continue; /* don't destroy artifacts */
4612 if (obj
->in_use
&& obj
->quan
== 1L)
4613 continue; /* not available */
4615 /* lint suppression */
4621 if (osym
== POTION_CLASS
&& obj
->otyp
!= POT_OIL
) {
4629 xresist
= (Fire_resistance
&& obj
->oclass
!= POTION_CLASS
4630 && obj
->otyp
!= GLOB_OF_GREEN_SLIME
);
4632 if (obj
->otyp
== SCR_FIRE
|| obj
->otyp
== SPE_FIREBALL
)
4634 if (obj
->otyp
== SPE_BOOK_OF_THE_DEAD
) {
4637 pline("%s glows a strange %s, but remains intact.",
4638 The(xname(obj
)), hcolor("dark red"));
4643 dindx
= (obj
->otyp
!= POT_OIL
) ? 1 : 2;
4655 if (obj
->otyp
== GLOB_OF_GREEN_SLIME
) {
4656 dindx
= 1; /* boil and explode */
4657 dmg
= (obj
->owt
+ 19) / 20;
4668 xresist
= (Shock_resistance
&& obj
->oclass
!= RING_CLASS
);
4672 if (obj
->otyp
== RIN_SHOCK_RESISTANCE
) {
4680 if (obj
->otyp
== WAN_LIGHTNING
) {
4685 if (obj
== current_wand
) { skip
++; break; }
4701 --quan
; /* one will be used up elsewhere */
4702 for (i
= cnt
= 0L; i
< quan
; i
++)
4708 mult
= (cnt
== quan
)
4709 ? (quan
> 1) ? "All of your " : "Your"
4710 : (cnt
== 1L) ? "One of your" : "Some of your";
4711 pline("%s %s %s!", mult
, xname(obj
),
4712 destroy_strings
[dindx
][(cnt
> 1L)]);
4713 if (osym
== POTION_CLASS
&& dmgtyp
!= AD_COLD
) {
4714 if (!breathless(youmonst
.data
) || haseyes(youmonst
.data
))
4717 if (obj
->owornmask
) {
4718 if (obj
->owornmask
& W_RING
) /* ring being worn */
4723 if (obj
== current_wand
)
4724 current_wand
= 0; /* destroyed */
4725 for (i
= 0; i
< cnt
; i
++)
4729 You("aren't hurt!");
4731 const char *how
= destroy_strings
[dindx
][2];
4732 boolean one
= (cnt
== 1L);
4734 if (dmgtyp
== AD_FIRE
&& osym
== FOOD_CLASS
)
4735 how
= "exploding glob of slime";
4736 if (physical_damage
)
4737 dmg
= Maybe_Half_Phys(dmg
);
4738 losehp(dmg
, one
? how
: (const char *) makeplural(how
),
4739 one
? KILLED_BY_AN
: KILLED_BY
);
4740 exercise(A_STR
, FALSE
);
4749 destroy_mitem(mtmp
, osym
, dmgtyp
)
4753 struct obj
*obj
, *obj2
;
4759 if (mtmp
== &youmonst
) { /* this simplifies artifact_hit() */
4760 destroy_item(osym
, dmgtyp
);
4761 return 0; /* arbitrary; value doesn't matter to artifact_hit() */
4764 vis
= canseemon(mtmp
);
4765 for (obj
= mtmp
->minvent
; obj
; obj
= obj2
) {
4767 if (obj
->oclass
!= osym
)
4768 continue; /* test only objs of type osym */
4775 if (osym
== POTION_CLASS
&& obj
->otyp
!= POT_OIL
) {
4783 if (obj
->otyp
== SCR_FIRE
|| obj
->otyp
== SPE_FIREBALL
)
4785 if (obj
->otyp
== SPE_BOOK_OF_THE_DEAD
) {
4788 pline("%s glows a strange %s, but remains intact.",
4789 The(distant_name(obj
, xname
)), hcolor("dark red"));
4794 dindx
= (obj
->otyp
!= POT_OIL
) ? 1 : 2;
4806 if (obj
->otyp
== GLOB_OF_GREEN_SLIME
) {
4807 dindx
= 1; /* boil and explode */
4808 tmp
+= (obj
->owt
+ 19) / 20;
4822 if (obj
->otyp
== RIN_SHOCK_RESISTANCE
) {
4829 if (obj
->otyp
== WAN_LIGHTNING
) {
4846 for (i
= cnt
= 0L; i
< quan
; i
++)
4854 (cnt
== obj
->quan
) ? "" : (cnt
> 1L) ? "Some of "
4856 (cnt
== obj
->quan
) ? Yname2(obj
) : yname(obj
),
4857 destroy_strings
[dindx
][(cnt
> 1L)]);
4858 for (i
= 0; i
< cnt
; i
++)
4866 resist(mtmp
, oclass
, damage
, tell
)
4881 break; /* instrument */
4884 break; /* artifact */
4899 dlev
= (int) mtmp
->m_lev
;
4903 dlev
= is_mplayer(mtmp
->data
) ? u
.ulevel
: 1;
4905 resisted
= rn2(100 + alev
- dlev
) < mtmp
->data
->mr
;
4908 shieldeff(mtmp
->mx
, mtmp
->my
);
4909 pline("%s resists!", Monnam(mtmp
));
4911 damage
= (damage
+ 1) / 2;
4915 mtmp
->mhp
-= damage
;
4916 if (mtmp
->mhp
< 1) {
4918 monkilled(mtmp
, "", AD_RBRE
);
4926 #define MAXWISHTRY 5
4929 wishcmdassist(triesleft
)
4932 static NEARDATA
const char *
4936 "Enter the name of an object, such as \"potion of monster detection\",",
4937 "\"scroll labeled README\", \"elven mithril-coat\", or \"Grimtooth\"",
4938 "(without the quotes).",
4940 "For object types which come in stacks, you may specify a plural name",
4941 "such as \"potions of healing\", or specify a count, such as \"1000 gold",
4942 "pieces\", although that aspect of your wish might not be granted.",
4944 "You may also specify various prefix values which might be used to",
4945 "modify the item, such as \"uncursed\" or \"rustproof\" or \"+1\".",
4946 "Most modifiers shown when viewing your inventory can be specified.",
4948 "You may specify 'nothing' to explicitly decline this wish.",
4951 preserve_wishless
[] = "Doing so will preserve 'wishless' conduct.",
4953 "If you specify an unrecognized object name %s%s time%s,",
4954 retry_too
[] = "a randomly chosen item will be granted.",
4955 suppress_cmdassist
[] =
4956 "(Suppress this assistance with !cmdassist in your config file.)",
4957 *cardinals
[] = { "zero", "one", "two", "three", "four", "five" },
4958 too_many
[] = "too many";
4963 win
= create_nhwindow(NHW_TEXT
);
4966 for (i
= 0; i
< SIZE(wishinfo
) - 1; ++i
)
4967 putstr(win
, 0, wishinfo
[i
]);
4968 if (!u
.uconduct
.wishes
)
4969 putstr(win
, 0, preserve_wishless
);
4971 Sprintf(buf
, retry_info
,
4972 (triesleft
>= 0 && triesleft
< SIZE(cardinals
))
4973 ? cardinals
[triesleft
]
4975 (triesleft
< MAXWISHTRY
) ? " more" : "",
4977 putstr(win
, 0, buf
);
4978 putstr(win
, 0, retry_too
);
4980 if (iflags
.cmdassist
)
4981 putstr(win
, 0, suppress_cmdassist
);
4982 display_nhwindow(win
, FALSE
);
4983 destroy_nhwindow(win
);
4989 char buf
[BUFSZ
], promptbuf
[BUFSZ
];
4990 struct obj
*otmp
, nothing
;
4993 promptbuf
[0] = '\0';
4994 nothing
= zeroobj
; /* lint suppression; only its address matters */
4996 You("may wish for an object.");
4998 Strcpy(promptbuf
, "For what do you wish");
4999 if (iflags
.cmdassist
&& tries
> 0)
5000 Strcat(promptbuf
, " (enter 'help' for assistance)");
5001 Strcat(promptbuf
, "?");
5002 getlin(promptbuf
, buf
);
5003 (void) mungspaces(buf
);
5004 if (buf
[0] == '\033') {
5006 } else if (!strcmpi(buf
, "help")) {
5007 wishcmdassist(MAXWISHTRY
- tries
);
5011 * Note: if they wished for and got a non-object successfully,
5012 * otmp == &zeroobj. That includes gold, or an artifact that
5013 * has been denied. Wishing for "nothing" requires a separate
5014 * value to remain distinct.
5016 otmp
= readobjnam(buf
, ¬hing
);
5018 pline("Nothing fitting that description exists in the game.");
5019 if (++tries
< MAXWISHTRY
)
5021 pline1(thats_enough_tries
);
5022 otmp
= readobjnam((char *) 0, (struct obj
*) 0);
5024 return; /* for safety; should never happen */
5025 } else if (otmp
== ¬hing
) {
5026 /* explicitly wished for "nothing", presumably attempting
5027 to retain wishless conduct */
5032 u
.uconduct
.wishes
++;
5034 if (otmp
!= &zeroobj
) {
5036 *verb
= ((Is_airlevel(&u
.uz
) || u
.uinwater
) ? "slip" : "drop"),
5037 *oops_msg
= (u
.uswallow
5038 ? "Oops! %s out of your reach!"
5039 : (Is_airlevel(&u
.uz
) || Is_waterlevel(&u
.uz
)
5040 || levl
[u
.ux
][u
.uy
].typ
< IRONBARS
5041 || levl
[u
.ux
][u
.uy
].typ
>= ICE
)
5042 ? "Oops! %s away from you!"
5043 : "Oops! %s to the floor!");
5045 /* The(aobjnam()) is safe since otmp is unidentified -dlc */
5046 (void) hold_another_object(otmp
, oops_msg
,
5047 The(aobjnam(otmp
, verb
)),
5049 u
.ublesscnt
+= rn1(100, 50); /* the gods take notice */