1 /* NetHack 3.6 zap.c $NHDT-Date: 1449669396 2015/12/09 13:56:36 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.238 $ */
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
[] =
59 { /* 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", "blast of poison gas",
72 "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
=
144 (mtmp
->data
->mlet
== S_MIMIC
&& mtmp
->m_ap_type
!= M_AP_NOTHING
);
146 if (u
.uswallow
&& mtmp
== u
.ustuck
)
147 reveal_invis
= FALSE
;
151 zap_type_text
= "wand";
157 if (resists_magm(mtmp
)) { /* match effect on player */
158 shieldeff(mtmp
->mx
, mtmp
->my
);
160 break; /* skip makeknown */
161 } else if (u
.uswallow
|| rnd(20) < 10 + find_mac(mtmp
)) {
165 if (otyp
== SPE_FORCE_BOLT
)
166 dmg
= spell_damage_bonus(dmg
);
167 hit(zap_type_text
, mtmp
, exclam(dmg
));
168 (void) resist(mtmp
, otmp
->oclass
, dmg
, TELL
);
170 miss(zap_type_text
, mtmp
);
173 case WAN_SLOW_MONSTER
:
174 case SPE_SLOW_MONSTER
:
175 if (!resist(mtmp
, otmp
->oclass
, 0, NOTELL
)) {
178 mon_adjust_speed(mtmp
, -1, otmp
);
179 m_dowear(mtmp
, FALSE
); /* might want speed boots */
180 if (u
.uswallow
&& (mtmp
== u
.ustuck
) && is_whirly(mtmp
->data
)) {
181 You("disrupt %s!", mon_nam(mtmp
));
182 pline("A huge hole opens up...");
183 expels(mtmp
, mtmp
->data
, TRUE
);
187 case WAN_SPEED_MONSTER
:
188 if (!resist(mtmp
, otmp
->oclass
, 0, NOTELL
)) {
191 mon_adjust_speed(mtmp
, 1, otmp
);
192 m_dowear(mtmp
, FALSE
); /* might want speed boots */
195 case WAN_UNDEAD_TURNING
:
196 case SPE_TURN_UNDEAD
:
198 if (unturn_dead(mtmp
))
200 if (is_undead(mtmp
->data
) || is_vampshifter(mtmp
)) {
206 if (otyp
== SPE_TURN_UNDEAD
)
207 dmg
= spell_damage_bonus(dmg
);
208 context
.bypasses
= TRUE
; /* for make_corpse() */
209 if (!resist(mtmp
, otmp
->oclass
, dmg
, NOTELL
)) {
211 monflee(mtmp
, 0, FALSE
, TRUE
);
218 if (resists_magm(mtmp
)) {
219 /* magic resistance protects from polymorph traps, so make
220 it guard against involuntary polymorph attacks too... */
221 shieldeff(mtmp
->mx
, mtmp
->my
);
222 } else if (!resist(mtmp
, otmp
->oclass
, 0, NOTELL
)) {
223 /* dropped inventory (due to death by system shock,
224 or loss of wielded weapon and/or worn armor due to
225 limitations of new shape) won't be hit by this zap */
226 for (obj
= mtmp
->minvent
; obj
; obj
= obj
->nobj
)
228 /* natural shapechangers aren't affected by system shock
229 (unless protection from shapechangers is interfering
230 with their metabolism...) */
231 if (mtmp
->cham
== NON_PM
&& !rn2(25)) {
232 if (canseemon(mtmp
)) {
233 pline("%s shudders!", Monnam(mtmp
));
236 /* context.bypasses = TRUE; ## for make_corpse() */
237 /* no corpse after system shock */
239 } else if (newcham(mtmp
, (struct permonst
*) 0,
240 (otyp
!= POT_POLYMORPH
), FALSE
)) {
241 if (!Hallucination
&& canspotmon(mtmp
))
246 case WAN_CANCELLATION
:
247 case SPE_CANCELLATION
:
250 (void) cancel_monst(mtmp
, otmp
, TRUE
, TRUE
, FALSE
);
252 case WAN_TELEPORTATION
:
253 case SPE_TELEPORT_AWAY
:
256 reveal_invis
= !u_teleport_mon(mtmp
, TRUE
);
258 case WAN_MAKE_INVISIBLE
: {
259 int oldinvis
= mtmp
->minvis
;
264 /* format monster's name before altering its visibility */
265 Strcpy(nambuf
, Monnam(mtmp
));
266 mon_set_minvis(mtmp
);
267 if (!oldinvis
&& knowninvisible(mtmp
)) {
268 pline("%s turns transparent!", nambuf
);
274 case SPE_WIZARD_LOCK
:
275 wake
= closeholdingtrap(mtmp
, &learn_it
);
285 wake
= FALSE
; /* don't want immediate counterattack */
286 if (u
.uswallow
&& mtmp
== u
.ustuck
) {
287 if (is_animal(mtmp
->data
)) {
289 You_feel("a sudden rush of air!");
291 pline("%s opens its mouth!", Monnam(mtmp
));
293 expels(mtmp
, mtmp
->data
, TRUE
);
294 /* zap which hits steed will only release saddle if it
295 doesn't hit a holding or falling trap; playability
296 here overrides the more logical target ordering */
297 } else if (openholdingtrap(mtmp
, &learn_it
)) {
299 } else if (openfallingtrap(mtmp
, TRUE
, &learn_it
)) {
300 /* mtmp might now be on the migrating monsters list */
302 } else if ((obj
= which_armor(mtmp
, W_SADDLE
)) != 0) {
305 Sprintf(buf
, "%s %s", s_suffix(Monnam(mtmp
)),
306 distant_name(obj
, xname
));
307 if (cansee(mtmp
->mx
, mtmp
->my
)) {
308 if (!canspotmon(mtmp
))
309 Strcpy(buf
, An(distant_name(obj
, xname
)));
310 pline("%s falls to the %s.", buf
,
311 surface(mtmp
->mx
, mtmp
->my
));
312 } else if (canspotmon(mtmp
)) {
313 pline("%s falls off.", buf
);
315 obj_extract_self(obj
);
316 mdrop_obj(mtmp
, obj
, FALSE
);
320 case SPE_EXTRA_HEALING
:
322 if (mtmp
->data
!= &mons
[PM_PESTILENCE
]) {
323 wake
= FALSE
; /* wakeup() makes the target angry */
324 mtmp
->mhp
+= d(6, otyp
== SPE_EXTRA_HEALING
? 8 : 4);
325 if (mtmp
->mhp
> mtmp
->mhpmax
)
326 mtmp
->mhp
= mtmp
->mhpmax
;
327 if (mtmp
->mblinded
) {
331 if (canseemon(mtmp
)) {
332 if (disguised_mimic
) {
333 if (is_obj_mappear(mtmp
,STRANGE_OBJECT
)) {
334 /* it can do better now */
336 newsym(mtmp
->mx
, mtmp
->my
);
338 mimic_hit_msg(mtmp
, otyp
);
340 pline("%s looks%s better.", Monnam(mtmp
),
341 otyp
== SPE_EXTRA_HEALING
? " much" : "");
343 if (mtmp
->mtame
|| mtmp
->mpeaceful
) {
344 adjalign(Role_if(PM_HEALER
) ? 1 : sgn(u
.ualign
.type
));
346 } else { /* Pestilence */
347 /* Pestilence will always resist; damage is half of 3d{4,8} */
348 (void) resist(mtmp
, otmp
->oclass
,
349 d(3, otyp
== SPE_EXTRA_HEALING
? 8 : 4), TELL
);
352 case WAN_LIGHT
: /* (broken wand) */
353 if (flash_hits_mon(mtmp
, otmp
)) {
358 case WAN_SLEEP
: /* (broken wand) */
359 /* [wakeup() doesn't rouse victims of temporary sleep,
360 so it's okay to leave `wake' set to TRUE here] */
362 if (sleep_monst(mtmp
, d(1 + otmp
->spe
, 12), WAND_CLASS
))
367 case SPE_STONE_TO_FLESH
:
368 if (monsndx(mtmp
->data
) == PM_STONE_GOLEM
) {
369 char *name
= Monnam(mtmp
);
371 /* turn into flesh golem */
372 if (newcham(mtmp
, &mons
[PM_FLESH_GOLEM
], FALSE
, FALSE
)) {
374 pline("%s turns to flesh!", name
);
377 pline("%s looks rather fleshy for a moment.", name
);
385 dmg
= monhp_per_lvl(mtmp
);
388 if (otyp
== SPE_DRAIN_LIFE
)
389 dmg
= spell_damage_bonus(dmg
);
390 if (resists_drli(mtmp
))
391 shieldeff(mtmp
->mx
, mtmp
->my
);
392 else if (!resist(mtmp
, otmp
->oclass
, dmg
, NOTELL
) && mtmp
->mhp
> 0) {
395 if (mtmp
->mhp
<= 0 || mtmp
->mhpmax
<= 0 || mtmp
->m_lev
< 1)
400 pline("%s suddenly seems weaker!", Monnam(mtmp
));
408 impossible("What an interesting effect (%d)", otyp
);
415 if (mtmp
->isshk
&& !*u
.ushops
)
417 } else if (mtmp
->m_ap_type
)
418 seemimic(mtmp
); /* might unblock if mimicing a boulder/door */
420 /* note: bhitpos won't be set if swallowed, but that's okay since
421 * reveal_invis will be false. We can't use mtmp->mx, my since it
422 * might be an invisible worm hit on the tail.
425 if (mtmp
->mhp
> 0 && cansee(bhitpos
.x
, bhitpos
.y
)
426 && !canspotmon(mtmp
))
427 map_invisible(bhitpos
.x
, bhitpos
.y
);
429 /* if effect was observable then discover the wand type provided
430 that the wand itself has been seen */
444 return; /* don't show minvent for long worm tail */
447 for (otmp
= mtmp
->minvent
; otmp
; otmp
= otmp
->nobj
) {
448 otmp
->dknown
= 1; /* treat as "seen" */
449 if (Is_container(otmp
) || otmp
->otyp
== STATUE
) {
451 if (!SchroedingersBox(otmp
))
455 (void) display_minventory(mtmp
, MINV_ALL
| MINV_NOLET
, (char *) 0);
457 pline("%s is not carrying anything%s.", noit_Monnam(mtmp
),
458 (u
.uswallow
&& mtmp
== u
.ustuck
) ? " besides you" : "");
463 * Return the object's physical location. This only makes sense for
464 * objects that are currently on the level (i.e. migrating objects
465 * are nowhere). By default, only things that can be seen (in hero's
466 * inventory, monster's inventory, or on the ground) are reported.
467 * By adding BURIED_TOO and/or CONTAINED_TOO flags, you can also get
468 * the location of buried and contained objects. Note that if an
469 * object is carried by a monster, its reported position may change
470 * from turn to turn. This function returns FALSE if the position
471 * is not available or subject to the constraints above.
474 get_obj_location(obj
, xp
, yp
, locflags
)
479 switch (obj
->where
) {
489 if (obj
->ocarry
->mx
) {
490 *xp
= obj
->ocarry
->mx
;
491 *yp
= obj
->ocarry
->my
;
494 break; /* !mx => migrating monster */
496 if (locflags
& BURIED_TOO
) {
503 if (locflags
& CONTAINED_TOO
)
504 return get_obj_location(obj
->ocontainer
, xp
, yp
, locflags
);
512 get_mon_location(mon
, xp
, yp
, locflags
)
515 int locflags
; /* non-zero means get location even if monster is buried */
517 if (mon
== &youmonst
) {
521 } else if (mon
->mx
> 0 && (!mon
->mburied
|| locflags
)) {
525 } else { /* migrating or buried */
531 /* used by revive() and animate_statue() */
537 struct monst
*mtmp
= (struct monst
*) 0;
538 struct monst
*mtmp2
= (struct monst
*) 0;
541 mtmp2
= get_mtraits(obj
, TRUE
);
543 /* save_mtraits() validated mtmp2->mnum */
544 mtmp2
->data
= &mons
[mtmp2
->mnum
];
545 if (mtmp2
->mhpmax
<= 0 && !is_rider(mtmp2
->data
))
546 return (struct monst
*) 0;
547 mtmp
= makemon(mtmp2
->data
, cc
->x
, cc
->y
,
548 NO_MINVENT
| MM_NOWAIT
| MM_NOCOUNTBIRTH
);
552 /* heal the monster */
553 if (mtmp
->mhpmax
> mtmp2
->mhpmax
&& is_rider(mtmp2
->data
))
554 mtmp2
->mhpmax
= mtmp
->mhpmax
;
555 mtmp2
->mhp
= mtmp2
->mhpmax
;
556 /* Get these ones from mtmp */
557 mtmp2
->minvent
= mtmp
->minvent
; /*redundant*/
558 /* monster ID is available if the monster died in the current
559 game, but will be zero if the corpse was in a bones level
560 (we cleared it when loading bones) */
562 mtmp2
->m_id
= mtmp
->m_id
;
563 /* might be bringing quest leader back to life */
564 if (quest_status
.leader_is_dead
&&
565 /* leader_is_dead implies leader_m_id is valid */
566 mtmp2
->m_id
== quest_status
.leader_m_id
)
567 quest_status
.leader_is_dead
= FALSE
;
569 mtmp2
->mx
= mtmp
->mx
;
570 mtmp2
->my
= mtmp
->my
;
571 mtmp2
->mux
= mtmp
->mux
;
572 mtmp2
->muy
= mtmp
->muy
;
573 mtmp2
->mw
= mtmp
->mw
;
574 mtmp2
->wormno
= mtmp
->wormno
;
575 mtmp2
->misc_worn_check
= mtmp
->misc_worn_check
;
576 mtmp2
->weapon_check
= mtmp
->weapon_check
;
577 mtmp2
->mtrapseen
= mtmp
->mtrapseen
;
578 mtmp2
->mflee
= mtmp
->mflee
;
579 mtmp2
->mburied
= mtmp
->mburied
;
580 mtmp2
->mundetected
= mtmp
->mundetected
;
581 mtmp2
->mfleetim
= mtmp
->mfleetim
;
582 mtmp2
->mlstmv
= mtmp
->mlstmv
;
583 mtmp2
->m_ap_type
= mtmp
->m_ap_type
;
584 /* set these ones explicitly */
590 mtmp2
->msleeping
= 0;
593 /* most cancelled monsters return to normal,
594 but some need to stay cancelled */
595 if (!dmgtype(mtmp2
->data
, AD_SEDU
)
596 && (!SYSOPT_SEDUCE
|| !dmgtype(mtmp2
->data
, AD_SSEX
)))
598 mtmp2
->mcansee
= 1; /* set like in makemon */
602 replmon(mtmp
, mtmp2
);
603 newsym(mtmp2
->mx
, mtmp2
->my
); /* Might now be invisible */
605 /* in case Protection_from_shape_changers is different
606 now than it was when the traits were stored */
613 * get_container_location() returns the following information
614 * about the outermost container:
615 * loc argument gets set to:
616 * OBJ_INVENT if in hero's inventory; return 0.
617 * OBJ_FLOOR if on the floor; return 0.
618 * OBJ_BURIED if buried; return 0.
619 * OBJ_MINVENT if in monster's inventory; return monster.
620 * container_nesting is updated with the nesting depth of the containers
624 get_container_location(obj
, loc
, container_nesting
)
627 int *container_nesting
;
632 if (container_nesting
)
633 *container_nesting
= 0;
634 while (obj
&& obj
->where
== OBJ_CONTAINED
) {
635 if (container_nesting
)
636 *container_nesting
+= 1;
637 obj
= obj
->ocontainer
;
640 *loc
= obj
->where
; /* outermost container's location */
641 if (obj
->where
== OBJ_MINVENT
)
644 return (struct monst
*) 0;
648 * Attempt to revive the given corpse, return the revived monster if
649 * successful. Note: this does NOT use up the corpse if it fails.
652 revive(corpse
, by_hero
)
656 struct monst
*mtmp
= 0;
657 struct permonst
*mptr
;
658 struct obj
*container
;
661 int montype
, container_nesting
= 0;
663 if (corpse
->otyp
!= CORPSE
) {
664 impossible("Attempting to revive %s?", xname(corpse
));
665 return (struct monst
*) 0;
669 if (corpse
->where
!= OBJ_CONTAINED
) {
670 /* only for invent, minvent, or floor */
672 (void) get_obj_location(corpse
, &x
, &y
, 0);
674 /* deal with corpses in [possibly nested] containers */
675 struct monst
*carrier
;
676 int holder
= OBJ_FREE
;
678 container
= corpse
->ocontainer
;
680 get_container_location(container
, &holder
, &container_nesting
);
683 x
= carrier
->mx
, y
= carrier
->my
;
689 (void) get_obj_location(corpse
, &x
, &y
, CONTAINED_TOO
);
692 break; /* x,y are 0 */
696 /* Rules for revival from containers:
697 - the container cannot be locked
698 - the container cannot be heavily nested (>2 is arbitrary)
699 - the container cannot be a statue or bag of holding
700 (except in very rare cases for the latter)
702 (container
&& (container
->olocked
|| container_nesting
> 2
703 || container
->otyp
== STATUE
704 || (container
->otyp
== BAG_OF_HOLDING
&& rn2(40)))))
705 return (struct monst
*) 0;
707 /* record the object's location now that we're sure where it is */
708 corpse
->ox
= x
, corpse
->oy
= y
;
710 /* prepare for the monster */
711 montype
= corpse
->corpsenm
;
712 mptr
= &mons
[montype
];
713 /* [should probably handle recorporealization first; if corpse and
714 ghost are at same location, revived creature shouldn't be bumped
715 to an adjacent spot by ghost which joins with it] */
717 if (enexto(&xy
, x
, y
, mptr
))
721 if (mons
[montype
].mlet
== S_EEL
&& !IS_POOL(levl
[x
][y
].typ
)) {
722 if (by_hero
&& cansee(x
,y
))
723 pline("%s twitches feebly.",
724 upstart(corpse_xname(corpse
, (const char *) 0, CXN_PFX_THE
)));
725 return (struct monst
*) 0;
728 if (cant_revive(&montype
, TRUE
, corpse
)) {
729 /* make a zombie or doppelganger instead */
730 /* note: montype has changed; mptr keeps old value for newcham() */
731 mtmp
= makemon(&mons
[montype
], x
, y
, NO_MINVENT
| MM_NOWAIT
);
733 /* skip ghost handling */
734 if (has_omid(corpse
))
736 if (has_omonst(corpse
))
738 if (mtmp
->cham
== PM_DOPPELGANGER
) {
739 /* change shape to match the corpse */
740 (void) newcham(mtmp
, mptr
, FALSE
, FALSE
);
741 } else if (mtmp
->data
->mlet
== S_ZOMBIE
) {
742 mtmp
->mhp
= mtmp
->mhpmax
= 100;
743 mon_adjust_speed(mtmp
, 2, (struct obj
*) 0); /* MFAST */
746 } else if (has_omonst(corpse
)) {
747 /* use saved traits */
749 mtmp
= montraits(corpse
, &xy
);
750 if (mtmp
&& mtmp
->mtame
&& !mtmp
->isminion
)
751 wary_dog(mtmp
, TRUE
);
753 /* make a new monster */
754 mtmp
= makemon(mptr
, x
, y
, NO_MINVENT
| MM_NOWAIT
| MM_NOCOUNTBIRTH
);
757 return (struct monst
*) 0;
759 /* hiders shouldn't already be re-hidden when they revive */
760 if (mtmp
->mundetected
) {
761 mtmp
->mundetected
= 0;
762 newsym(mtmp
->mx
, mtmp
->my
);
767 /* if this is caused by the hero there might be a shop charge */
769 struct monst
*shkp
= 0;
771 x
= corpse
->ox
, y
= corpse
->oy
;
772 if (costly_spot(x
, y
))
773 shkp
= shop_keeper(*in_rooms(x
, y
, SHOPBASE
));
777 unsigned pfx
= CXN_PFX_THE
;
779 Strcpy(buf
, (corpse
->quan
> 1L) ? "one of " : "");
780 if (carried(corpse
) && !corpse
->unpaid
) {
781 Strcat(buf
, "your ");
784 Strcat(buf
, corpse_xname(corpse
, (const char *) 0, pfx
));
785 pline("%s glows iridescently.", upstart(buf
));
787 /* need some prior description of the corpse since
788 stolen_value() will refer to the object as "it" */
789 pline("A corpse is resuscitated.");
791 /* don't charge for shopkeeper's own corpse if we just revived him */
792 if (shkp
&& mtmp
!= shkp
)
793 (void) stolen_value(corpse
, x
, y
, (boolean
) shkp
->mpeaceful
,
796 /* [we don't give any comparable message about the corpse for
797 the !by_hero case because caller might have already done so] */
800 /* handle recorporealization of an active ghost */
801 if (has_omid(corpse
)) {
806 (void) memcpy((genericptr_t
) &m_id
, (genericptr_t
) OMID(corpse
),
808 ghost
= find_mid(m_id
, FM_FMON
);
809 if (ghost
&& ghost
->data
== &mons
[PM_GHOST
]) {
810 if (canseemon(ghost
))
811 pline("%s is suddenly drawn into its former body!",
813 /* transfer the ghost's inventory along with it */
814 while ((otmp
= ghost
->minvent
) != 0) {
815 obj_extract_self(otmp
);
816 add_to_minv(mtmp
, otmp
);
818 /* tame the revived monster if its ghost was tame */
819 if (ghost
->mtame
&& !mtmp
->mtame
) {
820 if (tamedog(mtmp
, (struct obj
*) 0)) {
821 /* ghost's edog data is ignored */
822 mtmp
->mtame
= ghost
->mtame
;
825 /* was ghost, now alive, it's all very confusing */
827 /* separate ghost monster no longer exists */
833 /* monster retains its name */
834 if (has_oname(corpse
))
835 mtmp
= christen_monst(mtmp
, ONAME(corpse
));
836 /* partially eaten corpse yields wounded monster */
838 mtmp
->mhp
= eaten_stat(mtmp
->mhp
, corpse
);
839 /* track that this monster was revived at least once */
842 /* finally, get rid of the corpse--it's gone now */
843 switch (corpse
->where
) {
848 /* in case MON_AT+enexto for invisible mon */
849 x
= corpse
->ox
, y
= corpse
->oy
;
850 /* not useupf(), which charges */
851 if (corpse
->quan
> 1L)
852 corpse
= splitobj(corpse
, 1L);
857 m_useup(corpse
->ocarry
, corpse
);
860 obj_extract_self(corpse
);
861 obfree(corpse
, (struct obj
*) 0);
875 * Note: generic eggs with corpsenm set to NON_PM will never hatch.
877 if (obj
->otyp
!= EGG
)
879 if (obj
->corpsenm
!= NON_PM
&& !dead_species(obj
->corpsenm
, TRUE
))
880 attach_egg_hatch_timeout(obj
, 0L);
883 /* try to revive all corpses and eggs carried by `mon' */
888 struct obj
*otmp
, *otmp2
;
890 char owner
[BUFSZ
], corpse
[BUFSZ
];
892 int once
= 0, res
= 0;
894 youseeit
= (mon
== &youmonst
) ? TRUE
: canseemon(mon
);
895 otmp2
= (mon
== &youmonst
) ? invent
: mon
->minvent
;
897 while ((otmp
= otmp2
) != 0) {
899 if (otmp
->otyp
== EGG
)
901 if (otmp
->otyp
!= CORPSE
)
903 /* save the name; the object is liable to go away */
906 corpse_xname(otmp
, (const char *) 0, CXN_SINGULAR
));
908 /* for a merged group, only one is revived; should this be fixed? */
909 if ((mtmp2
= revive(otmp
, !context
.mon_moving
)) != 0) {
913 Strcpy(owner
, (mon
== &youmonst
) ? "Your"
914 : s_suffix(Monnam(mon
)));
915 pline("%s %s suddenly comes alive!", owner
, corpse
);
916 } else if (canseemon(mtmp2
))
917 pline("%s suddenly appears!", Amonnam(mtmp2
));
923 /* cancel obj, possibly carried by you or a monster */
926 register struct obj
*obj
;
928 boolean u_ring
= (obj
== uleft
|| obj
== uright
);
929 int otyp
= obj
->otyp
;
932 case RIN_GAIN_STRENGTH
:
933 if ((obj
->owornmask
& W_RING
) && u_ring
) {
934 ABON(A_STR
) -= obj
->spe
;
938 case RIN_GAIN_CONSTITUTION
:
939 if ((obj
->owornmask
& W_RING
) && u_ring
) {
940 ABON(A_CON
) -= obj
->spe
;
945 if ((obj
->owornmask
& W_RING
) && u_ring
) {
946 ABON(A_CHA
) -= obj
->spe
;
950 case RIN_INCREASE_ACCURACY
:
951 if ((obj
->owornmask
& W_RING
) && u_ring
)
952 u
.uhitinc
-= obj
->spe
;
954 case RIN_INCREASE_DAMAGE
:
955 if ((obj
->owornmask
& W_RING
) && u_ring
)
956 u
.udaminc
-= obj
->spe
;
958 case GAUNTLETS_OF_DEXTERITY
:
959 if ((obj
->owornmask
& W_ARMG
) && (obj
== uarmg
)) {
960 ABON(A_DEX
) -= obj
->spe
;
964 case HELM_OF_BRILLIANCE
:
965 if ((obj
->owornmask
& W_ARMH
) && (obj
== uarmh
)) {
966 ABON(A_INT
) -= obj
->spe
;
967 ABON(A_WIS
) -= obj
->spe
;
971 /* case RIN_PROTECTION: not needed */
973 if (objects
[otyp
].oc_magic
974 || (obj
->spe
&& (obj
->oclass
== ARMOR_CLASS
975 || obj
->oclass
== WEAPON_CLASS
|| is_weptool(obj
)))
977 || otyp
== POT_SICKNESS
978 || (otyp
== POT_WATER
&& (obj
->blessed
|| obj
->cursed
))) {
979 if (obj
->spe
!= ((obj
->oclass
== WAND_CLASS
) ? -1 : 0)
980 && otyp
!= WAN_CANCELLATION
/* can't cancel cancellation */
981 && otyp
!= MAGIC_LAMP
/* cancelling doesn't remove djinni */
982 && otyp
!= CANDELABRUM_OF_INVOCATION
) {
983 costly_alteration(obj
, COST_CANCEL
);
984 obj
->spe
= (obj
->oclass
== WAND_CLASS
) ? -1 : 0;
986 switch (obj
->oclass
) {
988 costly_alteration(obj
, COST_CANCEL
);
989 obj
->otyp
= SCR_BLANK_PAPER
;
993 if (otyp
!= SPE_CANCELLATION
&& otyp
!= SPE_NOVEL
994 && otyp
!= SPE_BOOK_OF_THE_DEAD
) {
995 costly_alteration(obj
, COST_CANCEL
);
996 obj
->otyp
= SPE_BLANK_PAPER
;
1000 costly_alteration(obj
,
1003 : obj
->cursed
? COST_UNCURS
: COST_UNBLSS
);
1004 if (otyp
== POT_SICKNESS
|| otyp
== POT_SEE_INVISIBLE
) {
1005 /* sickness is "biologically contaminated" fruit juice;
1006 cancel it and it just becomes fruit juice...
1007 whereas see invisible tastes like "enchanted" fruit
1008 juice, it similarly cancels */
1009 obj
->otyp
= POT_FRUIT_JUICE
;
1011 obj
->otyp
= POT_WATER
;
1012 obj
->odiluted
= 0; /* same as any other water */
1022 /* Remove a positive enchantment or charge from obj,
1023 * possibly carried by you or a monster
1027 register struct obj
*obj
;
1031 /* Is this a charged/enchanted object? */
1033 || (!objects
[obj
->otyp
].oc_charged
&& obj
->oclass
!= WEAPON_CLASS
1034 && obj
->oclass
!= ARMOR_CLASS
&& !is_weptool(obj
))
1037 if (defends(AD_DRLI
, obj
) || defends_when_carried(AD_DRLI
, obj
)
1038 || obj_resists(obj
, 10, 90))
1041 /* Charge for the cost of the object */
1042 costly_alteration(obj
, COST_DRAIN
);
1044 /* Drain the object and any implied effects */
1046 u_ring
= (obj
== uleft
) || (obj
== uright
);
1047 switch (obj
->otyp
) {
1048 case RIN_GAIN_STRENGTH
:
1049 if ((obj
->owornmask
& W_RING
) && u_ring
) {
1054 case RIN_GAIN_CONSTITUTION
:
1055 if ((obj
->owornmask
& W_RING
) && u_ring
) {
1061 if ((obj
->owornmask
& W_RING
) && u_ring
) {
1066 case RIN_INCREASE_ACCURACY
:
1067 if ((obj
->owornmask
& W_RING
) && u_ring
)
1070 case RIN_INCREASE_DAMAGE
:
1071 if ((obj
->owornmask
& W_RING
) && u_ring
)
1074 case HELM_OF_BRILLIANCE
:
1075 if ((obj
->owornmask
& W_ARMH
) && (obj
== uarmh
)) {
1081 case GAUNTLETS_OF_DEXTERITY
:
1082 if ((obj
->owornmask
& W_ARMG
) && (obj
== uarmg
)) {
1087 case RIN_PROTECTION
:
1097 obj_resists(obj
, ochance
, achance
)
1099 int ochance
, achance
; /* percent chance for ordinary objects, artifacts */
1101 if (obj
->otyp
== AMULET_OF_YENDOR
1102 || obj
->otyp
== SPE_BOOK_OF_THE_DEAD
1103 || obj
->otyp
== CANDELABRUM_OF_INVOCATION
1104 || obj
->otyp
== BELL_OF_OPENING
1105 || (obj
->otyp
== CORPSE
&& is_rider(&mons
[obj
->corpsenm
]))) {
1108 int chance
= rn2(100);
1110 return (boolean
) (chance
< (obj
->oartifact
? achance
: ochance
));
1120 if (context
.bypasses
&& obj
->bypass
)
1123 if (obj
->oclass
== WAND_CLASS
)
1124 zap_odds
= 3; /* half-life = 2 zaps */
1125 else if (obj
->cursed
)
1126 zap_odds
= 3; /* half-life = 2 zaps */
1127 else if (obj
->blessed
)
1128 zap_odds
= 12; /* half-life = 8 zaps */
1130 zap_odds
= 8; /* half-life = 6 zaps */
1132 /* adjust for "large" quantities of identical things */
1136 return (boolean
) !rn2(zap_odds
);
1139 /* Use up at least minwt number of things made of material mat.
1140 * There's also a chance that other stuff will be used up. Finally,
1141 * there's a random factor here to keep from always using the stuff
1142 * at the top of the pile.
1145 polyuse(objhdr
, mat
, minwt
)
1149 register struct obj
*otmp
, *otmp2
;
1151 for (otmp
= objhdr
; minwt
> 0 && otmp
; otmp
= otmp2
) {
1152 otmp2
= otmp
->nexthere
;
1153 if (context
.bypasses
&& otmp
->bypass
)
1155 if (otmp
== uball
|| otmp
== uchain
)
1157 if (obj_resists(otmp
, 0, 0))
1158 continue; /* preserve unique objects */
1160 if (otmp
->otyp
== SCR_MAIL
)
1164 if (((int) objects
[otmp
->otyp
].oc_material
== mat
)
1165 == (rn2(minwt
+ 1) != 0)) {
1166 /* appropriately add damage to bill */
1167 if (costly_spot(otmp
->ox
, otmp
->oy
)) {
1169 addtobill(otmp
, FALSE
, FALSE
, FALSE
);
1171 (void) stolen_value(otmp
, otmp
->ox
, otmp
->oy
, FALSE
,
1174 if (otmp
->quan
< LARGEST_INT
)
1175 minwt
-= (int) otmp
->quan
;
1184 * Polymorph some of the stuff in this pile into a monster, preferably
1185 * a golem of the kind okind.
1188 create_polymon(obj
, okind
)
1192 struct permonst
*mdat
= (struct permonst
*) 0;
1194 const char *material
;
1197 if (context
.bypasses
) {
1198 /* this is approximate because the "no golems" !obj->nexthere
1199 check below doesn't understand bypassed objects; but it
1200 should suffice since bypassed objects always end up as a
1201 consecutive group at the top of their pile */
1202 while (obj
&& obj
->bypass
)
1203 obj
= obj
->nexthere
;
1206 /* no golems if you zap only one object -- not enough stuff */
1207 if (!obj
|| (!obj
->nexthere
&& obj
->quan
== 1L))
1210 /* some of these choices are arbitrary */
1215 pm_index
= PM_IRON_GOLEM
;
1216 material
= "metal ";
1223 pm_index
= rn2(2) ? PM_STONE_GOLEM
: PM_CLAY_GOLEM
;
1224 material
= "lithic ";
1228 /* there is no flesh type, but all food is type 0, so we use it */
1229 pm_index
= PM_FLESH_GOLEM
;
1230 material
= "organic ";
1233 pm_index
= PM_WOOD_GOLEM
;
1237 pm_index
= PM_LEATHER_GOLEM
;
1238 material
= "leather ";
1241 pm_index
= PM_ROPE_GOLEM
;
1242 material
= "cloth ";
1245 pm_index
= PM_SKELETON
; /* nearest thing to "bone golem" */
1249 pm_index
= PM_GOLD_GOLEM
;
1253 pm_index
= PM_GLASS_GOLEM
;
1254 material
= "glassy ";
1257 pm_index
= PM_PAPER_GOLEM
;
1258 material
= "paper ";
1261 /* if all else fails... */
1262 pm_index
= PM_STRAW_GOLEM
;
1267 if (!(mvitals
[pm_index
].mvflags
& G_GENOD
))
1268 mdat
= &mons
[pm_index
];
1270 mtmp
= makemon(mdat
, obj
->ox
, obj
->oy
, NO_MM_FLAGS
);
1271 polyuse(obj
, okind
, (int) mons
[pm_index
].cwt
);
1273 if (mtmp
&& cansee(mtmp
->mx
, mtmp
->my
)) {
1274 pline("Some %sobjects meld, and %s arises from the pile!", material
,
1279 /* Assumes obj is on the floor. */
1287 if (obj
->otyp
== SCR_MAIL
)
1292 if (poly_zapped
< 0) {
1293 /* some may metamorphosize */
1294 for (i
= obj
->quan
; i
; i
--)
1295 if (!rn2(Luck
+ 45)) {
1296 poly_zapped
= objects
[obj
->otyp
].oc_material
;
1301 /* if quan > 1 then some will survive intact */
1302 if (obj
->quan
> 1L) {
1303 if (obj
->quan
> LARGEST_INT
)
1304 obj
= splitobj(obj
, (long) rnd(30000));
1306 obj
= splitobj(obj
, (long) rnd((int) obj
->quan
- 1));
1309 /* appropriately add damage to bill */
1310 if (costly_spot(obj
->ox
, obj
->oy
)) {
1312 addtobill(obj
, FALSE
, FALSE
, FALSE
);
1314 (void) stolen_value(obj
, obj
->ox
, obj
->oy
, FALSE
, FALSE
);
1317 /* zap the object */
1321 /* classes of items whose current charge count carries over across polymorph
1323 static const char charged_objs
[] = { WAND_CLASS
, WEAPON_CLASS
, ARMOR_CLASS
,
1327 * Polymorph the object to the given object ID. If the ID is STRANGE_OBJECT
1328 * then pick random object from the source's class (this is the standard
1329 * "polymorph" case). If ID is set to a specific object, inhibit fusing
1330 * n objects into 1. This could have been added as a flag, but currently
1331 * it is tied to not being the standard polymorph case. The new polymorphed
1332 * object replaces obj in its link chains. Return value is a pointer to
1335 * This should be safe to call for an object anywhere.
1344 boolean can_merge
= (id
== STRANGE_OBJECT
);
1345 int obj_location
= obj
->where
;
1347 if (obj
->otyp
== BOULDER
)
1349 if (id
== STRANGE_OBJECT
) { /* preserve symbol */
1351 unsigned magic_obj
= objects
[obj
->otyp
].oc_magic
;
1353 if (obj
->otyp
== UNICORN_HORN
&& obj
->degraded_horn
)
1355 /* Try up to 3 times to make the magic-or-not status of
1356 the new item be the same as it was for the old one. */
1357 otmp
= (struct obj
*) 0;
1361 otmp
= mkobj(obj
->oclass
, FALSE
);
1362 } while (--try_limit
> 0
1363 && objects
[otmp
->otyp
].oc_magic
!= magic_obj
);
1365 /* literally replace obj with this new thing */
1366 otmp
= mksobj(id
, FALSE
, FALSE
);
1367 /* Actually more things use corpsenm but they polymorph differently */
1368 #define USES_CORPSENM(typ) \
1369 ((typ) == CORPSE || (typ) == STATUE || (typ) == FIGURINE)
1371 if (USES_CORPSENM(obj
->otyp
) && USES_CORPSENM(id
))
1372 set_corpsenm(otmp
, obj
->corpsenm
);
1373 #undef USES_CORPSENM
1376 /* preserve quantity */
1377 otmp
->quan
= obj
->quan
;
1378 /* preserve the shopkeepers (lack of) interest */
1379 otmp
->no_charge
= obj
->no_charge
;
1380 /* preserve inventory letter if in inventory */
1381 if (obj_location
== OBJ_INVENT
)
1382 otmp
->invlet
= obj
->invlet
;
1384 /* You can't send yourself 100 mail messages and then
1385 * polymorph them into useful scrolls
1387 if (obj
->otyp
== SCR_MAIL
) {
1388 otmp
->otyp
= SCR_MAIL
;
1393 /* avoid abusing eggs laid by you */
1394 if (obj
->otyp
== EGG
&& obj
->spe
) {
1395 int mnum
, tryct
= 100;
1397 /* first, turn into a generic egg */
1398 if (otmp
->otyp
== EGG
)
1402 otmp
->owt
= weight(otmp
);
1404 otmp
->corpsenm
= NON_PM
;
1407 /* now change it into something laid by the hero */
1409 mnum
= can_be_hatched(random_monster());
1410 if (mnum
!= NON_PM
&& !dead_species(mnum
, TRUE
)) {
1411 otmp
->spe
= 1; /* laid by hero */
1412 set_corpsenm(otmp
, mnum
); /* also sets hatch timer */
1418 /* keep special fields (including charges on wands) */
1419 if (index(charged_objs
, otmp
->oclass
))
1420 otmp
->spe
= obj
->spe
;
1421 otmp
->recharged
= obj
->recharged
;
1423 otmp
->cursed
= obj
->cursed
;
1424 otmp
->blessed
= obj
->blessed
;
1425 otmp
->oeroded
= obj
->oeroded
;
1426 otmp
->oeroded2
= obj
->oeroded2
;
1427 if (!is_flammable(otmp
) && !is_rustprone(otmp
))
1429 if (!is_corrodeable(otmp
) && !is_rottable(otmp
))
1431 if (is_damageable(otmp
))
1432 otmp
->oerodeproof
= obj
->oerodeproof
;
1434 /* Keep chest/box traps and poisoned ammo if we may */
1435 if (obj
->otrapped
&& Is_box(otmp
))
1436 otmp
->otrapped
= TRUE
;
1438 if (obj
->opoisoned
&& is_poisonable(otmp
))
1439 otmp
->opoisoned
= TRUE
;
1441 if (id
== STRANGE_OBJECT
&& obj
->otyp
== CORPSE
) {
1442 /* turn crocodile corpses into shoes */
1443 if (obj
->corpsenm
== PM_CROCODILE
) {
1444 otmp
->otyp
= LOW_BOOTS
;
1445 otmp
->oclass
= ARMOR_CLASS
;
1448 otmp
->oerodeproof
= TRUE
;
1450 otmp
->cursed
= FALSE
;
1454 /* no box contents --KAA */
1455 if (Has_contents(otmp
))
1456 delete_contents(otmp
);
1458 /* 'n' merged objects may be fused into 1 object */
1459 if (otmp
->quan
> 1L && (!objects
[otmp
->otyp
].oc_merge
1460 || (can_merge
&& otmp
->quan
> (long) rn2(1000))))
1463 switch (otmp
->oclass
) {
1465 if (otmp
->otyp
== MAGIC_LAMP
) {
1466 otmp
->otyp
= OIL_LAMP
;
1467 otmp
->age
= 1500L; /* "best" oil lamp possible */
1468 } else if (otmp
->otyp
== MAGIC_MARKER
) {
1469 otmp
->recharged
= 1; /* degraded quality */
1471 /* don't care about the recharge count of other tools */
1475 while (otmp
->otyp
== WAN_WISHING
|| otmp
->otyp
== WAN_POLYMORPH
)
1476 otmp
->otyp
= rnd_class(WAN_LIGHT
, WAN_LIGHTNING
);
1477 /* altering the object tends to degrade its quality
1478 (analogous to spellbook `read count' handling) */
1479 if ((int) otmp
->recharged
< rn2(7)) /* recharge_limit */
1484 while (otmp
->otyp
== POT_POLYMORPH
)
1485 otmp
->otyp
= rnd_class(POT_GAIN_ABILITY
, POT_WATER
);
1489 while (otmp
->otyp
== SPE_POLYMORPH
)
1490 otmp
->otyp
= rnd_class(SPE_DIG
, SPE_BLANK_PAPER
);
1491 /* reduce spellbook abuse; non-blank books degrade */
1492 if (otmp
->otyp
!= SPE_BLANK_PAPER
) {
1493 otmp
->spestudied
= obj
->spestudied
+ 1;
1494 if (otmp
->spestudied
> MAX_SPELL_STUDY
) {
1495 otmp
->otyp
= SPE_BLANK_PAPER
;
1496 /* writing a new book over it will yield an unstudied
1497 one; re-polymorphing this one as-is may or may not
1498 get something non-blank */
1499 otmp
->spestudied
= rn2(otmp
->spestudied
);
1505 if (otmp
->quan
> (long) rnd(4)
1506 && objects
[obj
->otyp
].oc_material
== MINERAL
1507 && objects
[otmp
->otyp
].oc_material
!= MINERAL
) {
1508 otmp
->otyp
= ROCK
; /* transmutation backfired */
1509 otmp
->quan
/= 2L; /* some material has been lost */
1514 /* update the weight */
1515 otmp
->owt
= weight(otmp
);
1517 /* handle polymorph of worn item: stone-to-flesh cast on self can
1518 affect multiple objects at once, but their new forms won't
1519 produce any side-effects; a single worn item dipped into potion
1520 of polymorph can produce side-effects but those won't yield out
1521 of sequence messages because current polymorph is finished */
1522 if (obj_location
== OBJ_INVENT
&& obj
->owornmask
) {
1523 long old_wornmask
= obj
->owornmask
& ~(W_ART
| W_ARTI
),
1524 new_wornmask
= wearslot(otmp
);
1525 boolean was_twohanded
= bimanual(obj
), was_twoweap
= u
.twoweap
;
1527 remove_worn_item(obj
, TRUE
);
1528 /* if the new form can be worn in the same slot, make it so
1529 [possible extension: if it could be worn in some other
1530 slot which is currently unfilled, wear it there instead] */
1531 if ((old_wornmask
& W_QUIVER
) != 0L) {
1533 } else if ((old_wornmask
& W_SWAPWEP
) != 0L) {
1534 if (was_twohanded
|| !bimanual(otmp
))
1536 if (was_twoweap
&& uswapwep
)
1538 } else if ((old_wornmask
& W_WEP
) != 0L) {
1539 if (was_twohanded
|| !bimanual(otmp
) || !uarms
)
1541 if (was_twoweap
&& uwep
&& !bimanual(uwep
))
1543 } else if ((old_wornmask
& new_wornmask
) != 0L) {
1544 new_wornmask
&= old_wornmask
;
1545 setworn(otmp
, new_wornmask
);
1546 set_wear(otmp
); /* Armor_on() for side-effects */
1550 /* ** we are now done adjusting the object ** */
1552 /* swap otmp for obj */
1553 replace_object(obj
, otmp
);
1554 if (obj_location
== OBJ_INVENT
) {
1556 * We may need to do extra adjustments for the hero if we're
1557 * messing with the hero's inventory. The following calls are
1558 * equivalent to calling freeinv on obj and addinv on otmp,
1559 * while doing an in-place swap of the actual objects.
1564 } else if (obj_location
== OBJ_FLOOR
) {
1565 ox
= otmp
->ox
, oy
= otmp
->oy
; /* set by replace_object() */
1566 if (obj
->otyp
== BOULDER
&& otmp
->otyp
!= BOULDER
1567 && !does_block(ox
, oy
, &levl
[ox
][oy
]))
1568 unblock_point(ox
, oy
);
1569 else if (obj
->otyp
!= BOULDER
&& otmp
->otyp
== BOULDER
)
1570 /* (checking does_block() here would be redundant) */
1571 block_point(ox
, oy
);
1574 if ((!carried(otmp
) || obj
->unpaid
)
1575 && get_obj_location(otmp
, &ox
, &oy
, BURIED_TOO
| CONTAINED_TOO
)
1576 && costly_spot(ox
, oy
)) {
1577 register struct monst
*shkp
=
1578 shop_keeper(*in_rooms(ox
, oy
, SHOPBASE
));
1580 if ((!obj
->no_charge
1581 || (Has_contents(obj
)
1582 && (contained_cost(obj
, shkp
, 0L, FALSE
, FALSE
) != 0L)))
1583 && inhishop(shkp
)) {
1584 if (shkp
->mpeaceful
) {
1586 && *in_rooms(u
.ux
, u
.uy
, 0)
1587 == *in_rooms(shkp
->mx
, shkp
->my
, 0)
1588 && !costly_spot(u
.ux
, u
.uy
))
1589 make_angry_shk(shkp
, ox
, oy
);
1591 pline("%s gets angry!", Monnam(shkp
));
1595 Norep("%s is furious!", Monnam(shkp
));
1602 /* stone-to-flesh spell hits and maybe transforms or animates obj */
1604 stone_to_flesh_obj(obj
)
1607 int res
= 1; /* affected object by default */
1608 struct permonst
*ptr
;
1612 boolean smell
= FALSE
, golem_xform
= FALSE
;
1614 if (objects
[obj
->otyp
].oc_material
!= MINERAL
1615 && objects
[obj
->otyp
].oc_material
!= GEMSTONE
)
1617 /* Heart of Ahriman usually resists; ordinary items rarely do */
1618 if (obj_resists(obj
, 2, 98))
1621 (void) get_obj_location(obj
, &oox
, &ooy
, 0);
1622 /* add more if stone objects are added.. */
1623 switch (objects
[obj
->otyp
].oc_class
) {
1624 case ROCK_CLASS
: /* boulders and statues */
1625 case TOOL_CLASS
: /* figurines */
1626 if (obj
->otyp
== BOULDER
) {
1627 obj
= poly_obj(obj
, HUGE_CHUNK_OF_MEAT
);
1629 } else if (obj
->otyp
== STATUE
|| obj
->otyp
== FIGURINE
) {
1630 ptr
= &mons
[obj
->corpsenm
];
1631 if (is_golem(ptr
)) {
1632 golem_xform
= (ptr
!= &mons
[PM_FLESH_GOLEM
]);
1633 } else if (vegetarian(ptr
)) {
1634 /* Don't animate monsters that aren't flesh */
1635 obj
= poly_obj(obj
, MEATBALL
);
1639 if (obj
->otyp
== STATUE
) {
1640 /* animate_statue() forces all golems to become flesh golems
1642 mon
= animate_statue(obj
, oox
, ooy
, ANIMATE_SPELL
, (int *) 0);
1643 } else { /* (obj->otyp == FIGURINE) */
1645 ptr
= &mons
[PM_FLESH_GOLEM
];
1646 mon
= makemon(ptr
, oox
, ooy
, NO_MINVENT
);
1648 if (costly_spot(oox
, ooy
) && !obj
->no_charge
) {
1649 if (costly_spot(u
.ux
, u
.uy
))
1650 addtobill(obj
, carried(obj
), FALSE
, FALSE
);
1652 stolen_value(obj
, oox
, ooy
, TRUE
, FALSE
);
1655 obj_stop_timers(obj
);
1660 if (cansee(mon
->mx
, mon
->my
))
1661 pline_The("figurine %sanimates!",
1662 golem_xform
? "turns to flesh and " : "");
1667 /* this golem handling is redundant... */
1668 if (is_golem(ptr
) && ptr
!= &mons
[PM_FLESH_GOLEM
])
1669 (void) newcham(mon
, &mons
[PM_FLESH_GOLEM
], TRUE
, FALSE
);
1670 } else if ((ptr
->geno
& (G_NOCORPSE
| G_UNIQ
)) != 0) {
1671 /* didn't revive but can't leave corpse either */
1674 /* unlikely to get here since genociding monsters also
1675 sets the G_NOCORPSE flag; drop statue's contents */
1676 while ((item
= obj
->cobj
) != 0) {
1677 bypass_obj(item
); /* make stone-to-flesh miss it */
1678 obj_extract_self(item
);
1679 place_object(item
, oox
, ooy
);
1681 obj
= poly_obj(obj
, CORPSE
);
1683 } else { /* miscellaneous tool or unexpected rock... */
1687 /* maybe add weird things to become? */
1688 case RING_CLASS
: /* some of the rings are stone */
1689 obj
= poly_obj(obj
, MEAT_RING
);
1692 case WAND_CLASS
: /* marble wand */
1693 obj
= poly_obj(obj
, MEAT_STICK
);
1696 case GEM_CLASS
: /* stones & gems */
1697 obj
= poly_obj(obj
, MEATBALL
);
1700 case WEAPON_CLASS
: /* crysknife */
1708 /* non-meat eaters smell meat, meat eaters smell its flavor;
1709 monks are considered non-meat eaters regardless of behavior;
1710 other roles are non-meat eaters if they haven't broken
1711 vegetarian conduct yet (or if poly'd into non-carnivorous/
1712 non-omnivorous form, regardless of whether it's herbivorous,
1713 non-eating, or something stranger) */
1714 if (Role_if(PM_MONK
) || !u
.uconduct
.unvegetarian
1715 || !carnivorous(youmonst
.data
))
1716 Norep("You smell the odor of meat.");
1718 Norep("You smell a delicious smell.");
1725 * Object obj was hit by the effect of the wand/spell otmp. Return
1726 * non-zero if the wand/spell had any effect.
1730 struct obj
*obj
, *otmp
;
1732 int res
= 1; /* affected object by default */
1733 boolean learn_it
= FALSE
, maybelearnit
;
1735 /* fundamental: a wand effect hitting itself doesn't do anything;
1736 otherwise we need to guard against accessing otmp after something
1737 strange has happened to it (along the lines of polymorph or
1738 stone-to-flesh [which aren't good examples since polymorph wands
1739 aren't affected by polymorph zaps and stone-to-flesh isn't
1740 available in wand form, but the concept still applies...]) */
1745 /* The bypass bit is currently only used as follows:
1747 * POLYMORPH - When a monster being polymorphed drops something
1748 * from its inventory as a result of the change.
1749 * If the items fall to the floor, they are not
1750 * subject to direct subsequent polymorphing
1751 * themselves on that same zap. This makes it
1752 * consistent with items that remain in the
1753 * monster's inventory. They are not polymorphed
1755 * UNDEAD_TURNING - When an undead creature gets killed via
1756 * undead turning, prevent its corpse from being
1757 * immediately revived by the same effect.
1758 * STONE_TO_FLESH - If a statue can't be revived, its
1759 * contents get dropped before turning it into
1760 * meat; prevent those contents from being hit.
1761 * retouch_equipment() - bypass flag is used to track which
1762 * items have been handled (bhito isn't involved).
1763 * menu_drop(), askchain() - inventory traversal where multiple
1764 * Drop can alter the invent chain while traversal
1765 * is in progress (bhito isn't involved).
1767 * The bypass bit on all objects is reset each turn, whenever
1768 * context.bypasses is set.
1770 * We check the obj->bypass bit above AND context.bypasses
1771 * as a safeguard against any stray occurrence left in an obj
1772 * struct someplace, although that should never happen.
1774 if (context
.bypasses
) {
1777 debugpline1("%s for a moment.", Tobjnam(obj
, "pulsate"));
1783 * Some parts of this function expect the object to be on the floor
1784 * obj->{ox,oy} to be valid. The exception to this (so far) is
1785 * for the STONE_TO_FLESH spell.
1787 if (!(obj
->where
== OBJ_FLOOR
|| otmp
->otyp
== SPE_STONE_TO_FLESH
))
1788 impossible("bhito: obj is not floor or Stone To Flesh spell");
1792 } else if (obj
== uchain
) {
1793 if (otmp
->otyp
== WAN_OPENING
|| otmp
->otyp
== SPE_KNOCK
) {
1799 switch (otmp
->otyp
) {
1802 if (obj
->otyp
== WAN_POLYMORPH
|| obj
->otyp
== SPE_POLYMORPH
1803 || obj
->otyp
== POT_POLYMORPH
|| obj_resists(obj
, 5, 95)) {
1808 u
.uconduct
.polypiles
++;
1809 /* any saved lock context will be dangerously obsolete */
1811 (void) boxlock(obj
, otmp
);
1813 if (obj_shudders(obj
)) {
1815 ((obj
== level
.objects
[u
.ux
][u
.uy
]) && u
.uundetected
1816 && hides_under(youmonst
.data
));
1818 if (cansee(obj
->ox
, obj
->oy
))
1821 /* eek - your cover might have been blown */
1823 (void) hideunder(&youmonst
);
1826 obj
= poly_obj(obj
, STRANGE_OBJECT
);
1827 newsym(obj
->ox
, obj
->oy
);
1831 /* target object has now been "seen (up close)" */
1833 if (Is_container(obj
) || obj
->otyp
== STATUE
) {
1834 obj
->cknown
= obj
->lknown
= 1;
1836 boolean catbox
= SchroedingersBox(obj
);
1838 /* we don't want to force alive vs dead
1839 determination for Schroedinger's Cat here,
1840 so just make probing be inconclusive for it */
1843 pline("%s empty.", Tobjnam(obj
, catbox
? "seem" : "are"));
1846 /* view contents (not recursively) */
1847 for (o
= obj
->cobj
; o
; o
= o
->nobj
)
1848 o
->dknown
= 1; /* "seen", even if blind */
1849 (void) display_cinventory(obj
);
1857 case SPE_FORCE_BOLT
:
1858 /* learn the type if you see or hear something break
1859 (the sound could be implicit) */
1860 maybelearnit
= cansee(obj
->ox
, obj
->oy
) || !Deaf
;
1861 if (obj
->otyp
== BOULDER
) {
1862 if (cansee(obj
->ox
, obj
->oy
))
1863 pline_The("boulder falls apart.");
1865 You_hear("a crumbling sound.");
1867 } else if (obj
->otyp
== STATUE
) {
1868 if (break_statue(obj
)) {
1869 if (cansee(obj
->ox
, obj
->oy
)) {
1871 pline_The("%s shatters.", rndmonnam(NULL
));
1873 pline_The("statue shatters.");
1875 You_hear("a crumbling sound.");
1878 if (context
.mon_moving
1879 ? !breaks(obj
, obj
->ox
, obj
->oy
)
1880 : !hero_breaks(obj
, obj
->ox
, obj
->oy
, FALSE
))
1881 maybelearnit
= FALSE
; /* nothing broke */
1887 case WAN_CANCELLATION
:
1888 case SPE_CANCELLATION
:
1891 newsym(obj
->ox
, obj
->oy
); /* might change color */
1894 case SPE_DRAIN_LIFE
:
1895 (void) drain_item(obj
);
1897 case WAN_TELEPORTATION
:
1898 case SPE_TELEPORT_AWAY
:
1901 case WAN_MAKE_INVISIBLE
:
1903 case WAN_UNDEAD_TURNING
:
1904 case SPE_TURN_UNDEAD
:
1905 if (obj
->otyp
== EGG
) {
1907 } else if (obj
->otyp
== CORPSE
) {
1908 int corpsenm
= corpse_revive_type(obj
);
1910 res
= !!revive(obj
, TRUE
);
1911 if (res
&& Role_if(PM_HEALER
)) {
1912 if (Hallucination
&& !Deaf
) {
1913 You_hear("the sound of a defibrillator.");
1915 } else if (!Blind
) {
1916 You("observe %s %s change dramatically.",
1917 s_suffix(an(mons
[corpsenm
].mname
)),
1918 nonliving(&mons
[corpsenm
]) ? "motility"
1923 exercise(A_WIS
, TRUE
);
1930 case SPE_WIZARD_LOCK
:
1932 res
= boxlock(obj
, otmp
);
1938 case WAN_SLOW_MONSTER
: /* no effect on objects */
1939 case SPE_SLOW_MONSTER
:
1940 case WAN_SPEED_MONSTER
:
1943 case SPE_EXTRA_HEALING
:
1946 case SPE_STONE_TO_FLESH
:
1947 res
= stone_to_flesh_obj(obj
);
1950 impossible("What an interesting effect (%d)", otmp
->otyp
);
1953 /* if effect was observable then discover the wand type provided
1954 that the wand itself has been seen */
1960 /* returns nonzero if something was hit */
1962 bhitpile(obj
, fhito
, tx
, ty
, zz
)
1964 int FDECL((*fhito
), (OBJ_P
, OBJ_P
));
1968 int hitanything
= 0;
1969 register struct obj
*otmp
, *next_obj
;
1971 if (obj
->otyp
== SPE_FORCE_BOLT
|| obj
->otyp
== WAN_STRIKING
) {
1972 struct trap
*t
= t_at(tx
, ty
);
1974 /* We can't settle for the default calling sequence of
1975 bhito(otmp) -> break_statue(otmp) -> activate_statue_trap(ox,oy)
1976 because that last call might end up operating on our `next_obj'
1977 (below), rather than on the current object, if it happens to
1978 encounter a statue which mustn't become animated. */
1979 if (t
&& t
->ttyp
== STATUE_TRAP
1980 && activate_statue_trap(t
, tx
, ty
, TRUE
))
1985 for (otmp
= level
.objects
[tx
][ty
]; otmp
; otmp
= next_obj
) {
1986 next_obj
= otmp
->nexthere
;
1987 /* for zap downwards, don't hit object poly'd hero is hiding under */
1988 if (zz
> 0 && u
.uundetected
&& otmp
== level
.objects
[u
.ux
][u
.uy
]
1989 && hides_under(youmonst
.data
))
1992 hitanything
+= (*fhito
)(otmp
, obj
);
1994 if (poly_zapped
>= 0)
1995 create_polymon(level
.objects
[tx
][ty
], poly_zapped
);
2001 * zappable - returns 1 if zap is available, 0 otherwise.
2002 * it removes a charge from the wand if zappable.
2003 * added by GAN 11/03/86
2007 register struct obj
*wand
;
2009 if (wand
->spe
< 0 || (wand
->spe
== 0 && rn2(121)))
2012 You("wrest one last charge from the worn-out wand.");
2018 * zapnodir - zaps a NODIR wand/spell.
2019 * added by GAN 11/03/86
2023 register struct obj
*obj
;
2025 boolean known
= FALSE
;
2027 switch (obj
->otyp
) {
2033 if (lightdamage(obj
, TRUE
, 5))
2036 case WAN_SECRET_DOOR_DETECTION
:
2037 case SPE_DETECT_UNSEEN
:
2043 case WAN_CREATE_MONSTER
:
2044 known
= create_critters(rn2(23) ? 1 : rn1(7, 2),
2045 (struct permonst
*) 0, FALSE
);
2049 if (Luck
+ rn2(5) < 0) {
2050 pline("Unfortunately, nothing happens.");
2055 case WAN_ENLIGHTENMENT
:
2057 You_feel("self-knowledgeable...");
2058 display_nhwindow(WIN_MESSAGE
, FALSE
);
2059 enlightenment(MAGICENLIGHTENMENT
, ENL_GAMEINPROGRESS
);
2060 pline_The("feeling subsides.");
2061 exercise(A_WIS
, TRUE
);
2065 if (!objects
[obj
->otyp
].oc_name_known
)
2066 more_experienced(0, 10);
2067 /* effect was observable; discover the wand type provided
2068 that the wand itself has been seen */
2078 otmp
->in_use
= TRUE
; /* in case losehp() is fatal */
2079 pline("%s suddenly explodes!", The(xname(otmp
)));
2080 dmg
= d(otmp
->spe
+ 2, 6);
2081 losehp(Maybe_Half_Phys(dmg
), "exploding wand", KILLED_BY_AN
);
2085 static NEARDATA
const char zap_syms
[] = { WAND_CLASS
, 0 };
2087 /* 'z' command (or 'y' if numbed_pad==-1) */
2091 register struct obj
*obj
;
2094 if (check_capacity((char *) 0))
2096 obj
= getobj(zap_syms
, "zap");
2102 /* zappable addition done by GAN 11/03/86 */
2104 pline1(nothing_happens
);
2105 else if (obj
->cursed
&& !rn2(WAND_BACKFIRE_CHANCE
)) {
2106 backfire(obj
); /* the wand blows up in your face! */
2107 exercise(A_STR
, FALSE
);
2109 } else if (!(objects
[obj
->otyp
].oc_dir
== NODIR
) && !getdir((char *) 0)) {
2111 pline("%s glows and fades.", The(xname(obj
)));
2112 /* make him pay for knowing !NODIR */
2113 } else if (!u
.dx
&& !u
.dy
&& !u
.dz
2114 && !(objects
[obj
->otyp
].oc_dir
== NODIR
)) {
2115 if ((damage
= zapyourself(obj
, TRUE
)) != 0) {
2117 Sprintf(buf
, "zapped %sself with a wand", uhim());
2118 losehp(Maybe_Half_Phys(damage
), buf
, NO_KILLER_PREFIX
);
2121 /* Are we having fun yet?
2122 * weffects -> buzz(obj->otyp) -> zhitm (temple priest) ->
2123 * attack -> hitum -> known_hitum -> ghod_hitsu ->
2124 * buzz(AD_ELEC) -> destroy_item(WAND_CLASS) ->
2125 * useup -> obfree -> dealloc_obj -> free(obj)
2132 if (obj
&& obj
->spe
< 0) {
2133 pline("%s to dust.", Tobjnam(obj
, "turn"));
2136 update_inventory(); /* maybe used a charge */
2141 zapyourself(obj
, ordinary
)
2145 boolean learn_it
= FALSE
;
2148 switch (obj
->otyp
) {
2150 case SPE_FORCE_BOLT
:
2153 shieldeff(u
.ux
, u
.uy
);
2157 You("bash yourself!");
2160 damage
= d(1 + obj
->spe
, 6);
2161 exercise(A_STR
, FALSE
);
2167 if (!Shock_resistance
) {
2168 You("shock yourself!");
2170 exercise(A_CON
, FALSE
);
2172 shieldeff(u
.ux
, u
.uy
);
2173 You("zap yourself, but seem unharmed.");
2174 ugolemeffects(AD_ELEC
, d(12, 6));
2176 destroy_item(WAND_CLASS
, AD_ELEC
);
2177 destroy_item(RING_CLASS
, AD_ELEC
);
2178 (void) flashburn((long) rnd(100));
2182 You("explode a fireball on top of yourself!");
2183 explode(u
.ux
, u
.uy
, 11, d(6, 6), WAND_CLASS
, EXPL_FIERY
);
2188 if (Fire_resistance
) {
2189 shieldeff(u
.ux
, u
.uy
);
2190 You_feel("rather warm.");
2191 ugolemeffects(AD_FIRE
, d(12, 6));
2193 pline("You've set yourself afire!");
2197 (void) burnarmor(&youmonst
);
2198 destroy_item(SCROLL_CLASS
, AD_FIRE
);
2199 destroy_item(POTION_CLASS
, AD_FIRE
);
2200 destroy_item(SPBOOK_CLASS
, AD_FIRE
);
2201 destroy_item(FOOD_CLASS
, AD_FIRE
); /* only slime for now */
2205 case SPE_CONE_OF_COLD
:
2208 if (Cold_resistance
) {
2209 shieldeff(u
.ux
, u
.uy
);
2210 You_feel("a little chill.");
2211 ugolemeffects(AD_COLD
, d(12, 6));
2213 You("imitate a popsicle!");
2216 destroy_item(POTION_CLASS
, AD_COLD
);
2219 case WAN_MAGIC_MISSILE
:
2220 case SPE_MAGIC_MISSILE
:
2223 shieldeff(u
.ux
, u
.uy
);
2224 pline_The("missiles bounce!");
2227 pline("Idiot! You've shot yourself!");
2239 case WAN_CANCELLATION
:
2240 case SPE_CANCELLATION
:
2241 (void) cancel_monst(&youmonst
, obj
, TRUE
, FALSE
, TRUE
);
2244 case SPE_DRAIN_LIFE
:
2245 if (!Drain_resistance
) {
2246 learn_it
= TRUE
; /* (no effect for spells...) */
2247 losexp("life drainage");
2249 damage
= 0; /* No additional damage */
2252 case WAN_MAKE_INVISIBLE
: {
2253 /* have to test before changing HInvis but must change
2254 * HInvis before doing newsym().
2256 int msg
= !Invis
&& !Blind
&& !BInvis
;
2258 if (BInvis
&& uarmc
->otyp
== MUMMY_WRAPPING
) {
2259 /* A mummy wrapping absorbs it and protects you */
2260 You_feel("rather itchy under %s.", yname(uarmc
));
2263 if (ordinary
|| !rn2(10)) { /* permanent */
2264 HInvis
|= FROMOUTSIDE
;
2265 } else { /* temporary */
2266 incr_itimeout(&HInvis
, d(obj
->spe
, 250));
2271 self_invis_message();
2276 case WAN_SPEED_MONSTER
:
2277 if (!(HFast
& INTRINSIC
)) {
2282 Your("quickness feels more natural.");
2283 exercise(A_DEX
, TRUE
);
2285 HFast
|= FROMOUTSIDE
;
2291 if (Sleep_resistance
) {
2292 shieldeff(u
.ux
, u
.uy
);
2293 You("don't feel sleepy!");
2295 pline_The("sleep ray hits you!");
2296 fall_asleep(-rnd(50), TRUE
);
2300 case WAN_SLOW_MONSTER
:
2301 case SPE_SLOW_MONSTER
:
2302 if (HFast
& (TIMEOUT
| INTRINSIC
)) {
2308 case WAN_TELEPORTATION
:
2309 case SPE_TELEPORT_AWAY
:
2311 /* same criteria as when mounted (zap_steed) */
2312 if ((Teleport_control
&& !Stunned
) || !couldsee(u
.ux0
, u
.uy0
)
2313 || distu(u
.ux0
, u
.uy0
) >= 16)
2318 case SPE_FINGER_OF_DEATH
:
2319 if (nonliving(youmonst
.data
) || is_demon(youmonst
.data
)) {
2320 pline((obj
->otyp
== WAN_DEATH
)
2321 ? "The wand shoots an apparently harmless beam at you."
2322 : "You seem no deader than before.");
2326 Sprintf(killer
.name
, "shot %sself with a death ray", uhim());
2327 killer
.format
= NO_KILLER_PREFIX
;
2328 You("irradiate yourself with pure energy!");
2330 /* They might survive with an amulet of life saving */
2333 case WAN_UNDEAD_TURNING
:
2334 case SPE_TURN_UNDEAD
:
2336 (void) unturn_dead(&youmonst
);
2337 if (is_undead(youmonst
.data
)) {
2338 You_feel("frightened and %sstunned.",
2339 Stunned
? "even more " : "");
2340 make_stunned((HStun
& TIMEOUT
) + (long) rnd(30), FALSE
);
2342 You("shudder in dread.");
2345 case SPE_EXTRA_HEALING
:
2346 learn_it
= TRUE
; /* (no effect for spells...) */
2347 healup(d(6, obj
->otyp
== SPE_EXTRA_HEALING
? 8 : 4), 0, FALSE
,
2348 (obj
->otyp
== SPE_EXTRA_HEALING
));
2349 You_feel("%sbetter.", obj
->otyp
== SPE_EXTRA_HEALING
? "much " : "");
2351 case WAN_LIGHT
: /* (broken wand) */
2352 /* assert( !ordinary ); */
2353 damage
= d(obj
->spe
, 25);
2354 case EXPENSIVE_CAMERA
:
2357 damage
= lightdamage(obj
, ordinary
, damage
);
2359 if (flashburn((long) damage
))
2361 damage
= 0; /* reset */
2369 if (u
.utrap
) { /* escape web or bear trap */
2370 (void) openholdingtrap(&youmonst
, &learn_it
);
2373 /* unlock carried boxes */
2374 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
2376 (void) boxlock(otmp
, obj
);
2377 /* trigger previously escaped trapdoor */
2378 (void) openfallingtrap(&youmonst
, TRUE
, &learn_it
);
2382 case SPE_WIZARD_LOCK
:
2384 (void) closeholdingtrap(&youmonst
, &learn_it
);
2389 case SPE_DETECT_UNSEEN
:
2395 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
) {
2397 if (Is_container(otmp
) || otmp
->otyp
== STATUE
) {
2399 if (!SchroedingersBox(otmp
))
2407 case SPE_STONE_TO_FLESH
: {
2408 struct obj
*otmp
, *onxt
;
2411 if (u
.umonnum
== PM_STONE_GOLEM
) {
2413 (void) polymon(PM_FLESH_GOLEM
);
2417 fix_petrification(); /* saved! */
2419 /* but at a cost.. */
2420 for (otmp
= invent
; otmp
; otmp
= onxt
) {
2422 if (bhito(otmp
, obj
))
2426 * It is possible that we can now merge some inventory.
2427 * Do a highly paranoid merge. Restart from the beginning
2432 for (otmp
= invent
; !didmerge
&& otmp
; otmp
= otmp
->nobj
)
2433 for (onxt
= otmp
->nobj
; onxt
; onxt
= onxt
->nobj
)
2434 if (merged(&otmp
, &onxt
)) {
2442 impossible("zapyourself: object %d used?", obj
->otyp
);
2445 /* if effect was observable then discover the wand type provided
2446 that the wand itself has been seen */
2452 /* called when poly'd hero uses breath attack against self */
2455 struct attack
*mattk
;
2457 int dtyp
= 20 + mattk
->adtyp
- 1; /* breath by hero */
2458 const char *fltxt
= flash_types
[dtyp
]; /* blast of <something> */
2460 zhitu(dtyp
, mattk
->damn
, fltxt
, u
.ux
, u
.uy
);
2463 /* light damages hero in gremlin form */
2465 lightdamage(obj
, ordinary
, amt
)
2466 struct obj
*obj
; /* item making light (fake book if spell) */
2467 boolean ordinary
; /* wand/camera zap vs wand destruction */
2468 int amt
; /* pseudo-damage used to determine blindness duration */
2474 if (dmg
&& youmonst
.data
== &mons
[PM_GREMLIN
]) {
2475 /* reduce high values (from destruction of wand with many charges) */
2478 dmg
= 10 + rnd(dmg
- 10);
2481 pline("Ow, that light hurts%c", (dmg
> 2 || u
.mh
<= 5) ? '!' : '.');
2482 /* [composing killer/reason is superfluous here; if fatal, cause
2483 of death will always be "killed while stuck in creature form"] */
2484 if (obj
->oclass
== SCROLL_CLASS
|| obj
->oclass
== SPBOOK_CLASS
)
2485 ordinary
= FALSE
; /* say blasted rather than zapped */
2486 how
= (obj
->oclass
!= SPBOOK_CLASS
)
2487 ? (const char *) ansimpleoname(obj
)
2489 Sprintf(buf
, "%s %sself with %s", ordinary
? "zapped" : "blasted",
2491 /* might rehumanize(); could be fatal, but only for Unchanging */
2492 losehp(Maybe_Half_Phys(dmg
), buf
, NO_KILLER_PREFIX
);
2497 /* light[ning] causes blindness */
2502 if (!resists_blnd(&youmonst
)) {
2503 You(are_blinded_by_the_flash
);
2504 make_blinded(duration
, FALSE
);
2506 Your1(vision_clears
);
2512 /* you've zapped a wand downwards while riding
2513 * Return TRUE if the steed was hit by the wand.
2514 * Return FALSE if the steed was not hit by the wand.
2518 struct obj
*obj
; /* wand or spell */
2520 int steedhit
= FALSE
;
2522 switch (obj
->otyp
) {
2524 * Wands that are allowed to hit the steed
2525 * Carefully test the results of any that are
2526 * moved here from the bottom section.
2529 probe_monster(u
.usteed
);
2533 case WAN_TELEPORTATION
:
2534 case SPE_TELEPORT_AWAY
:
2535 /* you go together */
2537 /* same criteria as when unmounted (zapyourself) */
2538 if ((Teleport_control
&& !Stunned
) || !couldsee(u
.ux0
, u
.uy0
)
2539 || distu(u
.ux0
, u
.uy0
) >= 16)
2544 /* Default processing via bhitm() for these */
2545 case SPE_CURE_SICKNESS
:
2546 case WAN_MAKE_INVISIBLE
:
2547 case WAN_CANCELLATION
:
2548 case SPE_CANCELLATION
:
2552 case SPE_FORCE_BOLT
:
2553 case WAN_SLOW_MONSTER
:
2554 case SPE_SLOW_MONSTER
:
2555 case WAN_SPEED_MONSTER
:
2557 case SPE_EXTRA_HEALING
:
2558 case SPE_DRAIN_LIFE
:
2561 (void) bhitm(u
.usteed
, obj
);
2573 * cancel a monster (possibly the hero). inventory is cancelled only
2574 * if the monster is zapping itself directly, since otherwise the
2575 * effect is too strong. currently non-hero monsters do not zap
2576 * themselves with cancellation.
2579 cancel_monst(mdef
, obj
, youattack
, allow_cancel_kill
, self_cancel
)
2580 register struct monst
*mdef
;
2581 register struct obj
*obj
;
2582 boolean youattack
, allow_cancel_kill
, self_cancel
;
2584 boolean youdefend
= (mdef
== &youmonst
);
2585 static const char writing_vanishes
[] =
2586 "Some writing vanishes from %s head!";
2587 static const char your
[] = "your"; /* should be extern */
2589 if (youdefend
? (!youattack
&& Antimagic
)
2590 : resist(mdef
, obj
->oclass
, 0, NOTELL
))
2591 return FALSE
; /* resisted cancellation */
2593 if (self_cancel
) { /* 1st cancel inventory */
2596 for (otmp
= (youdefend
? invent
: mdef
->minvent
); otmp
;
2600 context
.botl
= 1; /* potential AC change */
2605 /* now handle special cases */
2608 if ((u
.umonnum
== PM_CLAY_GOLEM
) && !Blind
)
2609 pline(writing_vanishes
, your
);
2612 Your("amulet grows hot for a moment, then cools.");
2619 if (is_were(mdef
->data
) && mdef
->data
->mlet
!= S_HUMAN
)
2622 if (mdef
->data
== &mons
[PM_CLAY_GOLEM
]) {
2623 if (canseemon(mdef
))
2624 pline(writing_vanishes
, s_suffix(mon_nam(mdef
)));
2626 if (allow_cancel_kill
) {
2630 monkilled(mdef
, "", AD_SPEL
);
2637 /* you've zapped an immediate type wand up or down */
2640 struct obj
*obj
; /* wand or spell */
2642 boolean striking
= FALSE
, disclose
= FALSE
;
2643 int x
, y
, xx
, yy
, ptmp
;
2649 /* some wands have special effects other than normal bhitpile */
2650 /* drawbridge might change <u.ux,u.uy> */
2651 x
= xx
= u
.ux
; /* <x,y> is zap location */
2652 y
= yy
= u
.uy
; /* <xx,yy> is drawbridge (portcullis) position */
2653 ttmp
= t_at(x
, y
); /* trap if there is one */
2655 switch (obj
->otyp
) {
2659 You("probe towards the %s.", ceiling(x
, y
));
2661 ptmp
+= bhitpile(obj
, bhito
, x
, y
, u
.dz
);
2662 You("probe beneath the %s.", surface(x
, y
));
2663 ptmp
+= display_binventory(x
, y
, TRUE
);
2666 Your("probe reveals nothing.");
2667 return TRUE
; /* we've done our own bhitpile */
2670 /* up or down, but at closed portcullis only */
2671 if (is_db_wall(x
, y
) && find_drawbridge(&xx
, &yy
)) {
2672 open_drawbridge(xx
, yy
);
2674 } else if (u
.dz
> 0 && (x
== xdnstair
&& y
== ydnstair
) &&
2675 /* can't use the stairs down to quest level 2 until
2676 leader "unlocks" them; give feedback if you try */
2677 on_level(&u
.uz
, &qstart_level
) && !ok_to_quest()) {
2678 pline_The("stairs seem to ripple momentarily.");
2681 /* down will release you from bear trap or web */
2682 if (u
.dz
> 0 && u
.utrap
) {
2683 (void) openholdingtrap(&youmonst
, &disclose
);
2684 /* down will trigger trapdoor, hole, or [spiked-] pit */
2685 } else if (u
.dz
> 0 && !u
.utrap
) {
2686 (void) openfallingtrap(&youmonst
, FALSE
, &disclose
);
2690 case SPE_FORCE_BOLT
:
2694 case SPE_WIZARD_LOCK
:
2695 /* down at open bridge or up or down at open portcullis */
2696 if (((levl
[x
][y
].typ
== DRAWBRIDGE_DOWN
)
2698 : (is_drawbridge_wall(x
, y
) >= 0 && !is_db_wall(x
, y
)))
2699 && find_drawbridge(&xx
, &yy
)) {
2701 close_drawbridge(xx
, yy
);
2703 destroy_drawbridge(xx
, yy
);
2705 } else if (striking
&& u
.dz
< 0 && rn2(3) && !Is_airlevel(&u
.uz
)
2706 && !Is_waterlevel(&u
.uz
) && !Underwater
2707 && !Is_qstart(&u
.uz
)) {
2709 /* similar to zap_dig() */
2710 pline("A rock is dislodged from the %s and falls on your %s.",
2711 ceiling(x
, y
), body_part(HEAD
));
2712 dmg
= rnd((uarmh
&& is_metallic(uarmh
)) ? 2 : 6);
2713 losehp(Maybe_Half_Phys(dmg
), "falling rock", KILLED_BY_AN
);
2714 if ((otmp
= mksobj_at(ROCK
, x
, y
, FALSE
, FALSE
)) != 0) {
2715 (void) xname(otmp
); /* set dknown, maybe bknown */
2719 } else if (u
.dz
> 0 && ttmp
) {
2720 if (!striking
&& closeholdingtrap(&youmonst
, &disclose
)) {
2721 ; /* now stuck in web or bear trap */
2722 } else if (striking
&& ttmp
->ttyp
== TRAPDOOR
) {
2723 /* striking transforms trapdoor into hole */
2724 if (Blind
&& !ttmp
->tseen
) {
2725 pline("%s beneath you shatters.", Something
);
2726 } else if (!ttmp
->tseen
) { /* => !Blind */
2727 pline("There's a trapdoor beneath you; it shatters.");
2729 pline("The trapdoor beneath you shatters.");
2735 /* might fall down hole */
2737 } else if (!striking
&& ttmp
->ttyp
== HOLE
) {
2738 /* locking transforms hole into trapdoor */
2739 ttmp
->ttyp
= TRAPDOOR
;
2740 if (Blind
|| !ttmp
->tseen
) {
2741 pline("Some %s swirls beneath you.",
2742 is_ice(x
, y
) ? "frost" : "dust");
2746 pline("A trapdoor appears beneath you.");
2749 /* hadn't fallen down hole; won't fall now */
2753 case SPE_STONE_TO_FLESH
:
2754 if (Is_airlevel(&u
.uz
) || Is_waterlevel(&u
.uz
) || Underwater
2755 || (Is_qstart(&u
.uz
) && u
.dz
< 0)) {
2756 pline1(nothing_happens
);
2757 } else if (u
.dz
< 0) { /* we should do more... */
2758 pline("Blood drips on your %s.", body_part(FACE
));
2759 } else if (u
.dz
> 0 && !OBJ_AT(u
.ux
, u
.uy
)) {
2761 Print this message only if there wasn't an engraving
2762 affected here. If water or ice, act like waterlevel case.
2764 e
= engr_at(u
.ux
, u
.uy
);
2765 if (!(e
&& e
->engr_type
== ENGRAVE
)) {
2766 if (is_pool(u
.ux
, u
.uy
) || is_ice(u
.ux
, u
.uy
))
2767 pline1(nothing_happens
);
2769 pline("Blood %ss %s your %s.",
2770 is_lava(u
.ux
, u
.uy
) ? "boil" : "pool",
2771 Levitation
? "beneath" : "at",
2772 makeplural(body_part(FOOT
)));
2781 /* zapping downward */
2782 (void) bhitpile(obj
, bhito
, x
, y
, u
.dz
);
2784 /* subset of engraving effects; none sets `disclose' */
2785 if ((e
= engr_at(x
, y
)) != 0 && e
->engr_type
!= HEADSTONE
) {
2786 switch (obj
->otyp
) {
2790 make_engr_at(x
, y
, random_engraving(buf
), moves
, (xchar
) 0);
2792 case WAN_CANCELLATION
:
2793 case SPE_CANCELLATION
:
2794 case WAN_MAKE_INVISIBLE
:
2797 case WAN_TELEPORTATION
:
2798 case SPE_TELEPORT_AWAY
:
2801 case SPE_STONE_TO_FLESH
:
2802 if (e
->engr_type
== ENGRAVE
) {
2803 /* only affects things in stone */
2804 pline_The(Hallucination
2805 ? "floor runs like butter!"
2806 : "edges on the floor get smoother.");
2807 wipe_engr_at(x
, y
, d(2, 4), TRUE
);
2811 case SPE_FORCE_BOLT
:
2812 wipe_engr_at(x
, y
, d(2, 4), TRUE
);
2818 } else if (u
.dz
< 0) {
2819 /* zapping upward */
2821 /* game flavor: if you're hiding under "something"
2822 * a zap upward should hit that "something".
2824 if (u
.uundetected
&& hides_under(youmonst
.data
)) {
2826 otmp
= level
.objects
[u
.ux
][u
.uy
];
2829 hitit
= bhito(otmp
, obj
);
2831 (void) hideunder(&youmonst
);
2840 /* used by do_break_wand() was well as by weffects() */
2850 /* if do_osshock() set obj_zapped while polying, give a message now */
2852 You_feel("shuddering vibrations.");
2856 /* called for various wand and spell effects - M. Stephenson */
2861 int otyp
= obj
->otyp
;
2862 boolean disclose
= FALSE
, was_unkn
= !objects
[otyp
].oc_name_known
;
2864 exercise(A_WIS
, TRUE
);
2865 if (u
.usteed
&& (objects
[otyp
].oc_dir
!= NODIR
) && !u
.dx
&& !u
.dy
2866 && (u
.dz
> 0) && zap_steed(obj
)) {
2868 } else if (objects
[otyp
].oc_dir
== IMMEDIATE
) {
2869 zapsetup(); /* reset obj_zapped */
2871 (void) bhitm(u
.ustuck
, obj
);
2872 /* [how about `bhitpile(u.ustuck->minvent)' effect?] */
2874 disclose
= zap_updown(obj
);
2876 (void) bhit(u
.dx
, u
.dy
, rn1(8, 6), ZAPPED_WAND
, bhitm
, bhito
,
2879 zapwrapup(); /* give feedback for obj_zapped */
2881 } else if (objects
[otyp
].oc_dir
== NODIR
) {
2885 /* neither immediate nor directionless */
2887 if (otyp
== WAN_DIGGING
|| otyp
== SPE_DIG
)
2889 else if (otyp
>= SPE_MAGIC_MISSILE
&& otyp
<= SPE_FINGER_OF_DEATH
)
2890 buzz(otyp
- SPE_MAGIC_MISSILE
+ 10, u
.ulevel
/ 2 + 1, u
.ux
, u
.uy
,
2892 else if (otyp
>= WAN_MAGIC_MISSILE
&& otyp
<= WAN_LIGHTNING
)
2893 buzz(otyp
- WAN_MAGIC_MISSILE
,
2894 (otyp
== WAN_MAGIC_MISSILE
) ? 2 : 6, u
.ux
, u
.uy
, u
.dx
, u
.dy
);
2896 impossible("weffects: unexpected spell or wand");
2902 more_experienced(0, 10);
2907 /* augment damage for a spell dased on the hero's intelligence (and level) */
2909 spell_damage_bonus(dmg
)
2910 int dmg
; /* base amount to be adjusted by bonus or penalty */
2912 int intell
= ACURR(A_INT
);
2914 /* Punish low intelligence before low level else low intelligence
2915 gets punished only when high level */
2917 /* -3 penalty, but never reduce combined amount below 1
2918 (if dmg is 0 for some reason, we're careful to leave it there) */
2920 dmg
= (dmg
<= 3) ? 1 : dmg
- 3;
2921 } else if (intell
<= 13 || u
.ulevel
< 5)
2922 ; /* no bonus or penalty; dmg remains same */
2923 else if (intell
<= 18)
2925 else if (intell
<= 24 || u
.ulevel
< 14)
2928 dmg
+= 3; /* Int 25 */
2934 * Generate the to hit bonus for a spell. Based on the hero's skill in
2935 * spell class and dexterity.
2938 spell_hit_bonus(skill
)
2942 int dex
= ACURR(A_DEX
);
2944 switch (P_SKILL(spell_skilltype(skill
))) {
2945 case P_ISRESTRICTED
:
2967 /* Will change when print stuff below removed */
2970 /* Even increment for dextrous heroes (see weapon.c abon) */
2971 hit_bon
+= dex
- 14;
2980 /* force == 0 occurs e.g. with sleep ray */
2981 /* note that large force is usual with wands so that !! would
2982 require information about hand/weapon/wand */
2983 return (const char *) ((force
< 0) ? "?" : (force
<= 4) ? "." : "!");
2987 hit(str
, mtmp
, force
)
2990 const char *force
; /* usually either "." or "!" */
2992 if ((!cansee(bhitpos
.x
, bhitpos
.y
) && !canspotmon(mtmp
)
2993 && !(u
.uswallow
&& mtmp
== u
.ustuck
)) || !flags
.verbose
)
2994 pline("%s %s it.", The(str
), vtense(str
, "hit"));
2996 pline("%s %s %s%s", The(str
), vtense(str
, "hit"),
2997 mon_nam(mtmp
), force
);
3002 register const char *str
;
3003 register struct monst
*mtmp
;
3006 "%s %s %s.", The(str
), vtense(str
, "miss"),
3007 ((cansee(bhitpos
.x
, bhitpos
.y
) || canspotmon(mtmp
)) && flags
.verbose
)
3013 skiprange(range
, skipstart
, skipend
)
3014 int range
, *skipstart
, *skipend
;
3016 int tr
= (range
/ 4);
3017 int tmp
= range
- ((tr
> 0) ? rnd(tr
) : 0);
3019 *skipend
= tmp
- ((tmp
/ 4) * rnd(3));
3020 if (*skipend
>= tmp
)
3025 * Called for the following distance effects:
3026 * when a weapon is thrown (weapon == THROWN_WEAPON)
3027 * when an object is kicked (KICKED_WEAPON)
3028 * when an IMMEDIATE wand is zapped (ZAPPED_WAND)
3029 * when a light beam is flashed (FLASHED_LIGHT)
3030 * when a mirror is applied (INVIS_BEAM)
3031 * A thrown/kicked object falls down at end of its range or when a monster
3032 * is hit. The variable 'bhitpos' is set to the final position of the weapon
3033 * thrown/zapped. The ray of a wand may affect (by calling a provided
3034 * function) several objects and monsters on its path. The return value
3035 * is the monster hit (weapon != ZAPPED_WAND), or a null monster pointer.
3037 * Thrown and kicked objects (THROWN_WEAPON or KICKED_WEAPON) may be
3038 * destroyed and *pobj set to NULL to indicate this.
3040 * Check !u.uswallow before calling bhit().
3041 * This function reveals the absence of a remembered invisible monster in
3042 * necessary cases (throwing or kicking weapons). The presence of a real
3043 * one is revealed for a weapon, but if not a weapon is left up to fhitm().
3046 bhit(ddx
, ddy
, range
, weapon
, fhitm
, fhito
, pobj
)
3047 register int ddx
, ddy
, range
; /* direction and range */
3048 int weapon
; /* see values in hack.h */
3049 int FDECL((*fhitm
), (MONST_P
, OBJ_P
)), /* fns called when mon/obj hit */
3050 FDECL((*fhito
), (OBJ_P
, OBJ_P
));
3051 struct obj
**pobj
; /* object tossed/used, set to NULL
3052 * if object is destroyed */
3055 struct obj
*obj
= *pobj
;
3057 boolean shopdoor
= FALSE
, point_blank
= TRUE
;
3058 boolean in_skip
= FALSE
, allow_skip
= FALSE
;
3059 int skiprange_start
= 0, skiprange_end
= 0, skipcount
= 0;
3061 if (weapon
== KICKED_WEAPON
) {
3062 /* object starts one square in front of player */
3063 bhitpos
.x
= u
.ux
+ ddx
;
3064 bhitpos
.y
= u
.uy
+ ddy
;
3071 if (weapon
== THROWN_WEAPON
&& obj
&& obj
->otyp
== ROCK
) {
3072 skiprange(range
, &skiprange_start
, &skiprange_end
);
3073 allow_skip
= !rn2(3);
3076 if (weapon
== FLASHED_LIGHT
) {
3077 tmp_at(DISP_BEAM
, cmap_to_glyph(S_flashbeam
));
3078 } else if (weapon
!= ZAPPED_WAND
&& weapon
!= INVIS_BEAM
)
3079 tmp_at(DISP_FLASH
, obj_to_glyph(obj
));
3081 while (range
-- > 0) {
3095 if (is_pick(obj
) && inside_shop(x
, y
)
3096 && (mtmp
= shkcatch(obj
, x
, y
))) {
3097 tmp_at(DISP_END
, 0);
3101 typ
= levl
[bhitpos
.x
][bhitpos
.y
].typ
;
3103 /* iron bars will block anything big enough */
3104 if ((weapon
== THROWN_WEAPON
|| weapon
== KICKED_WEAPON
)
3105 && typ
== IRONBARS
&& hits_bars(pobj
, x
- ddx
, y
- ddy
,
3106 bhitpos
.x
, bhitpos
.y
,
3107 point_blank
? 0 : !rn2(5), 1)) {
3108 /* caveat: obj might now be null... */
3115 if (weapon
== ZAPPED_WAND
&& find_drawbridge(&x
, &y
)) {
3116 boolean learn_it
= FALSE
;
3118 switch (obj
->otyp
) {
3121 if (is_db_wall(bhitpos
.x
, bhitpos
.y
)) {
3122 if (cansee(x
, y
) || cansee(bhitpos
.x
, bhitpos
.y
))
3124 open_drawbridge(x
, y
);
3128 case SPE_WIZARD_LOCK
:
3129 if ((cansee(x
, y
) || cansee(bhitpos
.x
, bhitpos
.y
))
3130 && levl
[x
][y
].typ
== DRAWBRIDGE_DOWN
)
3132 close_drawbridge(x
, y
);
3135 case SPE_FORCE_BOLT
:
3136 if (typ
!= DRAWBRIDGE_UP
)
3137 destroy_drawbridge(x
, y
);
3145 mtmp
= m_at(bhitpos
.x
, bhitpos
.y
);
3150 * skiprange_start is only set if this is a thrown rock
3152 if (skiprange_start
&& (range
== skiprange_start
) && allow_skip
) {
3153 if (is_pool(bhitpos
.x
, bhitpos
.y
) && !mtmp
) {
3156 pline("%s %s%s.", Yname2(obj
), otense(obj
, "skip"),
3157 skipcount
? " again" : "");
3159 You_hear("%s skip.", yname(obj
));
3161 } else if (skiprange_start
> skiprange_end
+ 1) {
3166 if (range
<= skiprange_end
) {
3168 if (range
> 3) /* another bounce? */
3169 skiprange(range
, &skiprange_start
, &skiprange_end
);
3170 } else if (mtmp
&& M_IN_WATER(mtmp
->data
)) {
3171 if ((!Blind
&& canseemon(mtmp
)) || sensemon(mtmp
))
3172 pline("%s %s over %s.", Yname2(obj
), otense(obj
, "pass"),
3177 if (mtmp
&& !(in_skip
&& M_IN_WATER(mtmp
->data
))) {
3178 notonhead
= (bhitpos
.x
!= mtmp
->mx
|| bhitpos
.y
!= mtmp
->my
);
3179 if (weapon
== FLASHED_LIGHT
) {
3180 /* FLASHED_LIGHT hitting invisible monster should
3181 pass through instead of stop so we call
3182 flash_hits_mon() directly rather than returning
3183 mtmp back to caller. That allows the flash to
3184 keep on going. Note that we use mtmp->minvis
3185 not canspotmon() because it makes no difference
3186 whether the hero can see the monster or not. */
3188 obj
->ox
= u
.ux
, obj
->oy
= u
.uy
;
3189 (void) flash_hits_mon(mtmp
, obj
);
3191 tmp_at(DISP_END
, 0);
3192 return mtmp
; /* caller will call flash_hits_mon */
3194 } else if (weapon
== INVIS_BEAM
) {
3195 /* Like FLASHED_LIGHT, INVIS_BEAM should continue
3196 through invisible targets; unlike it, we aren't
3197 prepared for multiple hits so just get first one
3198 that's either visible or could see its invisible
3199 self. [No tmp_at() cleanup is needed here.] */
3200 if (!mtmp
->minvis
|| perceives(mtmp
->data
))
3202 } else if (weapon
!= ZAPPED_WAND
) {
3203 /* THROWN_WEAPON, KICKED_WEAPON */
3204 tmp_at(DISP_END
, 0);
3205 if (cansee(bhitpos
.x
, bhitpos
.y
) && !canspotmon(mtmp
))
3206 map_invisible(bhitpos
.x
, bhitpos
.y
);
3210 (*fhitm
)(mtmp
, obj
);
3214 if (weapon
== ZAPPED_WAND
&& obj
->otyp
== WAN_PROBING
3215 && glyph_is_invisible(levl
[bhitpos
.x
][bhitpos
.y
].glyph
)) {
3216 unmap_object(bhitpos
.x
, bhitpos
.y
);
3221 if (bhitpile(obj
, fhito
, bhitpos
.x
, bhitpos
.y
, 0))
3224 if (weapon
== KICKED_WEAPON
3225 && ((obj
->oclass
== COIN_CLASS
3226 && OBJ_AT(bhitpos
.x
, bhitpos
.y
))
3227 || ship_object(obj
, bhitpos
.x
, bhitpos
.y
,
3228 costly_spot(bhitpos
.x
, bhitpos
.y
)))) {
3229 tmp_at(DISP_END
, 0);
3230 return (struct monst
*) 0;
3233 if (weapon
== ZAPPED_WAND
&& (IS_DOOR(typ
) || typ
== SDOOR
)) {
3234 switch (obj
->otyp
) {
3239 case SPE_WIZARD_LOCK
:
3240 case SPE_FORCE_BOLT
:
3241 if (doorlock(obj
, bhitpos
.x
, bhitpos
.y
)) {
3242 if (cansee(bhitpos
.x
, bhitpos
.y
)
3243 || (obj
->otyp
== WAN_STRIKING
&& !Deaf
))
3245 if (levl
[bhitpos
.x
][bhitpos
.y
].doormask
== D_BROKEN
3246 && *in_rooms(bhitpos
.x
, bhitpos
.y
, SHOPBASE
)) {
3248 add_damage(bhitpos
.x
, bhitpos
.y
, 400L);
3254 if (!ZAP_POS(typ
) || closed_door(bhitpos
.x
, bhitpos
.y
)) {
3259 if (weapon
!= ZAPPED_WAND
&& weapon
!= INVIS_BEAM
) {
3260 /* 'I' present but no monster: erase */
3261 /* do this before the tmp_at() */
3262 if (glyph_is_invisible(levl
[bhitpos
.x
][bhitpos
.y
].glyph
)
3264 unmap_object(bhitpos
.x
, bhitpos
.y
);
3267 tmp_at(bhitpos
.x
, bhitpos
.y
);
3269 /* kicked objects fall in pools */
3270 if ((weapon
== KICKED_WEAPON
)
3271 && (is_pool(bhitpos
.x
, bhitpos
.y
)
3272 || is_lava(bhitpos
.x
, bhitpos
.y
)))
3274 if (IS_SINK(typ
) && weapon
!= FLASHED_LIGHT
)
3275 break; /* physical objects fall onto sink */
3277 /* limit range of ball so hero won't make an invalid move */
3278 if (weapon
== THROWN_WEAPON
&& range
> 0
3279 && obj
->otyp
== HEAVY_IRON_BALL
) {
3282 if ((bobj
= sobj_at(BOULDER
, x
, y
)) != 0) {
3284 pline("%s hits %s.", The(distant_name(obj
, xname
)),
3287 } else if (obj
== uball
) {
3288 if (!test_move(x
- ddx
, y
- ddy
, ddx
, ddy
, TEST_MOVE
)) {
3289 /* nb: it didn't hit anything directly */
3291 pline("%s jerks to an abrupt halt.",
3292 The(distant_name(obj
, xname
))); /* lame */
3294 } else if (Sokoban
&& (t
= t_at(x
, y
)) != 0
3295 && (t
->ttyp
== PIT
|| t
->ttyp
== SPIKED_PIT
3296 || t
->ttyp
== HOLE
|| t
->ttyp
== TRAPDOOR
)) {
3297 /* hero falls into the trap, so ball stops */
3303 /* thrown/kicked missile has moved away from its starting spot */
3304 point_blank
= FALSE
; /* affects passing through iron bars */
3307 if (weapon
!= ZAPPED_WAND
&& weapon
!= INVIS_BEAM
)
3308 tmp_at(DISP_END
, 0);
3311 pay_for_damage("destroy", FALSE
);
3313 return (struct monst
*) 0;
3316 /* process thrown boomerang, which travels a curving path...
3317 * A multi-shot volley ought to have all missiles in flight at once,
3318 * but we're called separately for each one. We terminate the volley
3319 * early on a failed catch since continuing to throw after being hit
3320 * is too obviously silly.
3323 boomhit(obj
, dx
, dy
)
3328 int boom
; /* showsym[] index */
3330 boolean counterclockwise
= TRUE
; /* right-handed throw */
3332 /* counterclockwise traversal patterns:
3333 * ..........................54.................................
3334 * ..................43.....6..3....765.........................
3335 * ..........32.....5..2...7...2...8...4....87..................
3336 * .........4..1....6..1...8..1....9...3...9..6.....98..........
3337 * ..21@....5...@...7..@....9@......@12....@...5...@..7.....@9..
3338 * .3...9....6..9....89.....................1..4...1..6....1..8.
3339 * .4...8.....78.............................23....2..5...2...7.
3340 * ..567............................................34....3..6..
3341 * ........................................................45...
3342 * (invert rows for corresponding clockwise patterns)
3347 boom
= counterclockwise
? S_boomleft
: S_boomright
;
3348 for (i
= 0; i
< 8; i
++)
3349 if (xdir
[i
] == dx
&& ydir
[i
] == dy
)
3351 tmp_at(DISP_FLASH
, cmap_to_glyph(boom
));
3352 for (ct
= 0; ct
< 10; ct
++) {
3353 i
= (i
+ 8) % 8; /* 0..7 (8 -> 0, -1 -> 7) */
3354 boom
= (S_boomleft
+ S_boomright
- boom
); /* toggle */
3355 tmp_at(DISP_CHANGE
, cmap_to_glyph(boom
)); /* change glyph */
3360 if ((mtmp
= m_at(bhitpos
.x
, bhitpos
.y
)) != 0) {
3362 tmp_at(DISP_END
, 0);
3365 if (!ZAP_POS(levl
[bhitpos
.x
][bhitpos
.y
].typ
)
3366 || closed_door(bhitpos
.x
, bhitpos
.y
)) {
3371 if (bhitpos
.x
== u
.ux
&& bhitpos
.y
== u
.uy
) { /* ct == 9 */
3372 if (Fumbling
|| rn2(20) >= ACURR(A_DEX
)) {
3373 /* we hit ourselves */
3374 (void) thitu(10 + obj
->spe
, dmgval(obj
, &youmonst
), obj
,
3378 } else { /* we catch it */
3379 tmp_at(DISP_END
, 0);
3380 You("skillfully catch the boomerang.");
3384 tmp_at(bhitpos
.x
, bhitpos
.y
);
3386 if (IS_SINK(levl
[bhitpos
.x
][bhitpos
.y
].typ
)) {
3389 break; /* boomerang falls on sink */
3391 /* ct==0, initial position, we want next delta to be same;
3392 ct==5, opposite position, repeat delta undoes first one */
3394 i
+= (counterclockwise
? -1 : 1);
3396 tmp_at(DISP_END
, 0); /* do not leave last symbol */
3397 return (struct monst
*) 0;
3400 /* used by buzz(); also used by munslime(muse.c); returns damage to mon */
3402 zhitm(mon
, type
, nd
, ootmp
)
3403 register struct monst
*mon
;
3404 register int type
, nd
;
3405 struct obj
**ootmp
; /* to return worn armor for caller to disintegrate */
3407 register int tmp
= 0;
3408 register int abstype
= abs(type
) % 10;
3409 boolean sho_shieldeff
= FALSE
;
3410 boolean spellcaster
= is_hero_spell(type
); /* maybe get a bonus! */
3412 *ootmp
= (struct obj
*) 0;
3414 case ZT_MAGIC_MISSILE
:
3415 if (resists_magm(mon
)) {
3416 sho_shieldeff
= TRUE
;
3421 tmp
= spell_damage_bonus(tmp
);
3424 if (resists_fire(mon
)) {
3425 sho_shieldeff
= TRUE
;
3429 if (resists_cold(mon
))
3432 tmp
= spell_damage_bonus(tmp
);
3433 if (burnarmor(mon
)) {
3435 (void) destroy_mitem(mon
, POTION_CLASS
, AD_FIRE
);
3437 (void) destroy_mitem(mon
, SCROLL_CLASS
, AD_FIRE
);
3439 (void) destroy_mitem(mon
, SPBOOK_CLASS
, AD_FIRE
);
3440 destroy_mitem(mon
, FOOD_CLASS
, AD_FIRE
); /* carried slime */
3444 if (resists_cold(mon
)) {
3445 sho_shieldeff
= TRUE
;
3449 if (resists_fire(mon
))
3452 tmp
= spell_damage_bonus(tmp
);
3454 (void) destroy_mitem(mon
, POTION_CLASS
, AD_COLD
);
3458 (void) sleep_monst(mon
, d(nd
, 25),
3459 type
== ZT_WAND(ZT_SLEEP
) ? WAND_CLASS
: '\0');
3461 case ZT_DEATH
: /* death/disintegration */
3462 if (abs(type
) != ZT_BREATH(ZT_DEATH
)) { /* death */
3463 if (mon
->data
== &mons
[PM_DEATH
]) {
3464 mon
->mhpmax
+= mon
->mhpmax
/ 2;
3465 if (mon
->mhpmax
>= MAGIC_COOKIE
)
3466 mon
->mhpmax
= MAGIC_COOKIE
- 1;
3467 mon
->mhp
= mon
->mhpmax
;
3471 if (nonliving(mon
->data
) || is_demon(mon
->data
)
3472 || is_vampshifter(mon
) || resists_magm(mon
)) {
3473 /* similar to player */
3474 sho_shieldeff
= TRUE
;
3477 type
= -1; /* so they don't get saving throws */
3481 if (resists_disint(mon
)) {
3482 sho_shieldeff
= TRUE
;
3483 } else if (mon
->misc_worn_check
& W_ARMS
) {
3484 /* destroy shield; victim survives */
3485 *ootmp
= which_armor(mon
, W_ARMS
);
3486 } else if (mon
->misc_worn_check
& W_ARM
) {
3487 /* destroy body armor, also cloak if present */
3488 *ootmp
= which_armor(mon
, W_ARM
);
3489 if ((otmp2
= which_armor(mon
, W_ARMC
)) != 0)
3490 m_useup(mon
, otmp2
);
3492 /* no body armor, victim dies; destroy cloak
3493 and shirt now in case target gets life-saved */
3495 if ((otmp2
= which_armor(mon
, W_ARMC
)) != 0)
3496 m_useup(mon
, otmp2
);
3497 if ((otmp2
= which_armor(mon
, W_ARMU
)) != 0)
3498 m_useup(mon
, otmp2
);
3500 type
= -1; /* no saving throw wanted */
3501 break; /* not ordinary damage */
3506 if (resists_elec(mon
)) {
3507 sho_shieldeff
= TRUE
;
3509 /* can still blind the monster */
3513 tmp
= spell_damage_bonus(tmp
);
3514 if (!resists_blnd(mon
)
3515 && !(type
> 0 && u
.uswallow
&& mon
== u
.ustuck
)) {
3516 register unsigned rnd_tmp
= rnd(50);
3518 if ((mon
->mblinded
+ rnd_tmp
) > 127)
3519 mon
->mblinded
= 127;
3521 mon
->mblinded
+= rnd_tmp
;
3524 (void) destroy_mitem(mon
, WAND_CLASS
, AD_ELEC
);
3525 /* not actually possible yet */
3527 (void) destroy_mitem(mon
, RING_CLASS
, AD_ELEC
);
3530 if (resists_poison(mon
)) {
3531 sho_shieldeff
= TRUE
;
3537 if (resists_acid(mon
)) {
3538 sho_shieldeff
= TRUE
;
3543 acid_damage(MON_WEP(mon
));
3545 erode_armor(mon
, ERODE_CORRODE
);
3549 shieldeff(mon
->mx
, mon
->my
);
3550 if (is_hero_spell(type
) && (Role_if(PM_KNIGHT
) && u
.uhave
.questart
))
3552 if (tmp
> 0 && type
>= 0
3553 && resist(mon
, type
< ZT_SPELL(0) ? WAND_CLASS
: '\0', 0, NOTELL
))
3556 tmp
= 0; /* don't allow negative damage */
3557 debugpline3("zapped monster hp = %d (= %d - %d)", mon
->mhp
- tmp
,
3564 zhitu(type
, nd
, fltxt
, sx
, sy
)
3569 int dam
= 0, abstyp
= abs(type
);
3571 switch (abstyp
% 10) {
3572 case ZT_MAGIC_MISSILE
:
3575 pline_The("missiles bounce off!");
3578 exercise(A_STR
, FALSE
);
3582 if (Fire_resistance
) {
3584 You("don't feel hot!");
3585 ugolemeffects(AD_FIRE
, d(nd
, 6));
3590 if (burnarmor(&youmonst
)) { /* "body hit" */
3592 destroy_item(POTION_CLASS
, AD_FIRE
);
3594 destroy_item(SCROLL_CLASS
, AD_FIRE
);
3596 destroy_item(SPBOOK_CLASS
, AD_FIRE
);
3597 destroy_item(FOOD_CLASS
, AD_FIRE
);
3601 if (Cold_resistance
) {
3603 You("don't feel cold.");
3604 ugolemeffects(AD_COLD
, d(nd
, 6));
3609 destroy_item(POTION_CLASS
, AD_COLD
);
3612 if (Sleep_resistance
) {
3613 shieldeff(u
.ux
, u
.uy
);
3614 You("don't feel sleepy.");
3616 fall_asleep(-d(nd
, 25), TRUE
); /* sleep ray */
3620 if (abstyp
== ZT_BREATH(ZT_DEATH
)) {
3621 if (Disint_resistance
) {
3622 You("are not disintegrated.");
3625 /* destroy shield; other possessions are safe */
3626 (void) destroy_arm(uarms
);
3629 /* destroy suit; if present, cloak goes too */
3631 (void) destroy_arm(uarmc
);
3632 (void) destroy_arm(uarm
);
3635 /* no shield or suit, you're dead; wipe out cloak
3636 and/or shirt in case of life-saving or bones */
3638 (void) destroy_arm(uarmc
);
3640 (void) destroy_arm(uarmu
);
3641 } else if (nonliving(youmonst
.data
) || is_demon(youmonst
.data
)) {
3643 You("seem unaffected.");
3645 } else if (Antimagic
) {
3647 You("aren't affected.");
3650 killer
.format
= KILLED_BY_AN
;
3651 Strcpy(killer
.name
, fltxt
? fltxt
: "");
3652 /* when killed by disintegration breath, don't leave corpse */
3653 u
.ugrave_arise
= (type
== -ZT_BREATH(ZT_DEATH
)) ? -3 : NON_PM
;
3655 return; /* lifesaved */
3657 if (Shock_resistance
) {
3659 You("aren't affected.");
3660 ugolemeffects(AD_ELEC
, d(nd
, 6));
3663 exercise(A_CON
, FALSE
);
3666 destroy_item(WAND_CLASS
, AD_ELEC
);
3668 destroy_item(RING_CLASS
, AD_ELEC
);
3671 poisoned("blast", A_DEX
, "poisoned blast", 15, FALSE
);
3674 if (Acid_resistance
) {
3675 pline_The("acid doesn't hurt.");
3678 pline_The("acid burns!");
3680 exercise(A_STR
, FALSE
);
3682 /* using two weapons at once makes both of them more vulnerable */
3683 if (!rn2(u
.twoweap
? 3 : 6))
3685 if (u
.twoweap
&& !rn2(3))
3686 acid_damage(uswapwep
);
3688 erode_armor(&youmonst
, ERODE_CORRODE
);
3692 /* Half_spell_damage protection yields half-damage for wands & spells,
3693 including hero's own ricochets; breath attacks do full damage */
3694 if (dam
&& Half_spell_damage
&& !(abstyp
>= 20 && abstyp
<= 29))
3695 dam
= (dam
+ 1) / 2;
3696 losehp(dam
, fltxt
, KILLED_BY_AN
);
3701 * burn objects (such as scrolls and spellbooks) on floor
3702 * at position x,y; return the number of objects burned
3705 burn_floor_objects(x
, y
, give_feedback
, u_caused
)
3707 boolean give_feedback
; /* caller needs to decide about visibility checks */
3710 struct obj
*obj
, *obj2
;
3711 long i
, scrquan
, delquan
;
3712 char buf1
[BUFSZ
], buf2
[BUFSZ
];
3715 for (obj
= level
.objects
[x
][y
]; obj
; obj
= obj2
) {
3716 obj2
= obj
->nexthere
;
3717 if (obj
->oclass
== SCROLL_CLASS
|| obj
->oclass
== SPBOOK_CLASS
3718 || (obj
->oclass
== FOOD_CLASS
3719 && obj
->otyp
== GLOB_OF_GREEN_SLIME
)) {
3720 if (obj
->otyp
== SCR_FIRE
|| obj
->otyp
== SPE_FIREBALL
3721 || obj_resists(obj
, 2, 100))
3723 scrquan
= obj
->quan
; /* number present */
3724 delquan
= 0L; /* number to destroy */
3725 for (i
= scrquan
; i
> 0L; i
--)
3729 /* save name before potential delobj() */
3730 if (give_feedback
) {
3732 Strcpy(buf1
, (x
== u
.ux
&& y
== u
.uy
)
3734 : distant_name(obj
, xname
));
3736 Strcpy(buf2
, (x
== u
.ux
&& y
== u
.uy
)
3738 : distant_name(obj
, xname
));
3739 obj
->quan
= scrquan
;
3741 /* useupf(), which charges, only if hero caused damage */
3743 useupf(obj
, delquan
);
3744 else if (delquan
< scrquan
)
3745 obj
->quan
-= delquan
;
3749 if (give_feedback
) {
3751 pline("%ld %s burn.", delquan
, buf2
);
3753 pline("%s burns.", An(buf1
));
3761 /* will zap/spell/breath attack score a hit against armor class `ac'? */
3765 int type
; /* either hero cast spell type or 0 */
3767 int chance
= rn2(20);
3768 int spell_bonus
= type
? spell_hit_bonus(type
) : 0;
3770 /* small chance for naked target to avoid being hit */
3772 return rnd(10) < ac
+ spell_bonus
;
3774 /* very high armor protection does not achieve invulnerability */
3777 return (3 - chance
< ac
+ spell_bonus
);
3781 disintegrate_mon(mon
, type
, fltxt
)
3783 int type
; /* hero vs other */
3786 struct obj
*otmp
, *otmp2
, *m_amulet
= mlifesaver(mon
);
3788 if (canseemon(mon
)) {
3790 pline("%s is disintegrated!", Monnam(mon
));
3792 hit(fltxt
, mon
, "!");
3795 /* note: worn amulet of life saving must be preserved in order to operate */
3796 #define oresist_disintegration(obj) \
3797 (objects[obj->otyp].oc_oprop == DISINT_RES || obj_resists(obj, 5, 50) \
3798 || is_quest_artifact(obj) || obj == m_amulet)
3800 for (otmp
= mon
->minvent
; otmp
; otmp
= otmp2
) {
3802 if (!oresist_disintegration(otmp
)) {
3803 if (otmp
->owornmask
) {
3804 /* in case monster's life gets saved */
3805 mon
->misc_worn_check
&= ~otmp
->owornmask
;
3806 if (otmp
->owornmask
& W_WEP
)
3807 setmnotwielded(mon
, otmp
);
3808 /* also dismounts hero if this object is steed's saddle */
3809 update_mon_intrinsics(mon
, otmp
, FALSE
, TRUE
);
3810 otmp
->owornmask
= 0L;
3812 obj_extract_self(otmp
);
3813 obfree(otmp
, (struct obj
*) 0);
3817 #undef oresist_disintegration
3820 monkilled(mon
, (char *) 0, -AD_RBRE
);
3826 * type == 0 to 9 : you shooting a wand
3827 * type == 10 to 19 : you casting a spell
3828 * type == 20 to 29 : you breathing as a monster
3829 * type == -10 to -19 : monster casting spell
3830 * type == -20 to -29 : monster breathing at you
3831 * type == -30 to -39 : monster shooting a wand
3832 * called with dx = dy = 0 with vertical bolts
3835 buzz(type
, nd
, sx
, sy
, dx
, dy
)
3836 register int type
, nd
;
3837 register xchar sx
, sy
;
3838 register int dx
, dy
;
3840 int range
, abstype
= abs(type
) % 10;
3842 register xchar lsx
, lsy
;
3845 boolean shopdamage
= FALSE
;
3850 /* if its a Hero Spell then get its SPE_TYPE */
3851 spell_type
= is_hero_spell(type
) ? SPE_MAGIC_MISSILE
+ abstype
: 0;
3853 fltxt
= flash_types
[(type
<= -30) ? abstype
: abs(type
)];
3859 tmp
= zhitm(u
.ustuck
, type
, nd
, &otmp
);
3863 pline("%s rips into %s%s", The(fltxt
), mon_nam(u
.ustuck
),
3865 /* Using disintegration from the inside only makes a hole... */
3866 if (tmp
== MAGIC_COOKIE
)
3868 if (u
.ustuck
->mhp
< 1)
3875 if (dx
== 0 && dy
== 0)
3877 save_bhitpos
= bhitpos
;
3879 tmp_at(DISP_BEAM
, zapdir_to_glyph(dx
, dy
, abstype
));
3880 while (range
-- > 0) {
3885 if (isok(sx
, sy
) && (lev
= &levl
[sx
][sy
])->typ
) {
3887 if (cansee(sx
, sy
)) {
3888 /* reveal/unreveal invisible monsters before tmp_at() */
3889 if (mon
&& !canspotmon(mon
))
3890 map_invisible(sx
, sy
);
3891 else if (!mon
&& glyph_is_invisible(levl
[sx
][sy
].glyph
)) {
3892 unmap_object(sx
, sy
);
3895 if (ZAP_POS(lev
->typ
) || (isok(lsx
, lsy
) && cansee(lsx
, lsy
)))
3897 delay_output(); /* wait a little */
3902 /* hit() and miss() need bhitpos to match the target */
3903 bhitpos
.x
= sx
, bhitpos
.y
= sy
;
3904 /* Fireballs only damage when they explode */
3905 if (type
!= ZT_SPELL(ZT_FIRE
))
3906 range
+= zap_over_floor(sx
, sy
, type
, &shopdamage
, 0);
3909 if (type
== ZT_SPELL(ZT_FIRE
))
3912 mon
->mstrategy
&= ~STRAT_WAITMASK
;
3914 if (zap_hit(find_mac(mon
), spell_type
)) {
3915 if (mon_reflects(mon
, (char *) 0)) {
3916 if (cansee(mon
->mx
, mon
->my
)) {
3917 hit(fltxt
, mon
, exclam(0));
3918 shieldeff(mon
->mx
, mon
->my
);
3919 (void) mon_reflects(mon
,
3920 "But it reflects from %s %s!");
3925 boolean mon_could_move
= mon
->mcanmove
;
3926 int tmp
= zhitm(mon
, type
, nd
, &otmp
);
3928 if (is_rider(mon
->data
)
3929 && abs(type
) == ZT_BREATH(ZT_DEATH
)) {
3930 if (canseemon(mon
)) {
3931 hit(fltxt
, mon
, ".");
3932 pline("%s disintegrates.", Monnam(mon
));
3933 pline("%s body reintegrates before your %s!",
3934 s_suffix(Monnam(mon
)),
3935 (eyecount(youmonst
.data
) == 1)
3937 : makeplural(body_part(EYE
)));
3938 pline("%s resurrects!", Monnam(mon
));
3940 mon
->mhp
= mon
->mhpmax
;
3941 break; /* Out of while loop */
3943 if (mon
->data
== &mons
[PM_DEATH
] && abstype
== ZT_DEATH
) {
3944 if (canseemon(mon
)) {
3945 hit(fltxt
, mon
, ".");
3946 pline("%s absorbs the deadly %s!", Monnam(mon
),
3947 type
== ZT_BREATH(ZT_DEATH
) ? "blast"
3949 pline("It seems even stronger than before.");
3951 break; /* Out of while loop */
3954 if (tmp
== MAGIC_COOKIE
) { /* disintegration */
3955 disintegrate_mon(mon
, type
, fltxt
);
3956 } else if (mon
->mhp
< 1) {
3958 monkilled(mon
, fltxt
, AD_RBRE
);
3963 /* normal non-fatal hit */
3964 hit(fltxt
, mon
, exclam(tmp
));
3966 /* some armor was destroyed; no damage done */
3968 pline("%s %s is disintegrated!",
3969 s_suffix(Monnam(mon
)),
3970 distant_name(otmp
, xname
));
3973 if (mon_could_move
&& !mon
->mcanmove
) /* ZT_SLEEP */
3981 } else if (sx
== u
.ux
&& sy
== u
.uy
&& range
>= 0) {
3983 if (u
.usteed
&& !rn2(3) && !mon_reflects(u
.usteed
, (char *) 0)) {
3986 } else if (zap_hit((int) u
.uac
, 0)) {
3988 pline("%s hits you!", The(fltxt
));
3991 (void) ureflects("But %s reflects from your %s!",
3994 pline("For some reason you are not affected.");
3999 zhitu(type
, nd
, fltxt
, sx
, sy
);
4001 } else if (!Blind
) {
4002 pline("%s whizzes by you!", The(fltxt
));
4003 } else if (abstype
== ZT_LIGHTNING
) {
4004 Your("%s tingles.", body_part(ARM
));
4006 if (abstype
== ZT_LIGHTNING
)
4007 (void) flashburn((long) d(nd
, 50));
4012 if (!ZAP_POS(lev
->typ
) || (closed_door(sx
, sy
) && (range
>= 0))) {
4017 if (type
== ZT_SPELL(ZT_FIRE
)) {
4020 break; /* fireballs explode before the wall */
4024 if (range
&& isok(lsx
, lsy
) && cansee(lsx
, lsy
)) {
4025 pline("%s %s!", The(fltxt
),
4027 ? "vanishes into the aether"
4029 if (Is_airlevel(&u
.uz
)) goto get_out_buzz
;
4031 if (!dx
|| !dy
|| !rn2(20)) {
4035 if (isok(sx
, lsy
) && ZAP_POS(rmn
= levl
[sx
][lsy
].typ
)
4036 && !closed_door(sx
, lsy
)
4037 && (IS_ROOM(rmn
) || (isok(sx
+ dx
, lsy
)
4038 && ZAP_POS(levl
[sx
+ dx
][lsy
].typ
))))
4040 if (isok(lsx
, sy
) && ZAP_POS(rmn
= levl
[lsx
][sy
].typ
)
4041 && !closed_door(lsx
, sy
)
4042 && (IS_ROOM(rmn
) || (isok(lsx
, sy
+ dy
)
4043 && ZAP_POS(levl
[lsx
][sy
+ dy
].typ
))))
4044 if (!bounce
|| rn2(2))
4049 dx
= -dx
; /* fall into... */
4057 tmp_at(DISP_CHANGE
, zapdir_to_glyph(dx
, dy
, abstype
));
4061 tmp_at(DISP_END
, 0);
4062 if (type
== ZT_SPELL(ZT_FIRE
))
4063 explode(sx
, sy
, type
, d(12, 6), 0, EXPL_FIERY
);
4066 pay_for_damage(abstype
== ZT_FIRE
4068 : abstype
== ZT_COLD
4070 /* "damage" indicates wall rather than door */
4071 : abstype
== ZT_ACID
4073 : abstype
== ZT_DEATH
4077 bhitpos
= save_bhitpos
;
4085 struct rm
*lev
= &levl
[x
][y
];
4089 msg
= "The ice crackles and melts.";
4090 if (lev
->typ
== DRAWBRIDGE_UP
) {
4091 lev
->drawbridgemask
&= ~DB_ICE
; /* revert to DB_MOAT */
4092 } else { /* lev->typ == ICE */
4094 if (lev
->icedpool
== ICED_POOL
)
4099 lev
->typ
= (lev
->icedpool
== ICED_POOL
? POOL
: MOAT
);
4103 spot_stop_timers(x
, y
, MELT_ICE_AWAY
); /* no more ice to melt away */
4104 obj_ice_effects(x
, y
, FALSE
);
4111 if ((otmp
= sobj_at(BOULDER
, x
, y
)) != 0) {
4113 pline("%s settles...", An(xname(otmp
)));
4115 obj_extract_self(otmp
); /* boulder isn't being pushed */
4116 if (!boulder_hits_pool(otmp
, x
, y
, FALSE
))
4117 impossible("melt_ice: no pool?");
4118 /* try again if there's another boulder and pool didn't fill */
4119 } while (is_pool(x
, y
) && (otmp
= sobj_at(BOULDER
, x
, y
)) != 0);
4122 if (x
== u
.ux
&& y
== u
.uy
)
4123 spoteffects(TRUE
); /* possibly drown, notice objects */
4126 #define MIN_ICE_TIME 50
4127 #define MAX_ICE_TIME 2000
4129 * Usually start a melt_ice timer; sometimes the ice will become
4130 * permanent instead.
4133 start_melt_ice_timeout(x
, y
, min_time
)
4135 long min_time
; /* <x,y>'s old melt timeout (deleted by time we get here) */
4140 when
= (int) min_time
;
4141 if (when
< MIN_ICE_TIME
- 1)
4142 when
= MIN_ICE_TIME
- 1;
4144 /* random timeout; surrounding ice locations ought to be a factor... */
4145 while (++when
<= MAX_ICE_TIME
)
4146 if (!rn2((MAX_ICE_TIME
- when
) + MIN_ICE_TIME
))
4149 /* if we're within MAX_ICE_TIME, install a melt timer;
4150 otherwise, omit it to leave this ice permanent */
4151 if (when
<= MAX_ICE_TIME
) {
4152 where
= ((long) x
<< 16) | (long) y
;
4153 (void) start_timer((long) when
, TIMER_LEVEL
, MELT_ICE_AWAY
,
4154 long_to_any(where
));
4161 * Called when ice has melted completely away.
4164 melt_ice_away(arg
, timeout
)
4166 long timeout UNUSED
;
4169 long where
= arg
->a_long
;
4171 y
= (xchar
) (where
& 0xFFFF);
4172 x
= (xchar
) ((where
>> 16) & 0xFFFF);
4173 /* melt_ice does newsym when appropriate */
4174 melt_ice(x
, y
, "Some ice melts away.");
4177 /* Burn floor scrolls, evaporate pools, etc... in a single square.
4178 * Used both for normal bolts of fire, cold, etc... and for fireballs.
4179 * Sets shopdamage to TRUE if a shop door is destroyed, and returns the
4180 * amount by which range is reduced (the latter is just ignored by fireballs)
4183 zap_over_floor(x
, y
, type
, shopdamage
, exploding_wand_typ
)
4186 boolean
*shopdamage
;
4187 short exploding_wand_typ
;
4189 const char *zapverb
;
4192 struct rm
*lev
= &levl
[x
][y
];
4193 boolean see_it
= cansee(x
, y
), yourzap
;
4194 int rangemod
= 0, abstype
= abs(type
) % 10;
4199 if (t
&& t
->ttyp
== WEB
) {
4200 /* a burning web is too flimsy to notice if you can't see it */
4202 Norep("A web bursts into flames!");
4203 (void) delfloortrap(t
);
4208 melt_ice(x
, y
, (char *) 0);
4209 } else if (is_pool(x
, y
)) {
4210 const char *msgtxt
= "You hear hissing gas.";
4212 if (lev
->typ
!= POOL
) { /* MOAT or DRAWBRIDGE_UP */
4214 msgtxt
= "Some water evaporates.";
4218 t
= maketrap(x
, y
, PIT
);
4222 msgtxt
= "The water evaporates.";
4224 Norep("%s", msgtxt
);
4225 if (lev
->typ
== ROOM
)
4227 } else if (IS_FOUNTAIN(lev
->typ
)) {
4229 pline("Steam billows from the fountain.");
4231 dryup(x
, y
, type
> 0);
4233 break; /* ZT_FIRE */
4236 if (is_pool(x
, y
) || is_lava(x
, y
)) {
4237 boolean lava
= is_lava(x
, y
);
4238 boolean moat
= is_moat(x
, y
);
4240 if (lev
->typ
== WATER
) {
4241 /* For now, don't let WATER freeze. */
4243 pline_The("water freezes for a moment.");
4245 You_hear("a soft crackling.");
4246 rangemod
-= 1000; /* stop */
4249 if (lev
->typ
== DRAWBRIDGE_UP
) {
4250 lev
->drawbridgemask
&= ~DB_UNDER
; /* clear lava */
4251 lev
->drawbridgemask
|= (lava
? DB_FLOOR
: DB_ICE
);
4255 (lev
->typ
== POOL
? ICED_POOL
: ICED_MOAT
);
4256 lev
->typ
= (lava
? ROOM
: ICE
);
4261 Norep("The lava cools and solidifies.");
4263 Norep("The %s is bridged with ice!",
4264 waterbody_name(x
, y
));
4266 Norep("The water freezes.");
4269 You_hear("a crackling sound.");
4271 if (x
== u
.ux
&& y
== u
.uy
) {
4272 if (u
.uinwater
) { /* not just `if (Underwater)' */
4273 /* leave the no longer existent water */
4277 vision_full_recalc
= 1;
4278 } else if (u
.utrap
&& u
.utraptype
== TT_LAVA
) {
4281 You("pass through the now-solid rock.");
4283 u
.utrap
= rn1(50, 20);
4284 u
.utraptype
= TT_INFLOOR
;
4285 You("are firmly stuck in the cooling rock.");
4288 } else if ((mon
= m_at(x
, y
)) != 0) {
4289 /* probably ought to do some hefty damage to any
4290 non-ice creature caught in freezing water;
4291 at a minimum, eels are forced out of hiding */
4292 if (is_swimmer(mon
->data
) && mon
->mundetected
) {
4293 mon
->mundetected
= 0;
4298 start_melt_ice_timeout(x
, y
, 0L);
4299 obj_ice_effects(x
, y
, TRUE
);
4303 } else if (is_ice(x
, y
)) {
4306 /* Already ice here, so just firm it up. */
4307 /* Now ensure that only ice that is already timed is affected */
4308 if ((melt_time
= spot_time_left(x
, y
, MELT_ICE_AWAY
)) != 0L) {
4309 spot_stop_timers(x
, y
, MELT_ICE_AWAY
);
4310 start_melt_ice_timeout(x
, y
, melt_time
);
4313 break; /* ZT_COLD */
4316 (void) create_gas_cloud(x
, y
, 1, 8);
4320 if (lev
->typ
== IRONBARS
) {
4321 if ((lev
->wall_info
& W_NONDIGGABLE
) != 0) {
4323 Norep("The %s corrode somewhat but remain intact.",
4324 defsyms
[S_bars
].explanation
);
4325 /* but nothing actually happens... */
4329 Norep("The %s melt.", defsyms
[S_bars
].explanation
);
4330 if (*in_rooms(x
, y
, SHOPBASE
)) {
4331 /* in case we ever have a shop bounded by bars */
4335 add_damage(x
, y
, (type
>= 0) ? 300L : 0L);
4340 lev
->doormask
= D_NODOOR
;
4346 break; /* ZT_ACID */
4352 /* set up zap text for possible door feedback; for exploding wand, we
4353 want "the blast" rather than "your blast" even if hero caused it */
4354 yourzap
= (type
>= 0 && !exploding_wand_typ
);
4355 zapverb
= "blast"; /* breath attack or wand explosion */
4356 if (!exploding_wand_typ
) {
4357 if (abs(type
) < ZT_SPELL(0))
4358 zapverb
= "bolt"; /* wand zap */
4359 else if (abs(type
) < ZT_BREATH(0))
4363 /* secret door gets revealed, converted into regular door */
4364 if (levl
[x
][y
].typ
== SDOOR
) {
4365 cvt_sdoor_to_door(&levl
[x
][y
]); /* .typ = DOOR */
4366 /* target spot will now pass closed_door() test below
4367 (except on rogue level) */
4370 pline("%s %s reveals a secret door.",
4371 yourzap
? "Your" : "The", zapverb
);
4372 else if (Is_rogue_level(&u
.uz
))
4373 draft_message(FALSE
); /* "You feel a draft." (open doorway) */
4376 /* regular door absorbs remaining zap range, possibly gets destroyed */
4377 if (closed_door(x
, y
)) {
4378 int new_doormask
= -1;
4379 const char *see_txt
= 0, *sense_txt
= 0, *hear_txt
= 0;
4384 new_doormask
= D_NODOOR
;
4385 see_txt
= "The door is consumed in flames!";
4386 sense_txt
= "smell smoke.";
4389 new_doormask
= D_NODOOR
;
4390 see_txt
= "The door freezes and shatters!";
4391 sense_txt
= "feel cold.";
4394 /* death spells/wands don't disintegrate */
4395 if (abs(type
) != ZT_BREATH(ZT_DEATH
))
4397 new_doormask
= D_NODOOR
;
4398 see_txt
= "The door disintegrates!";
4399 hear_txt
= "crashing wood.";
4402 new_doormask
= D_BROKEN
;
4403 see_txt
= "The door splinters!";
4404 hear_txt
= "crackling.";
4408 if (exploding_wand_typ
> 0) {
4409 /* Magical explosion from misc exploding wand */
4410 if (exploding_wand_typ
== WAN_STRIKING
) {
4411 new_doormask
= D_BROKEN
;
4412 see_txt
= "The door crashes open!";
4413 sense_txt
= "feel a burst of cool air.";
4418 /* "the door absorbs the blast" would be
4419 inaccurate for an exploding wand since
4420 other adjacent locations still get hit */
4421 if (exploding_wand_typ
)
4422 pline_The("door remains intact.");
4424 pline_The("door absorbs %s %s!", yourzap
? "your" : "the",
4427 You_feel("vibrations.");
4430 if (new_doormask
>= 0) { /* door gets broken */
4431 if (*in_rooms(x
, y
, SHOPBASE
)) {
4433 add_damage(x
, y
, 400L);
4435 } else /* caused by monster */
4436 add_damage(x
, y
, 0L);
4438 lev
->doormask
= new_doormask
;
4439 unblock_point(x
, y
); /* vision */
4443 } else if (sense_txt
) {
4445 } else if (hear_txt
)
4446 You_hear1(hear_txt
);
4447 if (picking_at(x
, y
)) {
4454 if (OBJ_AT(x
, y
) && abstype
== ZT_FIRE
)
4455 if (burn_floor_objects(x
, y
, FALSE
, type
> 0) && couldsee(x
, y
)) {
4457 You("%s of smoke.", !Blind
? "see a puff" : "smell a whiff");
4459 if ((mon
= m_at(x
, y
)) != 0) {
4460 /* Cannot use wakeup() which also angers the monster */
4466 if (mon
->ispriest
&& *in_rooms(mon
->mx
, mon
->my
, TEMPLE
))
4468 if (mon
->isshk
&& !*u
.ushops
)
4475 /* fractured by pick-axe or wand of striking */
4478 register struct obj
*obj
; /* no texts here! */
4481 boolean by_you
= !context
.mon_moving
;
4483 if (by_you
&& get_obj_location(obj
, &x
, &y
, 0) && costly_spot(x
, y
)) {
4484 struct monst
*shkp
= 0;
4485 char objroom
= *in_rooms(x
, y
, SHOPBASE
);
4487 if (billable(&shkp
, obj
, objroom
, FALSE
)) {
4488 /* shop message says "you owe <shk> <$> for it!" so we need
4489 to precede that with a message explaining what "it" is */
4490 You("fracture %s %s.", s_suffix(shkname(shkp
)), xname(obj
));
4491 breakobj(obj
, x
, y
, TRUE
, FALSE
); /* charges for shop goods */
4494 if (by_you
&& obj
->otyp
== BOULDER
)
4498 obj
->oclass
= GEM_CLASS
;
4499 obj
->quan
= (long) rn1(60, 7);
4500 obj
->owt
= weight(obj
);
4501 obj
->dknown
= obj
->bknown
= obj
->rknown
= 0;
4502 obj
->known
= objects
[obj
->otyp
].oc_uses_known
? 0 : 1;
4503 dealloc_oextra(obj
);
4505 if (obj
->where
== OBJ_FLOOR
) {
4506 obj_extract_self(obj
); /* move rocks back on top */
4507 place_object(obj
, obj
->ox
, obj
->oy
);
4508 if (!does_block(obj
->ox
, obj
->oy
, &levl
[obj
->ox
][obj
->oy
]))
4509 unblock_point(obj
->ox
, obj
->oy
);
4510 if (cansee(obj
->ox
, obj
->oy
))
4511 newsym(obj
->ox
, obj
->oy
);
4515 /* handle statue hit by striking/force bolt/pick-axe */
4518 register struct obj
*obj
;
4520 /* [obj is assumed to be on floor, so no get_obj_location() needed] */
4521 struct trap
*trap
= t_at(obj
->ox
, obj
->oy
);
4523 boolean by_you
= !context
.mon_moving
;
4525 if (trap
&& trap
->ttyp
== STATUE_TRAP
4526 && activate_statue_trap(trap
, obj
->ox
, obj
->oy
, TRUE
))
4528 /* drop any objects contained inside the statue */
4529 while ((item
= obj
->cobj
) != 0) {
4530 obj_extract_self(item
);
4531 place_object(item
, obj
->ox
, obj
->oy
);
4533 if (by_you
&& Role_if(PM_ARCHEOLOGIST
) && (obj
->spe
& STATUE_HISTORIC
)) {
4534 You_feel("guilty about damaging such a historic statue.");
4543 * destroy_strings[dindx][0:singular,1:plural,2:killer_reason]
4544 * [0] freezing potion
4545 * [1] boiling potion other than oil
4546 * [2] boiling potion of oil
4547 * [3] burning scroll
4548 * [4] burning spellbook
4551 * (books, rings, and wands don't stack so don't need plural form;
4552 * crumbling ring doesn't do damage so doesn't need killer reason)
4554 const char *const destroy_strings
[][3] = {
4555 /* also used in trap.c */
4556 { "freezes and shatters", "freeze and shatter", "shattered potion" },
4557 { "boils and explodes", "boil and explode", "boiling potion" },
4558 { "ignites and explodes", "ignite and explode", "exploding potion" },
4559 { "catches fire and burns", "catch fire and burn", "burning scroll" },
4560 { "catches fire and burns", "", "burning book" },
4561 { "turns to dust and vanishes", "", "" },
4562 { "breaks apart and explodes", "", "exploding wand" },
4566 destroy_item(osym
, dmgtyp
)
4567 register int osym
, dmgtyp
;
4569 register struct obj
*obj
, *obj2
;
4570 int dmg
, xresist
, skip
;
4574 boolean physical_damage
;
4576 for (obj
= invent
; obj
; obj
= obj2
) {
4578 physical_damage
= FALSE
;
4579 if (obj
->oclass
!= osym
)
4580 continue; /* test only objs of type osym */
4582 continue; /* don't destroy artifacts */
4583 if (obj
->in_use
&& obj
->quan
== 1L)
4584 continue; /* not available */
4586 /* lint suppression */
4592 if (osym
== POTION_CLASS
&& obj
->otyp
!= POT_OIL
) {
4600 xresist
= (Fire_resistance
&& obj
->oclass
!= POTION_CLASS
4601 && obj
->otyp
!= GLOB_OF_GREEN_SLIME
);
4603 if (obj
->otyp
== SCR_FIRE
|| obj
->otyp
== SPE_FIREBALL
)
4605 if (obj
->otyp
== SPE_BOOK_OF_THE_DEAD
) {
4608 pline("%s glows a strange %s, but remains intact.",
4609 The(xname(obj
)), hcolor("dark red"));
4614 dindx
= (obj
->otyp
!= POT_OIL
) ? 1 : 2;
4626 if (obj
->otyp
== GLOB_OF_GREEN_SLIME
) {
4627 dindx
= obj
->owt
/ 20;
4639 xresist
= (Shock_resistance
&& obj
->oclass
!= RING_CLASS
);
4643 if (obj
->otyp
== RIN_SHOCK_RESISTANCE
) {
4651 if (obj
->otyp
== WAN_LIGHTNING
) {
4656 if (obj
== current_wand
) { skip
++; break; }
4672 --quan
; /* one will be used up elsewhere */
4673 for (i
= cnt
= 0L; i
< quan
; i
++)
4679 mult
= (cnt
== quan
)
4680 ? (quan
> 1) ? "All of your " : "Your"
4681 : (cnt
== 1L) ? "One of your" : "Some of your";
4682 pline("%s %s %s!", mult
, xname(obj
),
4683 destroy_strings
[dindx
][(cnt
> 1L)]);
4684 if (osym
== POTION_CLASS
&& dmgtyp
!= AD_COLD
) {
4685 if (!breathless(youmonst
.data
) || haseyes(youmonst
.data
))
4688 if (obj
->owornmask
) {
4689 if (obj
->owornmask
& W_RING
) /* ring being worn */
4694 if (obj
== current_wand
)
4695 current_wand
= 0; /* destroyed */
4696 for (i
= 0; i
< cnt
; i
++)
4700 You("aren't hurt!");
4702 const char *how
= destroy_strings
[dindx
][2];
4703 boolean one
= (cnt
== 1L);
4705 if (physical_damage
)
4706 dmg
= Maybe_Half_Phys(dmg
);
4707 losehp(dmg
, one
? how
: (const char *) makeplural(how
),
4708 one
? KILLED_BY_AN
: KILLED_BY
);
4709 exercise(A_STR
, FALSE
);
4718 destroy_mitem(mtmp
, osym
, dmgtyp
)
4722 struct obj
*obj
, *obj2
;
4728 if (mtmp
== &youmonst
) { /* this simplifies artifact_hit() */
4729 destroy_item(osym
, dmgtyp
);
4730 return 0; /* arbitrary; value doesn't matter to artifact_hit() */
4733 vis
= canseemon(mtmp
);
4734 for (obj
= mtmp
->minvent
; obj
; obj
= obj2
) {
4736 if (obj
->oclass
!= osym
)
4737 continue; /* test only objs of type osym */
4744 if (osym
== POTION_CLASS
&& obj
->otyp
!= POT_OIL
) {
4752 if (obj
->otyp
== SCR_FIRE
|| obj
->otyp
== SPE_FIREBALL
)
4754 if (obj
->otyp
== SPE_BOOK_OF_THE_DEAD
) {
4757 pline("%s glows a strange %s, but remains intact.",
4758 The(distant_name(obj
, xname
)), hcolor("dark red"));
4763 dindx
= (obj
->otyp
!= POT_OIL
) ? 1 : 2;
4775 if (obj
->otyp
== GLOB_OF_GREEN_SLIME
) {
4776 dindx
= obj
->owt
/ 20;
4791 if (obj
->otyp
== RIN_SHOCK_RESISTANCE
) {
4798 if (obj
->otyp
== WAN_LIGHTNING
) {
4815 for (i
= cnt
= 0L; i
< quan
; i
++)
4823 (cnt
== obj
->quan
) ? "" : (cnt
> 1L) ? "Some of "
4825 (cnt
== obj
->quan
) ? Yname2(obj
) : yname(obj
),
4826 destroy_strings
[dindx
][(cnt
> 1L)]);
4827 for (i
= 0; i
< cnt
; i
++)
4835 resist(mtmp
, oclass
, damage
, tell
)
4850 break; /* instrument */
4853 break; /* artifact */
4868 dlev
= (int) mtmp
->m_lev
;
4872 dlev
= is_mplayer(mtmp
->data
) ? u
.ulevel
: 1;
4874 resisted
= rn2(100 + alev
- dlev
) < mtmp
->data
->mr
;
4877 shieldeff(mtmp
->mx
, mtmp
->my
);
4878 pline("%s resists!", Monnam(mtmp
));
4880 damage
= (damage
+ 1) / 2;
4884 mtmp
->mhp
-= damage
;
4885 if (mtmp
->mhp
< 1) {
4887 monkilled(mtmp
, "", AD_RBRE
);
4895 #define MAXWISHTRY 5
4898 wishcmdassist(triesleft
)
4901 static NEARDATA
const char *
4905 "Enter the name of an object, such as \"potion of monster detection\",",
4906 "\"scroll labeled README\", \"elven mithril-coat\", or \"Grimtooth\"",
4907 "(without the quotes).",
4909 "For object types which come in stacks, you may specify a plural name",
4910 "such as \"potions of healing\", or specify a count, such as \"1000 gold",
4911 "pieces\", although that aspect of your wish might not be granted.",
4913 "You may also specify various prefix values which might be used to",
4914 "modify the item, such as \"uncursed\" or \"rustproof\" or \"+1\".",
4915 "Most modifiers shown when viewing your inventory can be specified.",
4917 "You may specify 'nothing' to explicitly decline this wish.",
4920 preserve_wishless
[] = "Doing so will preserve 'wishless' conduct.",
4922 "If you specify an unrecognized object name %s%s time%s,",
4923 retry_too
[] = "a randomly chosen item will be granted.",
4924 suppress_cmdassist
[] =
4925 "(Suppress this assistance with !cmdassist in your config file.)",
4926 *cardinals
[] = { "zero", "one", "two", "three", "four", "five" },
4927 too_many
[] = "too many";
4932 win
= create_nhwindow(NHW_TEXT
);
4935 for (i
= 0; i
< SIZE(wishinfo
) - 1; ++i
)
4936 putstr(win
, 0, wishinfo
[i
]);
4937 if (!u
.uconduct
.wishes
)
4938 putstr(win
, 0, preserve_wishless
);
4940 Sprintf(buf
, retry_info
,
4941 (triesleft
>= 0 && triesleft
< SIZE(cardinals
))
4942 ? cardinals
[triesleft
]
4944 (triesleft
< MAXWISHTRY
) ? " more" : "",
4946 putstr(win
, 0, buf
);
4947 putstr(win
, 0, retry_too
);
4949 if (iflags
.cmdassist
)
4950 putstr(win
, 0, suppress_cmdassist
);
4951 display_nhwindow(win
, FALSE
);
4952 destroy_nhwindow(win
);
4958 char buf
[BUFSZ
], promptbuf
[BUFSZ
];
4959 struct obj
*otmp
, nothing
;
4962 promptbuf
[0] = '\0';
4963 nothing
= zeroobj
; /* lint suppression; only its address matters */
4965 You("may wish for an object.");
4967 Strcpy(promptbuf
, "For what do you wish");
4968 if (iflags
.cmdassist
&& tries
> 0)
4969 Strcat(promptbuf
, " (enter 'help' for assistance)");
4970 Strcat(promptbuf
, "?");
4971 getlin(promptbuf
, buf
);
4972 (void) mungspaces(buf
);
4973 if (buf
[0] == '\033') {
4975 } else if (!strcmpi(buf
, "help")) {
4976 wishcmdassist(MAXWISHTRY
- tries
);
4980 * Note: if they wished for and got a non-object successfully,
4981 * otmp == &zeroobj. That includes gold, or an artifact that
4982 * has been denied. Wishing for "nothing" requires a separate
4983 * value to remain distinct.
4985 otmp
= readobjnam(buf
, ¬hing
);
4987 pline("Nothing fitting that description exists in the game.");
4988 if (++tries
< MAXWISHTRY
)
4990 pline1(thats_enough_tries
);
4991 otmp
= readobjnam((char *) 0, (struct obj
*) 0);
4993 return; /* for safety; should never happen */
4994 } else if (otmp
== ¬hing
) {
4995 /* explicitly wished for "nothing", presumably attempting
4996 to retain wishless conduct */
5001 u
.uconduct
.wishes
++;
5003 if (otmp
!= &zeroobj
) {
5005 *verb
= ((Is_airlevel(&u
.uz
) || u
.uinwater
) ? "slip" : "drop"),
5006 *oops_msg
= (u
.uswallow
5007 ? "Oops! %s out of your reach!"
5008 : (Is_airlevel(&u
.uz
) || Is_waterlevel(&u
.uz
)
5009 || levl
[u
.ux
][u
.uy
].typ
< IRONBARS
5010 || levl
[u
.ux
][u
.uy
].typ
>= ICE
)
5011 ? "Oops! %s away from you!"
5012 : "Oops! %s to the floor!");
5014 /* The(aobjnam()) is safe since otmp is unidentified -dlc */
5015 (void) hold_another_object(otmp
, oops_msg
,
5016 The(aobjnam(otmp
, verb
)),
5018 u
.ublesscnt
+= rn1(100, 50); /* the gods take notice */