1 /* NetHack 3.6 zap.c $NHDT-Date: 1470819844 2016/08/10 09:04:04 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.263 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
7 /* Disintegration rays have special treatment; corpses are never left.
8 * But the routine which calculates the damage is separate from the routine
9 * which kills the monster. The damage routine returns this cookie to
10 * indicate that the monster should be disintegrated.
12 #define MAGIC_COOKIE 1000
14 static NEARDATA boolean obj_zapped
;
15 static NEARDATA
int poly_zapped
;
17 extern boolean notonhead
; /* for long worms */
19 /* kludge to use mondied instead of killed */
20 extern boolean m_using
;
22 STATIC_DCL
void FDECL(polyuse
, (struct obj
*, int, int));
23 STATIC_DCL
void FDECL(create_polymon
, (struct obj
*, int));
24 STATIC_DCL
int FDECL(stone_to_flesh_obj
, (struct obj
*));
25 STATIC_DCL boolean
FDECL(zap_updown
, (struct obj
*));
26 STATIC_DCL
void FDECL(zhitu
, (int, int, const char *, XCHAR_P
, XCHAR_P
));
27 STATIC_DCL
void FDECL(revive_egg
, (struct obj
*));
28 STATIC_DCL boolean
FDECL(zap_steed
, (struct obj
*));
29 STATIC_DCL
void FDECL(skiprange
, (int, int *, int *));
31 STATIC_DCL
int FDECL(zap_hit
, (int, int));
32 STATIC_OVL
void FDECL(disintegrate_mon
, (struct monst
*, int, const char *));
33 STATIC_DCL
void FDECL(backfire
, (struct obj
*));
34 STATIC_DCL
int FDECL(spell_hit_bonus
, (int));
36 #define ZT_MAGIC_MISSILE (AD_MAGM - 1)
37 #define ZT_FIRE (AD_FIRE - 1)
38 #define ZT_COLD (AD_COLD - 1)
39 #define ZT_SLEEP (AD_SLEE - 1)
40 #define ZT_DEATH (AD_DISN - 1) /* or disintegration */
41 #define ZT_LIGHTNING (AD_ELEC - 1)
42 #define ZT_POISON_GAS (AD_DRST - 1)
43 #define ZT_ACID (AD_ACID - 1)
44 /* 8 and 9 are currently unassigned */
46 #define ZT_WAND(x) (x)
47 #define ZT_SPELL(x) (10 + (x))
48 #define ZT_BREATH(x) (20 + (x))
50 #define is_hero_spell(type) ((type) >= 10 && (type) < 20)
52 #define M_IN_WATER(ptr) \
53 ((ptr)->mlet == S_EEL || amphibious(ptr) || is_swimmer(ptr))
55 STATIC_VAR
const char are_blinded_by_the_flash
[] =
56 "are blinded by the flash!";
58 const char *const flash_types
[] = /* also used in buzzmu(mcastu.c) */
60 "magic missile", /* Wands must be 0-9 */
61 "bolt of fire", "bolt of cold", "sleep ray", "death ray",
62 "bolt of lightning", "", "", "", "",
64 "magic missile", /* Spell equivalents must be 10-19 */
65 "fireball", "cone of cold", "sleep ray", "finger of death",
66 "bolt of lightning", /* there is no spell, used for retribution */
69 "blast of missiles", /* Dragon breath equivalents 20-29*/
70 "blast of fire", "blast of frost", "blast of sleep gas",
71 "blast of disintegration", "blast of lightning",
72 "blast of poison gas", "blast of acid", "", ""
76 * Recognizing unseen wands by zapping: in 3.4.3 and earlier, zapping
77 * most wand types while blind would add that type to the discoveries
78 * list even if it had never been seen (ie, picked up while blinded
79 * and shown in inventory as simply "a wand"). This behavior has been
80 * changed; now such wands won't be discovered. But if the type is
81 * already discovered, then the individual wand whose effect was just
82 * observed will be flagged as if seen. [You already know wands of
83 * striking; you zap "a wand" and observe striking effect (presumably
84 * by sound or touch); it'll become shown in inventory as "a wand of
87 * Unfortunately, the new behavior isn't really correct either. There
88 * should be an `eknown' bit for "effect known" added for wands (and
89 * for potions since quaffing one of a stack is similar) so that the
90 * particular wand which has been zapped would have its type become
91 * known (it would change from "a wand" to "a wand of striking", for
92 * example) without the type becoming discovered or other unknown wands
93 * of that type showing additional information. When blindness ends,
94 * all objects in inventory with the eknown bit set would be discovered
95 * and other items of the same type would become known as such.
98 /* wand discovery gets special handling when hero is blinded */
103 /* For a wand (or wand-like tool) zapped by the player, if the
104 effect was observable (determined by caller; usually seen, but
105 possibly heard or felt if the hero is blinded) then discover the
106 object type provided that the object itself is known (as more
107 than just "a wand"). If object type is already discovered and
108 we observed the effect, mark the individual wand as having been
109 seen. Suppress spells (which use fake spellbook object for `obj')
110 so that casting a spell won't re-discover its forgotten book. */
111 if (obj
->oclass
!= SPBOOK_CLASS
) {
112 /* if type already discovered, treat this item has having been seen
113 even if hero is currently blinded (skips redundant makeknown) */
114 if (objects
[obj
->otyp
].oc_name_known
) {
115 obj
->dknown
= 1; /* will usually be set already */
117 /* otherwise discover it if item itself has been or can be seen */
119 /* in case it was picked up while blind and then zapped without
120 examining inventory after regaining sight (bypassing xname) */
123 /* make the discovery iff we know what we're manipulating */
125 makeknown(obj
->otyp
);
130 /* Routines for IMMEDIATE wands and spells. */
131 /* bhitm: monster mtmp was hit by the effect of wand or spell otmp */
137 boolean wake
= TRUE
; /* Most 'zaps' should wake monster */
138 boolean reveal_invis
= FALSE
, learn_it
= FALSE
;
139 boolean dbldam
= Role_if(PM_KNIGHT
) && u
.uhave
.questart
;
140 int dmg
, otyp
= otmp
->otyp
;
141 const char *zap_type_text
= "spell";
143 boolean disguised_mimic
= (mtmp
->data
->mlet
== S_MIMIC
144 && mtmp
->m_ap_type
!= M_AP_NOTHING
);
146 if (u
.uswallow
&& mtmp
== u
.ustuck
)
147 reveal_invis
= FALSE
;
149 notonhead
= (mtmp
->mx
!= bhitpos
.x
|| mtmp
->my
!= bhitpos
.y
);
152 zap_type_text
= "wand";
158 if (resists_magm(mtmp
)) { /* match effect on player */
159 shieldeff(mtmp
->mx
, mtmp
->my
);
161 break; /* skip makeknown */
162 } else if (u
.uswallow
|| rnd(20) < 10 + find_mac(mtmp
)) {
166 if (otyp
== SPE_FORCE_BOLT
)
167 dmg
= spell_damage_bonus(dmg
);
168 hit(zap_type_text
, mtmp
, exclam(dmg
));
169 (void) resist(mtmp
, otmp
->oclass
, dmg
, TELL
);
171 miss(zap_type_text
, mtmp
);
174 case WAN_SLOW_MONSTER
:
175 case SPE_SLOW_MONSTER
:
176 if (!resist(mtmp
, otmp
->oclass
, 0, NOTELL
)) {
179 mon_adjust_speed(mtmp
, -1, otmp
);
180 m_dowear(mtmp
, FALSE
); /* might want speed boots */
181 if (u
.uswallow
&& (mtmp
== u
.ustuck
) && is_whirly(mtmp
->data
)) {
182 You("disrupt %s!", mon_nam(mtmp
));
183 pline("A huge hole opens up...");
184 expels(mtmp
, mtmp
->data
, TRUE
);
188 case WAN_SPEED_MONSTER
:
189 if (!resist(mtmp
, otmp
->oclass
, 0, NOTELL
)) {
192 mon_adjust_speed(mtmp
, 1, otmp
);
193 m_dowear(mtmp
, FALSE
); /* might want speed boots */
196 case WAN_UNDEAD_TURNING
:
197 case SPE_TURN_UNDEAD
:
199 if (unturn_dead(mtmp
))
201 if (is_undead(mtmp
->data
) || is_vampshifter(mtmp
)) {
207 if (otyp
== SPE_TURN_UNDEAD
)
208 dmg
= spell_damage_bonus(dmg
);
209 context
.bypasses
= TRUE
; /* for make_corpse() */
210 if (!resist(mtmp
, otmp
->oclass
, dmg
, NOTELL
)) {
212 monflee(mtmp
, 0, FALSE
, TRUE
);
219 if (resists_magm(mtmp
)) {
220 /* magic resistance protects from polymorph traps, so make
221 it guard against involuntary polymorph attacks too... */
222 shieldeff(mtmp
->mx
, mtmp
->my
);
223 } else if (!resist(mtmp
, otmp
->oclass
, 0, NOTELL
)) {
224 boolean polyspot
= (otyp
!= POT_POLYMORPH
),
225 give_msg
= (!Hallucination
227 || (u
.uswallow
&& mtmp
== u
.ustuck
)));
229 /* dropped inventory (due to death by system shock,
230 or loss of wielded weapon and/or worn armor due to
231 limitations of new shape) won't be hit by this zap */
233 for (obj
= mtmp
->minvent
; obj
; obj
= obj
->nobj
)
235 /* natural shapechangers aren't affected by system shock
236 (unless protection from shapechangers is interfering
237 with their metabolism...) */
238 if (mtmp
->cham
== NON_PM
&& !rn2(25)) {
239 if (canseemon(mtmp
)) {
240 pline("%s shudders!", Monnam(mtmp
));
243 /* context.bypasses = TRUE; ## for make_corpse() */
244 /* no corpse after system shock */
245 xkilled(mtmp
, XKILL_GIVEMSG
| XKILL_NOCORPSE
);
246 } else if (newcham(mtmp
, (struct permonst
*) 0,
247 polyspot
, give_msg
) != 0
248 /* if shapechange failed because there aren't
249 enough eligible candidates (most likely for
250 vampshifter), try reverting to original form */
251 || (mtmp
->cham
>= LOW_PM
252 && newcham(mtmp
, &mons
[mtmp
->cham
],
253 polyspot
, give_msg
) != 0)) {
254 if (give_msg
&& (canspotmon(mtmp
)
255 || (u
.uswallow
&& mtmp
== u
.ustuck
)))
260 case WAN_CANCELLATION
:
261 case SPE_CANCELLATION
:
264 (void) cancel_monst(mtmp
, otmp
, TRUE
, TRUE
, FALSE
);
266 case WAN_TELEPORTATION
:
267 case SPE_TELEPORT_AWAY
:
270 reveal_invis
= !u_teleport_mon(mtmp
, TRUE
);
272 case WAN_MAKE_INVISIBLE
: {
273 int oldinvis
= mtmp
->minvis
;
278 /* format monster's name before altering its visibility */
279 Strcpy(nambuf
, Monnam(mtmp
));
280 mon_set_minvis(mtmp
);
281 if (!oldinvis
&& knowninvisible(mtmp
)) {
282 pline("%s turns transparent!", nambuf
);
289 case SPE_WIZARD_LOCK
:
290 wake
= closeholdingtrap(mtmp
, &learn_it
);
300 wake
= FALSE
; /* don't want immediate counterattack */
301 if (u
.uswallow
&& mtmp
== u
.ustuck
) {
302 if (is_animal(mtmp
->data
)) {
304 You_feel("a sudden rush of air!");
306 pline("%s opens its mouth!", Monnam(mtmp
));
308 expels(mtmp
, mtmp
->data
, TRUE
);
309 /* zap which hits steed will only release saddle if it
310 doesn't hit a holding or falling trap; playability
311 here overrides the more logical target ordering */
312 } else if (openholdingtrap(mtmp
, &learn_it
)) {
314 } else if (openfallingtrap(mtmp
, TRUE
, &learn_it
)) {
315 /* mtmp might now be on the migrating monsters list */
317 } else if ((obj
= which_armor(mtmp
, W_SADDLE
)) != 0) {
320 Sprintf(buf
, "%s %s", s_suffix(Monnam(mtmp
)),
321 distant_name(obj
, xname
));
322 if (cansee(mtmp
->mx
, mtmp
->my
)) {
323 if (!canspotmon(mtmp
))
324 Strcpy(buf
, An(distant_name(obj
, xname
)));
325 pline("%s falls to the %s.", buf
,
326 surface(mtmp
->mx
, mtmp
->my
));
327 } else if (canspotmon(mtmp
)) {
328 pline("%s falls off.", buf
);
330 obj_extract_self(obj
);
331 mdrop_obj(mtmp
, obj
, FALSE
);
335 case SPE_EXTRA_HEALING
:
337 if (mtmp
->data
!= &mons
[PM_PESTILENCE
]) {
338 wake
= FALSE
; /* wakeup() makes the target angry */
339 mtmp
->mhp
+= d(6, otyp
== SPE_EXTRA_HEALING
? 8 : 4);
340 if (mtmp
->mhp
> mtmp
->mhpmax
)
341 mtmp
->mhp
= mtmp
->mhpmax
;
342 if (mtmp
->mblinded
) {
346 if (canseemon(mtmp
)) {
347 if (disguised_mimic
) {
348 if (is_obj_mappear(mtmp
,STRANGE_OBJECT
)) {
349 /* it can do better now */
351 newsym(mtmp
->mx
, mtmp
->my
);
353 mimic_hit_msg(mtmp
, otyp
);
355 pline("%s looks%s better.", Monnam(mtmp
),
356 otyp
== SPE_EXTRA_HEALING
? " much" : "");
358 if (mtmp
->mtame
|| mtmp
->mpeaceful
) {
359 adjalign(Role_if(PM_HEALER
) ? 1 : sgn(u
.ualign
.type
));
361 } else { /* Pestilence */
362 /* Pestilence will always resist; damage is half of 3d{4,8} */
363 (void) resist(mtmp
, otmp
->oclass
,
364 d(3, otyp
== SPE_EXTRA_HEALING
? 8 : 4), TELL
);
367 case WAN_LIGHT
: /* (broken wand) */
368 if (flash_hits_mon(mtmp
, otmp
)) {
373 case WAN_SLEEP
: /* (broken wand) */
374 /* [wakeup() doesn't rouse victims of temporary sleep,
375 so it's okay to leave `wake' set to TRUE here] */
377 if (sleep_monst(mtmp
, d(1 + otmp
->spe
, 12), WAND_CLASS
))
382 case SPE_STONE_TO_FLESH
:
383 if (monsndx(mtmp
->data
) == PM_STONE_GOLEM
) {
384 char *name
= Monnam(mtmp
);
386 /* turn into flesh golem */
387 if (newcham(mtmp
, &mons
[PM_FLESH_GOLEM
], FALSE
, FALSE
)) {
389 pline("%s turns to flesh!", name
);
392 pline("%s looks rather fleshy for a moment.", name
);
400 dmg
= monhp_per_lvl(mtmp
);
403 if (otyp
== SPE_DRAIN_LIFE
)
404 dmg
= spell_damage_bonus(dmg
);
405 if (resists_drli(mtmp
)) {
406 shieldeff(mtmp
->mx
, mtmp
->my
);
407 } else if (!resist(mtmp
, otmp
->oclass
, dmg
, NOTELL
) && mtmp
->mhp
> 0) {
410 /* die if already level 0, regardless of hit points */
411 if (mtmp
->mhp
<= 0 || mtmp
->mhpmax
<= 0 || mtmp
->m_lev
< 1) {
416 pline("%s suddenly seems weaker!", Monnam(mtmp
));
424 impossible("What an interesting effect (%d)", otyp
);
431 if (mtmp
->isshk
&& !*u
.ushops
)
433 } else if (mtmp
->m_ap_type
)
434 seemimic(mtmp
); /* might unblock if mimicing a boulder/door */
436 /* note: bhitpos won't be set if swallowed, but that's okay since
437 * reveal_invis will be false. We can't use mtmp->mx, my since it
438 * might be an invisible worm hit on the tail.
441 if (mtmp
->mhp
> 0 && cansee(bhitpos
.x
, bhitpos
.y
)
442 && !canspotmon(mtmp
))
443 map_invisible(bhitpos
.x
, bhitpos
.y
);
445 /* if effect was observable then discover the wand type provided
446 that the wand itself has been seen */
460 return; /* don't show minvent for long worm tail */
463 for (otmp
= mtmp
->minvent
; otmp
; otmp
= otmp
->nobj
) {
464 otmp
->dknown
= 1; /* treat as "seen" */
465 if (Is_container(otmp
) || otmp
->otyp
== STATUE
) {
467 if (!SchroedingersBox(otmp
))
471 (void) display_minventory(mtmp
, MINV_ALL
| MINV_NOLET
| PICK_NONE
,
474 pline("%s is not carrying anything%s.", noit_Monnam(mtmp
),
475 (u
.uswallow
&& mtmp
== u
.ustuck
) ? " besides you" : "");
480 * Return the object's physical location. This only makes sense for
481 * objects that are currently on the level (i.e. migrating objects
482 * are nowhere). By default, only things that can be seen (in hero's
483 * inventory, monster's inventory, or on the ground) are reported.
484 * By adding BURIED_TOO and/or CONTAINED_TOO flags, you can also get
485 * the location of buried and contained objects. Note that if an
486 * object is carried by a monster, its reported position may change
487 * from turn to turn. This function returns FALSE if the position
488 * is not available or subject to the constraints above.
491 get_obj_location(obj
, xp
, yp
, locflags
)
496 switch (obj
->where
) {
506 if (obj
->ocarry
->mx
) {
507 *xp
= obj
->ocarry
->mx
;
508 *yp
= obj
->ocarry
->my
;
511 break; /* !mx => migrating monster */
513 if (locflags
& BURIED_TOO
) {
520 if (locflags
& CONTAINED_TOO
)
521 return get_obj_location(obj
->ocontainer
, xp
, yp
, locflags
);
529 get_mon_location(mon
, xp
, yp
, locflags
)
532 int locflags
; /* non-zero means get location even if monster is buried */
534 if (mon
== &youmonst
) {
538 } else if (mon
->mx
> 0 && (!mon
->mburied
|| locflags
)) {
542 } else { /* migrating or buried */
548 /* used by revive() and animate_statue() */
554 struct monst
*mtmp
= (struct monst
*) 0;
555 struct monst
*mtmp2
= (struct monst
*) 0;
558 mtmp2
= get_mtraits(obj
, TRUE
);
560 /* save_mtraits() validated mtmp2->mnum */
561 mtmp2
->data
= &mons
[mtmp2
->mnum
];
562 if (mtmp2
->mhpmax
<= 0 && !is_rider(mtmp2
->data
))
563 return (struct monst
*) 0;
564 mtmp
= makemon(mtmp2
->data
, cc
->x
, cc
->y
,
565 NO_MINVENT
| MM_NOWAIT
| MM_NOCOUNTBIRTH
);
569 /* heal the monster */
570 if (mtmp
->mhpmax
> mtmp2
->mhpmax
&& is_rider(mtmp2
->data
))
571 mtmp2
->mhpmax
= mtmp
->mhpmax
;
572 mtmp2
->mhp
= mtmp2
->mhpmax
;
573 /* Get these ones from mtmp */
574 mtmp2
->minvent
= mtmp
->minvent
; /*redundant*/
575 /* monster ID is available if the monster died in the current
576 game, but will be zero if the corpse was in a bones level
577 (we cleared it when loading bones) */
579 mtmp2
->m_id
= mtmp
->m_id
;
580 /* might be bringing quest leader back to life */
581 if (quest_status
.leader_is_dead
582 /* leader_is_dead implies leader_m_id is valid */
583 && mtmp2
->m_id
== quest_status
.leader_m_id
)
584 quest_status
.leader_is_dead
= FALSE
;
586 mtmp2
->mx
= mtmp
->mx
;
587 mtmp2
->my
= mtmp
->my
;
588 mtmp2
->mux
= mtmp
->mux
;
589 mtmp2
->muy
= mtmp
->muy
;
590 mtmp2
->mw
= mtmp
->mw
;
591 mtmp2
->wormno
= mtmp
->wormno
;
592 mtmp2
->misc_worn_check
= mtmp
->misc_worn_check
;
593 mtmp2
->weapon_check
= mtmp
->weapon_check
;
594 mtmp2
->mtrapseen
= mtmp
->mtrapseen
;
595 mtmp2
->mflee
= mtmp
->mflee
;
596 mtmp2
->mburied
= mtmp
->mburied
;
597 mtmp2
->mundetected
= mtmp
->mundetected
;
598 mtmp2
->mfleetim
= mtmp
->mfleetim
;
599 mtmp2
->mlstmv
= mtmp
->mlstmv
;
600 mtmp2
->m_ap_type
= mtmp
->m_ap_type
;
601 /* set these ones explicitly */
607 mtmp2
->msleeping
= 0;
610 /* most cancelled monsters return to normal,
611 but some need to stay cancelled */
612 if (!dmgtype(mtmp2
->data
, AD_SEDU
)
613 && (!SYSOPT_SEDUCE
|| !dmgtype(mtmp2
->data
, AD_SSEX
)))
615 mtmp2
->mcansee
= 1; /* set like in makemon */
619 /* when traits are for a shopeekper, dummy monster 'mtmp' won't
620 have necessary eshk data for replmon() -> replshk() */
623 *ESHK(mtmp
) = *ESHK(mtmp2
);
624 if (ESHK(mtmp2
)->bill_p
!= 0
625 && ESHK(mtmp2
)->bill_p
!= (struct bill_x
*) -1000)
626 ESHK(mtmp
)->bill_p
= &(ESHK(mtmp
)->bill
[0]);
629 replmon(mtmp
, mtmp2
);
630 newsym(mtmp2
->mx
, mtmp2
->my
); /* Might now be invisible */
632 /* in case Protection_from_shape_changers is different
633 now than it was when the traits were stored */
640 * get_container_location() returns the following information
641 * about the outermost container:
642 * loc argument gets set to:
643 * OBJ_INVENT if in hero's inventory; return 0.
644 * OBJ_FLOOR if on the floor; return 0.
645 * OBJ_BURIED if buried; return 0.
646 * OBJ_MINVENT if in monster's inventory; return monster.
647 * container_nesting is updated with the nesting depth of the containers
651 get_container_location(obj
, loc
, container_nesting
)
654 int *container_nesting
;
659 if (container_nesting
)
660 *container_nesting
= 0;
661 while (obj
&& obj
->where
== OBJ_CONTAINED
) {
662 if (container_nesting
)
663 *container_nesting
+= 1;
664 obj
= obj
->ocontainer
;
667 *loc
= obj
->where
; /* outermost container's location */
668 if (obj
->where
== OBJ_MINVENT
)
671 return (struct monst
*) 0;
675 * Attempt to revive the given corpse, return the revived monster if
676 * successful. Note: this does NOT use up the corpse if it fails.
677 * If corpse->quan is more than 1, only one corpse will be affected
678 * and only one monster will be resurrected.
681 revive(corpse
, by_hero
)
685 struct monst
*mtmp
= 0;
686 struct permonst
*mptr
;
687 struct obj
*container
;
691 int montype
, container_nesting
= 0;
693 if (corpse
->otyp
!= CORPSE
) {
694 impossible("Attempting to revive %s?", xname(corpse
));
695 return (struct monst
*) 0;
699 if (corpse
->where
!= OBJ_CONTAINED
) {
700 /* only for invent, minvent, or floor */
702 (void) get_obj_location(corpse
, &x
, &y
, 0);
704 /* deal with corpses in [possibly nested] containers */
705 struct monst
*carrier
;
706 int holder
= OBJ_FREE
;
708 container
= corpse
->ocontainer
;
710 get_container_location(container
, &holder
, &container_nesting
);
713 x
= carrier
->mx
, y
= carrier
->my
;
719 (void) get_obj_location(corpse
, &x
, &y
, CONTAINED_TOO
);
722 break; /* x,y are 0 */
726 /* Rules for revival from containers:
727 * - the container cannot be locked
728 * - the container cannot be heavily nested (>2 is arbitrary)
729 * - the container cannot be a statue or bag of holding
730 * (except in very rare cases for the latter)
732 || (container
&& (container
->olocked
|| container_nesting
> 2
733 || container
->otyp
== STATUE
734 || (container
->otyp
== BAG_OF_HOLDING
&& rn2(40)))))
735 return (struct monst
*) 0;
737 /* record the object's location now that we're sure where it is */
738 corpse
->ox
= x
, corpse
->oy
= y
;
740 /* prepare for the monster */
741 montype
= corpse
->corpsenm
;
742 mptr
= &mons
[montype
];
743 /* [should probably handle recorporealization first; if corpse and
744 ghost are at same location, revived creature shouldn't be bumped
745 to an adjacent spot by ghost which joins with it] */
747 if (enexto(&xy
, x
, y
, mptr
))
751 if ((mons
[montype
].mlet
== S_EEL
&& !IS_POOL(levl
[x
][y
].typ
))
752 || (mons
[montype
].mlet
== S_TROLL
753 && uwep
&& uwep
->oartifact
== ART_TROLLSBANE
)) {
754 if (by_hero
&& cansee(x
,y
))
755 pline("%s twitches feebly.",
756 upstart(corpse_xname(corpse
, (const char *) 0, CXN_PFX_THE
)));
757 return (struct monst
*) 0;
760 if (cant_revive(&montype
, TRUE
, corpse
)) {
761 /* make a zombie or doppelganger instead */
762 /* note: montype has changed; mptr keeps old value for newcham() */
763 mtmp
= makemon(&mons
[montype
], x
, y
, NO_MINVENT
| MM_NOWAIT
);
765 /* skip ghost handling */
766 if (has_omid(corpse
))
768 if (has_omonst(corpse
))
770 if (mtmp
->cham
== PM_DOPPELGANGER
) {
771 /* change shape to match the corpse */
772 (void) newcham(mtmp
, mptr
, FALSE
, FALSE
);
773 } else if (mtmp
->data
->mlet
== S_ZOMBIE
) {
774 mtmp
->mhp
= mtmp
->mhpmax
= 100;
775 mon_adjust_speed(mtmp
, 2, (struct obj
*) 0); /* MFAST */
778 } else if (has_omonst(corpse
)) {
779 /* use saved traits */
781 mtmp
= montraits(corpse
, &xy
);
782 if (mtmp
&& mtmp
->mtame
&& !mtmp
->isminion
)
783 wary_dog(mtmp
, TRUE
);
785 /* make a new monster */
786 mtmp
= makemon(mptr
, x
, y
, NO_MINVENT
| MM_NOWAIT
| MM_NOCOUNTBIRTH
);
789 return (struct monst
*) 0;
791 /* hiders shouldn't already be re-hidden when they revive */
792 if (mtmp
->mundetected
) {
793 mtmp
->mundetected
= 0;
794 newsym(mtmp
->mx
, mtmp
->my
);
799 one_of
= (corpse
->quan
> 1L);
801 corpse
= splitobj(corpse
, 1L);
803 /* if this is caused by the hero there might be a shop charge */
805 struct monst
*shkp
= 0;
807 x
= corpse
->ox
, y
= corpse
->oy
;
808 if (costly_spot(x
, y
)
809 && (carried(corpse
) ? corpse
->unpaid
: !corpse
->no_charge
))
810 shkp
= shop_keeper(*in_rooms(x
, y
, SHOPBASE
));
814 unsigned pfx
= CXN_PFX_THE
;
816 Strcpy(buf
, one_of
? "one of " : "");
817 if (carried(corpse
) && !corpse
->unpaid
) {
818 Strcat(buf
, "your ");
822 corpse
->quan
++; /* force plural */
823 Strcat(buf
, corpse_xname(corpse
, (const char *) 0, pfx
));
824 if (one_of
) /* could be simplified to ''corpse->quan = 1L;'' */
826 pline("%s glows iridescently.", upstart(buf
));
828 /* need some prior description of the corpse since
829 stolen_value() will refer to the object as "it" */
830 pline("A corpse is resuscitated.");
832 /* don't charge for shopkeeper's own corpse if we just revived him */
833 if (shkp
&& mtmp
!= shkp
)
834 (void) stolen_value(corpse
, x
, y
, (boolean
) shkp
->mpeaceful
,
837 /* [we don't give any comparable message about the corpse for
838 the !by_hero case because caller might have already done so] */
841 /* handle recorporealization of an active ghost */
842 if (has_omid(corpse
)) {
847 (void) memcpy((genericptr_t
) &m_id
, (genericptr_t
) OMID(corpse
),
849 ghost
= find_mid(m_id
, FM_FMON
);
850 if (ghost
&& ghost
->data
== &mons
[PM_GHOST
]) {
851 if (canseemon(ghost
))
852 pline("%s is suddenly drawn into its former body!",
854 /* transfer the ghost's inventory along with it */
855 while ((otmp
= ghost
->minvent
) != 0) {
856 obj_extract_self(otmp
);
857 add_to_minv(mtmp
, otmp
);
859 /* tame the revived monster if its ghost was tame */
860 if (ghost
->mtame
&& !mtmp
->mtame
) {
861 if (tamedog(mtmp
, (struct obj
*) 0)) {
862 /* ghost's edog data is ignored */
863 mtmp
->mtame
= ghost
->mtame
;
866 /* was ghost, now alive, it's all very confusing */
868 /* separate ghost monster no longer exists */
874 /* monster retains its name */
875 if (has_oname(corpse
) && !unique_corpstat(mtmp
->data
))
876 mtmp
= christen_monst(mtmp
, ONAME(corpse
));
877 /* partially eaten corpse yields wounded monster */
879 mtmp
->mhp
= eaten_stat(mtmp
->mhp
, corpse
);
880 /* track that this monster was revived at least once */
883 /* finally, get rid of the corpse--it's gone now */
884 switch (corpse
->where
) {
889 /* in case MON_AT+enexto for invisible mon */
890 x
= corpse
->ox
, y
= corpse
->oy
;
891 /* not useupf(), which charges */
892 if (corpse
->quan
> 1L)
893 corpse
= splitobj(corpse
, 1L);
898 m_useup(corpse
->ocarry
, corpse
);
901 obj_extract_self(corpse
);
902 obfree(corpse
, (struct obj
*) 0);
916 * Note: generic eggs with corpsenm set to NON_PM will never hatch.
918 if (obj
->otyp
!= EGG
)
920 if (obj
->corpsenm
!= NON_PM
&& !dead_species(obj
->corpsenm
, TRUE
))
921 attach_egg_hatch_timeout(obj
, 0L);
924 /* try to revive all corpses and eggs carried by `mon' */
929 struct obj
*otmp
, *otmp2
;
931 char owner
[BUFSZ
], corpse
[BUFSZ
];
935 youseeit
= (mon
== &youmonst
) ? TRUE
: canseemon(mon
);
936 otmp2
= (mon
== &youmonst
) ? invent
: mon
->minvent
;
937 owner
[0] = corpse
[0] = '\0'; /* lint suppression */
939 while ((otmp
= otmp2
) != 0) {
941 if (otmp
->otyp
== EGG
)
943 if (otmp
->otyp
!= CORPSE
)
945 /* save the name; the object is liable to go away */
948 corpse_xname(otmp
, (const char *) 0, CXN_SINGULAR
));
949 Shk_Your(owner
, otmp
); /* includes a trailing space */
952 /* for a stack, only one is revived */
953 if ((mtmp2
= revive(otmp
, !context
.mon_moving
)) != 0) {
956 pline("%s%s suddenly comes alive!", owner
, corpse
);
957 else if (canseemon(mtmp2
))
958 pline("%s suddenly appears!", Amonnam(mtmp2
));
964 /* cancel obj, possibly carried by you or a monster */
967 register struct obj
*obj
;
969 boolean u_ring
= (obj
== uleft
|| obj
== uright
);
970 int otyp
= obj
->otyp
;
973 case RIN_GAIN_STRENGTH
:
974 if ((obj
->owornmask
& W_RING
) && u_ring
) {
975 ABON(A_STR
) -= obj
->spe
;
979 case RIN_GAIN_CONSTITUTION
:
980 if ((obj
->owornmask
& W_RING
) && u_ring
) {
981 ABON(A_CON
) -= obj
->spe
;
986 if ((obj
->owornmask
& W_RING
) && u_ring
) {
987 ABON(A_CHA
) -= obj
->spe
;
991 case RIN_INCREASE_ACCURACY
:
992 if ((obj
->owornmask
& W_RING
) && u_ring
)
993 u
.uhitinc
-= obj
->spe
;
995 case RIN_INCREASE_DAMAGE
:
996 if ((obj
->owornmask
& W_RING
) && u_ring
)
997 u
.udaminc
-= obj
->spe
;
999 case GAUNTLETS_OF_DEXTERITY
:
1000 if ((obj
->owornmask
& W_ARMG
) && (obj
== uarmg
)) {
1001 ABON(A_DEX
) -= obj
->spe
;
1005 case HELM_OF_BRILLIANCE
:
1006 if ((obj
->owornmask
& W_ARMH
) && (obj
== uarmh
)) {
1007 ABON(A_INT
) -= obj
->spe
;
1008 ABON(A_WIS
) -= obj
->spe
;
1012 /* case RIN_PROTECTION: not needed */
1014 if (objects
[otyp
].oc_magic
1015 || (obj
->spe
&& (obj
->oclass
== ARMOR_CLASS
1016 || obj
->oclass
== WEAPON_CLASS
|| is_weptool(obj
)))
1018 || otyp
== POT_SICKNESS
1019 || (otyp
== POT_WATER
&& (obj
->blessed
|| obj
->cursed
))) {
1020 if (obj
->spe
!= ((obj
->oclass
== WAND_CLASS
) ? -1 : 0)
1021 && otyp
!= WAN_CANCELLATION
/* can't cancel cancellation */
1022 && otyp
!= MAGIC_LAMP
/* cancelling doesn't remove djinni */
1023 && otyp
!= CANDELABRUM_OF_INVOCATION
) {
1024 costly_alteration(obj
, COST_CANCEL
);
1025 obj
->spe
= (obj
->oclass
== WAND_CLASS
) ? -1 : 0;
1027 switch (obj
->oclass
) {
1029 costly_alteration(obj
, COST_CANCEL
);
1030 obj
->otyp
= SCR_BLANK_PAPER
;
1034 if (otyp
!= SPE_CANCELLATION
&& otyp
!= SPE_NOVEL
1035 && otyp
!= SPE_BOOK_OF_THE_DEAD
) {
1036 costly_alteration(obj
, COST_CANCEL
);
1037 obj
->otyp
= SPE_BLANK_PAPER
;
1041 costly_alteration(obj
,
1044 : obj
->cursed
? COST_UNCURS
: COST_UNBLSS
);
1045 if (otyp
== POT_SICKNESS
|| otyp
== POT_SEE_INVISIBLE
) {
1046 /* sickness is "biologically contaminated" fruit juice;
1047 cancel it and it just becomes fruit juice...
1048 whereas see invisible tastes like "enchanted" fruit
1049 juice, it similarly cancels */
1050 obj
->otyp
= POT_FRUIT_JUICE
;
1052 obj
->otyp
= POT_WATER
;
1053 obj
->odiluted
= 0; /* same as any other water */
1063 /* Remove a positive enchantment or charge from obj,
1064 * possibly carried by you or a monster
1067 drain_item(obj
, by_you
)
1073 /* Is this a charged/enchanted object? */
1075 || (!objects
[obj
->otyp
].oc_charged
&& obj
->oclass
!= WEAPON_CLASS
1076 && obj
->oclass
!= ARMOR_CLASS
&& !is_weptool(obj
))
1079 if (defends(AD_DRLI
, obj
) || defends_when_carried(AD_DRLI
, obj
)
1080 || obj_resists(obj
, 10, 90))
1083 /* Charge for the cost of the object */
1085 costly_alteration(obj
, COST_DRAIN
);
1087 /* Drain the object and any implied effects */
1089 u_ring
= (obj
== uleft
) || (obj
== uright
);
1090 switch (obj
->otyp
) {
1091 case RIN_GAIN_STRENGTH
:
1092 if ((obj
->owornmask
& W_RING
) && u_ring
) {
1097 case RIN_GAIN_CONSTITUTION
:
1098 if ((obj
->owornmask
& W_RING
) && u_ring
) {
1104 if ((obj
->owornmask
& W_RING
) && u_ring
) {
1109 case RIN_INCREASE_ACCURACY
:
1110 if ((obj
->owornmask
& W_RING
) && u_ring
)
1113 case RIN_INCREASE_DAMAGE
:
1114 if ((obj
->owornmask
& W_RING
) && u_ring
)
1117 case RIN_PROTECTION
:
1119 context
.botl
= 1; /* bot() will recalc u.uac */
1121 case HELM_OF_BRILLIANCE
:
1122 if ((obj
->owornmask
& W_ARMH
) && (obj
== uarmh
)) {
1128 case GAUNTLETS_OF_DEXTERITY
:
1129 if ((obj
->owornmask
& W_ARMG
) && (obj
== uarmg
)) {
1145 obj_resists(obj
, ochance
, achance
)
1147 int ochance
, achance
; /* percent chance for ordinary objects, artifacts */
1149 if (obj
->otyp
== AMULET_OF_YENDOR
1150 || obj
->otyp
== SPE_BOOK_OF_THE_DEAD
1151 || obj
->otyp
== CANDELABRUM_OF_INVOCATION
1152 || obj
->otyp
== BELL_OF_OPENING
1153 || (obj
->otyp
== CORPSE
&& is_rider(&mons
[obj
->corpsenm
]))) {
1156 int chance
= rn2(100);
1158 return (boolean
) (chance
< (obj
->oartifact
? achance
: ochance
));
1168 if (context
.bypasses
&& obj
->bypass
)
1171 if (obj
->oclass
== WAND_CLASS
)
1172 zap_odds
= 3; /* half-life = 2 zaps */
1173 else if (obj
->cursed
)
1174 zap_odds
= 3; /* half-life = 2 zaps */
1175 else if (obj
->blessed
)
1176 zap_odds
= 12; /* half-life = 8 zaps */
1178 zap_odds
= 8; /* half-life = 6 zaps */
1180 /* adjust for "large" quantities of identical things */
1184 return (boolean
) !rn2(zap_odds
);
1187 /* Use up at least minwt number of things made of material mat.
1188 * There's also a chance that other stuff will be used up. Finally,
1189 * there's a random factor here to keep from always using the stuff
1190 * at the top of the pile.
1193 polyuse(objhdr
, mat
, minwt
)
1197 register struct obj
*otmp
, *otmp2
;
1199 for (otmp
= objhdr
; minwt
> 0 && otmp
; otmp
= otmp2
) {
1200 otmp2
= otmp
->nexthere
;
1201 if (context
.bypasses
&& otmp
->bypass
)
1203 if (otmp
== uball
|| otmp
== uchain
)
1205 if (obj_resists(otmp
, 0, 0))
1206 continue; /* preserve unique objects */
1208 if (otmp
->otyp
== SCR_MAIL
)
1212 if (((int) objects
[otmp
->otyp
].oc_material
== mat
)
1213 == (rn2(minwt
+ 1) != 0)) {
1214 /* appropriately add damage to bill */
1215 if (costly_spot(otmp
->ox
, otmp
->oy
)) {
1217 addtobill(otmp
, FALSE
, FALSE
, FALSE
);
1219 (void) stolen_value(otmp
, otmp
->ox
, otmp
->oy
, FALSE
,
1222 if (otmp
->quan
< LARGEST_INT
)
1223 minwt
-= (int) otmp
->quan
;
1232 * Polymorph some of the stuff in this pile into a monster, preferably
1233 * a golem of the kind okind.
1236 create_polymon(obj
, okind
)
1240 struct permonst
*mdat
= (struct permonst
*) 0;
1242 const char *material
;
1245 if (context
.bypasses
) {
1246 /* this is approximate because the "no golems" !obj->nexthere
1247 check below doesn't understand bypassed objects; but it
1248 should suffice since bypassed objects always end up as a
1249 consecutive group at the top of their pile */
1250 while (obj
&& obj
->bypass
)
1251 obj
= obj
->nexthere
;
1254 /* no golems if you zap only one object -- not enough stuff */
1255 if (!obj
|| (!obj
->nexthere
&& obj
->quan
== 1L))
1258 /* some of these choices are arbitrary */
1263 pm_index
= PM_IRON_GOLEM
;
1264 material
= "metal ";
1271 pm_index
= rn2(2) ? PM_STONE_GOLEM
: PM_CLAY_GOLEM
;
1272 material
= "lithic ";
1276 /* there is no flesh type, but all food is type 0, so we use it */
1277 pm_index
= PM_FLESH_GOLEM
;
1278 material
= "organic ";
1281 pm_index
= PM_WOOD_GOLEM
;
1285 pm_index
= PM_LEATHER_GOLEM
;
1286 material
= "leather ";
1289 pm_index
= PM_ROPE_GOLEM
;
1290 material
= "cloth ";
1293 pm_index
= PM_SKELETON
; /* nearest thing to "bone golem" */
1297 pm_index
= PM_GOLD_GOLEM
;
1301 pm_index
= PM_GLASS_GOLEM
;
1302 material
= "glassy ";
1305 pm_index
= PM_PAPER_GOLEM
;
1306 material
= "paper ";
1309 /* if all else fails... */
1310 pm_index
= PM_STRAW_GOLEM
;
1315 if (!(mvitals
[pm_index
].mvflags
& G_GENOD
))
1316 mdat
= &mons
[pm_index
];
1318 mtmp
= makemon(mdat
, obj
->ox
, obj
->oy
, NO_MM_FLAGS
);
1319 polyuse(obj
, okind
, (int) mons
[pm_index
].cwt
);
1321 if (mtmp
&& cansee(mtmp
->mx
, mtmp
->my
)) {
1322 pline("Some %sobjects meld, and %s arises from the pile!", material
,
1327 /* Assumes obj is on the floor. */
1335 if (obj
->otyp
== SCR_MAIL
)
1340 if (poly_zapped
< 0) {
1341 /* some may metamorphosize */
1342 for (i
= obj
->quan
; i
; i
--)
1343 if (!rn2(Luck
+ 45)) {
1344 poly_zapped
= objects
[obj
->otyp
].oc_material
;
1349 /* if quan > 1 then some will survive intact */
1350 if (obj
->quan
> 1L) {
1351 if (obj
->quan
> LARGEST_INT
)
1352 obj
= splitobj(obj
, (long) rnd(30000));
1354 obj
= splitobj(obj
, (long) rnd((int) obj
->quan
- 1));
1357 /* appropriately add damage to bill */
1358 if (costly_spot(obj
->ox
, obj
->oy
)) {
1360 addtobill(obj
, FALSE
, FALSE
, FALSE
);
1362 (void) stolen_value(obj
, obj
->ox
, obj
->oy
, FALSE
, FALSE
);
1365 /* zap the object */
1369 /* classes of items whose current charge count carries over across polymorph
1371 static const char charged_objs
[] = { WAND_CLASS
, WEAPON_CLASS
, ARMOR_CLASS
,
1375 * Polymorph the object to the given object ID. If the ID is STRANGE_OBJECT
1376 * then pick random object from the source's class (this is the standard
1377 * "polymorph" case). If ID is set to a specific object, inhibit fusing
1378 * n objects into 1. This could have been added as a flag, but currently
1379 * it is tied to not being the standard polymorph case. The new polymorphed
1380 * object replaces obj in its link chains. Return value is a pointer to
1383 * This should be safe to call for an object anywhere.
1392 boolean can_merge
= (id
== STRANGE_OBJECT
);
1393 int obj_location
= obj
->where
;
1395 if (obj
->otyp
== BOULDER
)
1397 if (id
== STRANGE_OBJECT
) { /* preserve symbol */
1399 unsigned magic_obj
= objects
[obj
->otyp
].oc_magic
;
1401 if (obj
->otyp
== UNICORN_HORN
&& obj
->degraded_horn
)
1403 /* Try up to 3 times to make the magic-or-not status of
1404 the new item be the same as it was for the old one. */
1405 otmp
= (struct obj
*) 0;
1409 otmp
= mkobj(obj
->oclass
, FALSE
);
1410 } while (--try_limit
> 0
1411 && objects
[otmp
->otyp
].oc_magic
!= magic_obj
);
1413 /* literally replace obj with this new thing */
1414 otmp
= mksobj(id
, FALSE
, FALSE
);
1415 /* Actually more things use corpsenm but they polymorph differently */
1416 #define USES_CORPSENM(typ) \
1417 ((typ) == CORPSE || (typ) == STATUE || (typ) == FIGURINE)
1419 if (USES_CORPSENM(obj
->otyp
) && USES_CORPSENM(id
))
1420 set_corpsenm(otmp
, obj
->corpsenm
);
1421 #undef USES_CORPSENM
1424 /* preserve quantity */
1425 otmp
->quan
= obj
->quan
;
1426 /* preserve the shopkeepers (lack of) interest */
1427 otmp
->no_charge
= obj
->no_charge
;
1428 /* preserve inventory letter if in inventory */
1429 if (obj_location
== OBJ_INVENT
)
1430 otmp
->invlet
= obj
->invlet
;
1432 /* You can't send yourself 100 mail messages and then
1433 * polymorph them into useful scrolls
1435 if (obj
->otyp
== SCR_MAIL
) {
1436 otmp
->otyp
= SCR_MAIL
;
1441 /* avoid abusing eggs laid by you */
1442 if (obj
->otyp
== EGG
&& obj
->spe
) {
1443 int mnum
, tryct
= 100;
1445 /* first, turn into a generic egg */
1446 if (otmp
->otyp
== EGG
)
1450 otmp
->owt
= weight(otmp
);
1452 otmp
->corpsenm
= NON_PM
;
1455 /* now change it into something laid by the hero */
1457 mnum
= can_be_hatched(random_monster());
1458 if (mnum
!= NON_PM
&& !dead_species(mnum
, TRUE
)) {
1459 otmp
->spe
= 1; /* laid by hero */
1460 set_corpsenm(otmp
, mnum
); /* also sets hatch timer */
1466 /* keep special fields (including charges on wands) */
1467 if (index(charged_objs
, otmp
->oclass
))
1468 otmp
->spe
= obj
->spe
;
1469 otmp
->recharged
= obj
->recharged
;
1471 otmp
->cursed
= obj
->cursed
;
1472 otmp
->blessed
= obj
->blessed
;
1474 if (erosion_matters(otmp
)) {
1475 if (is_flammable(otmp
) || is_rustprone(otmp
))
1476 otmp
->oeroded
= obj
->oeroded
;
1477 if (is_corrodeable(otmp
) || is_rottable(otmp
))
1478 otmp
->oeroded2
= obj
->oeroded2
;
1479 if (is_damageable(otmp
))
1480 otmp
->oerodeproof
= obj
->oerodeproof
;
1483 /* Keep chest/box traps and poisoned ammo if we may */
1484 if (obj
->otrapped
&& Is_box(otmp
))
1485 otmp
->otrapped
= TRUE
;
1487 if (obj
->opoisoned
&& is_poisonable(otmp
))
1488 otmp
->opoisoned
= TRUE
;
1490 if (id
== STRANGE_OBJECT
&& obj
->otyp
== CORPSE
) {
1491 /* turn crocodile corpses into shoes */
1492 if (obj
->corpsenm
== PM_CROCODILE
) {
1493 otmp
->otyp
= LOW_BOOTS
;
1494 otmp
->oclass
= ARMOR_CLASS
;
1497 otmp
->oerodeproof
= TRUE
;
1499 otmp
->cursed
= FALSE
;
1503 /* no box contents --KAA */
1504 if (Has_contents(otmp
))
1505 delete_contents(otmp
);
1507 /* 'n' merged objects may be fused into 1 object */
1508 if (otmp
->quan
> 1L && (!objects
[otmp
->otyp
].oc_merge
1509 || (can_merge
&& otmp
->quan
> (long) rn2(1000))))
1512 switch (otmp
->oclass
) {
1514 if (otmp
->otyp
== MAGIC_LAMP
) {
1515 otmp
->otyp
= OIL_LAMP
;
1516 otmp
->age
= 1500L; /* "best" oil lamp possible */
1517 } else if (otmp
->otyp
== MAGIC_MARKER
) {
1518 otmp
->recharged
= 1; /* degraded quality */
1520 /* don't care about the recharge count of other tools */
1524 while (otmp
->otyp
== WAN_WISHING
|| otmp
->otyp
== WAN_POLYMORPH
)
1525 otmp
->otyp
= rnd_class(WAN_LIGHT
, WAN_LIGHTNING
);
1526 /* altering the object tends to degrade its quality
1527 (analogous to spellbook `read count' handling) */
1528 if ((int) otmp
->recharged
< rn2(7)) /* recharge_limit */
1533 while (otmp
->otyp
== POT_POLYMORPH
)
1534 otmp
->otyp
= rnd_class(POT_GAIN_ABILITY
, POT_WATER
);
1538 while (otmp
->otyp
== SPE_POLYMORPH
)
1539 otmp
->otyp
= rnd_class(SPE_DIG
, SPE_BLANK_PAPER
);
1540 /* reduce spellbook abuse; non-blank books degrade */
1541 if (otmp
->otyp
!= SPE_BLANK_PAPER
) {
1542 otmp
->spestudied
= obj
->spestudied
+ 1;
1543 if (otmp
->spestudied
> MAX_SPELL_STUDY
) {
1544 otmp
->otyp
= SPE_BLANK_PAPER
;
1545 /* writing a new book over it will yield an unstudied
1546 one; re-polymorphing this one as-is may or may not
1547 get something non-blank */
1548 otmp
->spestudied
= rn2(otmp
->spestudied
);
1554 if (otmp
->quan
> (long) rnd(4)
1555 && objects
[obj
->otyp
].oc_material
== MINERAL
1556 && objects
[otmp
->otyp
].oc_material
!= MINERAL
) {
1557 otmp
->otyp
= ROCK
; /* transmutation backfired */
1558 otmp
->quan
/= 2L; /* some material has been lost */
1563 /* update the weight */
1564 otmp
->owt
= weight(otmp
);
1566 /* handle polymorph of worn item: stone-to-flesh cast on self can
1567 affect multiple objects at once, but their new forms won't
1568 produce any side-effects; a single worn item dipped into potion
1569 of polymorph can produce side-effects but those won't yield out
1570 of sequence messages because current polymorph is finished */
1571 if (obj_location
== OBJ_INVENT
&& obj
->owornmask
) {
1572 long old_wornmask
= obj
->owornmask
& ~(W_ART
| W_ARTI
),
1573 new_wornmask
= wearslot(otmp
);
1574 boolean was_twohanded
= bimanual(obj
), was_twoweap
= u
.twoweap
;
1576 remove_worn_item(obj
, TRUE
);
1577 /* if the new form can be worn in the same slot, make it so
1578 [possible extension: if it could be worn in some other
1579 slot which is currently unfilled, wear it there instead] */
1580 if ((old_wornmask
& W_QUIVER
) != 0L) {
1582 } else if ((old_wornmask
& W_SWAPWEP
) != 0L) {
1583 if (was_twohanded
|| !bimanual(otmp
))
1585 if (was_twoweap
&& uswapwep
)
1587 } else if ((old_wornmask
& W_WEP
) != 0L) {
1588 if (was_twohanded
|| !bimanual(otmp
) || !uarms
)
1590 if (was_twoweap
&& uwep
&& !bimanual(uwep
))
1592 } else if ((old_wornmask
& new_wornmask
) != 0L) {
1593 new_wornmask
&= old_wornmask
;
1594 setworn(otmp
, new_wornmask
);
1595 set_wear(otmp
); /* Armor_on() for side-effects */
1599 /* ** we are now done adjusting the object ** */
1601 /* swap otmp for obj */
1602 replace_object(obj
, otmp
);
1603 if (obj_location
== OBJ_INVENT
) {
1605 * We may need to do extra adjustments for the hero if we're
1606 * messing with the hero's inventory. The following calls are
1607 * equivalent to calling freeinv on obj and addinv on otmp,
1608 * while doing an in-place swap of the actual objects.
1613 } else if (obj_location
== OBJ_FLOOR
) {
1614 ox
= otmp
->ox
, oy
= otmp
->oy
; /* set by replace_object() */
1615 if (obj
->otyp
== BOULDER
&& otmp
->otyp
!= BOULDER
1616 && !does_block(ox
, oy
, &levl
[ox
][oy
]))
1617 unblock_point(ox
, oy
);
1618 else if (obj
->otyp
!= BOULDER
&& otmp
->otyp
== BOULDER
)
1619 /* (checking does_block() here would be redundant) */
1620 block_point(ox
, oy
);
1623 if ((!carried(otmp
) || obj
->unpaid
)
1624 && get_obj_location(otmp
, &ox
, &oy
, BURIED_TOO
| CONTAINED_TOO
)
1625 && costly_spot(ox
, oy
)) {
1626 register struct monst
*shkp
=
1627 shop_keeper(*in_rooms(ox
, oy
, SHOPBASE
));
1629 if ((!obj
->no_charge
1630 || (Has_contents(obj
)
1631 && (contained_cost(obj
, shkp
, 0L, FALSE
, FALSE
) != 0L)))
1632 && inhishop(shkp
)) {
1633 if (shkp
->mpeaceful
) {
1635 && *in_rooms(u
.ux
, u
.uy
, 0)
1636 == *in_rooms(shkp
->mx
, shkp
->my
, 0)
1637 && !costly_spot(u
.ux
, u
.uy
)) {
1638 make_angry_shk(shkp
, ox
, oy
);
1640 pline("%s gets angry!", Monnam(shkp
));
1644 Norep("%s is furious!", Monnam(shkp
));
1651 /* stone-to-flesh spell hits and maybe transforms or animates obj */
1653 stone_to_flesh_obj(obj
)
1656 int res
= 1; /* affected object by default */
1657 struct permonst
*ptr
;
1658 struct monst
*mon
, *shkp
;
1661 boolean smell
= FALSE
, golem_xform
= FALSE
;
1663 if (objects
[obj
->otyp
].oc_material
!= MINERAL
1664 && objects
[obj
->otyp
].oc_material
!= GEMSTONE
)
1666 /* Heart of Ahriman usually resists; ordinary items rarely do */
1667 if (obj_resists(obj
, 2, 98))
1670 (void) get_obj_location(obj
, &oox
, &ooy
, 0);
1671 /* add more if stone objects are added.. */
1672 switch (objects
[obj
->otyp
].oc_class
) {
1673 case ROCK_CLASS
: /* boulders and statues */
1674 case TOOL_CLASS
: /* figurines */
1675 if (obj
->otyp
== BOULDER
) {
1676 obj
= poly_obj(obj
, HUGE_CHUNK_OF_MEAT
);
1678 } else if (obj
->otyp
== STATUE
|| obj
->otyp
== FIGURINE
) {
1679 ptr
= &mons
[obj
->corpsenm
];
1680 if (is_golem(ptr
)) {
1681 golem_xform
= (ptr
!= &mons
[PM_FLESH_GOLEM
]);
1682 } else if (vegetarian(ptr
)) {
1683 /* Don't animate monsters that aren't flesh */
1684 obj
= poly_obj(obj
, MEATBALL
);
1688 if (obj
->otyp
== STATUE
) {
1689 /* animate_statue() forces all golems to become flesh golems */
1690 mon
= animate_statue(obj
, oox
, ooy
, ANIMATE_SPELL
, (int *) 0);
1691 } else { /* (obj->otyp == FIGURINE) */
1693 ptr
= &mons
[PM_FLESH_GOLEM
];
1694 mon
= makemon(ptr
, oox
, ooy
, NO_MINVENT
);
1696 if (costly_spot(oox
, ooy
)
1697 && (carried(obj
) ? obj
->unpaid
: !obj
->no_charge
)) {
1698 shkp
= shop_keeper(*in_rooms(oox
, ooy
, SHOPBASE
));
1699 stolen_value(obj
, oox
, ooy
,
1700 (shkp
&& shkp
->mpeaceful
), FALSE
);
1703 obj_stop_timers(obj
);
1708 if (cansee(mon
->mx
, mon
->my
))
1709 pline_The("figurine %sanimates!",
1710 golem_xform
? "turns to flesh and " : "");
1715 /* this golem handling is redundant... */
1716 if (is_golem(ptr
) && ptr
!= &mons
[PM_FLESH_GOLEM
])
1717 (void) newcham(mon
, &mons
[PM_FLESH_GOLEM
], TRUE
, FALSE
);
1718 } else if ((ptr
->geno
& (G_NOCORPSE
| G_UNIQ
)) != 0) {
1719 /* didn't revive but can't leave corpse either */
1722 /* unlikely to get here since genociding monsters also
1723 sets the G_NOCORPSE flag; drop statue's contents */
1724 while ((item
= obj
->cobj
) != 0) {
1725 bypass_obj(item
); /* make stone-to-flesh miss it */
1726 obj_extract_self(item
);
1727 place_object(item
, oox
, ooy
);
1729 obj
= poly_obj(obj
, CORPSE
);
1731 } else { /* miscellaneous tool or unexpected rock... */
1735 /* maybe add weird things to become? */
1736 case RING_CLASS
: /* some of the rings are stone */
1737 obj
= poly_obj(obj
, MEAT_RING
);
1740 case WAND_CLASS
: /* marble wand */
1741 obj
= poly_obj(obj
, MEAT_STICK
);
1744 case GEM_CLASS
: /* stones & gems */
1745 obj
= poly_obj(obj
, MEATBALL
);
1748 case WEAPON_CLASS
: /* crysknife */
1756 /* non-meat eaters smell meat, meat eaters smell its flavor;
1757 monks are considered non-meat eaters regardless of behavior;
1758 other roles are non-meat eaters if they haven't broken
1759 vegetarian conduct yet (or if poly'd into non-carnivorous/
1760 non-omnivorous form, regardless of whether it's herbivorous,
1761 non-eating, or something stranger) */
1762 if (Role_if(PM_MONK
) || !u
.uconduct
.unvegetarian
1763 || !carnivorous(youmonst
.data
))
1764 Norep("You smell the odor of meat.");
1766 Norep("You smell a delicious smell.");
1773 * Object obj was hit by the effect of the wand/spell otmp. Return
1774 * non-zero if the wand/spell had any effect.
1778 struct obj
*obj
, *otmp
;
1780 int res
= 1; /* affected object by default */
1781 boolean learn_it
= FALSE
, maybelearnit
;
1783 /* fundamental: a wand effect hitting itself doesn't do anything;
1784 otherwise we need to guard against accessing otmp after something
1785 strange has happened to it (along the lines of polymorph or
1786 stone-to-flesh [which aren't good examples since polymorph wands
1787 aren't affected by polymorph zaps and stone-to-flesh isn't
1788 available in wand form, but the concept still applies...]) */
1793 /* The bypass bit is currently only used as follows:
1795 * POLYMORPH - When a monster being polymorphed drops something
1796 * from its inventory as a result of the change.
1797 * If the items fall to the floor, they are not
1798 * subject to direct subsequent polymorphing
1799 * themselves on that same zap. This makes it
1800 * consistent with items that remain in the
1801 * monster's inventory. They are not polymorphed
1803 * UNDEAD_TURNING - When an undead creature gets killed via
1804 * undead turning, prevent its corpse from being
1805 * immediately revived by the same effect.
1806 * STONE_TO_FLESH - If a statue can't be revived, its
1807 * contents get dropped before turning it into
1808 * meat; prevent those contents from being hit.
1809 * retouch_equipment() - bypass flag is used to track which
1810 * items have been handled (bhito isn't involved).
1811 * menu_drop(), askchain() - inventory traversal where multiple
1812 * Drop can alter the invent chain while traversal
1813 * is in progress (bhito isn't involved).
1815 * The bypass bit on all objects is reset each turn, whenever
1816 * context.bypasses is set.
1818 * We check the obj->bypass bit above AND context.bypasses
1819 * as a safeguard against any stray occurrence left in an obj
1820 * struct someplace, although that should never happen.
1822 if (context
.bypasses
) {
1825 debugpline1("%s for a moment.", Tobjnam(obj
, "pulsate"));
1831 * Some parts of this function expect the object to be on the floor
1832 * obj->{ox,oy} to be valid. The exception to this (so far) is
1833 * for the STONE_TO_FLESH spell.
1835 if (!(obj
->where
== OBJ_FLOOR
|| otmp
->otyp
== SPE_STONE_TO_FLESH
))
1836 impossible("bhito: obj is not floor or Stone To Flesh spell");
1840 } else if (obj
== uchain
) {
1841 if (otmp
->otyp
== WAN_OPENING
|| otmp
->otyp
== SPE_KNOCK
) {
1847 switch (otmp
->otyp
) {
1850 if (obj
->otyp
== WAN_POLYMORPH
|| obj
->otyp
== SPE_POLYMORPH
1851 || obj
->otyp
== POT_POLYMORPH
|| obj_resists(obj
, 5, 95)) {
1856 u
.uconduct
.polypiles
++;
1857 /* any saved lock context will be dangerously obsolete */
1859 (void) boxlock(obj
, otmp
);
1861 if (obj_shudders(obj
)) {
1863 ((obj
== level
.objects
[u
.ux
][u
.uy
]) && u
.uundetected
1864 && hides_under(youmonst
.data
));
1866 if (cansee(obj
->ox
, obj
->oy
))
1869 /* eek - your cover might have been blown */
1871 (void) hideunder(&youmonst
);
1874 obj
= poly_obj(obj
, STRANGE_OBJECT
);
1875 newsym(obj
->ox
, obj
->oy
);
1879 /* target object has now been "seen (up close)" */
1881 if (Is_container(obj
) || obj
->otyp
== STATUE
) {
1882 obj
->cknown
= obj
->lknown
= 1;
1884 boolean catbox
= SchroedingersBox(obj
);
1886 /* we don't want to force alive vs dead
1887 determination for Schroedinger's Cat here,
1888 so just make probing be inconclusive for it */
1891 pline("%s empty.", Tobjnam(obj
, catbox
? "seem" : "are"));
1894 /* view contents (not recursively) */
1895 for (o
= obj
->cobj
; o
; o
= o
->nobj
)
1896 o
->dknown
= 1; /* "seen", even if blind */
1897 (void) display_cinventory(obj
);
1905 case SPE_FORCE_BOLT
:
1906 /* learn the type if you see or hear something break
1907 (the sound could be implicit) */
1908 maybelearnit
= cansee(obj
->ox
, obj
->oy
) || !Deaf
;
1909 if (obj
->otyp
== BOULDER
) {
1910 if (cansee(obj
->ox
, obj
->oy
))
1911 pline_The("boulder falls apart.");
1913 You_hear("a crumbling sound.");
1915 } else if (obj
->otyp
== STATUE
) {
1916 if (break_statue(obj
)) {
1917 if (cansee(obj
->ox
, obj
->oy
)) {
1919 pline_The("%s shatters.", rndmonnam(NULL
));
1921 pline_The("statue shatters.");
1923 You_hear("a crumbling sound.");
1928 if (context
.mon_moving
1929 ? !breaks(obj
, obj
->ox
, obj
->oy
)
1930 : !hero_breaks(obj
, obj
->ox
, obj
->oy
, FALSE
))
1931 maybelearnit
= FALSE
; /* nothing broke */
1933 newsym_force(oox
,ooy
);
1939 case WAN_CANCELLATION
:
1940 case SPE_CANCELLATION
:
1943 newsym(obj
->ox
, obj
->oy
); /* might change color */
1946 case SPE_DRAIN_LIFE
:
1947 (void) drain_item(obj
, TRUE
);
1949 case WAN_TELEPORTATION
:
1950 case SPE_TELEPORT_AWAY
:
1953 case WAN_MAKE_INVISIBLE
:
1955 case WAN_UNDEAD_TURNING
:
1956 case SPE_TURN_UNDEAD
:
1957 if (obj
->otyp
== EGG
) {
1959 } else if (obj
->otyp
== CORPSE
) {
1960 int corpsenm
= corpse_revive_type(obj
);
1962 res
= !!revive(obj
, TRUE
);
1963 if (res
&& Role_if(PM_HEALER
)) {
1964 if (Hallucination
&& !Deaf
) {
1965 You_hear("the sound of a defibrillator.");
1967 } else if (!Blind
) {
1968 You("observe %s %s change dramatically.",
1969 s_suffix(an(mons
[corpsenm
].mname
)),
1970 nonliving(&mons
[corpsenm
]) ? "motility"
1975 exercise(A_WIS
, TRUE
);
1982 case SPE_WIZARD_LOCK
:
1984 res
= boxlock(obj
, otmp
);
1990 case WAN_SLOW_MONSTER
: /* no effect on objects */
1991 case SPE_SLOW_MONSTER
:
1992 case WAN_SPEED_MONSTER
:
1995 case SPE_EXTRA_HEALING
:
1998 case SPE_STONE_TO_FLESH
:
1999 res
= stone_to_flesh_obj(obj
);
2002 impossible("What an interesting effect (%d)", otmp
->otyp
);
2005 /* if effect was observable then discover the wand type provided
2006 that the wand itself has been seen */
2012 /* returns nonzero if something was hit */
2014 bhitpile(obj
, fhito
, tx
, ty
, zz
)
2016 int FDECL((*fhito
), (OBJ_P
, OBJ_P
));
2020 int hitanything
= 0;
2021 register struct obj
*otmp
, *next_obj
;
2023 if (obj
->otyp
== SPE_FORCE_BOLT
|| obj
->otyp
== WAN_STRIKING
) {
2024 struct trap
*t
= t_at(tx
, ty
);
2026 /* We can't settle for the default calling sequence of
2027 bhito(otmp) -> break_statue(otmp) -> activate_statue_trap(ox,oy)
2028 because that last call might end up operating on our `next_obj'
2029 (below), rather than on the current object, if it happens to
2030 encounter a statue which mustn't become animated. */
2031 if (t
&& t
->ttyp
== STATUE_TRAP
2032 && activate_statue_trap(t
, tx
, ty
, TRUE
))
2037 for (otmp
= level
.objects
[tx
][ty
]; otmp
; otmp
= next_obj
) {
2038 next_obj
= otmp
->nexthere
;
2039 /* for zap downwards, don't hit object poly'd hero is hiding under */
2040 if (zz
> 0 && u
.uundetected
&& otmp
== level
.objects
[u
.ux
][u
.uy
]
2041 && hides_under(youmonst
.data
))
2044 hitanything
+= (*fhito
)(otmp
, obj
);
2046 if (poly_zapped
>= 0)
2047 create_polymon(level
.objects
[tx
][ty
], poly_zapped
);
2053 * zappable - returns 1 if zap is available, 0 otherwise.
2054 * it removes a charge from the wand if zappable.
2055 * added by GAN 11/03/86
2059 register struct obj
*wand
;
2061 if (wand
->spe
< 0 || (wand
->spe
== 0 && rn2(121)))
2064 You("wrest one last charge from the worn-out wand.");
2070 * zapnodir - zaps a NODIR wand/spell.
2071 * added by GAN 11/03/86
2075 register struct obj
*obj
;
2077 boolean known
= FALSE
;
2079 switch (obj
->otyp
) {
2085 if (lightdamage(obj
, TRUE
, 5))
2088 case WAN_SECRET_DOOR_DETECTION
:
2089 case SPE_DETECT_UNSEEN
:
2095 case WAN_CREATE_MONSTER
:
2096 known
= create_critters(rn2(23) ? 1 : rn1(7, 2),
2097 (struct permonst
*) 0, FALSE
);
2101 if (Luck
+ rn2(5) < 0) {
2102 pline("Unfortunately, nothing happens.");
2107 case WAN_ENLIGHTENMENT
:
2109 You_feel("self-knowledgeable...");
2110 display_nhwindow(WIN_MESSAGE
, FALSE
);
2111 enlightenment(MAGICENLIGHTENMENT
, ENL_GAMEINPROGRESS
);
2112 pline_The("feeling subsides.");
2113 exercise(A_WIS
, TRUE
);
2117 if (!objects
[obj
->otyp
].oc_name_known
)
2118 more_experienced(0, 10);
2119 /* effect was observable; discover the wand type provided
2120 that the wand itself has been seen */
2130 otmp
->in_use
= TRUE
; /* in case losehp() is fatal */
2131 pline("%s suddenly explodes!", The(xname(otmp
)));
2132 dmg
= d(otmp
->spe
+ 2, 6);
2133 losehp(Maybe_Half_Phys(dmg
), "exploding wand", KILLED_BY_AN
);
2137 static NEARDATA
const char zap_syms
[] = { WAND_CLASS
, 0 };
2139 /* 'z' command (or 'y' if numbed_pad==-1) */
2143 register struct obj
*obj
;
2146 if (check_capacity((char *) 0))
2148 obj
= getobj(zap_syms
, "zap");
2154 /* zappable addition done by GAN 11/03/86 */
2156 pline1(nothing_happens
);
2157 else if (obj
->cursed
&& !rn2(WAND_BACKFIRE_CHANCE
)) {
2158 backfire(obj
); /* the wand blows up in your face! */
2159 exercise(A_STR
, FALSE
);
2161 } else if (!(objects
[obj
->otyp
].oc_dir
== NODIR
) && !getdir((char *) 0)) {
2163 pline("%s glows and fades.", The(xname(obj
)));
2164 /* make him pay for knowing !NODIR */
2165 } else if (!u
.dx
&& !u
.dy
&& !u
.dz
2166 && !(objects
[obj
->otyp
].oc_dir
== NODIR
)) {
2167 if ((damage
= zapyourself(obj
, TRUE
)) != 0) {
2170 Sprintf(buf
, "zapped %sself with a wand", uhim());
2171 losehp(Maybe_Half_Phys(damage
), buf
, NO_KILLER_PREFIX
);
2174 /* Are we having fun yet?
2175 * weffects -> buzz(obj->otyp) -> zhitm (temple priest) ->
2176 * attack -> hitum -> known_hitum -> ghod_hitsu ->
2177 * buzz(AD_ELEC) -> destroy_item(WAND_CLASS) ->
2178 * useup -> obfree -> dealloc_obj -> free(obj)
2185 if (obj
&& obj
->spe
< 0) {
2186 pline("%s to dust.", Tobjnam(obj
, "turn"));
2189 update_inventory(); /* maybe used a charge */
2194 zapyourself(obj
, ordinary
)
2198 boolean learn_it
= FALSE
;
2201 switch (obj
->otyp
) {
2203 case SPE_FORCE_BOLT
:
2206 shieldeff(u
.ux
, u
.uy
);
2210 You("bash yourself!");
2213 damage
= d(1 + obj
->spe
, 6);
2214 exercise(A_STR
, FALSE
);
2220 if (!Shock_resistance
) {
2221 You("shock yourself!");
2223 exercise(A_CON
, FALSE
);
2225 shieldeff(u
.ux
, u
.uy
);
2226 You("zap yourself, but seem unharmed.");
2227 ugolemeffects(AD_ELEC
, d(12, 6));
2229 destroy_item(WAND_CLASS
, AD_ELEC
);
2230 destroy_item(RING_CLASS
, AD_ELEC
);
2231 (void) flashburn((long) rnd(100));
2235 You("explode a fireball on top of yourself!");
2236 explode(u
.ux
, u
.uy
, 11, d(6, 6), WAND_CLASS
, EXPL_FIERY
);
2241 if (Fire_resistance
) {
2242 shieldeff(u
.ux
, u
.uy
);
2243 You_feel("rather warm.");
2244 ugolemeffects(AD_FIRE
, d(12, 6));
2246 pline("You've set yourself afire!");
2250 (void) burnarmor(&youmonst
);
2251 destroy_item(SCROLL_CLASS
, AD_FIRE
);
2252 destroy_item(POTION_CLASS
, AD_FIRE
);
2253 destroy_item(SPBOOK_CLASS
, AD_FIRE
);
2254 destroy_item(FOOD_CLASS
, AD_FIRE
); /* only slime for now */
2258 case SPE_CONE_OF_COLD
:
2261 if (Cold_resistance
) {
2262 shieldeff(u
.ux
, u
.uy
);
2263 You_feel("a little chill.");
2264 ugolemeffects(AD_COLD
, d(12, 6));
2266 You("imitate a popsicle!");
2269 destroy_item(POTION_CLASS
, AD_COLD
);
2272 case WAN_MAGIC_MISSILE
:
2273 case SPE_MAGIC_MISSILE
:
2276 shieldeff(u
.ux
, u
.uy
);
2277 pline_The("missiles bounce!");
2280 pline("Idiot! You've shot yourself!");
2292 case WAN_CANCELLATION
:
2293 case SPE_CANCELLATION
:
2294 (void) cancel_monst(&youmonst
, obj
, TRUE
, FALSE
, TRUE
);
2297 case SPE_DRAIN_LIFE
:
2298 if (!Drain_resistance
) {
2299 learn_it
= TRUE
; /* (no effect for spells...) */
2300 losexp("life drainage");
2302 damage
= 0; /* No additional damage */
2305 case WAN_MAKE_INVISIBLE
: {
2306 /* have to test before changing HInvis but must change
2307 * HInvis before doing newsym().
2309 int msg
= !Invis
&& !Blind
&& !BInvis
;
2311 if (BInvis
&& uarmc
->otyp
== MUMMY_WRAPPING
) {
2312 /* A mummy wrapping absorbs it and protects you */
2313 You_feel("rather itchy under %s.", yname(uarmc
));
2316 if (ordinary
|| !rn2(10)) { /* permanent */
2317 HInvis
|= FROMOUTSIDE
;
2318 } else { /* temporary */
2319 incr_itimeout(&HInvis
, d(obj
->spe
, 250));
2324 self_invis_message();
2329 case WAN_SPEED_MONSTER
:
2330 if (!(HFast
& INTRINSIC
)) {
2335 Your("quickness feels more natural.");
2336 exercise(A_DEX
, TRUE
);
2338 HFast
|= FROMOUTSIDE
;
2344 if (Sleep_resistance
) {
2345 shieldeff(u
.ux
, u
.uy
);
2346 You("don't feel sleepy!");
2348 pline_The("sleep ray hits you!");
2349 fall_asleep(-rnd(50), TRUE
);
2353 case WAN_SLOW_MONSTER
:
2354 case SPE_SLOW_MONSTER
:
2355 if (HFast
& (TIMEOUT
| INTRINSIC
)) {
2361 case WAN_TELEPORTATION
:
2362 case SPE_TELEPORT_AWAY
:
2364 /* same criteria as when mounted (zap_steed) */
2365 if ((Teleport_control
&& !Stunned
) || !couldsee(u
.ux0
, u
.uy0
)
2366 || distu(u
.ux0
, u
.uy0
) >= 16)
2371 case SPE_FINGER_OF_DEATH
:
2372 if (nonliving(youmonst
.data
) || is_demon(youmonst
.data
)) {
2373 pline((obj
->otyp
== WAN_DEATH
)
2374 ? "The wand shoots an apparently harmless beam at you."
2375 : "You seem no deader than before.");
2379 Sprintf(killer
.name
, "shot %sself with a death ray", uhim());
2380 killer
.format
= NO_KILLER_PREFIX
;
2381 You("irradiate yourself with pure energy!");
2383 /* They might survive with an amulet of life saving */
2386 case WAN_UNDEAD_TURNING
:
2387 case SPE_TURN_UNDEAD
:
2389 (void) unturn_dead(&youmonst
);
2390 if (is_undead(youmonst
.data
)) {
2391 You_feel("frightened and %sstunned.",
2392 Stunned
? "even more " : "");
2393 make_stunned((HStun
& TIMEOUT
) + (long) rnd(30), FALSE
);
2395 You("shudder in dread.");
2398 case SPE_EXTRA_HEALING
:
2399 learn_it
= TRUE
; /* (no effect for spells...) */
2400 healup(d(6, obj
->otyp
== SPE_EXTRA_HEALING
? 8 : 4), 0, FALSE
,
2401 (obj
->otyp
== SPE_EXTRA_HEALING
));
2402 You_feel("%sbetter.", obj
->otyp
== SPE_EXTRA_HEALING
? "much " : "");
2404 case WAN_LIGHT
: /* (broken wand) */
2405 /* assert( !ordinary ); */
2406 damage
= d(obj
->spe
, 25);
2407 case EXPENSIVE_CAMERA
:
2410 damage
= lightdamage(obj
, ordinary
, damage
);
2412 if (flashburn((long) damage
))
2414 damage
= 0; /* reset */
2422 if (u
.utrap
) { /* escape web or bear trap */
2423 (void) openholdingtrap(&youmonst
, &learn_it
);
2426 /* unlock carried boxes */
2427 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
2429 (void) boxlock(otmp
, obj
);
2430 /* trigger previously escaped trapdoor */
2431 (void) openfallingtrap(&youmonst
, TRUE
, &learn_it
);
2435 case SPE_WIZARD_LOCK
:
2437 (void) closeholdingtrap(&youmonst
, &learn_it
);
2442 case SPE_DETECT_UNSEEN
:
2448 for (otmp
= invent
; otmp
; otmp
= otmp
->nobj
) {
2450 if (Is_container(otmp
) || otmp
->otyp
== STATUE
) {
2452 if (!SchroedingersBox(otmp
))
2460 case SPE_STONE_TO_FLESH
: {
2461 struct obj
*otmp
, *onxt
;
2464 if (u
.umonnum
== PM_STONE_GOLEM
) {
2466 (void) polymon(PM_FLESH_GOLEM
);
2470 fix_petrification(); /* saved! */
2472 /* but at a cost.. */
2473 for (otmp
= invent
; otmp
; otmp
= onxt
) {
2475 if (bhito(otmp
, obj
))
2479 * It is possible that we can now merge some inventory.
2480 * Do a highly paranoid merge. Restart from the beginning
2485 for (otmp
= invent
; !didmerge
&& otmp
; otmp
= otmp
->nobj
)
2486 for (onxt
= otmp
->nobj
; onxt
; onxt
= onxt
->nobj
)
2487 if (merged(&otmp
, &onxt
)) {
2495 impossible("zapyourself: object %d used?", obj
->otyp
);
2498 /* if effect was observable then discover the wand type provided
2499 that the wand itself has been seen */
2505 /* called when poly'd hero uses breath attack against self */
2508 struct attack
*mattk
;
2510 int dtyp
= 20 + mattk
->adtyp
- 1; /* breath by hero */
2511 const char *fltxt
= flash_types
[dtyp
]; /* blast of <something> */
2513 zhitu(dtyp
, mattk
->damn
, fltxt
, u
.ux
, u
.uy
);
2516 /* light damages hero in gremlin form */
2518 lightdamage(obj
, ordinary
, amt
)
2519 struct obj
*obj
; /* item making light (fake book if spell) */
2520 boolean ordinary
; /* wand/camera zap vs wand destruction */
2521 int amt
; /* pseudo-damage used to determine blindness duration */
2527 if (dmg
&& youmonst
.data
== &mons
[PM_GREMLIN
]) {
2528 /* reduce high values (from destruction of wand with many charges) */
2531 dmg
= 10 + rnd(dmg
- 10);
2534 pline("Ow, that light hurts%c", (dmg
> 2 || u
.mh
<= 5) ? '!' : '.');
2535 /* [composing killer/reason is superfluous here; if fatal, cause
2536 of death will always be "killed while stuck in creature form"] */
2537 if (obj
->oclass
== SCROLL_CLASS
|| obj
->oclass
== SPBOOK_CLASS
)
2538 ordinary
= FALSE
; /* say blasted rather than zapped */
2539 how
= (obj
->oclass
!= SPBOOK_CLASS
)
2540 ? (const char *) ansimpleoname(obj
)
2542 Sprintf(buf
, "%s %sself with %s", ordinary
? "zapped" : "blasted",
2544 /* might rehumanize(); could be fatal, but only for Unchanging */
2545 losehp(Maybe_Half_Phys(dmg
), buf
, NO_KILLER_PREFIX
);
2550 /* light[ning] causes blindness */
2555 if (!resists_blnd(&youmonst
)) {
2556 You(are_blinded_by_the_flash
);
2557 make_blinded(duration
, FALSE
);
2559 Your1(vision_clears
);
2565 /* you've zapped a wand downwards while riding
2566 * Return TRUE if the steed was hit by the wand.
2567 * Return FALSE if the steed was not hit by the wand.
2571 struct obj
*obj
; /* wand or spell */
2573 int steedhit
= FALSE
;
2575 bhitpos
.x
= u
.usteed
->mx
, bhitpos
.y
= u
.usteed
->my
;
2577 switch (obj
->otyp
) {
2579 * Wands that are allowed to hit the steed
2580 * Carefully test the results of any that are
2581 * moved here from the bottom section.
2584 probe_monster(u
.usteed
);
2588 case WAN_TELEPORTATION
:
2589 case SPE_TELEPORT_AWAY
:
2590 /* you go together */
2592 /* same criteria as when unmounted (zapyourself) */
2593 if ((Teleport_control
&& !Stunned
) || !couldsee(u
.ux0
, u
.uy0
)
2594 || distu(u
.ux0
, u
.uy0
) >= 16)
2599 /* Default processing via bhitm() for these */
2600 case SPE_CURE_SICKNESS
:
2601 case WAN_MAKE_INVISIBLE
:
2602 case WAN_CANCELLATION
:
2603 case SPE_CANCELLATION
:
2607 case SPE_FORCE_BOLT
:
2608 case WAN_SLOW_MONSTER
:
2609 case SPE_SLOW_MONSTER
:
2610 case WAN_SPEED_MONSTER
:
2612 case SPE_EXTRA_HEALING
:
2613 case SPE_DRAIN_LIFE
:
2616 (void) bhitm(u
.usteed
, obj
);
2628 * cancel a monster (possibly the hero). inventory is cancelled only
2629 * if the monster is zapping itself directly, since otherwise the
2630 * effect is too strong. currently non-hero monsters do not zap
2631 * themselves with cancellation.
2634 cancel_monst(mdef
, obj
, youattack
, allow_cancel_kill
, self_cancel
)
2635 register struct monst
*mdef
;
2636 register struct obj
*obj
;
2637 boolean youattack
, allow_cancel_kill
, self_cancel
;
2639 boolean youdefend
= (mdef
== &youmonst
);
2640 static const char writing_vanishes
[] =
2641 "Some writing vanishes from %s head!";
2642 static const char your
[] = "your"; /* should be extern */
2644 if (youdefend
? (!youattack
&& Antimagic
)
2645 : resist(mdef
, obj
->oclass
, 0, NOTELL
))
2646 return FALSE
; /* resisted cancellation */
2648 if (self_cancel
) { /* 1st cancel inventory */
2651 for (otmp
= (youdefend
? invent
: mdef
->minvent
); otmp
;
2655 context
.botl
= 1; /* potential AC change */
2660 /* now handle special cases */
2663 if ((u
.umonnum
== PM_CLAY_GOLEM
) && !Blind
)
2664 pline(writing_vanishes
, your
);
2667 Your("amulet grows hot for a moment, then cools.");
2674 if (is_were(mdef
->data
) && mdef
->data
->mlet
!= S_HUMAN
)
2677 if (mdef
->data
== &mons
[PM_CLAY_GOLEM
]) {
2678 if (canseemon(mdef
))
2679 pline(writing_vanishes
, s_suffix(mon_nam(mdef
)));
2681 if (allow_cancel_kill
) {
2685 monkilled(mdef
, "", AD_SPEL
);
2692 /* you've zapped an immediate type wand up or down */
2695 struct obj
*obj
; /* wand or spell */
2697 boolean striking
= FALSE
, disclose
= FALSE
;
2698 int x
, y
, xx
, yy
, ptmp
;
2704 /* some wands have special effects other than normal bhitpile */
2705 /* drawbridge might change <u.ux,u.uy> */
2706 x
= xx
= u
.ux
; /* <x,y> is zap location */
2707 y
= yy
= u
.uy
; /* <xx,yy> is drawbridge (portcullis) position */
2708 ttmp
= t_at(x
, y
); /* trap if there is one */
2710 switch (obj
->otyp
) {
2714 You("probe towards the %s.", ceiling(x
, y
));
2716 ptmp
+= bhitpile(obj
, bhito
, x
, y
, u
.dz
);
2717 You("probe beneath the %s.", surface(x
, y
));
2718 ptmp
+= display_binventory(x
, y
, TRUE
);
2721 Your("probe reveals nothing.");
2722 return TRUE
; /* we've done our own bhitpile */
2725 /* up or down, but at closed portcullis only */
2726 if (is_db_wall(x
, y
) && find_drawbridge(&xx
, &yy
)) {
2727 open_drawbridge(xx
, yy
);
2729 } else if (u
.dz
> 0 && (x
== xdnstair
&& y
== ydnstair
)
2730 /* can't use the stairs down to quest level 2 until
2731 leader "unlocks" them; give feedback if you try */
2732 && on_level(&u
.uz
, &qstart_level
) && !ok_to_quest()) {
2733 pline_The("stairs seem to ripple momentarily.");
2736 /* down will release you from bear trap or web */
2737 if (u
.dz
> 0 && u
.utrap
) {
2738 (void) openholdingtrap(&youmonst
, &disclose
);
2739 /* down will trigger trapdoor, hole, or [spiked-] pit */
2740 } else if (u
.dz
> 0 && !u
.utrap
) {
2741 (void) openfallingtrap(&youmonst
, FALSE
, &disclose
);
2745 case SPE_FORCE_BOLT
:
2749 case SPE_WIZARD_LOCK
:
2750 /* down at open bridge or up or down at open portcullis */
2751 if (((levl
[x
][y
].typ
== DRAWBRIDGE_DOWN
)
2753 : (is_drawbridge_wall(x
, y
) >= 0 && !is_db_wall(x
, y
)))
2754 && find_drawbridge(&xx
, &yy
)) {
2756 close_drawbridge(xx
, yy
);
2758 destroy_drawbridge(xx
, yy
);
2760 } else if (striking
&& u
.dz
< 0 && rn2(3) && !Is_airlevel(&u
.uz
)
2761 && !Is_waterlevel(&u
.uz
) && !Underwater
2762 && !Is_qstart(&u
.uz
)) {
2764 /* similar to zap_dig() */
2765 pline("A rock is dislodged from the %s and falls on your %s.",
2766 ceiling(x
, y
), body_part(HEAD
));
2767 dmg
= rnd((uarmh
&& is_metallic(uarmh
)) ? 2 : 6);
2768 losehp(Maybe_Half_Phys(dmg
), "falling rock", KILLED_BY_AN
);
2769 if ((otmp
= mksobj_at(ROCK
, x
, y
, FALSE
, FALSE
)) != 0) {
2770 (void) xname(otmp
); /* set dknown, maybe bknown */
2774 } else if (u
.dz
> 0 && ttmp
) {
2775 if (!striking
&& closeholdingtrap(&youmonst
, &disclose
)) {
2776 ; /* now stuck in web or bear trap */
2777 } else if (striking
&& ttmp
->ttyp
== TRAPDOOR
) {
2778 /* striking transforms trapdoor into hole */
2779 if (Blind
&& !ttmp
->tseen
) {
2780 pline("%s beneath you shatters.", Something
);
2781 } else if (!ttmp
->tseen
) { /* => !Blind */
2782 pline("There's a trapdoor beneath you; it shatters.");
2784 pline("The trapdoor beneath you shatters.");
2790 /* might fall down hole */
2792 } else if (!striking
&& ttmp
->ttyp
== HOLE
) {
2793 /* locking transforms hole into trapdoor */
2794 ttmp
->ttyp
= TRAPDOOR
;
2795 if (Blind
|| !ttmp
->tseen
) {
2796 pline("Some %s swirls beneath you.",
2797 is_ice(x
, y
) ? "frost" : "dust");
2801 pline("A trapdoor appears beneath you.");
2804 /* hadn't fallen down hole; won't fall now */
2808 case SPE_STONE_TO_FLESH
:
2809 if (Is_airlevel(&u
.uz
) || Is_waterlevel(&u
.uz
) || Underwater
2810 || (Is_qstart(&u
.uz
) && u
.dz
< 0)) {
2811 pline1(nothing_happens
);
2812 } else if (u
.dz
< 0) { /* we should do more... */
2813 pline("Blood drips on your %s.", body_part(FACE
));
2814 } else if (u
.dz
> 0 && !OBJ_AT(u
.ux
, u
.uy
)) {
2816 Print this message only if there wasn't an engraving
2817 affected here. If water or ice, act like waterlevel case.
2819 e
= engr_at(u
.ux
, u
.uy
);
2820 if (!(e
&& e
->engr_type
== ENGRAVE
)) {
2821 if (is_pool(u
.ux
, u
.uy
) || is_ice(u
.ux
, u
.uy
))
2822 pline1(nothing_happens
);
2824 pline("Blood %ss %s your %s.",
2825 is_lava(u
.ux
, u
.uy
) ? "boil" : "pool",
2826 Levitation
? "beneath" : "at",
2827 makeplural(body_part(FOOT
)));
2836 /* zapping downward */
2837 (void) bhitpile(obj
, bhito
, x
, y
, u
.dz
);
2839 /* subset of engraving effects; none sets `disclose' */
2840 if ((e
= engr_at(x
, y
)) != 0 && e
->engr_type
!= HEADSTONE
) {
2841 switch (obj
->otyp
) {
2845 make_engr_at(x
, y
, random_engraving(buf
), moves
, (xchar
) 0);
2847 case WAN_CANCELLATION
:
2848 case SPE_CANCELLATION
:
2849 case WAN_MAKE_INVISIBLE
:
2852 case WAN_TELEPORTATION
:
2853 case SPE_TELEPORT_AWAY
:
2856 case SPE_STONE_TO_FLESH
:
2857 if (e
->engr_type
== ENGRAVE
) {
2858 /* only affects things in stone */
2859 pline_The(Hallucination
2860 ? "floor runs like butter!"
2861 : "edges on the floor get smoother.");
2862 wipe_engr_at(x
, y
, d(2, 4), TRUE
);
2866 case SPE_FORCE_BOLT
:
2867 wipe_engr_at(x
, y
, d(2, 4), TRUE
);
2873 } else if (u
.dz
< 0) {
2874 /* zapping upward */
2876 /* game flavor: if you're hiding under "something"
2877 * a zap upward should hit that "something".
2879 if (u
.uundetected
&& hides_under(youmonst
.data
)) {
2881 otmp
= level
.objects
[u
.ux
][u
.uy
];
2884 hitit
= bhito(otmp
, obj
);
2886 (void) hideunder(&youmonst
);
2895 /* used by do_break_wand() was well as by weffects() */
2905 /* if do_osshock() set obj_zapped while polying, give a message now */
2907 You_feel("shuddering vibrations.");
2911 /* called for various wand and spell effects - M. Stephenson */
2916 int otyp
= obj
->otyp
;
2917 boolean disclose
= FALSE
, was_unkn
= !objects
[otyp
].oc_name_known
;
2919 exercise(A_WIS
, TRUE
);
2920 if (u
.usteed
&& (objects
[otyp
].oc_dir
!= NODIR
) && !u
.dx
&& !u
.dy
2921 && (u
.dz
> 0) && zap_steed(obj
)) {
2923 } else if (objects
[otyp
].oc_dir
== IMMEDIATE
) {
2924 zapsetup(); /* reset obj_zapped */
2926 (void) bhitm(u
.ustuck
, obj
);
2927 /* [how about `bhitpile(u.ustuck->minvent)' effect?] */
2929 disclose
= zap_updown(obj
);
2931 (void) bhit(u
.dx
, u
.dy
, rn1(8, 6), ZAPPED_WAND
, bhitm
, bhito
,
2934 zapwrapup(); /* give feedback for obj_zapped */
2936 } else if (objects
[otyp
].oc_dir
== NODIR
) {
2940 /* neither immediate nor directionless */
2942 if (otyp
== WAN_DIGGING
|| otyp
== SPE_DIG
)
2944 else if (otyp
>= SPE_MAGIC_MISSILE
&& otyp
<= SPE_FINGER_OF_DEATH
)
2945 buzz(otyp
- SPE_MAGIC_MISSILE
+ 10, u
.ulevel
/ 2 + 1, u
.ux
, u
.uy
,
2947 else if (otyp
>= WAN_MAGIC_MISSILE
&& otyp
<= WAN_LIGHTNING
)
2948 buzz(otyp
- WAN_MAGIC_MISSILE
,
2949 (otyp
== WAN_MAGIC_MISSILE
) ? 2 : 6, u
.ux
, u
.uy
, u
.dx
, u
.dy
);
2951 impossible("weffects: unexpected spell or wand");
2957 more_experienced(0, 10);
2962 /* augment damage for a spell dased on the hero's intelligence (and level) */
2964 spell_damage_bonus(dmg
)
2965 int dmg
; /* base amount to be adjusted by bonus or penalty */
2967 int intell
= ACURR(A_INT
);
2969 /* Punish low intelligence before low level else low intelligence
2970 gets punished only when high level */
2972 /* -3 penalty, but never reduce combined amount below 1
2973 (if dmg is 0 for some reason, we're careful to leave it there) */
2975 dmg
= (dmg
<= 3) ? 1 : dmg
- 3;
2976 } else if (intell
<= 13 || u
.ulevel
< 5)
2977 ; /* no bonus or penalty; dmg remains same */
2978 else if (intell
<= 18)
2980 else if (intell
<= 24 || u
.ulevel
< 14)
2983 dmg
+= 3; /* Int 25 */
2989 * Generate the to hit bonus for a spell. Based on the hero's skill in
2990 * spell class and dexterity.
2993 spell_hit_bonus(skill
)
2997 int dex
= ACURR(A_DEX
);
2999 switch (P_SKILL(spell_skilltype(skill
))) {
3000 case P_ISRESTRICTED
:
3022 /* Will change when print stuff below removed */
3025 /* Even increment for dextrous heroes (see weapon.c abon) */
3026 hit_bon
+= dex
- 14;
3035 /* force == 0 occurs e.g. with sleep ray */
3036 /* note that large force is usual with wands so that !! would
3037 require information about hand/weapon/wand */
3038 return (const char *) ((force
< 0) ? "?" : (force
<= 4) ? "." : "!");
3042 hit(str
, mtmp
, force
)
3045 const char *force
; /* usually either "." or "!" */
3047 if ((!cansee(bhitpos
.x
, bhitpos
.y
) && !canspotmon(mtmp
)
3048 && !(u
.uswallow
&& mtmp
== u
.ustuck
)) || !flags
.verbose
)
3049 pline("%s %s it.", The(str
), vtense(str
, "hit"));
3051 pline("%s %s %s%s", The(str
), vtense(str
, "hit"),
3052 mon_nam(mtmp
), force
);
3057 register const char *str
;
3058 register struct monst
*mtmp
;
3061 "%s %s %s.", The(str
), vtense(str
, "miss"),
3062 ((cansee(bhitpos
.x
, bhitpos
.y
) || canspotmon(mtmp
)) && flags
.verbose
)
3068 skiprange(range
, skipstart
, skipend
)
3069 int range
, *skipstart
, *skipend
;
3071 int tr
= (range
/ 4);
3072 int tmp
= range
- ((tr
> 0) ? rnd(tr
) : 0);
3074 *skipend
= tmp
- ((tmp
/ 4) * rnd(3));
3075 if (*skipend
>= tmp
)
3080 * Called for the following distance effects:
3081 * when a weapon is thrown (weapon == THROWN_WEAPON)
3082 * when an object is kicked (KICKED_WEAPON)
3083 * when an IMMEDIATE wand is zapped (ZAPPED_WAND)
3084 * when a light beam is flashed (FLASHED_LIGHT)
3085 * when a mirror is applied (INVIS_BEAM)
3086 * A thrown/kicked object falls down at end of its range or when a monster
3087 * is hit. The variable 'bhitpos' is set to the final position of the weapon
3088 * thrown/zapped. The ray of a wand may affect (by calling a provided
3089 * function) several objects and monsters on its path. The return value
3090 * is the monster hit (weapon != ZAPPED_WAND), or a null monster pointer.
3092 * Thrown and kicked objects (THROWN_WEAPON or KICKED_WEAPON) may be
3093 * destroyed and *pobj set to NULL to indicate this.
3095 * Check !u.uswallow before calling bhit().
3096 * This function reveals the absence of a remembered invisible monster in
3097 * necessary cases (throwing or kicking weapons). The presence of a real
3098 * one is revealed for a weapon, but if not a weapon is left up to fhitm().
3101 bhit(ddx
, ddy
, range
, weapon
, fhitm
, fhito
, pobj
)
3102 register int ddx
, ddy
, range
; /* direction and range */
3103 int weapon
; /* see values in hack.h */
3104 int FDECL((*fhitm
), (MONST_P
, OBJ_P
)), /* fns called when mon/obj hit */
3105 FDECL((*fhito
), (OBJ_P
, OBJ_P
));
3106 struct obj
**pobj
; /* object tossed/used, set to NULL
3107 * if object is destroyed */
3110 struct obj
*obj
= *pobj
;
3112 boolean shopdoor
= FALSE
, point_blank
= TRUE
;
3113 boolean in_skip
= FALSE
, allow_skip
= FALSE
;
3114 int skiprange_start
= 0, skiprange_end
= 0, skipcount
= 0;
3116 if (weapon
== KICKED_WEAPON
) {
3117 /* object starts one square in front of player */
3118 bhitpos
.x
= u
.ux
+ ddx
;
3119 bhitpos
.y
= u
.uy
+ ddy
;
3126 if (weapon
== THROWN_WEAPON
&& obj
&& obj
->otyp
== ROCK
) {
3127 skiprange(range
, &skiprange_start
, &skiprange_end
);
3128 allow_skip
= !rn2(3);
3131 if (weapon
== FLASHED_LIGHT
) {
3132 tmp_at(DISP_BEAM
, cmap_to_glyph(S_flashbeam
));
3133 } else if (weapon
!= ZAPPED_WAND
&& weapon
!= INVIS_BEAM
)
3134 tmp_at(DISP_FLASH
, obj_to_glyph(obj
));
3136 while (range
-- > 0) {
3150 if (is_pick(obj
) && inside_shop(x
, y
)
3151 && (mtmp
= shkcatch(obj
, x
, y
)) != 0) {
3152 tmp_at(DISP_END
, 0);
3156 typ
= levl
[bhitpos
.x
][bhitpos
.y
].typ
;
3158 /* iron bars will block anything big enough */
3159 if ((weapon
== THROWN_WEAPON
|| weapon
== KICKED_WEAPON
)
3161 && hits_bars(pobj
, x
- ddx
, y
- ddy
, bhitpos
.x
, bhitpos
.y
,
3162 point_blank
? 0 : !rn2(5), 1)) {
3163 /* caveat: obj might now be null... */
3170 if (weapon
== ZAPPED_WAND
&& find_drawbridge(&x
, &y
)) {
3171 boolean learn_it
= FALSE
;
3173 switch (obj
->otyp
) {
3176 if (is_db_wall(bhitpos
.x
, bhitpos
.y
)) {
3177 if (cansee(x
, y
) || cansee(bhitpos
.x
, bhitpos
.y
))
3179 open_drawbridge(x
, y
);
3183 case SPE_WIZARD_LOCK
:
3184 if ((cansee(x
, y
) || cansee(bhitpos
.x
, bhitpos
.y
))
3185 && levl
[x
][y
].typ
== DRAWBRIDGE_DOWN
)
3187 close_drawbridge(x
, y
);
3190 case SPE_FORCE_BOLT
:
3191 if (typ
!= DRAWBRIDGE_UP
)
3192 destroy_drawbridge(x
, y
);
3200 mtmp
= m_at(bhitpos
.x
, bhitpos
.y
);
3205 * skiprange_start is only set if this is a thrown rock
3207 if (skiprange_start
&& (range
== skiprange_start
) && allow_skip
) {
3208 if (is_pool(bhitpos
.x
, bhitpos
.y
) && !mtmp
) {
3211 pline("%s %s%s.", Yname2(obj
), otense(obj
, "skip"),
3212 skipcount
? " again" : "");
3214 You_hear("%s skip.", yname(obj
));
3216 } else if (skiprange_start
> skiprange_end
+ 1) {
3221 if (range
<= skiprange_end
) {
3223 if (range
> 3) /* another bounce? */
3224 skiprange(range
, &skiprange_start
, &skiprange_end
);
3225 } else if (mtmp
&& M_IN_WATER(mtmp
->data
)) {
3226 if ((!Blind
&& canseemon(mtmp
)) || sensemon(mtmp
))
3227 pline("%s %s over %s.", Yname2(obj
), otense(obj
, "pass"),
3232 if (mtmp
&& !(in_skip
&& M_IN_WATER(mtmp
->data
))) {
3233 notonhead
= (bhitpos
.x
!= mtmp
->mx
|| bhitpos
.y
!= mtmp
->my
);
3234 if (weapon
== FLASHED_LIGHT
) {
3235 /* FLASHED_LIGHT hitting invisible monster should
3236 pass through instead of stop so we call
3237 flash_hits_mon() directly rather than returning
3238 mtmp back to caller. That allows the flash to
3239 keep on going. Note that we use mtmp->minvis
3240 not canspotmon() because it makes no difference
3241 whether the hero can see the monster or not. */
3243 obj
->ox
= u
.ux
, obj
->oy
= u
.uy
;
3244 (void) flash_hits_mon(mtmp
, obj
);
3246 tmp_at(DISP_END
, 0);
3247 return mtmp
; /* caller will call flash_hits_mon */
3249 } else if (weapon
== INVIS_BEAM
) {
3250 /* Like FLASHED_LIGHT, INVIS_BEAM should continue
3251 through invisible targets; unlike it, we aren't
3252 prepared for multiple hits so just get first one
3253 that's either visible or could see its invisible
3254 self. [No tmp_at() cleanup is needed here.] */
3255 if (!mtmp
->minvis
|| perceives(mtmp
->data
))
3257 } else if (weapon
!= ZAPPED_WAND
) {
3258 /* THROWN_WEAPON, KICKED_WEAPON */
3259 tmp_at(DISP_END
, 0);
3260 if (cansee(bhitpos
.x
, bhitpos
.y
) && !canspotmon(mtmp
))
3261 map_invisible(bhitpos
.x
, bhitpos
.y
);
3265 (*fhitm
)(mtmp
, obj
);
3269 if (weapon
== ZAPPED_WAND
&& obj
->otyp
== WAN_PROBING
3270 && glyph_is_invisible(levl
[bhitpos
.x
][bhitpos
.y
].glyph
)) {
3271 unmap_object(bhitpos
.x
, bhitpos
.y
);
3276 if (bhitpile(obj
, fhito
, bhitpos
.x
, bhitpos
.y
, 0))
3279 if (weapon
== KICKED_WEAPON
3280 && ((obj
->oclass
== COIN_CLASS
3281 && OBJ_AT(bhitpos
.x
, bhitpos
.y
))
3282 || ship_object(obj
, bhitpos
.x
, bhitpos
.y
,
3283 costly_spot(bhitpos
.x
, bhitpos
.y
)))) {
3284 tmp_at(DISP_END
, 0);
3285 return (struct monst
*) 0;
3288 if (weapon
== ZAPPED_WAND
&& (IS_DOOR(typ
) || typ
== SDOOR
)) {
3289 switch (obj
->otyp
) {
3294 case SPE_WIZARD_LOCK
:
3295 case SPE_FORCE_BOLT
:
3296 if (doorlock(obj
, bhitpos
.x
, bhitpos
.y
)) {
3297 if (cansee(bhitpos
.x
, bhitpos
.y
)
3298 || (obj
->otyp
== WAN_STRIKING
&& !Deaf
))
3300 if (levl
[bhitpos
.x
][bhitpos
.y
].doormask
== D_BROKEN
3301 && *in_rooms(bhitpos
.x
, bhitpos
.y
, SHOPBASE
)) {
3303 add_damage(bhitpos
.x
, bhitpos
.y
, 400L);
3309 if (!ZAP_POS(typ
) || closed_door(bhitpos
.x
, bhitpos
.y
)) {
3314 if (weapon
!= ZAPPED_WAND
&& weapon
!= INVIS_BEAM
) {
3315 /* 'I' present but no monster: erase */
3316 /* do this before the tmp_at() */
3317 if (glyph_is_invisible(levl
[bhitpos
.x
][bhitpos
.y
].glyph
)
3319 unmap_object(bhitpos
.x
, bhitpos
.y
);
3322 tmp_at(bhitpos
.x
, bhitpos
.y
);
3324 /* kicked objects fall in pools */
3325 if ((weapon
== KICKED_WEAPON
)
3326 && (is_pool(bhitpos
.x
, bhitpos
.y
)
3327 || is_lava(bhitpos
.x
, bhitpos
.y
)))
3329 if (IS_SINK(typ
) && weapon
!= FLASHED_LIGHT
)
3330 break; /* physical objects fall onto sink */
3332 /* limit range of ball so hero won't make an invalid move */
3333 if (weapon
== THROWN_WEAPON
&& range
> 0
3334 && obj
->otyp
== HEAVY_IRON_BALL
) {
3338 if ((bobj
= sobj_at(BOULDER
, x
, y
)) != 0) {
3340 pline("%s hits %s.", The(distant_name(obj
, xname
)),
3343 } else if (obj
== uball
) {
3344 if (!test_move(x
- ddx
, y
- ddy
, ddx
, ddy
, TEST_MOVE
)) {
3345 /* nb: it didn't hit anything directly */
3347 pline("%s jerks to an abrupt halt.",
3348 The(distant_name(obj
, xname
))); /* lame */
3350 } else if (Sokoban
&& (t
= t_at(x
, y
)) != 0
3351 && (t
->ttyp
== PIT
|| t
->ttyp
== SPIKED_PIT
3352 || t
->ttyp
== HOLE
|| t
->ttyp
== TRAPDOOR
)) {
3353 /* hero falls into the trap, so ball stops */
3359 /* thrown/kicked missile has moved away from its starting spot */
3360 point_blank
= FALSE
; /* affects passing through iron bars */
3363 if (weapon
!= ZAPPED_WAND
&& weapon
!= INVIS_BEAM
)
3364 tmp_at(DISP_END
, 0);
3367 pay_for_damage("destroy", FALSE
);
3369 return (struct monst
*) 0;
3372 /* process thrown boomerang, which travels a curving path...
3373 * A multi-shot volley ought to have all missiles in flight at once,
3374 * but we're called separately for each one. We terminate the volley
3375 * early on a failed catch since continuing to throw after being hit
3376 * is too obviously silly.
3379 boomhit(obj
, dx
, dy
)
3384 int boom
; /* showsym[] index */
3386 boolean counterclockwise
= TRUE
; /* right-handed throw */
3388 /* counterclockwise traversal patterns:
3389 * ..........................54.................................
3390 * ..................43.....6..3....765.........................
3391 * ..........32.....5..2...7...2...8...4....87..................
3392 * .........4..1....6..1...8..1....9...3...9..6.....98..........
3393 * ..21@....5...@...7..@....9@......@12....@...5...@..7.....@9..
3394 * .3...9....6..9....89.....................1..4...1..6....1..8.
3395 * .4...8.....78.............................23....2..5...2...7.
3396 * ..567............................................34....3..6..
3397 * ........................................................45...
3398 * (invert rows for corresponding clockwise patterns)
3403 boom
= counterclockwise
? S_boomleft
: S_boomright
;
3404 for (i
= 0; i
< 8; i
++)
3405 if (xdir
[i
] == dx
&& ydir
[i
] == dy
)
3407 tmp_at(DISP_FLASH
, cmap_to_glyph(boom
));
3408 for (ct
= 0; ct
< 10; ct
++) {
3409 i
= (i
+ 8) % 8; /* 0..7 (8 -> 0, -1 -> 7) */
3410 boom
= (S_boomleft
+ S_boomright
- boom
); /* toggle */
3411 tmp_at(DISP_CHANGE
, cmap_to_glyph(boom
)); /* change glyph */
3416 if ((mtmp
= m_at(bhitpos
.x
, bhitpos
.y
)) != 0) {
3418 tmp_at(DISP_END
, 0);
3421 if (!ZAP_POS(levl
[bhitpos
.x
][bhitpos
.y
].typ
)
3422 || closed_door(bhitpos
.x
, bhitpos
.y
)) {
3427 if (bhitpos
.x
== u
.ux
&& bhitpos
.y
== u
.uy
) { /* ct == 9 */
3428 if (Fumbling
|| rn2(20) >= ACURR(A_DEX
)) {
3429 /* we hit ourselves */
3430 (void) thitu(10 + obj
->spe
, dmgval(obj
, &youmonst
), obj
,
3434 } else { /* we catch it */
3435 tmp_at(DISP_END
, 0);
3436 You("skillfully catch the boomerang.");
3440 tmp_at(bhitpos
.x
, bhitpos
.y
);
3442 if (IS_SINK(levl
[bhitpos
.x
][bhitpos
.y
].typ
)) {
3445 break; /* boomerang falls on sink */
3447 /* ct==0, initial position, we want next delta to be same;
3448 ct==5, opposite position, repeat delta undoes first one */
3450 i
+= (counterclockwise
? -1 : 1);
3452 tmp_at(DISP_END
, 0); /* do not leave last symbol */
3453 return (struct monst
*) 0;
3456 /* used by buzz(); also used by munslime(muse.c); returns damage applied
3457 to mon; note: caller is responsible for killing mon if damage is fatal */
3459 zhitm(mon
, type
, nd
, ootmp
)
3460 register struct monst
*mon
;
3461 register int type
, nd
;
3462 struct obj
**ootmp
; /* to return worn armor for caller to disintegrate */
3464 register int tmp
= 0;
3465 register int abstype
= abs(type
) % 10;
3466 boolean sho_shieldeff
= FALSE
;
3467 boolean spellcaster
= is_hero_spell(type
); /* maybe get a bonus! */
3469 *ootmp
= (struct obj
*) 0;
3471 case ZT_MAGIC_MISSILE
:
3472 if (resists_magm(mon
)) {
3473 sho_shieldeff
= TRUE
;
3478 tmp
= spell_damage_bonus(tmp
);
3481 if (resists_fire(mon
)) {
3482 sho_shieldeff
= TRUE
;
3486 if (resists_cold(mon
))
3489 tmp
= spell_damage_bonus(tmp
);
3490 if (burnarmor(mon
)) {
3492 (void) destroy_mitem(mon
, POTION_CLASS
, AD_FIRE
);
3494 (void) destroy_mitem(mon
, SCROLL_CLASS
, AD_FIRE
);
3496 (void) destroy_mitem(mon
, SPBOOK_CLASS
, AD_FIRE
);
3497 destroy_mitem(mon
, FOOD_CLASS
, AD_FIRE
); /* carried slime */
3501 if (resists_cold(mon
)) {
3502 sho_shieldeff
= TRUE
;
3506 if (resists_fire(mon
))
3509 tmp
= spell_damage_bonus(tmp
);
3511 (void) destroy_mitem(mon
, POTION_CLASS
, AD_COLD
);
3515 (void) sleep_monst(mon
, d(nd
, 25),
3516 type
== ZT_WAND(ZT_SLEEP
) ? WAND_CLASS
: '\0');
3518 case ZT_DEATH
: /* death/disintegration */
3519 if (abs(type
) != ZT_BREATH(ZT_DEATH
)) { /* death */
3520 if (mon
->data
== &mons
[PM_DEATH
]) {
3521 mon
->mhpmax
+= mon
->mhpmax
/ 2;
3522 if (mon
->mhpmax
>= MAGIC_COOKIE
)
3523 mon
->mhpmax
= MAGIC_COOKIE
- 1;
3524 mon
->mhp
= mon
->mhpmax
;
3528 if (nonliving(mon
->data
) || is_demon(mon
->data
)
3529 || is_vampshifter(mon
) || resists_magm(mon
)) {
3530 /* similar to player */
3531 sho_shieldeff
= TRUE
;
3534 type
= -1; /* so they don't get saving throws */
3538 if (resists_disint(mon
)) {
3539 sho_shieldeff
= TRUE
;
3540 } else if (mon
->misc_worn_check
& W_ARMS
) {
3541 /* destroy shield; victim survives */
3542 *ootmp
= which_armor(mon
, W_ARMS
);
3543 } else if (mon
->misc_worn_check
& W_ARM
) {
3544 /* destroy body armor, also cloak if present */
3545 *ootmp
= which_armor(mon
, W_ARM
);
3546 if ((otmp2
= which_armor(mon
, W_ARMC
)) != 0)
3547 m_useup(mon
, otmp2
);
3549 /* no body armor, victim dies; destroy cloak
3550 and shirt now in case target gets life-saved */
3552 if ((otmp2
= which_armor(mon
, W_ARMC
)) != 0)
3553 m_useup(mon
, otmp2
);
3554 if ((otmp2
= which_armor(mon
, W_ARMU
)) != 0)
3555 m_useup(mon
, otmp2
);
3557 type
= -1; /* no saving throw wanted */
3558 break; /* not ordinary damage */
3563 if (resists_elec(mon
)) {
3564 sho_shieldeff
= TRUE
;
3566 /* can still blind the monster */
3570 tmp
= spell_damage_bonus(tmp
);
3571 if (!resists_blnd(mon
)
3572 && !(type
> 0 && u
.uswallow
&& mon
== u
.ustuck
)) {
3573 register unsigned rnd_tmp
= rnd(50);
3575 if ((mon
->mblinded
+ rnd_tmp
) > 127)
3576 mon
->mblinded
= 127;
3578 mon
->mblinded
+= rnd_tmp
;
3581 (void) destroy_mitem(mon
, WAND_CLASS
, AD_ELEC
);
3582 /* not actually possible yet */
3584 (void) destroy_mitem(mon
, RING_CLASS
, AD_ELEC
);
3587 if (resists_poison(mon
)) {
3588 sho_shieldeff
= TRUE
;
3594 if (resists_acid(mon
)) {
3595 sho_shieldeff
= TRUE
;
3600 acid_damage(MON_WEP(mon
));
3602 erode_armor(mon
, ERODE_CORRODE
);
3606 shieldeff(mon
->mx
, mon
->my
);
3607 if (is_hero_spell(type
) && (Role_if(PM_KNIGHT
) && u
.uhave
.questart
))
3609 if (tmp
> 0 && type
>= 0
3610 && resist(mon
, type
< ZT_SPELL(0) ? WAND_CLASS
: '\0', 0, NOTELL
))
3613 tmp
= 0; /* don't allow negative damage */
3614 debugpline3("zapped monster hp = %d (= %d - %d)", mon
->mhp
- tmp
,
3621 zhitu(type
, nd
, fltxt
, sx
, sy
)
3626 int dam
= 0, abstyp
= abs(type
);
3628 switch (abstyp
% 10) {
3629 case ZT_MAGIC_MISSILE
:
3632 pline_The("missiles bounce off!");
3635 exercise(A_STR
, FALSE
);
3639 if (Fire_resistance
) {
3641 You("don't feel hot!");
3642 ugolemeffects(AD_FIRE
, d(nd
, 6));
3647 if (burnarmor(&youmonst
)) { /* "body hit" */
3649 destroy_item(POTION_CLASS
, AD_FIRE
);
3651 destroy_item(SCROLL_CLASS
, AD_FIRE
);
3653 destroy_item(SPBOOK_CLASS
, AD_FIRE
);
3654 destroy_item(FOOD_CLASS
, AD_FIRE
);
3658 if (Cold_resistance
) {
3660 You("don't feel cold.");
3661 ugolemeffects(AD_COLD
, d(nd
, 6));
3666 destroy_item(POTION_CLASS
, AD_COLD
);
3669 if (Sleep_resistance
) {
3670 shieldeff(u
.ux
, u
.uy
);
3671 You("don't feel sleepy.");
3673 fall_asleep(-d(nd
, 25), TRUE
); /* sleep ray */
3677 if (abstyp
== ZT_BREATH(ZT_DEATH
)) {
3678 if (Disint_resistance
) {
3679 You("are not disintegrated.");
3682 /* destroy shield; other possessions are safe */
3683 (void) destroy_arm(uarms
);
3686 /* destroy suit; if present, cloak goes too */
3688 (void) destroy_arm(uarmc
);
3689 (void) destroy_arm(uarm
);
3692 /* no shield or suit, you're dead; wipe out cloak
3693 and/or shirt in case of life-saving or bones */
3695 (void) destroy_arm(uarmc
);
3697 (void) destroy_arm(uarmu
);
3698 } else if (nonliving(youmonst
.data
) || is_demon(youmonst
.data
)) {
3700 You("seem unaffected.");
3702 } else if (Antimagic
) {
3704 You("aren't affected.");
3707 killer
.format
= KILLED_BY_AN
;
3708 Strcpy(killer
.name
, fltxt
? fltxt
: "");
3709 /* when killed by disintegration breath, don't leave corpse */
3710 u
.ugrave_arise
= (type
== -ZT_BREATH(ZT_DEATH
)) ? -3 : NON_PM
;
3712 return; /* lifesaved */
3714 if (Shock_resistance
) {
3716 You("aren't affected.");
3717 ugolemeffects(AD_ELEC
, d(nd
, 6));
3720 exercise(A_CON
, FALSE
);
3723 destroy_item(WAND_CLASS
, AD_ELEC
);
3725 destroy_item(RING_CLASS
, AD_ELEC
);
3728 poisoned("blast", A_DEX
, "poisoned blast", 15, FALSE
);
3731 if (Acid_resistance
) {
3732 pline_The("%s doesn't hurt.", hliquid("acid"));
3735 pline_The("%s burns!", hliquid("acid"));
3737 exercise(A_STR
, FALSE
);
3739 /* using two weapons at once makes both of them more vulnerable */
3740 if (!rn2(u
.twoweap
? 3 : 6))
3742 if (u
.twoweap
&& !rn2(3))
3743 acid_damage(uswapwep
);
3745 erode_armor(&youmonst
, ERODE_CORRODE
);
3749 /* Half_spell_damage protection yields half-damage for wands & spells,
3750 including hero's own ricochets; breath attacks do full damage */
3751 if (dam
&& Half_spell_damage
&& !(abstyp
>= 20 && abstyp
<= 29))
3752 dam
= (dam
+ 1) / 2;
3753 losehp(dam
, fltxt
, KILLED_BY_AN
);
3758 * burn objects (such as scrolls and spellbooks) on floor
3759 * at position x,y; return the number of objects burned
3762 burn_floor_objects(x
, y
, give_feedback
, u_caused
)
3764 boolean give_feedback
; /* caller needs to decide about visibility checks */
3767 struct obj
*obj
, *obj2
;
3768 long i
, scrquan
, delquan
;
3769 char buf1
[BUFSZ
], buf2
[BUFSZ
];
3772 for (obj
= level
.objects
[x
][y
]; obj
; obj
= obj2
) {
3773 obj2
= obj
->nexthere
;
3774 if (obj
->oclass
== SCROLL_CLASS
|| obj
->oclass
== SPBOOK_CLASS
3775 || (obj
->oclass
== FOOD_CLASS
3776 && obj
->otyp
== GLOB_OF_GREEN_SLIME
)) {
3777 if (obj
->otyp
== SCR_FIRE
|| obj
->otyp
== SPE_FIREBALL
3778 || obj_resists(obj
, 2, 100))
3780 scrquan
= obj
->quan
; /* number present */
3781 delquan
= 0L; /* number to destroy */
3782 for (i
= scrquan
; i
> 0L; i
--)
3786 /* save name before potential delobj() */
3787 if (give_feedback
) {
3789 Strcpy(buf1
, (x
== u
.ux
&& y
== u
.uy
)
3791 : distant_name(obj
, xname
));
3793 Strcpy(buf2
, (x
== u
.ux
&& y
== u
.uy
)
3795 : distant_name(obj
, xname
));
3796 obj
->quan
= scrquan
;
3798 /* useupf(), which charges, only if hero caused damage */
3800 useupf(obj
, delquan
);
3801 else if (delquan
< scrquan
)
3802 obj
->quan
-= delquan
;
3806 if (give_feedback
) {
3808 pline("%ld %s burn.", delquan
, buf2
);
3810 pline("%s burns.", An(buf1
));
3818 /* will zap/spell/breath attack score a hit against armor class `ac'? */
3822 int type
; /* either hero cast spell type or 0 */
3824 int chance
= rn2(20);
3825 int spell_bonus
= type
? spell_hit_bonus(type
) : 0;
3827 /* small chance for naked target to avoid being hit */
3829 return rnd(10) < ac
+ spell_bonus
;
3831 /* very high armor protection does not achieve invulnerability */
3834 return (3 - chance
< ac
+ spell_bonus
);
3838 disintegrate_mon(mon
, type
, fltxt
)
3840 int type
; /* hero vs other */
3843 struct obj
*otmp
, *otmp2
, *m_amulet
= mlifesaver(mon
);
3845 if (canseemon(mon
)) {
3847 pline("%s is disintegrated!", Monnam(mon
));
3849 hit(fltxt
, mon
, "!");
3852 /* note: worn amulet of life saving must be preserved in order to operate */
3853 #define oresist_disintegration(obj) \
3854 (objects[obj->otyp].oc_oprop == DISINT_RES || obj_resists(obj, 5, 50) \
3855 || is_quest_artifact(obj) || obj == m_amulet)
3857 for (otmp
= mon
->minvent
; otmp
; otmp
= otmp2
) {
3859 if (!oresist_disintegration(otmp
)) {
3860 if (otmp
->owornmask
) {
3861 /* in case monster's life gets saved */
3862 mon
->misc_worn_check
&= ~otmp
->owornmask
;
3863 if (otmp
->owornmask
& W_WEP
)
3864 setmnotwielded(mon
, otmp
);
3865 /* also dismounts hero if this object is steed's saddle */
3866 update_mon_intrinsics(mon
, otmp
, FALSE
, TRUE
);
3867 otmp
->owornmask
= 0L;
3869 obj_extract_self(otmp
);
3870 obfree(otmp
, (struct obj
*) 0);
3874 #undef oresist_disintegration
3877 monkilled(mon
, (char *) 0, -AD_RBRE
);
3879 xkilled(mon
, XKILL_NOMSG
| XKILL_NOCORPSE
);
3883 buzz(type
,nd
,sx
,sy
,dx
,dy
)
3888 dobuzz(type
, nd
, sx
, sy
, dx
, dy
, TRUE
);
3892 * type == 0 to 9 : you shooting a wand
3893 * type == 10 to 19 : you casting a spell
3894 * type == 20 to 29 : you breathing as a monster
3895 * type == -10 to -19 : monster casting spell
3896 * type == -20 to -29 : monster breathing at you
3897 * type == -30 to -39 : monster shooting a wand
3898 * called with dx = dy = 0 with vertical bolts
3901 dobuzz(type
, nd
, sx
, sy
, dx
, dy
,say
)
3902 register int type
, nd
;
3903 register xchar sx
, sy
;
3904 register int dx
, dy
;
3905 boolean say
; /* Announce out of sight hit/miss events if true */
3907 int range
, abstype
= abs(type
) % 10;
3908 register xchar lsx
, lsy
;
3911 boolean shopdamage
= FALSE
;
3916 /* if its a Hero Spell then get its SPE_TYPE */
3917 spell_type
= is_hero_spell(type
) ? SPE_MAGIC_MISSILE
+ abstype
: 0;
3919 fltxt
= flash_types
[(type
<= -30) ? abstype
: abs(type
)];
3925 tmp
= zhitm(u
.ustuck
, type
, nd
, &otmp
);
3929 pline("%s rips into %s%s", The(fltxt
), mon_nam(u
.ustuck
),
3931 /* Using disintegration from the inside only makes a hole... */
3932 if (tmp
== MAGIC_COOKIE
)
3934 if (u
.ustuck
->mhp
< 1)
3941 if (dx
== 0 && dy
== 0)
3943 save_bhitpos
= bhitpos
;
3945 tmp_at(DISP_BEAM
, zapdir_to_glyph(dx
, dy
, abstype
));
3946 while (range
-- > 0) {
3951 if (!isok(sx
, sy
) || levl
[sx
][sy
].typ
== STONE
)
3955 if (cansee(sx
, sy
)) {
3956 /* reveal/unreveal invisible monsters before tmp_at() */
3957 if (mon
&& !canspotmon(mon
))
3958 map_invisible(sx
, sy
);
3959 else if (!mon
&& glyph_is_invisible(levl
[sx
][sy
].glyph
)) {
3960 unmap_object(sx
, sy
);
3963 if (ZAP_POS(levl
[sx
][sy
].typ
)
3964 || (isok(lsx
, lsy
) && cansee(lsx
, lsy
)))
3966 delay_output(); /* wait a little */
3969 /* hit() and miss() need bhitpos to match the target */
3970 bhitpos
.x
= sx
, bhitpos
.y
= sy
;
3971 /* Fireballs only damage when they explode */
3972 if (type
!= ZT_SPELL(ZT_FIRE
))
3973 range
+= zap_over_floor(sx
, sy
, type
, &shopdamage
, 0);
3976 if (type
== ZT_SPELL(ZT_FIRE
))
3979 mon
->mstrategy
&= ~STRAT_WAITMASK
;
3981 notonhead
= (mon
->mx
!= bhitpos
.x
|| mon
->my
!= bhitpos
.y
);
3982 if (zap_hit(find_mac(mon
), spell_type
)) {
3983 if (mon_reflects(mon
, (char *) 0)) {
3984 if (cansee(mon
->mx
, mon
->my
)) {
3985 hit(fltxt
, mon
, exclam(0));
3986 shieldeff(mon
->mx
, mon
->my
);
3987 (void) mon_reflects(mon
,
3988 "But it reflects from %s %s!");
3993 boolean mon_could_move
= mon
->mcanmove
;
3994 int tmp
= zhitm(mon
, type
, nd
, &otmp
);
3996 if (is_rider(mon
->data
)
3997 && abs(type
) == ZT_BREATH(ZT_DEATH
)) {
3998 if (canseemon(mon
)) {
3999 hit(fltxt
, mon
, ".");
4000 pline("%s disintegrates.", Monnam(mon
));
4001 pline("%s body reintegrates before your %s!",
4002 s_suffix(Monnam(mon
)),
4003 (eyecount(youmonst
.data
) == 1)
4005 : makeplural(body_part(EYE
)));
4006 pline("%s resurrects!", Monnam(mon
));
4008 mon
->mhp
= mon
->mhpmax
;
4009 break; /* Out of while loop */
4011 if (mon
->data
== &mons
[PM_DEATH
] && abstype
== ZT_DEATH
) {
4012 if (canseemon(mon
)) {
4013 hit(fltxt
, mon
, ".");
4014 pline("%s absorbs the deadly %s!", Monnam(mon
),
4015 type
== ZT_BREATH(ZT_DEATH
) ? "blast"
4017 pline("It seems even stronger than before.");
4019 break; /* Out of while loop */
4022 if (tmp
== MAGIC_COOKIE
) { /* disintegration */
4023 disintegrate_mon(mon
, type
, fltxt
);
4024 } else if (mon
->mhp
< 1) {
4026 monkilled(mon
, fltxt
, AD_RBRE
);
4031 /* normal non-fatal hit */
4032 if (say
|| canseemon(mon
))
4033 hit(fltxt
, mon
, exclam(tmp
));
4035 /* some armor was destroyed; no damage done */
4037 pline("%s %s is disintegrated!",
4038 s_suffix(Monnam(mon
)),
4039 distant_name(otmp
, xname
));
4042 if (mon_could_move
&& !mon
->mcanmove
) /* ZT_SLEEP */
4048 if (say
|| canseemon(mon
))
4051 } else if (sx
== u
.ux
&& sy
== u
.uy
&& range
>= 0) {
4053 if (u
.usteed
&& !rn2(3) && !mon_reflects(u
.usteed
, (char *) 0)) {
4056 } else if (zap_hit((int) u
.uac
, 0)) {
4058 pline("%s hits you!", The(fltxt
));
4061 (void) ureflects("But %s reflects from your %s!",
4064 pline("For some reason you are not affected.");
4069 zhitu(type
, nd
, fltxt
, sx
, sy
);
4071 } else if (!Blind
) {
4072 pline("%s whizzes by you!", The(fltxt
));
4073 } else if (abstype
== ZT_LIGHTNING
) {
4074 Your("%s tingles.", body_part(ARM
));
4076 if (abstype
== ZT_LIGHTNING
)
4077 (void) flashburn((long) d(nd
, 50));
4082 if (!ZAP_POS(levl
[sx
][sy
].typ
)
4083 || (closed_door(sx
, sy
) && range
>= 0)) {
4084 int bounce
, bchance
;
4089 bchance
= (levl
[sx
][sy
].typ
== STONE
) ? 10
4090 : (In_mines(&u
.uz
) && IS_WALL(levl
[sx
][sy
].typ
)) ? 20
4093 fireball
= (type
== ZT_SPELL(ZT_FIRE
));
4094 if ((--range
> 0 && isok(lsx
, lsy
) && cansee(lsx
, lsy
))
4096 if (Is_airlevel(&u
.uz
)) { /* nothing to bounce off of */
4097 pline_The("%s vanishes into the aether!", fltxt
);
4099 type
= ZT_WAND(ZT_FIRE
); /* skip pending fireball */
4101 } else if (fireball
) {
4104 break; /* fireballs explode before the obstacle */
4106 pline_The("%s bounces!", fltxt
);
4108 if (!dx
|| !dy
|| !rn2(bchance
)) {
4112 if (isok(sx
, lsy
) && ZAP_POS(rmn
= levl
[sx
][lsy
].typ
)
4113 && !closed_door(sx
, lsy
)
4114 && (IS_ROOM(rmn
) || (isok(sx
+ dx
, lsy
)
4115 && ZAP_POS(levl
[sx
+ dx
][lsy
].typ
))))
4117 if (isok(lsx
, sy
) && ZAP_POS(rmn
= levl
[lsx
][sy
].typ
)
4118 && !closed_door(lsx
, sy
)
4119 && (IS_ROOM(rmn
) || (isok(lsx
, sy
+ dy
)
4120 && ZAP_POS(levl
[lsx
][sy
+ dy
].typ
))))
4121 if (!bounce
|| rn2(2))
4126 dx
= -dx
; /* fall into... */
4134 tmp_at(DISP_CHANGE
, zapdir_to_glyph(dx
, dy
, abstype
));
4138 tmp_at(DISP_END
, 0);
4139 if (type
== ZT_SPELL(ZT_FIRE
))
4140 explode(sx
, sy
, type
, d(12, 6), 0, EXPL_FIERY
);
4142 pay_for_damage(abstype
== ZT_FIRE
4144 : abstype
== ZT_COLD
4146 /* "damage" indicates wall rather than door */
4147 : abstype
== ZT_ACID
4149 : abstype
== ZT_DEATH
4153 bhitpos
= save_bhitpos
;
4161 struct rm
*lev
= &levl
[x
][y
];
4165 msg
= "The ice crackles and melts.";
4166 if (lev
->typ
== DRAWBRIDGE_UP
) {
4167 lev
->drawbridgemask
&= ~DB_ICE
; /* revert to DB_MOAT */
4168 } else { /* lev->typ == ICE */
4170 if (lev
->icedpool
== ICED_POOL
)
4175 lev
->typ
= (lev
->icedpool
== ICED_POOL
? POOL
: MOAT
);
4179 spot_stop_timers(x
, y
, MELT_ICE_AWAY
); /* no more ice to melt away */
4180 obj_ice_effects(x
, y
, FALSE
);
4187 if ((otmp
= sobj_at(BOULDER
, x
, y
)) != 0) {
4189 pline("%s settles...", An(xname(otmp
)));
4191 obj_extract_self(otmp
); /* boulder isn't being pushed */
4192 if (!boulder_hits_pool(otmp
, x
, y
, FALSE
))
4193 impossible("melt_ice: no pool?");
4194 /* try again if there's another boulder and pool didn't fill */
4195 } while (is_pool(x
, y
) && (otmp
= sobj_at(BOULDER
, x
, y
)) != 0);
4198 if (x
== u
.ux
&& y
== u
.uy
)
4199 spoteffects(TRUE
); /* possibly drown, notice objects */
4202 #define MIN_ICE_TIME 50
4203 #define MAX_ICE_TIME 2000
4205 * Usually start a melt_ice timer; sometimes the ice will become
4206 * permanent instead.
4209 start_melt_ice_timeout(x
, y
, min_time
)
4211 long min_time
; /* <x,y>'s old melt timeout (deleted by time we get here) */
4216 when
= (int) min_time
;
4217 if (when
< MIN_ICE_TIME
- 1)
4218 when
= MIN_ICE_TIME
- 1;
4220 /* random timeout; surrounding ice locations ought to be a factor... */
4221 while (++when
<= MAX_ICE_TIME
)
4222 if (!rn2((MAX_ICE_TIME
- when
) + MIN_ICE_TIME
))
4225 /* if we're within MAX_ICE_TIME, install a melt timer;
4226 otherwise, omit it to leave this ice permanent */
4227 if (when
<= MAX_ICE_TIME
) {
4228 where
= ((long) x
<< 16) | (long) y
;
4229 (void) start_timer((long) when
, TIMER_LEVEL
, MELT_ICE_AWAY
,
4230 long_to_any(where
));
4237 * Called when ice has melted completely away.
4240 melt_ice_away(arg
, timeout
)
4242 long timeout UNUSED
;
4245 long where
= arg
->a_long
;
4247 y
= (xchar
) (where
& 0xFFFF);
4248 x
= (xchar
) ((where
>> 16) & 0xFFFF);
4249 /* melt_ice does newsym when appropriate */
4250 melt_ice(x
, y
, "Some ice melts away.");
4253 /* Burn floor scrolls, evaporate pools, etc... in a single square.
4254 * Used both for normal bolts of fire, cold, etc... and for fireballs.
4255 * Sets shopdamage to TRUE if a shop door is destroyed, and returns the
4256 * amount by which range is reduced (the latter is just ignored by fireballs)
4259 zap_over_floor(x
, y
, type
, shopdamage
, exploding_wand_typ
)
4262 boolean
*shopdamage
;
4263 short exploding_wand_typ
;
4265 const char *zapverb
;
4268 struct rm
*lev
= &levl
[x
][y
];
4269 boolean see_it
= cansee(x
, y
), yourzap
;
4270 int rangemod
= 0, abstype
= abs(type
) % 10;
4275 if (t
&& t
->ttyp
== WEB
) {
4276 /* a burning web is too flimsy to notice if you can't see it */
4278 Norep("A web bursts into flames!");
4279 (void) delfloortrap(t
);
4284 melt_ice(x
, y
, (char *) 0);
4285 } else if (is_pool(x
, y
)) {
4286 const char *msgtxt
= "You hear hissing gas.";
4288 if (lev
->typ
!= POOL
) { /* MOAT or DRAWBRIDGE_UP */
4290 msgtxt
= "Some water evaporates.";
4294 t
= maketrap(x
, y
, PIT
);
4298 msgtxt
= "The water evaporates.";
4300 Norep("%s", msgtxt
);
4301 if (lev
->typ
== ROOM
)
4303 } else if (IS_FOUNTAIN(lev
->typ
)) {
4305 pline("Steam billows from the fountain.");
4307 dryup(x
, y
, type
> 0);
4309 break; /* ZT_FIRE */
4312 if (is_pool(x
, y
) || is_lava(x
, y
)) {
4313 boolean lava
= is_lava(x
, y
),
4314 moat
= is_moat(x
, y
);
4316 if (lev
->typ
== WATER
) {
4317 /* For now, don't let WATER freeze. */
4319 pline_The("%s freezes for a moment.", hliquid("water"));
4321 You_hear("a soft crackling.");
4322 rangemod
-= 1000; /* stop */
4326 Strcpy(buf
, waterbody_name(x
, y
)); /* for MOAT */
4328 if (lev
->typ
== DRAWBRIDGE_UP
) {
4329 lev
->drawbridgemask
&= ~DB_UNDER
; /* clear lava */
4330 lev
->drawbridgemask
|= (lava
? DB_FLOOR
: DB_ICE
);
4333 lev
->icedpool
= (lev
->typ
== POOL
) ? ICED_POOL
4335 lev
->typ
= lava
? ROOM
: ICE
;
4340 Norep("The %s cools and solidifies.", hliquid("lava"));
4342 Norep("The %s is bridged with ice!", buf
);
4344 Norep("The %s freezes.", hliquid("water"));
4347 You_hear("a crackling sound.");
4349 if (x
== u
.ux
&& y
== u
.uy
) {
4350 if (u
.uinwater
) { /* not just `if (Underwater)' */
4351 /* leave the no longer existent water */
4355 vision_full_recalc
= 1;
4356 } else if (u
.utrap
&& u
.utraptype
== TT_LAVA
) {
4359 You("pass through the now-solid rock.");
4361 u
.utrap
= rn1(50, 20);
4362 u
.utraptype
= TT_INFLOOR
;
4363 You("are firmly stuck in the cooling rock.");
4366 } else if ((mon
= m_at(x
, y
)) != 0) {
4367 /* probably ought to do some hefty damage to any
4368 non-ice creature caught in freezing water;
4369 at a minimum, eels are forced out of hiding */
4370 if (is_swimmer(mon
->data
) && mon
->mundetected
) {
4371 mon
->mundetected
= 0;
4376 start_melt_ice_timeout(x
, y
, 0L);
4377 obj_ice_effects(x
, y
, TRUE
);
4381 } else if (is_ice(x
, y
)) {
4384 /* Already ice here, so just firm it up. */
4385 /* Now ensure that only ice that is already timed is affected */
4386 if ((melt_time
= spot_time_left(x
, y
, MELT_ICE_AWAY
)) != 0L) {
4387 spot_stop_timers(x
, y
, MELT_ICE_AWAY
);
4388 start_melt_ice_timeout(x
, y
, melt_time
);
4391 break; /* ZT_COLD */
4394 (void) create_gas_cloud(x
, y
, 1, 8);
4398 if (lev
->typ
== IRONBARS
) {
4399 if ((lev
->wall_info
& W_NONDIGGABLE
) != 0) {
4401 Norep("The %s corrode somewhat but remain intact.",
4402 defsyms
[S_bars
].explanation
);
4403 /* but nothing actually happens... */
4407 Norep("The %s melt.", defsyms
[S_bars
].explanation
);
4408 if (*in_rooms(x
, y
, SHOPBASE
)) {
4409 /* in case we ever have a shop bounded by bars */
4413 add_damage(x
, y
, (type
>= 0) ? 300L : 0L);
4418 lev
->doormask
= D_NODOOR
;
4424 break; /* ZT_ACID */
4430 /* set up zap text for possible door feedback; for exploding wand, we
4431 want "the blast" rather than "your blast" even if hero caused it */
4432 yourzap
= (type
>= 0 && !exploding_wand_typ
);
4433 zapverb
= "blast"; /* breath attack or wand explosion */
4434 if (!exploding_wand_typ
) {
4435 if (abs(type
) < ZT_SPELL(0))
4436 zapverb
= "bolt"; /* wand zap */
4437 else if (abs(type
) < ZT_BREATH(0))
4441 /* secret door gets revealed, converted into regular door */
4442 if (levl
[x
][y
].typ
== SDOOR
) {
4443 cvt_sdoor_to_door(&levl
[x
][y
]); /* .typ = DOOR */
4444 /* target spot will now pass closed_door() test below
4445 (except on rogue level) */
4448 pline("%s %s reveals a secret door.",
4449 yourzap
? "Your" : "The", zapverb
);
4450 else if (Is_rogue_level(&u
.uz
))
4451 draft_message(FALSE
); /* "You feel a draft." (open doorway) */
4454 /* regular door absorbs remaining zap range, possibly gets destroyed */
4455 if (closed_door(x
, y
)) {
4456 int new_doormask
= -1;
4457 const char *see_txt
= 0, *sense_txt
= 0, *hear_txt
= 0;
4462 new_doormask
= D_NODOOR
;
4463 see_txt
= "The door is consumed in flames!";
4464 sense_txt
= "smell smoke.";
4467 new_doormask
= D_NODOOR
;
4468 see_txt
= "The door freezes and shatters!";
4469 sense_txt
= "feel cold.";
4472 /* death spells/wands don't disintegrate */
4473 if (abs(type
) != ZT_BREATH(ZT_DEATH
))
4475 new_doormask
= D_NODOOR
;
4476 see_txt
= "The door disintegrates!";
4477 hear_txt
= "crashing wood.";
4480 new_doormask
= D_BROKEN
;
4481 see_txt
= "The door splinters!";
4482 hear_txt
= "crackling.";
4486 if (exploding_wand_typ
> 0) {
4487 /* Magical explosion from misc exploding wand */
4488 if (exploding_wand_typ
== WAN_STRIKING
) {
4489 new_doormask
= D_BROKEN
;
4490 see_txt
= "The door crashes open!";
4491 sense_txt
= "feel a burst of cool air.";
4496 /* "the door absorbs the blast" would be
4497 inaccurate for an exploding wand since
4498 other adjacent locations still get hit */
4499 if (exploding_wand_typ
)
4500 pline_The("door remains intact.");
4502 pline_The("door absorbs %s %s!", yourzap
? "your" : "the",
4505 You_feel("vibrations.");
4508 if (new_doormask
>= 0) { /* door gets broken */
4509 if (*in_rooms(x
, y
, SHOPBASE
)) {
4511 add_damage(x
, y
, 400L);
4513 } else /* caused by monster */
4514 add_damage(x
, y
, 0L);
4516 lev
->doormask
= new_doormask
;
4517 unblock_point(x
, y
); /* vision */
4521 } else if (sense_txt
) {
4523 } else if (hear_txt
)
4524 You_hear1(hear_txt
);
4525 if (picking_at(x
, y
)) {
4532 if (OBJ_AT(x
, y
) && abstype
== ZT_FIRE
)
4533 if (burn_floor_objects(x
, y
, FALSE
, type
> 0) && couldsee(x
, y
)) {
4535 You("%s of smoke.", !Blind
? "see a puff" : "smell a whiff");
4537 if ((mon
= m_at(x
, y
)) != 0) {
4540 setmangry(mon
, TRUE
);
4541 if (mon
->ispriest
&& *in_rooms(mon
->mx
, mon
->my
, TEMPLE
))
4543 if (mon
->isshk
&& !*u
.ushops
)
4550 /* fractured by pick-axe or wand of striking */
4553 register struct obj
*obj
; /* no texts here! */
4556 boolean by_you
= !context
.mon_moving
;
4558 if (by_you
&& get_obj_location(obj
, &x
, &y
, 0) && costly_spot(x
, y
)) {
4559 struct monst
*shkp
= 0;
4560 char objroom
= *in_rooms(x
, y
, SHOPBASE
);
4562 if (billable(&shkp
, obj
, objroom
, FALSE
)) {
4563 /* shop message says "you owe <shk> <$> for it!" so we need
4564 to precede that with a message explaining what "it" is */
4565 You("fracture %s %s.", s_suffix(shkname(shkp
)), xname(obj
));
4566 breakobj(obj
, x
, y
, TRUE
, FALSE
); /* charges for shop goods */
4569 if (by_you
&& obj
->otyp
== BOULDER
)
4573 obj
->oclass
= GEM_CLASS
;
4574 obj
->quan
= (long) rn1(60, 7);
4575 obj
->owt
= weight(obj
);
4576 obj
->dknown
= obj
->bknown
= obj
->rknown
= 0;
4577 obj
->known
= objects
[obj
->otyp
].oc_uses_known
? 0 : 1;
4578 dealloc_oextra(obj
);
4580 if (obj
->where
== OBJ_FLOOR
) {
4581 obj_extract_self(obj
); /* move rocks back on top */
4582 place_object(obj
, obj
->ox
, obj
->oy
);
4583 if (!does_block(obj
->ox
, obj
->oy
, &levl
[obj
->ox
][obj
->oy
]))
4584 unblock_point(obj
->ox
, obj
->oy
);
4585 if (cansee(obj
->ox
, obj
->oy
))
4586 newsym(obj
->ox
, obj
->oy
);
4590 /* handle statue hit by striking/force bolt/pick-axe */
4593 register struct obj
*obj
;
4595 /* [obj is assumed to be on floor, so no get_obj_location() needed] */
4596 struct trap
*trap
= t_at(obj
->ox
, obj
->oy
);
4598 boolean by_you
= !context
.mon_moving
;
4600 if (trap
&& trap
->ttyp
== STATUE_TRAP
4601 && activate_statue_trap(trap
, obj
->ox
, obj
->oy
, TRUE
))
4603 /* drop any objects contained inside the statue */
4604 while ((item
= obj
->cobj
) != 0) {
4605 obj_extract_self(item
);
4606 place_object(item
, obj
->ox
, obj
->oy
);
4608 if (by_you
&& Role_if(PM_ARCHEOLOGIST
) && (obj
->spe
& STATUE_HISTORIC
)) {
4609 You_feel("guilty about damaging such a historic statue.");
4618 * destroy_strings[dindx][0:singular,1:plural,2:killer_reason]
4619 * [0] freezing potion
4620 * [1] boiling potion other than oil
4621 * [2] boiling potion of oil
4622 * [3] burning scroll
4623 * [4] burning spellbook
4626 * (books, rings, and wands don't stack so don't need plural form;
4627 * crumbling ring doesn't do damage so doesn't need killer reason)
4629 const char *const destroy_strings
[][3] = {
4630 /* also used in trap.c */
4631 { "freezes and shatters", "freeze and shatter", "shattered potion" },
4632 { "boils and explodes", "boil and explode", "boiling potion" },
4633 { "ignites and explodes", "ignite and explode", "exploding potion" },
4634 { "catches fire and burns", "catch fire and burn", "burning scroll" },
4635 { "catches fire and burns", "", "burning book" },
4636 { "turns to dust and vanishes", "", "" },
4637 { "breaks apart and explodes", "", "exploding wand" },
4641 destroy_item(osym
, dmgtyp
)
4642 register int osym
, dmgtyp
;
4644 register struct obj
*obj
, *obj2
;
4645 int dmg
, xresist
, skip
;
4649 boolean physical_damage
;
4651 for (obj
= invent
; obj
; obj
= obj2
) {
4653 physical_damage
= FALSE
;
4654 if (obj
->oclass
!= osym
)
4655 continue; /* test only objs of type osym */
4657 continue; /* don't destroy artifacts */
4658 if (obj
->in_use
&& obj
->quan
== 1L)
4659 continue; /* not available */
4661 /* lint suppression */
4667 if (osym
== POTION_CLASS
&& obj
->otyp
!= POT_OIL
) {
4675 xresist
= (Fire_resistance
&& obj
->oclass
!= POTION_CLASS
4676 && obj
->otyp
!= GLOB_OF_GREEN_SLIME
);
4678 if (obj
->otyp
== SCR_FIRE
|| obj
->otyp
== SPE_FIREBALL
)
4680 if (obj
->otyp
== SPE_BOOK_OF_THE_DEAD
) {
4683 pline("%s glows a strange %s, but remains intact.",
4684 The(xname(obj
)), hcolor("dark red"));
4689 dindx
= (obj
->otyp
!= POT_OIL
) ? 1 : 2;
4701 if (obj
->otyp
== GLOB_OF_GREEN_SLIME
) {
4702 dindx
= 1; /* boil and explode */
4703 dmg
= (obj
->owt
+ 19) / 20;
4714 xresist
= (Shock_resistance
&& obj
->oclass
!= RING_CLASS
);
4718 if (obj
->otyp
== RIN_SHOCK_RESISTANCE
) {
4726 if (obj
->otyp
== WAN_LIGHTNING
) {
4731 if (obj
== current_wand
) { skip
++; break; }
4747 --quan
; /* one will be used up elsewhere */
4748 for (i
= cnt
= 0L; i
< quan
; i
++)
4755 ? (quan
== 1L) ? "Your" /* 1 of 1 */
4756 : "One of your" /* 1 of N */
4757 : (cnt
< quan
) ? "Some of your" /* n of N */
4758 : (quan
== 2L) ? "Both of your" /* 2 of 2 */
4759 : "All of your"; /* N of N */
4760 pline("%s %s %s!", mult
, xname(obj
),
4761 destroy_strings
[dindx
][(cnt
> 1L)]);
4762 if (osym
== POTION_CLASS
&& dmgtyp
!= AD_COLD
) {
4763 if (!breathless(youmonst
.data
) || haseyes(youmonst
.data
))
4766 if (obj
->owornmask
) {
4767 if (obj
->owornmask
& W_RING
) /* ring being worn */
4772 if (obj
== current_wand
)
4773 current_wand
= 0; /* destroyed */
4774 for (i
= 0; i
< cnt
; i
++)
4778 You("aren't hurt!");
4780 const char *how
= destroy_strings
[dindx
][2];
4781 boolean one
= (cnt
== 1L);
4783 if (dmgtyp
== AD_FIRE
&& osym
== FOOD_CLASS
)
4784 how
= "exploding glob of slime";
4785 if (physical_damage
)
4786 dmg
= Maybe_Half_Phys(dmg
);
4787 losehp(dmg
, one
? how
: (const char *) makeplural(how
),
4788 one
? KILLED_BY_AN
: KILLED_BY
);
4789 exercise(A_STR
, FALSE
);
4798 destroy_mitem(mtmp
, osym
, dmgtyp
)
4802 struct obj
*obj
, *obj2
;
4808 if (mtmp
== &youmonst
) { /* this simplifies artifact_hit() */
4809 destroy_item(osym
, dmgtyp
);
4810 return 0; /* arbitrary; value doesn't matter to artifact_hit() */
4813 vis
= canseemon(mtmp
);
4814 for (obj
= mtmp
->minvent
; obj
; obj
= obj2
) {
4816 if (obj
->oclass
!= osym
)
4817 continue; /* test only objs of type osym */
4824 if (osym
== POTION_CLASS
&& obj
->otyp
!= POT_OIL
) {
4832 if (obj
->otyp
== SCR_FIRE
|| obj
->otyp
== SPE_FIREBALL
)
4834 if (obj
->otyp
== SPE_BOOK_OF_THE_DEAD
) {
4837 pline("%s glows a strange %s, but remains intact.",
4838 The(distant_name(obj
, xname
)), hcolor("dark red"));
4843 dindx
= (obj
->otyp
!= POT_OIL
) ? 1 : 2;
4855 if (obj
->otyp
== GLOB_OF_GREEN_SLIME
) {
4856 dindx
= 1; /* boil and explode */
4857 tmp
+= (obj
->owt
+ 19) / 20;
4871 if (obj
->otyp
== RIN_SHOCK_RESISTANCE
) {
4878 if (obj
->otyp
== WAN_LIGHTNING
) {
4895 for (i
= cnt
= 0L; i
< quan
; i
++)
4903 (cnt
== obj
->quan
) ? "" : (cnt
> 1L) ? "Some of "
4905 (cnt
== obj
->quan
) ? Yname2(obj
) : yname(obj
),
4906 destroy_strings
[dindx
][(cnt
> 1L)]);
4907 for (i
= 0; i
< cnt
; i
++)
4915 resist(mtmp
, oclass
, damage
, tell
)
4930 break; /* instrument */
4933 break; /* artifact */
4948 dlev
= (int) mtmp
->m_lev
;
4952 dlev
= is_mplayer(mtmp
->data
) ? u
.ulevel
: 1;
4954 resisted
= rn2(100 + alev
- dlev
) < mtmp
->data
->mr
;
4957 shieldeff(mtmp
->mx
, mtmp
->my
);
4958 pline("%s resists!", Monnam(mtmp
));
4960 damage
= (damage
+ 1) / 2;
4964 mtmp
->mhp
-= damage
;
4965 if (mtmp
->mhp
< 1) {
4967 monkilled(mtmp
, "", AD_RBRE
);
4975 #define MAXWISHTRY 5
4978 wishcmdassist(triesleft
)
4981 static NEARDATA
const char *
4985 "Enter the name of an object, such as \"potion of monster detection\",",
4986 "\"scroll labeled README\", \"elven mithril-coat\", or \"Grimtooth\"",
4987 "(without the quotes).",
4989 "For object types which come in stacks, you may specify a plural name",
4990 "such as \"potions of healing\", or specify a count, such as \"1000 gold",
4991 "pieces\", although that aspect of your wish might not be granted.",
4993 "You may also specify various prefix values which might be used to",
4994 "modify the item, such as \"uncursed\" or \"rustproof\" or \"+1\".",
4995 "Most modifiers shown when viewing your inventory can be specified.",
4997 "You may specify 'nothing' to explicitly decline this wish.",
5000 preserve_wishless
[] = "Doing so will preserve 'wishless' conduct.",
5002 "If you specify an unrecognized object name %s%s time%s,",
5003 retry_too
[] = "a randomly chosen item will be granted.",
5004 suppress_cmdassist
[] =
5005 "(Suppress this assistance with !cmdassist in your config file.)",
5006 *cardinals
[] = { "zero", "one", "two", "three", "four", "five" },
5007 too_many
[] = "too many";
5012 win
= create_nhwindow(NHW_TEXT
);
5015 for (i
= 0; i
< SIZE(wishinfo
) - 1; ++i
)
5016 putstr(win
, 0, wishinfo
[i
]);
5017 if (!u
.uconduct
.wishes
)
5018 putstr(win
, 0, preserve_wishless
);
5020 Sprintf(buf
, retry_info
,
5021 (triesleft
>= 0 && triesleft
< SIZE(cardinals
))
5022 ? cardinals
[triesleft
]
5024 (triesleft
< MAXWISHTRY
) ? " more" : "",
5026 putstr(win
, 0, buf
);
5027 putstr(win
, 0, retry_too
);
5029 if (iflags
.cmdassist
)
5030 putstr(win
, 0, suppress_cmdassist
);
5031 display_nhwindow(win
, FALSE
);
5032 destroy_nhwindow(win
);
5038 char buf
[BUFSZ
], promptbuf
[BUFSZ
];
5039 struct obj
*otmp
, nothing
;
5042 promptbuf
[0] = '\0';
5043 nothing
= zeroobj
; /* lint suppression; only its address matters */
5045 You("may wish for an object.");
5047 Strcpy(promptbuf
, "For what do you wish");
5048 if (iflags
.cmdassist
&& tries
> 0)
5049 Strcat(promptbuf
, " (enter 'help' for assistance)");
5050 Strcat(promptbuf
, "?");
5051 getlin(promptbuf
, buf
);
5052 (void) mungspaces(buf
);
5053 if (buf
[0] == '\033') {
5055 } else if (!strcmpi(buf
, "help")) {
5056 wishcmdassist(MAXWISHTRY
- tries
);
5060 * Note: if they wished for and got a non-object successfully,
5061 * otmp == &zeroobj. That includes gold, or an artifact that
5062 * has been denied. Wishing for "nothing" requires a separate
5063 * value to remain distinct.
5065 otmp
= readobjnam(buf
, ¬hing
);
5067 pline("Nothing fitting that description exists in the game.");
5068 if (++tries
< MAXWISHTRY
)
5070 pline1(thats_enough_tries
);
5071 otmp
= readobjnam((char *) 0, (struct obj
*) 0);
5073 return; /* for safety; should never happen */
5074 } else if (otmp
== ¬hing
) {
5075 /* explicitly wished for "nothing", presumably attempting
5076 to retain wishless conduct */
5081 u
.uconduct
.wishes
++;
5083 if (otmp
!= &zeroobj
) {
5085 *verb
= ((Is_airlevel(&u
.uz
) || u
.uinwater
) ? "slip" : "drop"),
5086 *oops_msg
= (u
.uswallow
5087 ? "Oops! %s out of your reach!"
5088 : (Is_airlevel(&u
.uz
) || Is_waterlevel(&u
.uz
)
5089 || levl
[u
.ux
][u
.uy
].typ
< IRONBARS
5090 || levl
[u
.ux
][u
.uy
].typ
>= ICE
)
5091 ? "Oops! %s away from you!"
5092 : "Oops! %s to the floor!");
5094 /* The(aobjnam()) is safe since otmp is unidentified -dlc */
5095 (void) hold_another_object(otmp
, oops_msg
,
5096 The(aobjnam(otmp
, verb
)),
5098 u
.ublesscnt
+= rn1(100, 50); /* the gods take notice */