1 /* SCCS Id: @(#)zap.c 3.4 2003/08/24 */
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
15 static NEARDATA boolean obj_zapped;
16 static NEARDATA int poly_zapped;
19 extern boolean notonhead; /* for long worms */
21 /* kludge to use mondied instead of killed */
22 extern boolean m_using;
24 STATIC_DCL void FDECL(costly_cancel, (struct obj *));
25 STATIC_DCL void FDECL(polyuse, (struct obj*, int, int));
26 STATIC_DCL void FDECL(create_polymon, (struct obj *, int));
27 STATIC_DCL boolean FDECL(zap_updown, (struct obj *));
28 STATIC_DCL int FDECL(zhitm, (struct monst *,int,int,struct obj **));
29 STATIC_DCL void FDECL(zhitu, (int,int,const char *,XCHAR_P,XCHAR_P));
30 STATIC_DCL void FDECL(revive_egg, (struct obj *));
32 STATIC_DCL boolean FDECL(zap_steed, (struct obj *));
36 STATIC_DCL int FDECL(zap_hit, (int,int));
39 STATIC_DCL void FDECL(backfire, (struct obj *));
40 STATIC_DCL int FDECL(spell_hit_bonus, (int));
43 #define ZT_MAGIC_MISSILE (AD_MAGM-1)
44 #define ZT_FIRE (AD_FIRE-1)
45 #define ZT_COLD (AD_COLD-1)
46 #define ZT_SLEEP (AD_SLEE-1)
47 #define ZT_DEATH (AD_DISN-1) /* or disintegration */
48 #define ZT_LIGHTNING (AD_ELEC-1)
49 #define ZT_POISON_GAS (AD_DRST-1)
50 #define ZT_ACID (AD_ACID-1)
51 /* 8 and 9 are currently unassigned */
53 #define ZT_WAND(x) (x)
54 #define ZT_SPELL(x) (10+(x))
55 #define ZT_BREATH(x) (20+(x))
57 #define is_hero_spell(type) ((type) >= 10 && (type) < 20)
60 STATIC_VAR const char are_blinded_by_the_flash[];
61 extern const char * const flash_types[];
63 STATIC_VAR const char are_blinded_by_the_flash[] = "are blinded by the flash!";
65 const char * const flash_types[] = { /* also used in buzzmu(mcastu.c) */
66 "magic missile", /* Wands must be 0-9 */
77 "magic missile", /* Spell equivalents must be 10-19 */
82 "bolt of lightning", /* There is no spell, used for retribution */
88 "blast of missiles", /* Dragon breath equivalents 20-29*/
92 "blast of disintegration",
94 "blast of poison gas",
100 /* Routines for IMMEDIATE wands and spells. */
101 /* bhitm: monster mtmp was hit by the effect of wand or spell otmp */
107 boolean wake = TRUE; /* Most 'zaps' should wake monster */
108 boolean reveal_invis = FALSE;
109 boolean dbldam = Role_if(PM_KNIGHT) && u.uhave.questart;
110 int dmg, otyp = otmp->otyp;
111 const char *zap_type_text = "spell";
113 boolean disguised_mimic = (mtmp->data->mlet == S_MIMIC &&
114 mtmp->m_ap_type != M_AP_NOTHING);
116 if (u.uswallow && mtmp == u.ustuck)
117 reveal_invis = FALSE;
121 zap_type_text = "wand";
125 if (resists_magm(mtmp)) { /* match effect on player */
126 shieldeff(mtmp->mx, mtmp->my);
127 break; /* skip makeknown */
128 } else if (u.uswallow || rnd(20) < 10 + find_mac(mtmp)) {
131 if (otyp == SPE_FORCE_BOLT)
132 dmg += spell_damage_bonus();
133 hit(zap_type_text, mtmp, exclam(dmg));
134 (void) resist(mtmp, otmp->oclass, dmg, TELL);
135 } else miss(zap_type_text, mtmp);
138 case WAN_SLOW_MONSTER:
139 case SPE_SLOW_MONSTER:
140 if (!resist(mtmp, otmp->oclass, 0, NOTELL)) {
141 mon_adjust_speed(mtmp, -1, otmp);
142 m_dowear(mtmp, FALSE); /* might want speed boots */
143 if (u.uswallow && (mtmp == u.ustuck) &&
144 is_whirly(mtmp->data)) {
145 You("disrupt %s!", mon_nam(mtmp));
146 pline("A huge hole opens up...");
147 expels(mtmp, mtmp->data, TRUE);
151 case WAN_SPEED_MONSTER:
152 if (!resist(mtmp, otmp->oclass, 0, NOTELL)) {
153 mon_adjust_speed(mtmp, 1, otmp);
154 m_dowear(mtmp, FALSE); /* might want speed boots */
157 case WAN_UNDEAD_TURNING:
158 case SPE_TURN_UNDEAD:
160 if (unturn_dead(mtmp)) wake = TRUE;
161 if (is_undead(mtmp->data)) {
166 if (otyp == SPE_TURN_UNDEAD)
167 dmg += spell_damage_bonus();
168 flags.bypasses = TRUE; /* for make_corpse() */
169 if (!resist(mtmp, otmp->oclass, dmg, NOTELL)) {
170 if (mtmp->mhp > 0) monflee(mtmp, 0, FALSE, TRUE);
177 if (resists_magm(mtmp)) {
178 /* magic resistance protects from polymorph traps, so make
179 it guard against involuntary polymorph attacks too... */
180 shieldeff(mtmp->mx, mtmp->my);
181 } else if (!resist(mtmp, otmp->oclass, 0, NOTELL)) {
182 /* natural shapechangers aren't affected by system shock
183 (unless protection from shapechangers is interfering
184 with their metabolism...) */
185 if (mtmp->cham == CHAM_ORDINARY && !rn2(25)) {
186 if (canseemon(mtmp)) {
187 pline("%s shudders!", Monnam(mtmp));
190 /* dropped inventory shouldn't be hit by this zap */
191 for (obj = mtmp->minvent; obj; obj = obj->nobj)
193 /* flags.bypasses = TRUE; ## for make_corpse() */
194 /* no corpse after system shock */
196 } else if (newcham(mtmp, (struct permonst *)0,
197 (otyp != POT_POLYMORPH), FALSE)) {
198 if (!Hallucination && canspotmon(mtmp))
203 case WAN_CANCELLATION:
204 case SPE_CANCELLATION:
205 (void) cancel_monst(mtmp, otmp, TRUE, TRUE, FALSE);
207 case WAN_TELEPORTATION:
208 case SPE_TELEPORT_AWAY:
209 reveal_invis = !u_teleport_mon(mtmp, TRUE);
211 case WAN_MAKE_INVISIBLE:
213 int oldinvis = mtmp->minvis;
216 /* format monster's name before altering its visibility */
217 Strcpy(nambuf, Monnam(mtmp));
218 mon_set_minvis(mtmp);
219 if (!oldinvis && knowninvisible(mtmp)) {
220 pline("%s turns transparent!", nambuf);
227 case SPE_WIZARD_LOCK:
238 wake = FALSE; /* don't want immediate counterattack */
239 if (u.uswallow && mtmp == u.ustuck) {
240 if (is_animal(mtmp->data)) {
241 if (Blind) You_feel("a sudden rush of air!");
242 else pline("%s opens its mouth!", Monnam(mtmp));
244 expels(mtmp, mtmp->data, TRUE);
246 } else if (!!(obj = which_armor(mtmp, W_SADDLE))) {
247 mtmp->misc_worn_check &= ~obj->owornmask;
248 update_mon_intrinsics(mtmp, obj, FALSE, FALSE);
250 obj_extract_self(obj);
251 place_object(obj, mtmp->mx, mtmp->my);
252 /* call stackobj() if we ever drop anything that can merge */
253 newsym(mtmp->mx, mtmp->my);
258 case SPE_EXTRA_HEALING:
260 if (mtmp->data != &mons[PM_PESTILENCE]) {
261 wake = FALSE; /* wakeup() makes the target angry */
262 mtmp->mhp += d(6, otyp == SPE_EXTRA_HEALING ? 8 : 4);
263 if (mtmp->mhp > mtmp->mhpmax)
264 mtmp->mhp = mtmp->mhpmax;
265 if (mtmp->mblinded) {
269 if (canseemon(mtmp)) {
270 if (disguised_mimic) {
271 if (mtmp->m_ap_type == M_AP_OBJECT &&
272 mtmp->mappearance == STRANGE_OBJECT) {
273 /* it can do better now */
275 newsym(mtmp->mx, mtmp->my);
277 mimic_hit_msg(mtmp, otyp);
278 } else pline("%s looks%s better.", Monnam(mtmp),
279 otyp == SPE_EXTRA_HEALING ? " much" : "" );
281 if (mtmp->mtame || mtmp->mpeaceful) {
282 adjalign(Role_if(PM_HEALER) ? 1 : sgn(u.ualign.type));
284 } else { /* Pestilence */
285 /* Pestilence will always resist; damage is half of 3d{4,8} */
286 (void) resist(mtmp, otmp->oclass,
287 d(3, otyp == SPE_EXTRA_HEALING ? 8 : 4), TELL);
290 case WAN_LIGHT: /* (broken wand) */
291 if (flash_hits_mon(mtmp, otmp)) {
292 makeknown(WAN_LIGHT);
296 case WAN_SLEEP: /* (broken wand) */
297 /* [wakeup() doesn't rouse victims of temporary sleep,
298 so it's okay to leave `wake' set to TRUE here] */
300 if (sleep_monst(mtmp, d(1 + otmp->spe, 12), WAND_CLASS))
302 if (!Blind) makeknown(WAN_SLEEP);
304 case SPE_STONE_TO_FLESH:
305 if (monsndx(mtmp->data) == PM_STONE_GOLEM) {
306 char *name = Monnam(mtmp);
307 /* turn into flesh golem */
308 if (newcham(mtmp, &mons[PM_FLESH_GOLEM], FALSE, FALSE)) {
310 pline("%s turns to flesh!", name);
313 pline("%s looks rather fleshy for a moment.",
322 if (otyp == SPE_DRAIN_LIFE)
323 dmg += spell_damage_bonus();
324 if (resists_drli(mtmp))
325 shieldeff(mtmp->mx, mtmp->my);
326 else if (!resist(mtmp, otmp->oclass, dmg, NOTELL) &&
330 if (mtmp->mhp <= 0 || mtmp->mhpmax <= 0 || mtmp->m_lev < 1)
335 pline("%s suddenly seems weaker!", Monnam(mtmp));
340 impossible("What an interesting effect (%d)", otyp);
347 if(mtmp->isshk && !*u.ushops) hot_pursuit(mtmp);
348 } else if(mtmp->m_ap_type)
349 seemimic(mtmp); /* might unblock if mimicing a boulder/door */
351 /* note: bhitpos won't be set if swallowed, but that's okay since
352 * reveal_invis will be false. We can't use mtmp->mx, my since it
353 * might be an invisible worm hit on the tail.
356 if (mtmp->mhp > 0 && cansee(bhitpos.x, bhitpos.y) &&
358 map_invisible(bhitpos.x, bhitpos.y);
370 if (notonhead) return; /* don't show minvent for long worm tail */
373 if (mtmp->minvent || mtmp->mgold) {
377 for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
378 otmp->dknown = 1; /* treat as "seen" */
379 (void) display_minventory(mtmp, MINV_ALL, (char *)0);
381 pline("%s is not carrying anything.", noit_Monnam(mtmp));
389 * Return the object's physical location. This only makes sense for
390 * objects that are currently on the level (i.e. migrating objects
391 * are nowhere). By default, only things that can be seen (in hero's
392 * inventory, monster's inventory, or on the ground) are reported.
393 * By adding BURIED_TOO and/or CONTAINED_TOO flags, you can also get
394 * the location of buried and contained objects. Note that if an
395 * object is carried by a monster, its reported position may change
396 * from turn to turn. This function returns FALSE if the position
397 * is not available or subject to the constraints above.
400 get_obj_location(obj, xp, yp, locflags)
405 switch (obj->where) {
415 if (obj->ocarry->mx) {
416 *xp = obj->ocarry->mx;
417 *yp = obj->ocarry->my;
420 break; /* !mx => migrating monster */
422 if (locflags & BURIED_TOO) {
429 if (locflags & CONTAINED_TOO)
430 return get_obj_location(obj->ocontainer, xp, yp, locflags);
438 get_mon_location(mon, xp, yp, locflags)
441 int locflags; /* non-zero means get location even if monster is buried */
443 if (mon == &youmonst) {
447 } else if (mon->mx > 0 && (!mon->mburied || locflags)) {
451 } else { /* migrating or buried */
457 /* used by revive() and animate_statue() */
463 struct monst *mtmp = (struct monst *)0;
464 struct monst *mtmp2 = (struct monst *)0;
466 if (obj->oxlth && (obj->oattached == OATTACHED_MONST))
467 mtmp2 = get_mtraits(obj, TRUE);
469 /* save_mtraits() validated mtmp2->mnum */
470 mtmp2->data = &mons[mtmp2->mnum];
471 if (mtmp2->mhpmax <= 0 && !is_rider(mtmp2->data))
472 return (struct monst *)0;
473 mtmp = makemon(mtmp2->data,
474 cc->x, cc->y, NO_MINVENT|MM_NOWAIT|MM_NOCOUNTBIRTH);
475 if (!mtmp) return mtmp;
477 /* heal the monster */
478 if (mtmp->mhpmax > mtmp2->mhpmax && is_rider(mtmp2->data))
479 mtmp2->mhpmax = mtmp->mhpmax;
480 mtmp2->mhp = mtmp2->mhpmax;
481 /* Get these ones from mtmp */
482 mtmp2->minvent = mtmp->minvent; /*redundant*/
483 /* monster ID is available if the monster died in the current
484 game, but should be zero if the corpse was in a bones level
485 (we cleared it when loading bones) */
487 mtmp2->m_id = mtmp->m_id;
488 mtmp2->mx = mtmp->mx;
489 mtmp2->my = mtmp->my;
490 mtmp2->mux = mtmp->mux;
491 mtmp2->muy = mtmp->muy;
492 mtmp2->mw = mtmp->mw;
493 mtmp2->wormno = mtmp->wormno;
494 mtmp2->misc_worn_check = mtmp->misc_worn_check;
495 mtmp2->weapon_check = mtmp->weapon_check;
496 mtmp2->mtrapseen = mtmp->mtrapseen;
497 mtmp2->mflee = mtmp->mflee;
498 mtmp2->mburied = mtmp->mburied;
499 mtmp2->mundetected = mtmp->mundetected;
500 mtmp2->mfleetim = mtmp->mfleetim;
501 mtmp2->mlstmv = mtmp->mlstmv;
502 mtmp2->m_ap_type = mtmp->m_ap_type;
503 /* set these ones explicitly */
508 mtmp2->msleeping = 0;
511 /* most cancelled monsters return to normal,
512 but some need to stay cancelled */
513 if (!dmgtype(mtmp2->data, AD_SEDU)
515 && !dmgtype(mtmp2->data, AD_SSEX)
518 mtmp2->mcansee = 1; /* set like in makemon */
528 * get_container_location() returns the following information
529 * about the outermost container:
530 * loc argument gets set to:
531 * OBJ_INVENT if in hero's inventory; return 0.
532 * OBJ_FLOOR if on the floor; return 0.
533 * OBJ_BURIED if buried; return 0.
534 * OBJ_MINVENT if in monster's inventory; return monster.
535 * container_nesting is updated with the nesting depth of the containers
539 get_container_location(obj, loc, container_nesting)
542 int *container_nesting;
547 if (container_nesting) *container_nesting = 0;
548 while (obj && obj->where == OBJ_CONTAINED) {
549 if (container_nesting) *container_nesting += 1;
550 obj = obj->ocontainer;
553 *loc = obj->where; /* outermost container's location */
554 if (obj->where == OBJ_MINVENT) return obj->ocarry;
556 return (struct monst *)0;
560 * Attempt to revive the given corpse, return the revived monster if
561 * successful. Note: this does NOT use up the corpse if it fails.
565 register struct obj *obj;
567 register struct monst *mtmp = (struct monst *)0;
568 struct obj *container = (struct obj *)0;
569 int container_nesting = 0;
571 boolean recorporealization = FALSE;
572 boolean in_container = FALSE;
573 if(obj->otyp == CORPSE) {
574 int montype = obj->corpsenm;
577 if (obj->where == OBJ_CONTAINED) {
578 /* deal with corpses in [possibly nested] containers */
579 struct monst *carrier;
582 container = obj->ocontainer;
583 carrier = get_container_location(container, &holder,
587 x = carrier->mx; y = carrier->my;
595 if (!get_obj_location(obj, &x, &y, CONTAINED_TOO))
596 return (struct monst *) 0;
600 return (struct monst *)0;
603 /* only for invent, minvent, or floor */
604 if (!get_obj_location(obj, &x, &y, 0))
605 return (struct monst *) 0;
608 /* Rules for revival from containers:
609 - the container cannot be locked
610 - the container cannot be heavily nested (>2 is arbitrary)
611 - the container cannot be a statue or bag of holding
612 (except in very rare cases for the latter)
614 if (!x || !y || container->olocked || container_nesting > 2 ||
615 container->otyp == STATUE ||
616 (container->otyp == BAG_OF_HOLDING && rn2(40)))
617 return (struct monst *)0;
623 if (enexto(&new_xy, x, y, &mons[montype]))
624 x = new_xy.x, y = new_xy.y;
627 if(cant_create(&montype, TRUE)) {
628 /* make a zombie or worm instead */
629 mtmp = makemon(&mons[montype], x, y,
630 NO_MINVENT|MM_NOWAIT);
632 mtmp->mhp = mtmp->mhpmax = 100;
633 mon_adjust_speed(mtmp, 2, (struct obj *)0); /* MFAST */
636 if (obj->oxlth && (obj->oattached == OATTACHED_MONST)) {
639 mtmp = montraits(obj, &xy);
640 if (mtmp && mtmp->mtame && !mtmp->isminion)
641 wary_dog(mtmp, TRUE);
643 mtmp = makemon(&mons[montype], x, y,
644 NO_MINVENT|MM_NOWAIT|MM_NOCOUNTBIRTH);
646 if (obj->oxlth && (obj->oattached == OATTACHED_M_ID)) {
649 (void) memcpy((genericptr_t)&m_id,
650 (genericptr_t)obj->oextra, sizeof(m_id));
651 ghost = find_mid(m_id, FM_FMON);
652 if (ghost && ghost->data == &mons[PM_GHOST]) {
654 x2 = ghost->mx; y2 = ghost->my;
656 savetame = ghost->mtame;
657 if (canseemon(ghost))
658 pline("%s is suddenly drawn into its former body!",
661 recorporealization = TRUE;
664 /* don't mess with obj->oxlth here */
665 obj->oattached = OATTACHED_NOTHING;
667 /* Monster retains its name */
669 mtmp = christen_monst(mtmp, ONAME(obj));
670 /* flag the quest leader as alive. */
671 if (mtmp->data->msound == MS_LEADER || mtmp->m_id ==
672 quest_status.leader_m_id)
673 quest_status.leader_is_dead = FALSE;
678 mtmp->mhp = eaten_stat(mtmp->mhp, obj);
679 /* track that this monster was revived at least once */
682 if (recorporealization) {
683 /* If mtmp is revivification of former tame ghost*/
685 struct monst *mtmp2 = tamedog(mtmp, (struct obj *)0);
687 mtmp2->mtame = savetame;
691 /* was ghost, now alive, it's all very confusing */
695 switch (obj->where) {
700 /* in case MON_AT+enexto for invisible mon */
701 x = obj->ox, y = obj->oy;
702 /* not useupf(), which charges */
704 obj = splitobj(obj, 1L);
709 m_useup(obj->ocarry, obj);
712 obj_extract_self(obj);
713 obfree(obj, (struct obj *) 0);
728 * Note: generic eggs with corpsenm set to NON_PM will never hatch.
730 if (obj->otyp != EGG) return;
731 if (obj->corpsenm != NON_PM && !dead_species(obj->corpsenm, TRUE))
732 attach_egg_hatch_timeout(obj);
735 /* try to revive all corpses and eggs carried by `mon' */
740 struct obj *otmp, *otmp2;
742 char owner[BUFSZ], corpse[BUFSZ];
744 int once = 0, res = 0;
746 youseeit = (mon == &youmonst) ? TRUE : canseemon(mon);
747 otmp2 = (mon == &youmonst) ? invent : mon->minvent;
749 while ((otmp = otmp2) != 0) {
751 if (otmp->otyp == EGG)
753 if (otmp->otyp != CORPSE) continue;
754 /* save the name; the object is liable to go away */
755 if (youseeit) Strcpy(corpse, corpse_xname(otmp, TRUE));
757 /* for a merged group, only one is revived; should this be fixed? */
758 if ((mtmp2 = revive(otmp)) != 0) {
761 if (!once++) Strcpy(owner,
762 (mon == &youmonst) ? "Your" :
763 s_suffix(Monnam(mon)));
764 pline("%s %s suddenly comes alive!", owner, corpse);
765 } else if (canseemon(mtmp2))
766 pline("%s suddenly appears!", Amonnam(mtmp2));
774 static const char charged_objs[] = { WAND_CLASS, WEAPON_CLASS, ARMOR_CLASS, 0 };
778 register struct obj *obj;
781 struct monst *shkp = (struct monst *)0;
783 if (obj->no_charge) return;
785 switch (obj->where) {
788 shkp = shop_keeper(*u.ushops);
790 Norep("You cancel an unpaid object, you pay for it!");
791 bill_dummy_object(obj);
795 objroom = *in_rooms(obj->ox, obj->oy, SHOPBASE);
796 shkp = shop_keeper(objroom);
797 if (!shkp || !inhishop(shkp)) return;
798 if (costly_spot(u.ux, u.uy) && objroom == *u.ushops) {
799 Norep("You cancel it, you pay for it!");
800 bill_dummy_object(obj);
802 (void) stolen_value(obj, obj->ox, obj->oy, FALSE, FALSE);
807 /* cancel obj, possibly carried by you or a monster */
810 register struct obj *obj;
812 boolean u_ring = (obj == uleft) || (obj == uright);
813 register boolean holy = (obj->otyp == POT_WATER && obj->blessed);
816 case RIN_GAIN_STRENGTH:
817 if ((obj->owornmask & W_RING) && u_ring) {
818 ABON(A_STR) -= obj->spe;
822 case RIN_GAIN_CONSTITUTION:
823 if ((obj->owornmask & W_RING) && u_ring) {
824 ABON(A_CON) -= obj->spe;
829 if ((obj->owornmask & W_RING) && u_ring) {
830 ABON(A_CHA) -= obj->spe;
834 case RIN_INCREASE_ACCURACY:
835 if ((obj->owornmask & W_RING) && u_ring)
836 u.uhitinc -= obj->spe;
838 case RIN_INCREASE_DAMAGE:
839 if ((obj->owornmask & W_RING) && u_ring)
840 u.udaminc -= obj->spe;
842 case GAUNTLETS_OF_DEXTERITY:
843 if ((obj->owornmask & W_ARMG) && (obj == uarmg)) {
844 ABON(A_DEX) -= obj->spe;
848 case HELM_OF_BRILLIANCE:
849 if ((obj->owornmask & W_ARMH) && (obj == uarmh)) {
850 ABON(A_INT) -= obj->spe;
851 ABON(A_WIS) -= obj->spe;
855 /* case RIN_PROTECTION: not needed */
857 if (objects[obj->otyp].oc_magic
858 || (obj->spe && (obj->oclass == ARMOR_CLASS ||
859 obj->oclass == WEAPON_CLASS || is_weptool(obj)))
860 || obj->otyp == POT_ACID || obj->otyp == POT_SICKNESS) {
861 if (obj->spe != ((obj->oclass == WAND_CLASS) ? -1 : 0) &&
862 obj->otyp != WAN_CANCELLATION &&
863 /* can't cancel cancellation */
864 obj->otyp != MAGIC_LAMP &&
865 obj->otyp != CANDELABRUM_OF_INVOCATION) {
867 obj->spe = (obj->oclass == WAND_CLASS) ? -1 : 0;
869 switch (obj->oclass) {
872 obj->otyp = SCR_BLANK_PAPER;
876 if (obj->otyp != SPE_CANCELLATION &&
877 obj->otyp != SPE_BOOK_OF_THE_DEAD) {
879 obj->otyp = SPE_BLANK_PAPER;
884 if (obj->otyp == POT_SICKNESS ||
885 obj->otyp == POT_SEE_INVISIBLE) {
886 /* sickness is "biologically contaminated" fruit juice; cancel it
887 * and it just becomes fruit juice... whereas see invisible
888 * tastes like "enchanted" fruit juice, it similarly cancels.
890 obj->otyp = POT_FRUIT_JUICE;
892 obj->otyp = POT_WATER;
893 obj->odiluted = 0; /* same as any other water */
898 if (holy) costly_cancel(obj);
901 #ifdef INVISIBLE_OBJECTS
902 if (obj->oinvis) obj->oinvis = 0;
907 /* Remove a positive enchantment or charge from obj,
908 * possibly carried by you or a monster
912 register struct obj *obj;
916 /* Is this a charged/enchanted object? */
917 if (!obj || (!objects[obj->otyp].oc_charged &&
918 obj->oclass != WEAPON_CLASS &&
919 obj->oclass != ARMOR_CLASS && !is_weptool(obj)) ||
922 if (obj_resists(obj, 10, 90))
925 /* Charge for the cost of the object */
926 costly_cancel(obj); /* The term "cancel" is okay for now */
928 /* Drain the object and any implied effects */
930 u_ring = (obj == uleft) || (obj == uright);
932 case RIN_GAIN_STRENGTH:
933 if ((obj->owornmask & W_RING) && u_ring) {
938 case RIN_GAIN_CONSTITUTION:
939 if ((obj->owornmask & W_RING) && u_ring) {
945 if ((obj->owornmask & W_RING) && u_ring) {
950 case RIN_INCREASE_ACCURACY:
951 if ((obj->owornmask & W_RING) && u_ring)
954 case RIN_INCREASE_DAMAGE:
955 if ((obj->owornmask & W_RING) && u_ring)
958 case HELM_OF_BRILLIANCE:
959 if ((obj->owornmask & W_ARMH) && (obj == uarmh)) {
965 case GAUNTLETS_OF_DEXTERITY:
966 if ((obj->owornmask & W_ARMG) && (obj == uarmg)) {
975 if (carried(obj)) update_inventory();
983 obj_resists(obj, ochance, achance)
985 int ochance, achance; /* percent chance for ordinary objects, artifacts */
987 if (obj->otyp == AMULET_OF_YENDOR ||
988 obj->otyp == SPE_BOOK_OF_THE_DEAD ||
989 obj->otyp == CANDELABRUM_OF_INVOCATION ||
990 obj->otyp == BELL_OF_OPENING ||
991 (obj->otyp == CORPSE && is_rider(&mons[obj->corpsenm]))) {
994 int chance = rn2(100);
996 return((boolean)(chance < (obj->oartifact ? achance : ochance)));
1006 if (obj->oclass == WAND_CLASS)
1007 zap_odds = 3; /* half-life = 2 zaps */
1008 else if (obj->cursed)
1009 zap_odds = 3; /* half-life = 2 zaps */
1010 else if (obj->blessed)
1011 zap_odds = 12; /* half-life = 8 zaps */
1013 zap_odds = 8; /* half-life = 6 zaps */
1015 /* adjust for "large" quantities of identical things */
1016 if(obj->quan > 4L) zap_odds /= 2;
1018 return((boolean)(! rn2(zap_odds)));
1023 /* Use up at least minwt number of things made of material mat.
1024 * There's also a chance that other stuff will be used up. Finally,
1025 * there's a random factor here to keep from always using the stuff
1026 * at the top of the pile.
1029 polyuse(objhdr, mat, minwt)
1033 register struct obj *otmp, *otmp2;
1035 for(otmp = objhdr; minwt > 0 && otmp; otmp = otmp2) {
1036 otmp2 = otmp->nexthere;
1037 if (otmp == uball || otmp == uchain) continue;
1038 if (obj_resists(otmp, 0, 0)) continue; /* preserve unique objects */
1040 if (otmp->otyp == SCR_MAIL) continue;
1043 if (((int) objects[otmp->otyp].oc_material == mat) ==
1044 (rn2(minwt + 1) != 0)) {
1045 /* appropriately add damage to bill */
1046 if (costly_spot(otmp->ox, otmp->oy)) {
1048 addtobill(otmp, FALSE, FALSE, FALSE);
1050 (void)stolen_value(otmp,
1051 otmp->ox, otmp->oy, FALSE, FALSE);
1053 if (otmp->quan < LARGEST_INT)
1054 minwt -= (int)otmp->quan;
1063 * Polymorph some of the stuff in this pile into a monster, preferably
1064 * a golem of the kind okind.
1067 create_polymon(obj, okind)
1071 struct permonst *mdat = (struct permonst *)0;
1073 const char *material;
1076 /* no golems if you zap only one object -- not enough stuff */
1077 if(!obj || (!obj->nexthere && obj->quan == 1L)) return;
1079 /* some of these choices are arbitrary */
1084 pm_index = PM_IRON_GOLEM;
1085 material = "metal ";
1092 pm_index = rn2(2) ? PM_STONE_GOLEM : PM_CLAY_GOLEM;
1093 material = "lithic ";
1097 /* there is no flesh type, but all food is type 0, so we use it */
1098 pm_index = PM_FLESH_GOLEM;
1099 material = "organic ";
1102 pm_index = PM_WOOD_GOLEM;
1106 pm_index = PM_LEATHER_GOLEM;
1107 material = "leather ";
1110 pm_index = PM_ROPE_GOLEM;
1111 material = "cloth ";
1114 pm_index = PM_SKELETON; /* nearest thing to "bone golem" */
1118 pm_index = PM_GOLD_GOLEM;
1122 pm_index = PM_GLASS_GOLEM;
1123 material = "glassy ";
1126 pm_index = PM_PAPER_GOLEM;
1127 material = "paper ";
1130 /* if all else fails... */
1131 pm_index = PM_STRAW_GOLEM;
1136 if (!(mvitals[pm_index].mvflags & G_GENOD))
1137 mdat = &mons[pm_index];
1139 mtmp = makemon(mdat, obj->ox, obj->oy, NO_MM_FLAGS);
1140 polyuse(obj, okind, (int)mons[pm_index].cwt);
1142 if(mtmp && cansee(mtmp->mx, mtmp->my)) {
1143 pline("Some %sobjects meld, and %s arises from the pile!",
1144 material, a_monnam(mtmp));
1148 /* Assumes obj is on the floor. */
1156 if (obj->otyp == SCR_MAIL) return;
1160 if(poly_zapped < 0) {
1161 /* some may metamorphosize */
1162 for (i = obj->quan; i; i--)
1163 if (! rn2(Luck + 45)) {
1164 poly_zapped = objects[obj->otyp].oc_material;
1169 /* if quan > 1 then some will survive intact */
1170 if (obj->quan > 1L) {
1171 if (obj->quan > LARGEST_INT)
1172 obj = splitobj(obj, (long)rnd(30000));
1174 obj = splitobj(obj, (long)rnd((int)obj->quan - 1));
1177 /* appropriately add damage to bill */
1178 if (costly_spot(obj->ox, obj->oy)) {
1180 addtobill(obj, FALSE, FALSE, FALSE);
1182 (void)stolen_value(obj,
1183 obj->ox, obj->oy, FALSE, FALSE);
1186 /* zap the object */
1191 * Polymorph the object to the given object ID. If the ID is STRANGE_OBJECT
1192 * then pick random object from the source's class (this is the standard
1193 * "polymorph" case). If ID is set to a specific object, inhibit fusing
1194 * n objects into 1. This could have been added as a flag, but currently
1195 * it is tied to not being the standard polymorph case. The new polymorphed
1196 * object replaces obj in its link chains. Return value is a pointer to
1199 * This should be safe to call for an object anywhere.
1208 boolean can_merge = (id == STRANGE_OBJECT);
1209 int obj_location = obj->where;
1211 if (obj->otyp == BOULDER && In_sokoban(&u.uz))
1212 change_luck(-1); /* Sokoban guilt */
1213 if (id == STRANGE_OBJECT) { /* preserve symbol */
1215 /* Try up to 3 times to make the magic-or-not status of
1216 the new item be the same as it was for the old one. */
1217 otmp = (struct obj *)0;
1219 if (otmp) delobj(otmp);
1220 otmp = mkobj(obj->oclass, FALSE);
1221 } while (--try_limit > 0 &&
1222 objects[obj->otyp].oc_magic != objects[otmp->otyp].oc_magic);
1224 /* literally replace obj with this new thing */
1225 otmp = mksobj(id, FALSE, FALSE);
1226 /* Actually more things use corpsenm but they polymorph differently */
1227 #define USES_CORPSENM(typ) ((typ)==CORPSE || (typ)==STATUE || (typ)==FIGURINE)
1228 if (USES_CORPSENM(obj->otyp) && USES_CORPSENM(id))
1229 otmp->corpsenm = obj->corpsenm;
1230 #undef USES_CORPSENM
1233 /* preserve quantity */
1234 otmp->quan = obj->quan;
1235 /* preserve the shopkeepers (lack of) interest */
1236 otmp->no_charge = obj->no_charge;
1237 /* preserve inventory letter if in inventory */
1238 if (obj_location == OBJ_INVENT)
1239 otmp->invlet = obj->invlet;
1241 /* You can't send yourself 100 mail messages and then
1242 * polymorph them into useful scrolls
1244 if (obj->otyp == SCR_MAIL) {
1245 otmp->otyp = SCR_MAIL;
1250 /* avoid abusing eggs laid by you */
1251 if (obj->otyp == EGG && obj->spe) {
1252 int mnum, tryct = 100;
1254 /* first, turn into a generic egg */
1255 if (otmp->otyp == EGG)
1259 otmp->owt = weight(otmp);
1261 otmp->corpsenm = NON_PM;
1264 /* now change it into something layed by the hero */
1266 mnum = can_be_hatched(random_monster());
1267 if (mnum != NON_PM && !dead_species(mnum, TRUE)) {
1268 otmp->spe = 1; /* layed by hero */
1269 otmp->corpsenm = mnum;
1270 attach_egg_hatch_timeout(otmp);
1276 /* keep special fields (including charges on wands) */
1277 if (index(charged_objs, otmp->oclass)) otmp->spe = obj->spe;
1278 otmp->recharged = obj->recharged;
1280 otmp->cursed = obj->cursed;
1281 otmp->blessed = obj->blessed;
1282 otmp->oeroded = obj->oeroded;
1283 otmp->oeroded2 = obj->oeroded2;
1284 if (!is_flammable(otmp) && !is_rustprone(otmp)) otmp->oeroded = 0;
1285 if (!is_corrodeable(otmp) && !is_rottable(otmp)) otmp->oeroded2 = 0;
1286 if (is_damageable(otmp))
1287 otmp->oerodeproof = obj->oerodeproof;
1289 /* Keep chest/box traps and poisoned ammo if we may */
1290 if (obj->otrapped && Is_box(otmp)) otmp->otrapped = TRUE;
1292 if (obj->opoisoned && is_poisonable(otmp))
1293 otmp->opoisoned = TRUE;
1295 if (id == STRANGE_OBJECT && obj->otyp == CORPSE) {
1296 /* turn crocodile corpses into shoes */
1297 if (obj->corpsenm == PM_CROCODILE) {
1298 otmp->otyp = LOW_BOOTS;
1299 otmp->oclass = ARMOR_CLASS;
1302 otmp->oerodeproof = TRUE;
1304 otmp->cursed = FALSE;
1308 /* no box contents --KAA */
1309 if (Has_contents(otmp)) delete_contents(otmp);
1311 /* 'n' merged objects may be fused into 1 object */
1312 if (otmp->quan > 1L && (!objects[otmp->otyp].oc_merge ||
1313 (can_merge && otmp->quan > (long)rn2(1000))))
1316 switch (otmp->oclass) {
1319 if (otmp->otyp == MAGIC_LAMP) {
1320 otmp->otyp = OIL_LAMP;
1321 otmp->age = 1500L; /* "best" oil lamp possible */
1322 } else if (otmp->otyp == MAGIC_MARKER) {
1323 otmp->recharged = 1; /* degraded quality */
1325 /* don't care about the recharge count of other tools */
1329 while (otmp->otyp == WAN_WISHING || otmp->otyp == WAN_POLYMORPH)
1330 otmp->otyp = rnd_class(WAN_LIGHT, WAN_LIGHTNING);
1331 /* altering the object tends to degrade its quality
1332 (analogous to spellbook `read count' handling) */
1333 if ((int)otmp->recharged < rn2(7)) /* recharge_limit */
1338 while (otmp->otyp == POT_POLYMORPH)
1339 otmp->otyp = rnd_class(POT_GAIN_ABILITY, POT_WATER);
1343 while (otmp->otyp == SPE_POLYMORPH)
1344 otmp->otyp = rnd_class(SPE_DIG, SPE_BLANK_PAPER);
1345 /* reduce spellbook abuse */
1346 otmp->spestudied = obj->spestudied + 1;
1350 if (otmp->quan > (long) rnd(4) &&
1351 objects[obj->otyp].oc_material == MINERAL &&
1352 objects[otmp->otyp].oc_material != MINERAL) {
1353 otmp->otyp = ROCK; /* transmutation backfired */
1354 otmp->quan /= 2L; /* some material has been lost */
1359 /* update the weight */
1360 otmp->owt = weight(otmp);
1362 /* for now, take off worn items being polymorphed */
1363 if (obj_location == OBJ_INVENT) {
1364 if (id == STRANGE_OBJECT)
1365 remove_worn_item(obj, TRUE);
1367 /* This is called only for stone to flesh. It's a lot simpler
1368 * than it otherwise might be. We don't need to check for
1369 * special effects when putting them on (no meat objects have
1370 * any) and only three worn masks are possible.
1372 otmp->owornmask = obj->owornmask;
1373 remove_worn_item(obj, TRUE);
1374 setworn(otmp, otmp->owornmask);
1375 if (otmp->owornmask & LEFT_RING)
1377 if (otmp->owornmask & RIGHT_RING)
1379 if (otmp->owornmask & W_WEP)
1381 if (otmp->owornmask & W_SWAPWEP)
1383 if (otmp->owornmask & W_QUIVER)
1389 /* preserve the mask in case being used by something else */
1390 otmp->owornmask = obj->owornmask;
1393 if (obj_location == OBJ_FLOOR && obj->otyp == BOULDER &&
1394 otmp->otyp != BOULDER)
1395 unblock_point(obj->ox, obj->oy);
1397 /* ** we are now done adjusting the object ** */
1400 /* swap otmp for obj */
1401 replace_object(obj, otmp);
1402 if (obj_location == OBJ_INVENT) {
1404 * We may need to do extra adjustments for the hero if we're
1405 * messing with the hero's inventory. The following calls are
1406 * equivalent to calling freeinv on obj and addinv on otmp,
1407 * while doing an in-place swap of the actual objects.
1414 if ((!carried(otmp) || obj->unpaid) &&
1415 get_obj_location(otmp, &ox, &oy, BURIED_TOO|CONTAINED_TOO) &&
1416 costly_spot(ox, oy)) {
1417 register struct monst *shkp =
1418 shop_keeper(*in_rooms(ox, oy, SHOPBASE));
1420 if ((!obj->no_charge ||
1421 (Has_contents(obj) &&
1422 (contained_cost(obj, shkp, 0L, FALSE, FALSE) != 0L)))
1423 && inhishop(shkp)) {
1424 if(shkp->mpeaceful) {
1425 if(*u.ushops && *in_rooms(u.ux, u.uy, 0) ==
1426 *in_rooms(shkp->mx, shkp->my, 0) &&
1427 !costly_spot(u.ux, u.uy))
1428 make_angry_shk(shkp, ox, oy);
1430 pline("%s gets angry!", Monnam(shkp));
1433 } else Norep("%s is furious!", Monnam(shkp));
1441 * Object obj was hit by the effect of the wand/spell otmp. Return
1442 * non-zero if the wand/spell had any effect.
1446 struct obj *obj, *otmp;
1448 int res = 1; /* affected object by default */
1449 xchar refresh_x, refresh_y;
1452 /* The bypass bit is currently only used as follows:
1454 * POLYMORPH - When a monster being polymorphed drops something
1455 * from its inventory as a result of the change.
1456 * If the items fall to the floor, they are not
1457 * subject to direct subsequent polymorphing
1458 * themselves on that same zap. This makes it
1459 * consistent with items that remain in the
1460 * monster's inventory. They are not polymorphed
1462 * UNDEAD_TURNING - When an undead creature gets killed via
1463 * undead turning, prevent its corpse from being
1464 * immediately revived by the same effect.
1466 * The bypass bit on all objects is reset each turn, whenever
1467 * flags.bypasses is set.
1469 * We check the obj->bypass bit above AND flags.bypasses
1470 * as a safeguard against any stray occurrence left in an obj
1471 * struct someplace, although that should never happen.
1477 pline("%s for a moment.", Tobjnam(obj, "pulsate"));
1484 * Some parts of this function expect the object to be on the floor
1485 * obj->{ox,oy} to be valid. The exception to this (so far) is
1486 * for the STONE_TO_FLESH spell.
1488 if (!(obj->where == OBJ_FLOOR || otmp->otyp == SPE_STONE_TO_FLESH))
1489 impossible("bhito: obj is not floor or Stone To Flesh spell");
1493 } else if (obj == uchain) {
1494 if (otmp->otyp == WAN_OPENING || otmp->otyp == SPE_KNOCK) {
1496 makeknown(otmp->otyp);
1500 switch(otmp->otyp) {
1503 if (obj->otyp == WAN_POLYMORPH ||
1504 obj->otyp == SPE_POLYMORPH ||
1505 obj->otyp == POT_POLYMORPH ||
1506 obj_resists(obj, 5, 95)) {
1511 u.uconduct.polypiles++;
1512 /* any saved lock context will be dangerously obsolete */
1513 if (Is_box(obj)) (void) boxlock(obj, otmp);
1515 if (obj_shudders(obj)) {
1516 if (cansee(obj->ox, obj->oy))
1517 makeknown(otmp->otyp);
1521 obj = poly_obj(obj, STRANGE_OBJECT);
1522 newsym(obj->ox,obj->oy);
1526 /* target object has now been "seen (up close)" */
1528 if (Is_container(obj) || obj->otyp == STATUE) {
1530 pline("%s empty.", Tobjnam(obj, "are"));
1533 /* view contents (not recursively) */
1534 for (o = obj->cobj; o; o = o->nobj)
1535 o->dknown = 1; /* "seen", even if blind */
1536 (void) display_cinventory(obj);
1540 if (res) makeknown(WAN_PROBING);
1543 case SPE_FORCE_BOLT:
1544 if (obj->otyp == BOULDER)
1546 else if (obj->otyp == STATUE)
1547 (void) break_statue(obj);
1549 if (!flags.mon_moving)
1550 (void)hero_breaks(obj, obj->ox, obj->oy, FALSE);
1552 (void)breaks(obj, obj->ox, obj->oy);
1555 /* BUG[?]: shouldn't this depend upon you seeing it happen? */
1556 makeknown(otmp->otyp);
1558 case WAN_CANCELLATION:
1559 case SPE_CANCELLATION:
1562 newsym(obj->ox,obj->oy); /* might change color */
1565 case SPE_DRAIN_LIFE:
1566 (void) drain_item(obj);
1568 case WAN_TELEPORTATION:
1569 case SPE_TELEPORT_AWAY:
1572 case WAN_MAKE_INVISIBLE:
1573 #ifdef INVISIBLE_OBJECTS
1575 newsym(obj->ox,obj->oy); /* make object disappear */
1578 case WAN_UNDEAD_TURNING:
1579 case SPE_TURN_UNDEAD:
1580 if (obj->otyp == EGG)
1583 res = !!revive(obj);
1588 case SPE_WIZARD_LOCK:
1590 res = boxlock(obj, otmp);
1593 if (res /* && otmp->oclass == WAND_CLASS */)
1594 makeknown(otmp->otyp);
1596 case WAN_SLOW_MONSTER: /* no effect on objects */
1597 case SPE_SLOW_MONSTER:
1598 case WAN_SPEED_MONSTER:
1601 case SPE_EXTRA_HEALING:
1604 case SPE_STONE_TO_FLESH:
1605 refresh_x = obj->ox; refresh_y = obj->oy;
1606 if (objects[obj->otyp].oc_material != MINERAL &&
1607 objects[obj->otyp].oc_material != GEMSTONE) {
1611 /* add more if stone objects are added.. */
1612 switch (objects[obj->otyp].oc_class) {
1613 case ROCK_CLASS: /* boulders and statues */
1614 if (obj->otyp == BOULDER) {
1615 obj = poly_obj(obj, HUGE_CHUNK_OF_MEAT);
1617 } else if (obj->otyp == STATUE) {
1620 (void) get_obj_location(obj, &oox, &ooy, 0);
1621 refresh_x = oox; refresh_y = ooy;
1622 if (vegetarian(&mons[obj->corpsenm])) {
1623 /* Don't animate monsters that aren't flesh */
1624 obj = poly_obj(obj, MEATBALL);
1627 if (!animate_statue(obj, oox, ooy,
1628 ANIMATE_SPELL, (int *)0)) {
1630 makecorpse: if (mons[obj->corpsenm].geno &
1631 (G_NOCORPSE|G_UNIQ)) {
1635 /* Unlikely to get here since genociding
1636 * monsters also sets the G_NOCORPSE flag.
1637 * Drop the contents, poly_obj looses them.
1639 while ((item = obj->cobj) != 0) {
1640 obj_extract_self(item);
1641 place_object(item, oox, ooy);
1643 obj = poly_obj(obj, CORPSE);
1646 } else { /* new rock class object... */
1651 case TOOL_CLASS: /* figurine */
1656 if (obj->otyp != FIGURINE) {
1660 if (vegetarian(&mons[obj->corpsenm])) {
1661 /* Don't animate monsters that aren't flesh */
1662 obj = poly_obj(obj, MEATBALL);
1665 (void) get_obj_location(obj, &oox, &ooy, 0);
1666 refresh_x = oox; refresh_y = ooy;
1667 mon = makemon(&mons[obj->corpsenm],
1668 oox, ooy, NO_MM_FLAGS);
1671 if (cansee(mon->mx, mon->my))
1672 pline_The("figurine animates!");
1677 /* maybe add weird things to become? */
1678 case RING_CLASS: /* some of the rings are stone */
1679 obj = poly_obj(obj, MEAT_RING);
1681 case WAND_CLASS: /* marble wand */
1682 obj = poly_obj(obj, MEAT_STICK);
1684 case GEM_CLASS: /* rocks & gems */
1685 obj = poly_obj(obj, MEATBALL);
1687 if (herbivorous(youmonst.data) &&
1688 (!carnivorous(youmonst.data) ||
1689 Role_if(PM_MONK) || !u.uconduct.unvegetarian))
1690 Norep("You smell the odor of meat.");
1692 Norep("You smell a delicious smell.");
1694 case WEAPON_CLASS: /* crysknife */
1700 newsym(refresh_x, refresh_y);
1703 impossible("What an interesting effect (%d)", otmp->otyp);
1709 /* returns nonzero if something was hit */
1711 bhitpile(obj,fhito,tx,ty)
1713 int FDECL((*fhito), (OBJ_P,OBJ_P));
1716 int hitanything = 0;
1717 register struct obj *otmp, *next_obj;
1719 if (obj->otyp == SPE_FORCE_BOLT || obj->otyp == WAN_STRIKING) {
1720 struct trap *t = t_at(tx, ty);
1722 /* We can't settle for the default calling sequence of
1723 bhito(otmp) -> break_statue(otmp) -> activate_statue_trap(ox,oy)
1724 because that last call might end up operating on our `next_obj'
1725 (below), rather than on the current object, if it happens to
1726 encounter a statue which mustn't become animated. */
1727 if (t && t->ttyp == STATUE_TRAP &&
1728 activate_statue_trap(t, tx, ty, TRUE) && obj->otyp == WAN_STRIKING)
1729 makeknown(obj->otyp);
1733 for(otmp = level.objects[tx][ty]; otmp; otmp = next_obj) {
1734 /* Fix for polymorph bug, Tim Wright */
1735 next_obj = otmp->nexthere;
1736 hitanything += (*fhito)(otmp, obj);
1738 if(poly_zapped >= 0)
1739 create_polymon(level.objects[tx][ty], poly_zapped);
1747 * zappable - returns 1 if zap is available, 0 otherwise.
1748 * it removes a charge from the wand if zappable.
1749 * added by GAN 11/03/86
1753 register struct obj *wand;
1755 if(wand->spe < 0 || (wand->spe == 0 && rn2(121)))
1758 You("wrest one last charge from the worn-out wand.");
1764 * zapnodir - zaps a NODIR wand/spell.
1765 * added by GAN 11/03/86
1769 register struct obj *obj;
1771 boolean known = FALSE;
1777 if (!Blind) known = TRUE;
1779 case WAN_SECRET_DOOR_DETECTION:
1780 case SPE_DETECT_UNSEEN:
1781 if(!findit()) return;
1782 if (!Blind) known = TRUE;
1784 case WAN_CREATE_MONSTER:
1785 known = create_critters(rn2(23) ? 1 : rn1(7,2),
1786 (struct permonst *)0);
1790 if(Luck + rn2(5) < 0) {
1791 pline("Unfortunately, nothing happens.");
1796 case WAN_ENLIGHTENMENT:
1798 You_feel("self-knowledgeable...");
1799 display_nhwindow(WIN_MESSAGE, FALSE);
1800 enlightenment(FALSE);
1801 pline_The("feeling subsides.");
1802 exercise(A_WIS, TRUE);
1805 if (known && !objects[obj->otyp].oc_name_known) {
1806 makeknown(obj->otyp);
1807 more_experienced(0,10);
1817 otmp->in_use = TRUE; /* in case losehp() is fatal */
1818 pline("%s suddenly explodes!", The(xname(otmp)));
1819 losehp(d(otmp->spe+2,6), "exploding wand", KILLED_BY_AN);
1823 static NEARDATA const char zap_syms[] = { WAND_CLASS, 0 };
1828 register struct obj *obj;
1831 if(check_capacity((char *)0)) return(0);
1832 obj = getobj(zap_syms, "zap");
1837 /* zappable addition done by GAN 11/03/86 */
1838 if(!zappable(obj)) pline(nothing_happens);
1839 else if(obj->cursed && !rn2(100)) {
1840 backfire(obj); /* the wand blows up in your face! */
1841 exercise(A_STR, FALSE);
1843 } else if(!(objects[obj->otyp].oc_dir == NODIR) && !getdir((char *)0)) {
1845 pline("%s glows and fades.", The(xname(obj)));
1846 /* make him pay for knowing !NODIR */
1847 } else if(!u.dx && !u.dy && !u.dz && !(objects[obj->otyp].oc_dir == NODIR)) {
1848 if ((damage = zapyourself(obj, TRUE)) != 0) {
1850 Sprintf(buf, "zapped %sself with a wand", uhim());
1851 losehp(damage, buf, NO_KILLER_PREFIX);
1855 /* Are we having fun yet?
1856 * weffects -> buzz(obj->otyp) -> zhitm (temple priest) ->
1857 * attack -> hitum -> known_hitum -> ghod_hitsu ->
1858 * buzz(AD_ELEC) -> destroy_item(WAND_CLASS) ->
1859 * useup -> obfree -> dealloc_obj -> free(obj)
1866 if (obj && obj->spe < 0) {
1867 pline("%s to dust.", Tobjnam(obj, "turn"));
1870 update_inventory(); /* maybe used a charge */
1875 zapyourself(obj, ordinary)
1884 makeknown(WAN_STRIKING);
1885 case SPE_FORCE_BOLT:
1887 shieldeff(u.ux, u.uy);
1891 You("bash yourself!");
1894 damage = d(1 + obj->spe,6);
1895 exercise(A_STR, FALSE);
1900 makeknown(WAN_LIGHTNING);
1901 if (!Shock_resistance) {
1902 You("shock yourself!");
1904 exercise(A_CON, FALSE);
1906 shieldeff(u.ux, u.uy);
1907 You("zap yourself, but seem unharmed.");
1908 ugolemeffects(AD_ELEC, d(12,6));
1910 destroy_item(WAND_CLASS, AD_ELEC);
1911 destroy_item(RING_CLASS, AD_ELEC);
1912 if (!resists_blnd(&youmonst)) {
1913 You(are_blinded_by_the_flash);
1914 make_blinded((long)rnd(100),FALSE);
1915 if (!Blind) Your(vision_clears);
1920 You("explode a fireball on top of yourself!");
1921 explode(u.ux, u.uy, 11, d(6,6), WAND_CLASS, EXPL_FIERY);
1924 makeknown(WAN_FIRE);
1926 if (Fire_resistance) {
1927 shieldeff(u.ux, u.uy);
1928 You_feel("rather warm.");
1929 ugolemeffects(AD_FIRE, d(12,6));
1931 pline("You've set yourself afire!");
1935 (void) burnarmor(&youmonst);
1936 destroy_item(SCROLL_CLASS, AD_FIRE);
1937 destroy_item(POTION_CLASS, AD_FIRE);
1938 destroy_item(SPBOOK_CLASS, AD_FIRE);
1942 makeknown(WAN_COLD);
1943 case SPE_CONE_OF_COLD:
1945 if (Cold_resistance) {
1946 shieldeff(u.ux, u.uy);
1947 You_feel("a little chill.");
1948 ugolemeffects(AD_COLD, d(12,6));
1950 You("imitate a popsicle!");
1953 destroy_item(POTION_CLASS, AD_COLD);
1956 case WAN_MAGIC_MISSILE:
1957 makeknown(WAN_MAGIC_MISSILE);
1958 case SPE_MAGIC_MISSILE:
1960 shieldeff(u.ux, u.uy);
1961 pline_The("missiles bounce!");
1964 pline("Idiot! You've shot yourself!");
1970 makeknown(WAN_POLYMORPH);
1976 case WAN_CANCELLATION:
1977 case SPE_CANCELLATION:
1978 (void) cancel_monst(&youmonst, obj, TRUE, FALSE, TRUE);
1981 case SPE_DRAIN_LIFE:
1982 if (!Drain_resistance) {
1983 losexp("life drainage");
1984 makeknown(obj->otyp);
1986 damage = 0; /* No additional damage */
1989 case WAN_MAKE_INVISIBLE: {
1990 /* have to test before changing HInvis but must change
1991 * HInvis before doing newsym().
1993 int msg = !Invis && !Blind && !BInvis;
1995 if (BInvis && uarmc->otyp == MUMMY_WRAPPING) {
1996 /* A mummy wrapping absorbs it and protects you */
1997 You_feel("rather itchy under your %s.", xname(uarmc));
2000 if (ordinary || !rn2(10)) { /* permanent */
2001 HInvis |= FROMOUTSIDE;
2002 } else { /* temporary */
2003 incr_itimeout(&HInvis, d(obj->spe, 250));
2006 makeknown(WAN_MAKE_INVISIBLE);
2008 self_invis_message();
2013 case WAN_SPEED_MONSTER:
2014 if (!(HFast & INTRINSIC)) {
2018 Your("quickness feels more natural.");
2019 makeknown(WAN_SPEED_MONSTER);
2020 exercise(A_DEX, TRUE);
2022 HFast |= FROMOUTSIDE;
2026 makeknown(WAN_SLEEP);
2028 if(Sleep_resistance) {
2029 shieldeff(u.ux, u.uy);
2030 You("don't feel sleepy!");
2032 pline_The("sleep ray hits you!");
2033 fall_asleep(-rnd(50), TRUE);
2037 case WAN_SLOW_MONSTER:
2038 case SPE_SLOW_MONSTER:
2039 if(HFast & (TIMEOUT | INTRINSIC)) {
2041 makeknown(obj->otyp);
2045 case WAN_TELEPORTATION:
2046 case SPE_TELEPORT_AWAY:
2051 case SPE_FINGER_OF_DEATH:
2052 if (nonliving(youmonst.data) || is_demon(youmonst.data)) {
2053 pline((obj->otyp == WAN_DEATH) ?
2054 "The wand shoots an apparently harmless beam at you."
2055 : "You seem no deader than before.");
2058 Sprintf(buf, "shot %sself with a death ray", uhim());
2060 killer_format = NO_KILLER_PREFIX;
2061 You("irradiate yourself with pure energy!");
2063 makeknown(obj->otyp);
2064 /* They might survive with an amulet of life saving */
2067 case WAN_UNDEAD_TURNING:
2068 makeknown(WAN_UNDEAD_TURNING);
2069 case SPE_TURN_UNDEAD:
2070 (void) unturn_dead(&youmonst);
2071 if (is_undead(youmonst.data)) {
2072 You_feel("frightened and %sstunned.",
2073 Stunned ? "even more " : "");
2074 make_stunned(HStun + rnd(30), FALSE);
2076 You("shudder in dread.");
2079 case SPE_EXTRA_HEALING:
2080 healup(d(6, obj->otyp == SPE_EXTRA_HEALING ? 8 : 4),
2081 0, FALSE, (obj->otyp == SPE_EXTRA_HEALING));
2082 You_feel("%sbetter.",
2083 obj->otyp == SPE_EXTRA_HEALING ? "much " : "");
2085 case WAN_LIGHT: /* (broken wand) */
2086 /* assert( !ordinary ); */
2087 damage = d(obj->spe, 25);
2089 case EXPENSIVE_CAMERA:
2092 if (!resists_blnd(&youmonst)) {
2093 You(are_blinded_by_the_flash);
2094 make_blinded((long)damage, FALSE);
2095 makeknown(obj->otyp);
2096 if (!Blind) Your(vision_clears);
2098 damage = 0; /* reset */
2101 if (Punished) makeknown(WAN_OPENING);
2103 if (Punished) Your("chain quivers for a moment.");
2107 case SPE_DETECT_UNSEEN:
2110 case SPE_WIZARD_LOCK:
2113 for (obj = invent; obj; obj = obj->nobj)
2115 /* note: `obj' reused; doesn't point at wand anymore */
2116 makeknown(WAN_PROBING);
2119 case SPE_STONE_TO_FLESH:
2121 struct obj *otemp, *onext;
2124 if (u.umonnum == PM_STONE_GOLEM)
2125 (void) polymon(PM_FLESH_GOLEM);
2126 if (Stoned) fix_petrification(); /* saved! */
2127 /* but at a cost.. */
2128 for (otemp = invent; otemp; otemp = onext) {
2129 onext = otemp->nobj;
2130 (void) bhito(otemp, obj);
2133 * It is possible that we can now merge some inventory.
2134 * Do a higly paranoid merge. Restart from the beginning
2139 for (otemp = invent; !didmerge && otemp; otemp = otemp->nobj)
2140 for (onext = otemp->nobj; onext; onext = onext->nobj)
2141 if (merged(&otemp, &onext)) {
2148 default: impossible("object %d used?",obj->otyp);
2155 /* you've zapped a wand downwards while riding
2156 * Return TRUE if the steed was hit by the wand.
2157 * Return FALSE if the steed was not hit by the wand.
2161 struct obj *obj; /* wand or spell */
2163 int steedhit = FALSE;
2165 switch (obj->otyp) {
2168 * Wands that are allowed to hit the steed
2169 * Carefully test the results of any that are
2170 * moved here from the bottom section.
2173 probe_monster(u.usteed);
2174 makeknown(WAN_PROBING);
2177 case WAN_TELEPORTATION:
2178 case SPE_TELEPORT_AWAY:
2179 /* you go together */
2181 if(Teleport_control || !couldsee(u.ux0, u.uy0) ||
2182 (distu(u.ux0, u.uy0) >= 16))
2183 makeknown(obj->otyp);
2187 /* Default processing via bhitm() for these */
2188 case SPE_CURE_SICKNESS:
2189 case WAN_MAKE_INVISIBLE:
2190 case WAN_CANCELLATION:
2191 case SPE_CANCELLATION:
2195 case SPE_FORCE_BOLT:
2196 case WAN_SLOW_MONSTER:
2197 case SPE_SLOW_MONSTER:
2198 case WAN_SPEED_MONSTER:
2200 case SPE_EXTRA_HEALING:
2201 case SPE_DRAIN_LIFE:
2204 (void) bhitm(u.usteed, obj);
2220 * cancel a monster (possibly the hero). inventory is cancelled only
2221 * if the monster is zapping itself directly, since otherwise the
2222 * effect is too strong. currently non-hero monsters do not zap
2223 * themselves with cancellation.
2226 cancel_monst(mdef, obj, youattack, allow_cancel_kill, self_cancel)
2227 register struct monst *mdef;
2228 register struct obj *obj;
2229 boolean youattack, allow_cancel_kill, self_cancel;
2231 boolean youdefend = (mdef == &youmonst);
2232 static const char writing_vanishes[] =
2233 "Some writing vanishes from %s head!";
2234 static const char your[] = "your"; /* should be extern */
2236 if (youdefend ? (!youattack && Antimagic)
2237 : resist(mdef, obj->oclass, 0, NOTELL))
2238 return FALSE; /* resisted cancellation */
2240 if (self_cancel) { /* 1st cancel inventory */
2243 for (otmp = (youdefend ? invent : mdef->minvent);
2244 otmp; otmp = otmp->nobj)
2247 flags.botl = 1; /* potential AC change */
2252 /* now handle special cases */
2255 if ((u.umonnum == PM_CLAY_GOLEM) && !Blind)
2256 pline(writing_vanishes, your);
2259 Your("amulet grows hot for a moment, then cools.");
2266 if (is_were(mdef->data) && mdef->data->mlet != S_HUMAN)
2269 if (mdef->data == &mons[PM_CLAY_GOLEM]) {
2270 if (canseemon(mdef))
2271 pline(writing_vanishes, s_suffix(mon_nam(mdef)));
2273 if (allow_cancel_kill) {
2277 monkilled(mdef, "", AD_SPEL);
2284 /* you've zapped an immediate type wand up or down */
2287 struct obj *obj; /* wand or spell */
2289 boolean striking = FALSE, disclose = FALSE;
2290 int x, y, xx, yy, ptmp;
2296 /* some wands have special effects other than normal bhitpile */
2297 /* drawbridge might change <u.ux,u.uy> */
2298 x = xx = u.ux; /* <x,y> is zap location */
2299 y = yy = u.uy; /* <xx,yy> is drawbridge (portcullis) position */
2300 ttmp = t_at(x, y); /* trap if there is one */
2302 switch (obj->otyp) {
2306 You("probe towards the %s.", ceiling(x,y));
2308 ptmp += bhitpile(obj, bhito, x, y);
2309 You("probe beneath the %s.", surface(x,y));
2310 ptmp += display_binventory(x, y, TRUE);
2312 if (!ptmp) Your("probe reveals nothing.");
2313 return TRUE; /* we've done our own bhitpile */
2316 /* up or down, but at closed portcullis only */
2317 if (is_db_wall(x,y) && find_drawbridge(&xx, &yy)) {
2318 open_drawbridge(xx, yy);
2320 } else if (u.dz > 0 && (x == xdnstair && y == ydnstair) &&
2321 /* can't use the stairs down to quest level 2 until
2322 leader "unlocks" them; give feedback if you try */
2323 on_level(&u.uz, &qstart_level) && !ok_to_quest()) {
2324 pline_The("stairs seem to ripple momentarily.");
2329 case SPE_FORCE_BOLT:
2333 case SPE_WIZARD_LOCK:
2334 /* down at open bridge or up or down at open portcullis */
2335 if ((levl[x][y].typ == DRAWBRIDGE_DOWN) ? (u.dz > 0) :
2336 (is_drawbridge_wall(x,y) && !is_db_wall(x,y)) &&
2337 find_drawbridge(&xx, &yy)) {
2339 close_drawbridge(xx, yy);
2341 destroy_drawbridge(xx, yy);
2343 } else if (striking && u.dz < 0 && rn2(3) &&
2344 !Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz) &&
2345 !Underwater && !Is_qstart(&u.uz)) {
2346 /* similar to zap_dig() */
2347 pline("A rock is dislodged from the %s and falls on your %s.",
2348 ceiling(x, y), body_part(HEAD));
2349 losehp(rnd((uarmh && is_metallic(uarmh)) ? 2 : 6),
2350 "falling rock", KILLED_BY_AN);
2351 if ((otmp = mksobj_at(ROCK, x, y, FALSE, FALSE)) != 0) {
2352 (void)xname(otmp); /* set dknown, maybe bknown */
2356 } else if (!striking && ttmp && ttmp->ttyp == TRAPDOOR && u.dz > 0) {
2359 pline("A trap door beneath you closes up then vanishes.");
2362 You("see a swirl of %s beneath you.",
2363 is_ice(x,y) ? "frost" : "dust");
2366 You_hear("a twang followed by a thud.");
2369 ttmp = (struct trap *)0;
2373 case SPE_STONE_TO_FLESH:
2374 if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) ||
2375 Underwater || (Is_qstart(&u.uz) && u.dz < 0)) {
2376 pline(nothing_happens);
2377 } else if (u.dz < 0) { /* we should do more... */
2378 pline("Blood drips on your %s.", body_part(FACE));
2379 } else if (u.dz > 0 && !OBJ_AT(u.ux, u.uy)) {
2381 Print this message only if there wasn't an engraving
2382 affected here. If water or ice, act like waterlevel case.
2384 e = engr_at(u.ux, u.uy);
2385 if (!(e && e->engr_type == ENGRAVE)) {
2386 if (is_pool(u.ux, u.uy) || is_ice(u.ux, u.uy))
2387 pline(nothing_happens);
2389 pline("Blood %ss %s your %s.",
2390 is_lava(u.ux, u.uy) ? "boil" : "pool",
2391 Levitation ? "beneath" : "at",
2392 makeplural(body_part(FOOT)));
2401 /* zapping downward */
2402 (void) bhitpile(obj, bhito, x, y);
2404 /* subset of engraving effects; none sets `disclose' */
2405 if ((e = engr_at(x, y)) != 0 && e->engr_type != HEADSTONE) {
2406 switch (obj->otyp) {
2410 make_engr_at(x, y, random_engraving(buf), moves, (xchar)0);
2412 case WAN_CANCELLATION:
2413 case SPE_CANCELLATION:
2414 case WAN_MAKE_INVISIBLE:
2417 case WAN_TELEPORTATION:
2418 case SPE_TELEPORT_AWAY:
2421 case SPE_STONE_TO_FLESH:
2422 if (e->engr_type == ENGRAVE) {
2423 /* only affects things in stone */
2424 pline_The(Hallucination ?
2425 "floor runs like butter!" :
2426 "edges on the floor get smoother.");
2427 wipe_engr_at(x, y, d(2,4));
2431 case SPE_FORCE_BOLT:
2432 wipe_engr_at(x, y, d(2,4));
2446 /* called for various wand and spell effects - M. Stephenson */
2449 register struct obj *obj;
2451 int otyp = obj->otyp;
2452 boolean disclose = FALSE, was_unkn = !objects[otyp].oc_name_known;
2454 exercise(A_WIS, TRUE);
2456 if (u.usteed && (objects[otyp].oc_dir != NODIR) &&
2457 !u.dx && !u.dy && (u.dz > 0) && zap_steed(obj)) {
2461 if (objects[otyp].oc_dir == IMMEDIATE) {
2465 (void) bhitm(u.ustuck, obj);
2466 /* [how about `bhitpile(u.ustuck->minvent)' effect?] */
2468 disclose = zap_updown(obj);
2470 (void) bhit(u.dx,u.dy, rn1(8,6),ZAPPED_WAND, bhitm,bhito, obj);
2472 /* give a clue if obj_zapped */
2474 You_feel("shuddering vibrations.");
2476 } else if (objects[otyp].oc_dir == NODIR) {
2480 /* neither immediate nor directionless */
2482 if (otyp == WAN_DIGGING || otyp == SPE_DIG)
2484 else if (otyp >= SPE_MAGIC_MISSILE && otyp <= SPE_FINGER_OF_DEATH)
2485 buzz(otyp - SPE_MAGIC_MISSILE + 10,
2487 u.ux, u.uy, u.dx, u.dy);
2488 else if (otyp >= WAN_MAGIC_MISSILE && otyp <= WAN_LIGHTNING)
2489 buzz(otyp - WAN_MAGIC_MISSILE,
2490 (otyp == WAN_MAGIC_MISSILE) ? 2 : 6,
2491 u.ux, u.uy, u.dx, u.dy);
2493 impossible("weffects: unexpected spell or wand");
2496 if (disclose && was_unkn) {
2498 more_experienced(0,10);
2506 * Generate the to damage bonus for a spell. Based on the hero's intelligence
2509 spell_damage_bonus()
2511 int tmp, intell = ACURR(A_INT);
2513 /* Punish low intellegence before low level else low intellegence
2514 gets punished only when high level */
2517 else if (u.ulevel < 5)
2519 else if (intell < 14)
2521 else if (intell <= 18)
2523 else /* helm of brilliance */
2530 * Generate the to hit bonus for a spell. Based on the hero's skill in
2531 * spell class and dexterity.
2534 spell_hit_bonus(skill)
2538 int dex = ACURR(A_DEX);
2540 switch (P_SKILL(spell_skilltype(skill))) {
2541 case P_ISRESTRICTED:
2542 case P_UNSKILLED: hit_bon = -4; break;
2543 case P_BASIC: hit_bon = 0; break;
2544 case P_SKILLED: hit_bon = 2; break;
2545 case P_EXPERT: hit_bon = 3; break;
2555 hit_bon -= 0; /* Will change when print stuff below removed */
2557 hit_bon += dex - 14; /* Even increment for dextrous heroes (see weapon.c abon) */
2566 /* force == 0 occurs e.g. with sleep ray */
2567 /* note that large force is usual with wands so that !! would
2568 require information about hand/weapon/wand */
2569 return (const char *)((force < 0) ? "?" : (force <= 4) ? "." : "!");
2574 register const char *str;
2575 register struct monst *mtmp;
2576 register const char *force; /* usually either "." or "!" */
2578 if((!cansee(bhitpos.x,bhitpos.y) && !canspotmon(mtmp) &&
2579 !(u.uswallow && mtmp == u.ustuck))
2581 pline("%s %s it.", The(str), vtense(str, "hit"));
2582 else pline("%s %s %s%s", The(str), vtense(str, "hit"),
2583 mon_nam(mtmp), force);
2588 register const char *str;
2589 register struct monst *mtmp;
2591 pline("%s %s %s.", The(str), vtense(str, "miss"),
2592 ((cansee(bhitpos.x,bhitpos.y) || canspotmon(mtmp))
2594 mon_nam(mtmp) : "it");
2600 * Called for the following distance effects:
2601 * when a weapon is thrown (weapon == THROWN_WEAPON)
2602 * when an object is kicked (KICKED_WEAPON)
2603 * when an IMMEDIATE wand is zapped (ZAPPED_WAND)
2604 * when a light beam is flashed (FLASHED_LIGHT)
2605 * when a mirror is applied (INVIS_BEAM)
2606 * A thrown/kicked object falls down at the end of its range or when a monster
2607 * is hit. The variable 'bhitpos' is set to the final position of the weapon
2608 * thrown/zapped. The ray of a wand may affect (by calling a provided
2609 * function) several objects and monsters on its path. The return value
2610 * is the monster hit (weapon != ZAPPED_WAND), or a null monster pointer.
2612 * Check !u.uswallow before calling bhit().
2613 * This function reveals the absence of a remembered invisible monster in
2614 * necessary cases (throwing or kicking weapons). The presence of a real
2615 * one is revealed for a weapon, but if not a weapon is left up to fhitm().
2618 bhit(ddx,ddy,range,weapon,fhitm,fhito,obj)
2619 register int ddx,ddy,range; /* direction and range */
2620 int weapon; /* see values in hack.h */
2621 int FDECL((*fhitm), (MONST_P, OBJ_P)), /* fns called when mon/obj hit */
2622 FDECL((*fhito), (OBJ_P, OBJ_P));
2623 struct obj *obj; /* object tossed/used */
2627 boolean shopdoor = FALSE, point_blank = TRUE;
2629 if (weapon == KICKED_WEAPON) {
2630 /* object starts one square in front of player */
2631 bhitpos.x = u.ux + ddx;
2632 bhitpos.y = u.uy + ddy;
2639 if (weapon == FLASHED_LIGHT) {
2640 tmp_at(DISP_BEAM, cmap_to_glyph(S_flashbeam));
2641 } else if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM)
2642 tmp_at(DISP_FLASH, obj_to_glyph(obj));
2644 while(range-- > 0) {
2649 x = bhitpos.x; y = bhitpos.y;
2657 if(is_pick(obj) && inside_shop(x, y) &&
2658 (mtmp = shkcatch(obj, x, y))) {
2659 tmp_at(DISP_END, 0);
2663 typ = levl[bhitpos.x][bhitpos.y].typ;
2665 /* iron bars will block anything big enough */
2666 if ((weapon == THROWN_WEAPON || weapon == KICKED_WEAPON) &&
2668 hits_bars(&obj, x - ddx, y - ddy,
2669 point_blank ? 0 : !rn2(5), 1)) {
2670 /* caveat: obj might now be null... */
2676 if (weapon == ZAPPED_WAND && find_drawbridge(&x,&y))
2677 switch (obj->otyp) {
2680 if (is_db_wall(bhitpos.x, bhitpos.y)) {
2681 if (cansee(x,y) || cansee(bhitpos.x,bhitpos.y))
2682 makeknown(obj->otyp);
2683 open_drawbridge(x,y);
2687 case SPE_WIZARD_LOCK:
2688 if ((cansee(x,y) || cansee(bhitpos.x, bhitpos.y))
2689 && levl[x][y].typ == DRAWBRIDGE_DOWN)
2690 makeknown(obj->otyp);
2691 close_drawbridge(x,y);
2694 case SPE_FORCE_BOLT:
2695 if (typ != DRAWBRIDGE_UP)
2696 destroy_drawbridge(x,y);
2697 makeknown(obj->otyp);
2701 if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
2702 notonhead = (bhitpos.x != mtmp->mx ||
2703 bhitpos.y != mtmp->my);
2704 if (weapon != FLASHED_LIGHT) {
2705 if(weapon != ZAPPED_WAND) {
2706 if(weapon != INVIS_BEAM) tmp_at(DISP_END, 0);
2707 if (cansee(bhitpos.x,bhitpos.y) && !canspotmon(mtmp)) {
2708 if (weapon != INVIS_BEAM) {
2709 map_invisible(bhitpos.x, bhitpos.y);
2715 if (weapon != INVIS_BEAM) {
2716 (*fhitm)(mtmp, obj);
2720 /* FLASHED_LIGHT hitting invisible monster
2721 should pass through instead of stop so
2722 we call flash_hits_mon() directly rather
2723 than returning mtmp back to caller. That
2724 allows the flash to keep on going. Note
2725 that we use mtmp->minvis not canspotmon()
2726 because it makes no difference whether
2727 the hero can see the monster or not.*/
2729 obj->ox = u.ux, obj->oy = u.uy;
2730 (void) flash_hits_mon(mtmp, obj);
2732 tmp_at(DISP_END, 0);
2733 return(mtmp); /* caller will call flash_hits_mon */
2737 if (weapon == ZAPPED_WAND && obj->otyp == WAN_PROBING &&
2738 glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph)) {
2739 unmap_object(bhitpos.x, bhitpos.y);
2744 if(bhitpile(obj,fhito,bhitpos.x,bhitpos.y))
2747 if(weapon == KICKED_WEAPON &&
2748 ((obj->oclass == COIN_CLASS &&
2749 OBJ_AT(bhitpos.x, bhitpos.y)) ||
2750 ship_object(obj, bhitpos.x, bhitpos.y,
2751 costly_spot(bhitpos.x, bhitpos.y)))) {
2752 tmp_at(DISP_END, 0);
2753 return (struct monst *)0;
2756 if(weapon == ZAPPED_WAND && (IS_DOOR(typ) || typ == SDOOR)) {
2757 switch (obj->otyp) {
2762 case SPE_WIZARD_LOCK:
2763 case SPE_FORCE_BOLT:
2764 if (doorlock(obj, bhitpos.x, bhitpos.y)) {
2765 if (cansee(bhitpos.x, bhitpos.y) ||
2766 (obj->otyp == WAN_STRIKING))
2767 makeknown(obj->otyp);
2768 if (levl[bhitpos.x][bhitpos.y].doormask == D_BROKEN
2769 && *in_rooms(bhitpos.x, bhitpos.y, SHOPBASE)) {
2771 add_damage(bhitpos.x, bhitpos.y, 400L);
2777 if(!ZAP_POS(typ) || closed_door(bhitpos.x, bhitpos.y)) {
2782 if(weapon != ZAPPED_WAND && weapon != INVIS_BEAM) {
2783 /* 'I' present but no monster: erase */
2784 /* do this before the tmp_at() */
2785 if (glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph)
2787 unmap_object(bhitpos.x, bhitpos.y);
2790 tmp_at(bhitpos.x, bhitpos.y);
2792 /* kicked objects fall in pools */
2793 if((weapon == KICKED_WEAPON) &&
2794 (is_pool(bhitpos.x, bhitpos.y) ||
2795 is_lava(bhitpos.x, bhitpos.y)))
2798 if(IS_SINK(typ) && weapon != FLASHED_LIGHT)
2799 break; /* physical objects fall onto sink */
2802 /* limit range of ball so hero won't make an invalid move */
2803 if (weapon == THROWN_WEAPON && range > 0 &&
2804 obj->otyp == HEAVY_IRON_BALL) {
2807 if ((bobj = sobj_at(BOULDER, x, y)) != 0) {
2809 pline("%s hits %s.",
2810 The(distant_name(obj, xname)), an(xname(bobj)));
2812 } else if (obj == uball) {
2813 if (!test_move(x - ddx, y - ddy, ddx, ddy, TEST_MOVE)) {
2814 /* nb: it didn't hit anything directly */
2816 pline("%s jerks to an abrupt halt.",
2817 The(distant_name(obj, xname))); /* lame */
2819 } else if (In_sokoban(&u.uz) && (t = t_at(x, y)) != 0 &&
2820 (t->ttyp == PIT || t->ttyp == SPIKED_PIT ||
2821 t->ttyp == HOLE || t->ttyp == TRAPDOOR)) {
2822 /* hero falls into the trap, so ball stops */
2828 /* thrown/kicked missile has moved away from its starting spot */
2829 point_blank = FALSE; /* affects passing through iron bars */
2832 if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM) tmp_at(DISP_END, 0);
2835 pay_for_damage("destroy", FALSE);
2837 return (struct monst *)0;
2845 int boom = S_boomleft; /* showsym[] index */
2851 for (i = 0; i < 8; i++) if (xdir[i] == dx && ydir[i] == dy) break;
2852 tmp_at(DISP_FLASH, cmap_to_glyph(boom));
2853 for (ct = 0; ct < 10; ct++) {
2855 boom = (boom == S_boomleft) ? S_boomright : S_boomleft;
2856 tmp_at(DISP_CHANGE, cmap_to_glyph(boom));/* change glyph */
2861 if(MON_AT(bhitpos.x, bhitpos.y)) {
2862 mtmp = m_at(bhitpos.x,bhitpos.y);
2864 tmp_at(DISP_END, 0);
2867 if(!ZAP_POS(levl[bhitpos.x][bhitpos.y].typ) ||
2868 closed_door(bhitpos.x, bhitpos.y)) {
2873 if(bhitpos.x == u.ux && bhitpos.y == u.uy) { /* ct == 9 */
2874 if(Fumbling || rn2(20) >= ACURR(A_DEX)) {
2875 /* we hit ourselves */
2876 (void) thitu(10, rnd(10), (struct obj *)0,
2879 } else { /* we catch it */
2880 tmp_at(DISP_END, 0);
2881 You("skillfully catch the boomerang.");
2885 tmp_at(bhitpos.x, bhitpos.y);
2887 if(ct % 5 != 0) i++;
2889 if(IS_SINK(levl[bhitpos.x][bhitpos.y].typ))
2890 break; /* boomerang falls on sink */
2893 tmp_at(DISP_END, 0); /* do not leave last symbol */
2894 return (struct monst *)0;
2898 zhitm(mon, type, nd, ootmp) /* returns damage to mon */
2899 register struct monst *mon;
2900 register int type, nd;
2901 struct obj **ootmp; /* to return worn armor for caller to disintegrate */
2903 register int tmp = 0;
2904 register int abstype = abs(type) % 10;
2905 boolean sho_shieldeff = FALSE;
2906 boolean spellcaster = is_hero_spell(type); /* maybe get a bonus! */
2908 *ootmp = (struct obj *)0;
2910 case ZT_MAGIC_MISSILE:
2911 if (resists_magm(mon)) {
2912 sho_shieldeff = TRUE;
2917 tmp += spell_damage_bonus();
2918 #ifdef WIZ_PATCH_DEBUG
2920 pline("Damage = %d + %d", tmp-spell_damage_bonus(),
2921 spell_damage_bonus());
2925 if (resists_fire(mon)) {
2926 sho_shieldeff = TRUE;
2930 if (resists_cold(mon)) tmp += 7;
2932 tmp += spell_damage_bonus();
2933 #ifdef WIZ_PATCH_DEBUG
2935 pline("Damage = %d + %d",tmp-spell_damage_bonus(),
2936 spell_damage_bonus());
2938 if (burnarmor(mon)) {
2939 if (!rn2(3)) (void)destroy_mitem(mon, POTION_CLASS, AD_FIRE);
2940 if (!rn2(3)) (void)destroy_mitem(mon, SCROLL_CLASS, AD_FIRE);
2941 if (!rn2(5)) (void)destroy_mitem(mon, SPBOOK_CLASS, AD_FIRE);
2945 if (resists_cold(mon)) {
2946 sho_shieldeff = TRUE;
2950 if (resists_fire(mon)) tmp += d(nd, 3);
2952 tmp += spell_damage_bonus();
2953 #ifdef WIZ_PATCH_DEBUG
2955 pline("Damage = %d + %d", tmp-spell_damage_bonus(),
2956 spell_damage_bonus());
2958 if (!rn2(3)) (void)destroy_mitem(mon, POTION_CLASS, AD_COLD);
2962 (void)sleep_monst(mon, d(nd, 25),
2963 type == ZT_WAND(ZT_SLEEP) ? WAND_CLASS : '\0');
2965 case ZT_DEATH: /* death/disintegration */
2966 if(abs(type) != ZT_BREATH(ZT_DEATH)) { /* death */
2967 if(mon->data == &mons[PM_DEATH]) {
2968 mon->mhpmax += mon->mhpmax/2;
2969 if (mon->mhpmax >= MAGIC_COOKIE)
2970 mon->mhpmax = MAGIC_COOKIE - 1;
2971 mon->mhp = mon->mhpmax;
2975 if (nonliving(mon->data) || is_demon(mon->data) ||
2976 resists_magm(mon)) { /* similar to player */
2977 sho_shieldeff = TRUE;
2980 type = -1; /* so they don't get saving throws */
2984 if (resists_disint(mon)) {
2985 sho_shieldeff = TRUE;
2986 } else if (mon->misc_worn_check & W_ARMS) {
2987 /* destroy shield; victim survives */
2988 *ootmp = which_armor(mon, W_ARMS);
2989 } else if (mon->misc_worn_check & W_ARM) {
2990 /* destroy body armor, also cloak if present */
2991 *ootmp = which_armor(mon, W_ARM);
2992 if ((otmp2 = which_armor(mon, W_ARMC)) != 0)
2993 m_useup(mon, otmp2);
2995 /* no body armor, victim dies; destroy cloak
2996 and shirt now in case target gets life-saved */
2998 if ((otmp2 = which_armor(mon, W_ARMC)) != 0)
2999 m_useup(mon, otmp2);
3001 if ((otmp2 = which_armor(mon, W_ARMU)) != 0)
3002 m_useup(mon, otmp2);
3005 type = -1; /* no saving throw wanted */
3006 break; /* not ordinary damage */
3011 if (resists_elec(mon)) {
3012 sho_shieldeff = TRUE;
3014 /* can still blind the monster */
3018 tmp += spell_damage_bonus();
3019 #ifdef WIZ_PATCH_DEBUG
3021 pline("Damage = %d + %d", tmp-spell_damage_bonus(),
3022 spell_damage_bonus());
3024 if (!resists_blnd(mon) &&
3025 !(type > 0 && u.uswallow && mon == u.ustuck)) {
3026 register unsigned rnd_tmp = rnd(50);
3028 if((mon->mblinded + rnd_tmp) > 127)
3029 mon->mblinded = 127;
3030 else mon->mblinded += rnd_tmp;
3032 if (!rn2(3)) (void)destroy_mitem(mon, WAND_CLASS, AD_ELEC);
3033 /* not actually possible yet */
3034 if (!rn2(3)) (void)destroy_mitem(mon, RING_CLASS, AD_ELEC);
3037 if (resists_poison(mon)) {
3038 sho_shieldeff = TRUE;
3044 if (resists_acid(mon)) {
3045 sho_shieldeff = TRUE;
3049 if (!rn2(6)) erode_obj(MON_WEP(mon), TRUE, TRUE);
3050 if (!rn2(6)) erode_armor(mon, TRUE);
3053 if (sho_shieldeff) shieldeff(mon->mx, mon->my);
3054 if (is_hero_spell(type) && (Role_if(PM_KNIGHT) && u.uhave.questart))
3056 if (tmp > 0 && type >= 0 &&
3057 resist(mon, type < ZT_SPELL(0) ? WAND_CLASS : '\0', 0, NOTELL))
3059 if (tmp < 0) tmp = 0; /* don't allow negative damage */
3060 #ifdef WIZ_PATCH_DEBUG
3061 pline("zapped monster hp = %d (= %d - %d)", mon->mhp-tmp,mon->mhp,tmp);
3068 zhitu(type, nd, fltxt, sx, sy)
3075 switch (abs(type) % 10) {
3076 case ZT_MAGIC_MISSILE:
3079 pline_The("missiles bounce off!");
3082 exercise(A_STR, FALSE);
3086 if (Fire_resistance) {
3088 You("don't feel hot!");
3089 ugolemeffects(AD_FIRE, d(nd, 6));
3094 if (burnarmor(&youmonst)) { /* "body hit" */
3095 if (!rn2(3)) destroy_item(POTION_CLASS, AD_FIRE);
3096 if (!rn2(3)) destroy_item(SCROLL_CLASS, AD_FIRE);
3097 if (!rn2(5)) destroy_item(SPBOOK_CLASS, AD_FIRE);
3101 if (Cold_resistance) {
3103 You("don't feel cold.");
3104 ugolemeffects(AD_COLD, d(nd, 6));
3108 if (!rn2(3)) destroy_item(POTION_CLASS, AD_COLD);
3111 if (Sleep_resistance) {
3112 shieldeff(u.ux, u.uy);
3113 You("don't feel sleepy.");
3115 fall_asleep(-d(nd,25), TRUE); /* sleep ray */
3119 if (abs(type) == ZT_BREATH(ZT_DEATH)) {
3120 if (Disint_resistance) {
3121 You("are not disintegrated.");
3124 /* destroy shield; other possessions are safe */
3125 (void) destroy_arm(uarms);
3128 /* destroy suit; if present, cloak goes too */
3129 if (uarmc) (void) destroy_arm(uarmc);
3130 (void) destroy_arm(uarm);
3133 /* no shield or suit, you're dead; wipe out cloak
3134 and/or shirt in case of life-saving or bones */
3135 if (uarmc) (void) destroy_arm(uarmc);
3137 if (uarmu) (void) destroy_arm(uarmu);
3139 } else if (nonliving(youmonst.data) || is_demon(youmonst.data)) {
3141 You("seem unaffected.");
3143 } else if (Antimagic) {
3145 You("aren't affected.");
3148 killer_format = KILLED_BY_AN;
3150 /* when killed by disintegration breath, don't leave corpse */
3151 u.ugrave_arise = (type == -ZT_BREATH(ZT_DEATH)) ? -3 : NON_PM;
3153 return; /* lifesaved */
3155 if (Shock_resistance) {
3157 You("aren't affected.");
3158 ugolemeffects(AD_ELEC, d(nd, 6));
3161 exercise(A_CON, FALSE);
3163 if (!rn2(3)) destroy_item(WAND_CLASS, AD_ELEC);
3164 if (!rn2(3)) destroy_item(RING_CLASS, AD_ELEC);
3167 poisoned("blast", A_DEX, "poisoned blast", 15);
3170 if (Acid_resistance) {
3173 pline_The("acid burns!");
3175 exercise(A_STR, FALSE);
3177 /* using two weapons at once makes both of them more vulnerable */
3178 if (!rn2(u.twoweap ? 3 : 6)) erode_obj(uwep, TRUE, TRUE);
3179 if (u.twoweap && !rn2(3)) erode_obj(uswapwep, TRUE, TRUE);
3180 if (!rn2(6)) erode_armor(&youmonst, TRUE);
3184 if (Half_spell_damage && dam &&
3185 type < 0 && (type > -20 || type < -29)) /* !Breath */
3186 dam = (dam + 1) / 2;
3187 losehp(dam, fltxt, KILLED_BY_AN);
3195 * burn scrolls and spellbooks on floor at position x,y
3196 * return the number of scrolls and spellbooks burned
3199 burn_floor_paper(x, y, give_feedback, u_caused)
3201 boolean give_feedback; /* caller needs to decide about visibility checks */
3204 struct obj *obj, *obj2;
3205 long i, scrquan, delquan;
3206 char buf1[BUFSZ], buf2[BUFSZ];
3209 for (obj = level.objects[x][y]; obj; obj = obj2) {
3210 obj2 = obj->nexthere;
3211 if (obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS) {
3212 if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL ||
3213 obj_resists(obj, 2, 100))
3215 scrquan = obj->quan; /* number present */
3216 delquan = 0; /* number to destroy */
3217 for (i = scrquan; i > 0; i--)
3218 if (!rn2(3)) delquan++;
3220 /* save name before potential delobj() */
3221 if (give_feedback) {
3223 Strcpy(buf1, (x == u.ux && y == u.uy) ?
3224 xname(obj) : distant_name(obj, xname));
3226 Strcpy(buf2, (x == u.ux && y == u.uy) ?
3227 xname(obj) : distant_name(obj, xname));
3228 obj->quan = scrquan;
3230 /* useupf(), which charges, only if hero caused damage */
3231 if (u_caused) useupf(obj, delquan);
3232 else if (delquan < scrquan) obj->quan -= delquan;
3235 if (give_feedback) {
3237 pline("%ld %s burn.", delquan, buf2);
3239 pline("%s burns.", An(buf1));
3247 /* will zap/spell/breath attack score a hit against armor class `ac'? */
3251 int type; /* either hero cast spell type or 0 */
3253 int chance = rn2(20);
3254 int spell_bonus = type ? spell_hit_bonus(type) : 0;
3256 /* small chance for naked target to avoid being hit */
3257 if (!chance) return rnd(10) < ac+spell_bonus;
3259 /* very high armor protection does not achieve invulnerability */
3262 return (3 - chance) < ac+spell_bonus;
3265 /* type == 0 to 9 : you shooting a wand */
3266 /* type == 10 to 19 : you casting a spell */
3267 /* type == 20 to 29 : you breathing as a monster */
3268 /* type == -10 to -19 : monster casting spell */
3269 /* type == -20 to -29 : monster breathing at you */
3270 /* type == -30 to -39 : monster shooting a wand */
3271 /* called with dx = dy = 0 with vertical bolts */
3273 buzz(type,nd,sx,sy,dx,dy)
3274 register int type, nd;
3275 register xchar sx,sy;
3278 int range, abstype = abs(type) % 10;
3280 register xchar lsx, lsy;
3283 boolean shopdamage = FALSE;
3284 register const char *fltxt;
3288 /* if its a Hero Spell then get its SPE_TYPE */
3289 spell_type = is_hero_spell(type) ? SPE_MAGIC_MISSILE + abstype : 0;
3291 fltxt = flash_types[(type <= -30) ? abstype : abs(type)];
3295 if(type < 0) return;
3296 tmp = zhitm(u.ustuck, type, nd, &otmp);
3297 if(!u.ustuck) u.uswallow = 0;
3298 else pline("%s rips into %s%s",
3299 The(fltxt), mon_nam(u.ustuck), exclam(tmp));
3300 /* Using disintegration from the inside only makes a hole... */
3301 if (tmp == MAGIC_COOKIE)
3303 if (u.ustuck->mhp < 1)
3307 if(type < 0) newsym(u.ux,u.uy);
3309 if(dx == 0 && dy == 0) range = 1;
3310 save_bhitpos = bhitpos;
3312 tmp_at(DISP_BEAM, zapdir_to_glyph(dx, dy, abstype));
3313 while(range-- > 0) {
3316 if(isok(sx,sy) && (lev = &levl[sx][sy])->typ) {
3319 /* reveal/unreveal invisible monsters before tmp_at() */
3320 if (mon && !canspotmon(mon))
3321 map_invisible(sx, sy);
3322 else if (!mon && glyph_is_invisible(levl[sx][sy].glyph)) {
3323 unmap_object(sx, sy);
3326 if(ZAP_POS(lev->typ) || cansee(lsx,lsy))
3328 delay_output(); /* wait a little */
3333 /* hit() and miss() need bhitpos to match the target */
3334 bhitpos.x = sx, bhitpos.y = sy;
3335 /* Fireballs only damage when they explode */
3336 if (type != ZT_SPELL(ZT_FIRE))
3337 range += zap_over_floor(sx, sy, type, &shopdamage);
3340 if (type == ZT_SPELL(ZT_FIRE)) break;
3341 if (type >= 0) mon->mstrategy &= ~STRAT_WAITMASK;
3345 if (zap_hit(find_mac(mon), spell_type)) {
3346 if (mon_reflects(mon, (char *)0)) {
3347 if(cansee(mon->mx,mon->my)) {
3348 hit(fltxt, mon, exclam(0));
3349 shieldeff(mon->mx, mon->my);
3350 (void) mon_reflects(mon, "But it reflects from %s %s!");
3355 boolean mon_could_move = mon->mcanmove;
3356 int tmp = zhitm(mon, type, nd, &otmp);
3358 if (is_rider(mon->data) && abs(type) == ZT_BREATH(ZT_DEATH)) {
3359 if (canseemon(mon)) {
3360 hit(fltxt, mon, ".");
3361 pline("%s disintegrates.", Monnam(mon));
3362 pline("%s body reintegrates before your %s!",
3363 s_suffix(Monnam(mon)),
3364 (eyecount(youmonst.data) == 1) ?
3365 body_part(EYE) : makeplural(body_part(EYE)));
3366 pline("%s resurrects!", Monnam(mon));
3368 mon->mhp = mon->mhpmax;
3369 break; /* Out of while loop */
3371 if (mon->data == &mons[PM_DEATH] && abstype == ZT_DEATH) {
3372 if (canseemon(mon)) {
3373 hit(fltxt, mon, ".");
3374 pline("%s absorbs the deadly %s!", Monnam(mon),
3375 type == ZT_BREATH(ZT_DEATH) ?
3377 pline("It seems even stronger than before.");
3379 break; /* Out of while loop */
3382 if (tmp == MAGIC_COOKIE) { /* disintegration */
3383 struct obj *otmp2, *m_amulet = mlifesaver(mon);
3385 if (canseemon(mon)) {
3387 pline("%s is disintegrated!", Monnam(mon));
3389 hit(fltxt, mon, "!");
3395 /* note: worn amulet of life saving must be preserved in order to operate */
3396 #define oresist_disintegration(obj) \
3397 (objects[obj->otyp].oc_oprop == DISINT_RES || \
3398 obj_resists(obj, 5, 50) || is_quest_artifact(obj) || \
3401 for (otmp = mon->minvent; otmp; otmp = otmp2) {
3403 if (!oresist_disintegration(otmp)) {
3404 obj_extract_self(otmp);
3405 obfree(otmp, (struct obj *)0);
3410 monkilled(mon, (char *)0, -AD_RBRE);
3413 } else if(mon->mhp < 1) {
3415 monkilled(mon, fltxt, AD_RBRE);
3420 /* normal non-fatal hit */
3421 hit(fltxt, mon, exclam(tmp));
3423 /* some armor was destroyed; no damage done */
3425 pline("%s %s is disintegrated!",
3426 s_suffix(Monnam(mon)),
3427 distant_name(otmp, xname));
3430 if (mon_could_move && !mon->mcanmove) /* ZT_SLEEP */
3438 } else if (sx == u.ux && sy == u.uy && range >= 0) {
3441 if (u.usteed && !rn2(3) && !mon_reflects(u.usteed, (char *)0)) {
3446 if (zap_hit((int) u.uac, 0)) {
3448 pline("%s hits you!", The(fltxt));
3451 (void) ureflects("But %s reflects from your %s!", "it");
3453 pline("For some reason you are not affected.");
3458 zhitu(type, nd, fltxt, sx, sy);
3461 pline("%s whizzes by you!", The(fltxt));
3463 if (abstype == ZT_LIGHTNING && !resists_blnd(&youmonst)) {
3464 You(are_blinded_by_the_flash);
3465 make_blinded((long)d(nd,50),FALSE);
3466 if (!Blind) Your(vision_clears);
3472 if(!ZAP_POS(lev->typ) || (closed_door(sx, sy) && (range >= 0))) {
3477 if (type == ZT_SPELL(ZT_FIRE)) {
3480 break; /* fireballs explode before the wall */
3484 if(range && isok(lsx, lsy) && cansee(lsx,lsy))
3485 pline("%s bounces!", The(fltxt));
3486 if(!dx || !dy || !rn2(20)) {
3490 if(isok(sx,lsy) && ZAP_POS(rmn = levl[sx][lsy].typ) &&
3491 !closed_door(sx,lsy) &&
3492 (IS_ROOM(rmn) || (isok(sx+dx,lsy) &&
3493 ZAP_POS(levl[sx+dx][lsy].typ))))
3495 if(isok(lsx,sy) && ZAP_POS(rmn = levl[lsx][sy].typ) &&
3496 !closed_door(lsx,sy) &&
3497 (IS_ROOM(rmn) || (isok(lsx,sy+dy) &&
3498 ZAP_POS(levl[lsx][sy+dy].typ))))
3499 if(!bounce || rn2(2))
3503 case 0: dx = -dx; /* fall into... */
3504 case 1: dy = -dy; break;
3505 case 2: dx = -dx; break;
3507 tmp_at(DISP_CHANGE, zapdir_to_glyph(dx,dy,abstype));
3512 if (type == ZT_SPELL(ZT_FIRE))
3513 explode(sx, sy, type, d(12,6), 0, EXPL_FIERY);
3515 pay_for_damage(abstype == ZT_FIRE ? "burn away" :
3516 abstype == ZT_COLD ? "shatter" :
3517 abstype == ZT_DEATH ? "disintegrate" : "destroy", FALSE);
3518 bhitpos = save_bhitpos;
3527 struct rm *lev = &levl[x][y];
3530 if (lev->typ == DRAWBRIDGE_UP)
3531 lev->drawbridgemask &= ~DB_ICE; /* revert to DB_MOAT */
3532 else { /* lev->typ == ICE */
3534 if (lev->icedpool == ICED_POOL) lev->typ = POOL;
3535 else lev->typ = MOAT;
3537 lev->typ = (lev->icedpool == ICED_POOL ? POOL : MOAT);
3541 obj_ice_effects(x, y, FALSE);
3543 if (Underwater) vision_recalc(1);
3545 if (cansee(x,y)) Norep("The ice crackles and melts.");
3546 if ((otmp = sobj_at(BOULDER, x, y)) != 0) {
3547 if (cansee(x,y)) pline("%s settles...", An(xname(otmp)));
3549 obj_extract_self(otmp); /* boulder isn't being pushed */
3550 if (!boulder_hits_pool(otmp, x, y, FALSE))
3551 impossible("melt_ice: no pool?");
3552 /* try again if there's another boulder and pool didn't fill */
3553 } while (is_pool(x,y) && (otmp = sobj_at(BOULDER, x, y)) != 0);
3556 if (x == u.ux && y == u.uy)
3557 spoteffects(TRUE); /* possibly drown, notice objects */
3560 /* Burn floor scrolls, evaporate pools, etc... in a single square. Used
3561 * both for normal bolts of fire, cold, etc... and for fireballs.
3562 * Sets shopdamage to TRUE if a shop door is destroyed, and returns the
3563 * amount by which range is reduced (the latter is just ignored by fireballs)
3566 zap_over_floor(x, y, type, shopdamage)
3569 boolean *shopdamage;
3572 int abstype = abs(type) % 10;
3573 struct rm *lev = &levl[x][y];
3576 if(abstype == ZT_FIRE) {
3577 struct trap *t = t_at(x, y);
3579 if (t && t->ttyp == WEB) {
3580 /* a burning web is too flimsy to notice if you can't see it */
3581 if (cansee(x,y)) Norep("A web bursts into flames!");
3582 (void) delfloortrap(t);
3583 if (cansee(x,y)) newsym(x,y);
3587 } else if(is_pool(x,y)) {
3588 const char *msgtxt = "You hear hissing gas.";
3589 if(lev->typ != POOL) { /* MOAT or DRAWBRIDGE_UP */
3590 if (cansee(x,y)) msgtxt = "Some water evaporates.";
3592 register struct trap *ttmp;
3596 ttmp = maketrap(x, y, PIT);
3597 if (ttmp) ttmp->tseen = 1;
3598 if (cansee(x,y)) msgtxt = "The water evaporates.";
3601 if (lev->typ == ROOM) newsym(x,y);
3602 } else if(IS_FOUNTAIN(lev->typ)) {
3604 pline("Steam billows from the fountain.");
3606 dryup(x, y, type > 0);
3609 else if(abstype == ZT_COLD && (is_pool(x,y) || is_lava(x,y))) {
3610 boolean lava = is_lava(x,y);
3611 boolean moat = (!lava && (lev->typ != POOL) &&
3612 (lev->typ != WATER) &&
3613 !Is_medusa_level(&u.uz) &&
3614 !Is_waterlevel(&u.uz));
3616 if (lev->typ == WATER) {
3617 /* For now, don't let WATER freeze. */
3619 pline_The("water freezes for a moment.");
3621 You_hear("a soft crackling.");
3622 rangemod -= 1000; /* stop */
3625 if (lev->typ == DRAWBRIDGE_UP) {
3626 lev->drawbridgemask &= ~DB_UNDER; /* clear lava */
3627 lev->drawbridgemask |= (lava ? DB_FLOOR : DB_ICE);
3631 (lev->typ == POOL ? ICED_POOL : ICED_MOAT);
3632 lev->typ = (lava ? ROOM : ICE);
3637 Norep("The moat is bridged with ice!");
3639 Norep("The lava cools and solidifies.");
3641 Norep("The water freezes.");
3643 } else if(flags.soundok && !lava)
3644 You_hear("a crackling sound.");
3646 if (x == u.ux && y == u.uy) {
3647 if (u.uinwater) { /* not just `if (Underwater)' */
3648 /* leave the no longer existent water */
3652 vision_full_recalc = 1;
3653 } else if (u.utrap && u.utraptype == TT_LAVA) {
3655 You("pass through the now-solid rock.");
3657 u.utrap = rn1(50,20);
3658 u.utraptype = TT_INFLOOR;
3659 You("are firmly stuck in the cooling rock.");
3662 } else if ((mon = m_at(x,y)) != 0) {
3663 /* probably ought to do some hefty damage to any
3664 non-ice creature caught in freezing water;
3665 at a minimum, eels are forced out of hiding */
3666 if (is_swimmer(mon->data) && mon->mundetected) {
3667 mon->mundetected = 0;
3672 obj_ice_effects(x,y,TRUE);
3674 if(closed_door(x, y)) {
3675 int new_doormask = -1;
3676 const char *see_txt = 0, *sense_txt = 0, *hear_txt = 0;
3680 new_doormask = D_NODOOR;
3681 see_txt = "The door is consumed in flames!";
3682 sense_txt = "smell smoke.";
3685 new_doormask = D_NODOOR;
3686 see_txt = "The door freezes and shatters!";
3687 sense_txt = "feel cold.";
3690 /* death spells/wands don't disintegrate */
3691 if(abs(type) != ZT_BREATH(ZT_DEATH))
3693 new_doormask = D_NODOOR;
3694 see_txt = "The door disintegrates!";
3695 hear_txt = "crashing wood.";
3698 new_doormask = D_BROKEN;
3699 see_txt = "The door splinters!";
3700 hear_txt = "crackling.";
3705 pline_The("door absorbs %s %s!",
3706 (type < 0) ? "the" : "your",
3707 abs(type) < ZT_SPELL(0) ? "bolt" :
3708 abs(type) < ZT_BREATH(0) ? "spell" :
3710 } else You_feel("vibrations.");
3713 if (new_doormask >= 0) { /* door gets broken */
3714 if (*in_rooms(x, y, SHOPBASE)) {
3716 add_damage(x, y, 400L);
3718 } else /* caused by monster */
3719 add_damage(x, y, 0L);
3721 lev->doormask = new_doormask;
3722 unblock_point(x, y); /* vision */
3726 } else if (sense_txt) {
3728 } else if (hear_txt) {
3729 if (flags.soundok) You_hear(hear_txt);
3731 if (picking_at(x, y)) {
3738 if(OBJ_AT(x, y) && abstype == ZT_FIRE)
3739 if (burn_floor_paper(x, y, FALSE, type > 0) && couldsee(x, y)) {
3742 !Blind ? "see a puff" : "smell a whiff");
3744 if ((mon = m_at(x,y)) != 0) {
3745 /* Cannot use wakeup() which also angers the monster */
3747 if(mon->m_ap_type) seemimic(mon);
3750 if(mon->ispriest && *in_rooms(mon->mx, mon->my, TEMPLE))
3752 if(mon->isshk && !*u.ushops)
3763 fracture_rock(obj) /* fractured by pick-axe or wand of striking */
3764 register struct obj *obj; /* no texts here! */
3766 /* A little Sokoban guilt... */
3767 if (obj->otyp == BOULDER && In_sokoban(&u.uz) && !flags.mon_moving)
3771 obj->quan = (long) rn1(60, 7);
3772 obj->owt = weight(obj);
3773 obj->oclass = GEM_CLASS;
3775 obj->onamelth = 0; /* no names */
3776 obj->oxlth = 0; /* no extra data */
3777 obj->oattached = OATTACHED_NOTHING;
3778 if (obj->where == OBJ_FLOOR) {
3779 obj_extract_self(obj); /* move rocks back on top */
3780 place_object(obj, obj->ox, obj->oy);
3781 if(!does_block(obj->ox,obj->oy,&levl[obj->ox][obj->oy]))
3782 unblock_point(obj->ox,obj->oy);
3783 if(cansee(obj->ox,obj->oy))
3784 newsym(obj->ox,obj->oy);
3788 /* handle statue hit by striking/force bolt/pick-axe */
3791 register struct obj *obj;
3793 /* [obj is assumed to be on floor, so no get_obj_location() needed] */
3794 struct trap *trap = t_at(obj->ox, obj->oy);
3797 if (trap && trap->ttyp == STATUE_TRAP &&
3798 activate_statue_trap(trap, obj->ox, obj->oy, TRUE))
3800 /* drop any objects contained inside the statue */
3801 while ((item = obj->cobj) != 0) {
3802 obj_extract_self(item);
3803 place_object(item, obj->ox, obj->oy);
3805 if (Role_if(PM_ARCHEOLOGIST) && !flags.mon_moving && (obj->spe & STATUE_HISTORIC)) {
3806 You_feel("guilty about damaging such a historic statue.");
3814 const char * const destroy_strings[] = { /* also used in trap.c */
3815 "freezes and shatters", "freeze and shatter", "shattered potion",
3816 "boils and explodes", "boil and explode", "boiling potion",
3817 "catches fire and burns", "catch fire and burn", "burning scroll",
3818 "catches fire and burns", "catch fire and burn", "burning book",
3819 "turns to dust and vanishes", "turn to dust and vanish", "",
3820 "breaks apart and explodes", "break apart and explode", "exploding wand"
3824 destroy_item(osym, dmgtyp)
3825 register int osym, dmgtyp;
3827 register struct obj *obj, *obj2;
3828 register int dmg, xresist, skip;
3829 register long i, cnt, quan;
3833 for(obj = invent; obj; obj = obj2) {
3835 if(obj->oclass != osym) continue; /* test only objs of type osym */
3836 if(obj->oartifact) continue; /* don't destroy artifacts */
3837 if(obj->in_use && obj->quan == 1) continue; /* not available */
3845 if(osym == POTION_CLASS && obj->otyp != POT_OIL) {
3852 xresist = (Fire_resistance && obj->oclass != POTION_CLASS);
3854 if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL)
3856 if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
3859 pline("%s glows a strange %s, but remains intact.",
3860 The(xname(obj)), hcolor("dark red"));
3882 xresist = (Shock_resistance && obj->oclass != RING_CLASS);
3886 if(obj->otyp == RIN_SHOCK_RESISTANCE)
3892 if(obj->otyp == WAN_LIGHTNING) { skip++; break; }
3894 if (obj == current_wand) { skip++; break; }
3909 if (obj->in_use) --quan; /* one will be used up elsewhere */
3910 for(i = cnt = 0L; i < quan; i++)
3914 if(cnt == quan) mult = "Your";
3915 else mult = (cnt == 1L) ? "One of your" : "Some of your";
3916 pline("%s %s %s!", mult, xname(obj),
3917 (cnt > 1L) ? destroy_strings[dindx*3 + 1]
3918 : destroy_strings[dindx*3]);
3919 if(osym == POTION_CLASS && dmgtyp != AD_COLD) {
3920 if (!breathless(youmonst.data) || haseyes(youmonst.data))
3923 if (obj->owornmask) {
3924 if (obj->owornmask & W_RING) /* ring being worn */
3929 if (obj == current_wand) current_wand = 0; /* destroyed */
3930 for (i = 0; i < cnt; i++)
3933 if(xresist) You("aren't hurt!");
3935 const char *how = destroy_strings[dindx * 3 + 2];
3936 boolean one = (cnt == 1L);
3938 losehp(dmg, one ? how : (const char *)makeplural(how),
3939 one ? KILLED_BY_AN : KILLED_BY);
3940 exercise(A_STR, FALSE);
3949 destroy_mitem(mtmp, osym, dmgtyp)
3953 struct obj *obj, *obj2;
3959 if (mtmp == &youmonst) { /* this simplifies artifact_hit() */
3960 destroy_item(osym, dmgtyp);
3961 return 0; /* arbitrary; value doesn't matter to artifact_hit() */
3964 vis = canseemon(mtmp);
3965 for(obj = mtmp->minvent; obj; obj = obj2) {
3967 if(obj->oclass != osym) continue; /* test only objs of type osym */
3974 if(osym == POTION_CLASS && obj->otyp != POT_OIL) {
3981 if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL)
3983 if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
3986 pline("%s glows a strange %s, but remains intact.",
3987 The(distant_name(obj, xname)),
3988 hcolor("dark red"));
4013 if(obj->otyp == RIN_SHOCK_RESISTANCE)
4018 if(obj->otyp == WAN_LIGHTNING) { skip++; break; }
4032 for(i = cnt = 0L; i < quan; i++)
4036 if (vis) pline("%s %s %s!",
4037 s_suffix(Monnam(mtmp)), xname(obj),
4038 (cnt > 1L) ? destroy_strings[dindx*3 + 1]
4039 : destroy_strings[dindx*3]);
4040 for(i = 0; i < cnt; i++) m_useup(mtmp, obj);
4050 resist(mtmp, oclass, damage, tell)
4060 case WAND_CLASS: alev = 12; break;
4061 case TOOL_CLASS: alev = 10; break; /* instrument */
4062 case WEAPON_CLASS: alev = 10; break; /* artifact */
4063 case SCROLL_CLASS: alev = 9; break;
4064 case POTION_CLASS: alev = 6; break;
4065 case RING_CLASS: alev = 5; break;
4066 default: alev = u.ulevel; break; /* spell */
4069 dlev = (int)mtmp->m_lev;
4070 if (dlev > 50) dlev = 50;
4071 else if (dlev < 1) dlev = is_mplayer(mtmp->data) ? u.ulevel : 1;
4073 resisted = rn2(100 + alev - dlev) < mtmp->data->mr;
4076 shieldeff(mtmp->mx, mtmp->my);
4077 pline("%s resists!", Monnam(mtmp));
4079 damage = (damage + 1) / 2;
4083 mtmp->mhp -= damage;
4084 if (mtmp->mhp < 1) {
4085 if(m_using) monkilled(mtmp, "", AD_RBRE);
4096 struct obj *otmp, nothing;
4099 nothing = zeroobj; /* lint suppression; only its address matters */
4100 if (flags.verbose) You("may wish for an object.");
4102 getlin("For what do you wish?", buf);
4103 if(buf[0] == '\033') buf[0] = 0;
4105 * Note: if they wished for and got a non-object successfully,
4106 * otmp == &zeroobj. That includes gold, or an artifact that
4107 * has been denied. Wishing for "nothing" requires a separate
4108 * value to remain distinct.
4110 otmp = readobjnam(buf, ¬hing, TRUE);
4112 pline("Nothing fitting that description exists in the game.");
4113 if (++tries < 5) goto retry;
4114 pline(thats_enough_tries);
4115 otmp = readobjnam((char *)0, (struct obj *)0, TRUE);
4116 if (!otmp) return; /* for safety; should never happen */
4117 } else if (otmp == ¬hing) {
4118 /* explicitly wished for "nothing", presumeably attempting
4119 to retain wishless conduct */
4124 u.uconduct.wishes++;
4126 if (otmp != &zeroobj) {
4127 /* The(aobjnam()) is safe since otmp is unidentified -dlc */
4128 (void) hold_another_object(otmp, u.uswallow ?
4129 "Oops! %s out of your reach!" :
4130 (Is_airlevel(&u.uz) ||
4131 Is_waterlevel(&u.uz) ||
4132 levl[u.ux][u.uy].typ < IRONBARS ||
4133 levl[u.ux][u.uy].typ >= ICE) ?
4134 "Oops! %s away from you!" :
4135 "Oops! %s to the floor!",
4137 Is_airlevel(&u.uz) || u.uinwater ?
4140 u.ublesscnt += rn1(100,50); /* the gods take notice */