OSDN Git Service

Initial Import
[nethackexpress/trunk.git] / src / zap.c
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. */
4
5 #include "hack.h"
6
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.
11  */
12 #define MAGIC_COOKIE 1000
13
14 #ifdef OVLB
15 static NEARDATA boolean obj_zapped;
16 static NEARDATA int poly_zapped;
17 #endif
18
19 extern boolean notonhead;       /* for long worms */
20
21 /* kludge to use mondied instead of killed */
22 extern boolean m_using;
23
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 *));
31 #ifdef STEED
32 STATIC_DCL boolean FDECL(zap_steed, (struct obj *));
33 #endif
34
35 #ifdef OVLB
36 STATIC_DCL int FDECL(zap_hit, (int,int));
37 #endif
38 #ifdef OVL0
39 STATIC_DCL void FDECL(backfire, (struct obj *));
40 STATIC_DCL int FDECL(spell_hit_bonus, (int));
41 #endif
42
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 */
52
53 #define ZT_WAND(x)              (x)
54 #define ZT_SPELL(x)             (10+(x))
55 #define ZT_BREATH(x)            (20+(x))
56
57 #define is_hero_spell(type)     ((type) >= 10 && (type) < 20)
58
59 #ifndef OVLB
60 STATIC_VAR const char are_blinded_by_the_flash[];
61 extern const char * const flash_types[];
62 #else
63 STATIC_VAR const char are_blinded_by_the_flash[] = "are blinded by the flash!";
64
65 const char * const flash_types[] = {    /* also used in buzzmu(mcastu.c) */
66         "magic missile",        /* Wands must be 0-9 */
67         "bolt of fire",
68         "bolt of cold",
69         "sleep ray",
70         "death ray",
71         "bolt of lightning",
72         "",
73         "",
74         "",
75         "",
76
77         "magic missile",        /* Spell equivalents must be 10-19 */
78         "fireball",
79         "cone of cold",
80         "sleep ray",
81         "finger of death",
82         "bolt of lightning",    /* There is no spell, used for retribution */
83         "",
84         "",
85         "",
86         "",
87
88         "blast of missiles",    /* Dragon breath equivalents 20-29*/
89         "blast of fire",
90         "blast of frost",
91         "blast of sleep gas",
92         "blast of disintegration",
93         "blast of lightning",
94         "blast of poison gas",
95         "blast of acid",
96         "",
97         ""
98 };
99
100 /* Routines for IMMEDIATE wands and spells. */
101 /* bhitm: monster mtmp was hit by the effect of wand or spell otmp */
102 int
103 bhitm(mtmp, otmp)
104 struct monst *mtmp;
105 struct obj *otmp;
106 {
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";
112         struct obj *obj;
113         boolean disguised_mimic = (mtmp->data->mlet == S_MIMIC &&
114                                    mtmp->m_ap_type != M_AP_NOTHING);
115
116         if (u.uswallow && mtmp == u.ustuck)
117             reveal_invis = FALSE;
118
119         switch(otyp) {
120         case WAN_STRIKING:
121                 zap_type_text = "wand";
122                 /* fall through */
123         case SPE_FORCE_BOLT:
124                 reveal_invis = TRUE;
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)) {
129                         dmg = d(2,12);
130                         if(dbldam) dmg *= 2;
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);
136                 makeknown(otyp);
137                 break;
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);
148                         }
149                 }
150                 break;
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 */
155                 }
156                 break;
157         case WAN_UNDEAD_TURNING:
158         case SPE_TURN_UNDEAD:
159                 wake = FALSE;
160                 if (unturn_dead(mtmp)) wake = TRUE;
161                 if (is_undead(mtmp->data)) {
162                         reveal_invis = TRUE;
163                         wake = TRUE;
164                         dmg = rnd(8);
165                         if(dbldam) dmg *= 2;
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);
171                         }
172                 }
173                 break;
174         case WAN_POLYMORPH:
175         case SPE_POLYMORPH:
176         case POT_POLYMORPH:
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));
188                             makeknown(otyp);
189                         }
190                         /* dropped inventory shouldn't be hit by this zap */
191                         for (obj = mtmp->minvent; obj; obj = obj->nobj)
192                             bypass_obj(obj);
193                         /* flags.bypasses = TRUE; ## for make_corpse() */
194                         /* no corpse after system shock */
195                         xkilled(mtmp, 3);
196                     } else if (newcham(mtmp, (struct permonst *)0,
197                                        (otyp != POT_POLYMORPH), FALSE)) {
198                         if (!Hallucination && canspotmon(mtmp))
199                             makeknown(otyp);
200                     }
201                 }
202                 break;
203         case WAN_CANCELLATION:
204         case SPE_CANCELLATION:
205                 (void) cancel_monst(mtmp, otmp, TRUE, TRUE, FALSE);
206                 break;
207         case WAN_TELEPORTATION:
208         case SPE_TELEPORT_AWAY:
209                 reveal_invis = !u_teleport_mon(mtmp, TRUE);
210                 break;
211         case WAN_MAKE_INVISIBLE:
212             {
213                 int oldinvis = mtmp->minvis;
214                 char nambuf[BUFSZ];
215
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);
221                     makeknown(otyp);
222                 }
223                 break;
224             }
225         case WAN_NOTHING:
226         case WAN_LOCKING:
227         case SPE_WIZARD_LOCK:
228                 wake = FALSE;
229                 break;
230         case WAN_PROBING:
231                 wake = FALSE;
232                 reveal_invis = TRUE;
233                 probe_monster(mtmp);
234                 makeknown(otyp);
235                 break;
236         case WAN_OPENING:
237         case SPE_KNOCK:
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));
243                         }
244                         expels(mtmp, mtmp->data, TRUE);
245 #ifdef STEED
246                 } else if (!!(obj = which_armor(mtmp, W_SADDLE))) {
247                         mtmp->misc_worn_check &= ~obj->owornmask;
248                         update_mon_intrinsics(mtmp, obj, FALSE, FALSE);
249                         obj->owornmask = 0L;
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);
254 #endif
255                 }
256                 break;
257         case SPE_HEALING:
258         case SPE_EXTRA_HEALING:
259                 reveal_invis = TRUE;
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) {
266                     mtmp->mblinded = 0;
267                     mtmp->mcansee = 1;
268                 }
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 */
274                             set_mimic_sym(mtmp);
275                             newsym(mtmp->mx, mtmp->my);
276                         } else
277                             mimic_hit_msg(mtmp, otyp);
278                     } else pline("%s looks%s better.", Monnam(mtmp),
279                                  otyp == SPE_EXTRA_HEALING ? " much" : "" );
280                 }
281                 if (mtmp->mtame || mtmp->mpeaceful) {
282                     adjalign(Role_if(PM_HEALER) ? 1 : sgn(u.ualign.type));
283                 }
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);
288             }
289                 break;
290         case WAN_LIGHT: /* (broken wand) */
291                 if (flash_hits_mon(mtmp, otmp)) {
292                     makeknown(WAN_LIGHT);
293                     reveal_invis = TRUE;
294                 }
295                 break;
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] */
299                 reveal_invis = TRUE;
300                 if (sleep_monst(mtmp, d(1 + otmp->spe, 12), WAND_CLASS))
301                     slept_monst(mtmp);
302                 if (!Blind) makeknown(WAN_SLEEP);
303                 break;
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)) {
309                         if (canseemon(mtmp))
310                             pline("%s turns to flesh!", name);
311                     } else {
312                         if (canseemon(mtmp))
313                             pline("%s looks rather fleshy for a moment.",
314                                   name);
315                     }
316                 } else
317                     wake = FALSE;
318                 break;
319         case SPE_DRAIN_LIFE:
320                 dmg = rnd(8);
321                 if(dbldam) dmg *= 2;
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) &&
327                                 mtmp->mhp > 0) {
328                     mtmp->mhp -= dmg;
329                     mtmp->mhpmax -= dmg;
330                     if (mtmp->mhp <= 0 || mtmp->mhpmax <= 0 || mtmp->m_lev < 1)
331                         xkilled(mtmp, 1);
332                     else {
333                         mtmp->m_lev--;
334                         if (canseemon(mtmp))
335                             pline("%s suddenly seems weaker!", Monnam(mtmp));
336                     }
337                 }
338                 break;
339         default:
340                 impossible("What an interesting effect (%d)", otyp);
341                 break;
342         }
343         if(wake) {
344             if(mtmp->mhp > 0) {
345                 wakeup(mtmp);
346                 m_respond(mtmp);
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 */
350         }
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.
354          */
355         if (reveal_invis) {
356             if (mtmp->mhp > 0 && cansee(bhitpos.x, bhitpos.y) &&
357                                                         !canspotmon(mtmp))
358                 map_invisible(bhitpos.x, bhitpos.y);
359         }
360         return 0;
361 }
362
363 void
364 probe_monster(mtmp)
365 struct monst *mtmp;
366 {
367         struct obj *otmp;
368
369         mstatusline(mtmp);
370         if (notonhead) return;  /* don't show minvent for long worm tail */
371
372 #ifndef GOLDOBJ
373         if (mtmp->minvent || mtmp->mgold) {
374 #else
375         if (mtmp->minvent) {
376 #endif
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);
380         } else {
381             pline("%s is not carrying anything.", noit_Monnam(mtmp));
382         }
383 }
384
385 #endif /*OVLB*/
386 #ifdef OVL1
387
388 /*
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.
398  */
399 boolean
400 get_obj_location(obj, xp, yp, locflags)
401 struct obj *obj;
402 xchar *xp, *yp;
403 int locflags;
404 {
405         switch (obj->where) {
406             case OBJ_INVENT:
407                 *xp = u.ux;
408                 *yp = u.uy;
409                 return TRUE;
410             case OBJ_FLOOR:
411                 *xp = obj->ox;
412                 *yp = obj->oy;
413                 return TRUE;
414             case OBJ_MINVENT:
415                 if (obj->ocarry->mx) {
416                     *xp = obj->ocarry->mx;
417                     *yp = obj->ocarry->my;
418                     return TRUE;
419                 }
420                 break;  /* !mx => migrating monster */
421             case OBJ_BURIED:
422                 if (locflags & BURIED_TOO) {
423                     *xp = obj->ox;
424                     *yp = obj->oy;
425                     return TRUE;
426                 }
427                 break;
428             case OBJ_CONTAINED:
429                 if (locflags & CONTAINED_TOO)
430                     return get_obj_location(obj->ocontainer, xp, yp, locflags);
431                 break;
432         }
433         *xp = *yp = 0;
434         return FALSE;
435 }
436
437 boolean
438 get_mon_location(mon, xp, yp, locflags)
439 struct monst *mon;
440 xchar *xp, *yp;
441 int locflags;   /* non-zero means get location even if monster is buried */
442 {
443         if (mon == &youmonst) {
444             *xp = u.ux;
445             *yp = u.uy;
446             return TRUE;
447         } else if (mon->mx > 0 && (!mon->mburied || locflags)) {
448             *xp = mon->mx;
449             *yp = mon->my;
450             return TRUE;
451         } else {        /* migrating or buried */
452             *xp = *yp = 0;
453             return FALSE;
454         }
455 }
456
457 /* used by revive() and animate_statue() */
458 struct monst *
459 montraits(obj,cc)
460 struct obj *obj;
461 coord *cc;
462 {
463         struct monst *mtmp = (struct monst *)0;
464         struct monst *mtmp2 = (struct monst *)0;
465
466         if (obj->oxlth && (obj->oattached == OATTACHED_MONST))
467                 mtmp2 = get_mtraits(obj, TRUE);
468         if (mtmp2) {
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;
476
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) */
486                 if (!mtmp2->m_id)
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 */
504                 mtmp2->mavenge = 0;
505                 mtmp2->meating = 0;
506                 mtmp2->mleashed = 0;
507                 mtmp2->mtrapped = 0;
508                 mtmp2->msleeping = 0;
509                 mtmp2->mfrozen = 0;
510                 mtmp2->mcanmove = 1;
511                 /* most cancelled monsters return to normal,
512                    but some need to stay cancelled */
513                 if (!dmgtype(mtmp2->data, AD_SEDU)
514 #ifdef SEDUCE
515                                 && !dmgtype(mtmp2->data, AD_SSEX)
516 #endif
517                     ) mtmp2->mcan = 0;
518                 mtmp2->mcansee = 1;     /* set like in makemon */
519                 mtmp2->mblinded = 0;
520                 mtmp2->mstun = 0;
521                 mtmp2->mconf = 0;
522                 replmon(mtmp,mtmp2);
523         }
524         return mtmp2;
525 }
526
527 /*
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
536  * if applicable.
537  */
538 struct monst *
539 get_container_location(obj, loc, container_nesting)
540 struct obj *obj;
541 int *loc;
542 int *container_nesting;
543 {
544         if (!obj || !loc)
545                 return 0;
546
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;
551         }
552         if (obj) {
553             *loc = obj->where;  /* outermost container's location */
554             if (obj->where == OBJ_MINVENT) return obj->ocarry;
555         }
556         return (struct monst *)0;
557 }
558
559 /*
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.
562  */
563 struct monst *
564 revive(obj)
565 register struct obj *obj;
566 {
567         register struct monst *mtmp = (struct monst *)0;
568         struct obj *container = (struct obj *)0;
569         int container_nesting = 0;
570         schar savetame = 0;
571         boolean recorporealization = FALSE;
572         boolean in_container = FALSE;
573         if(obj->otyp == CORPSE) {
574                 int montype = obj->corpsenm;
575                 xchar x, y;
576
577                 if (obj->where == OBJ_CONTAINED) {
578                         /* deal with corpses in [possibly nested] containers */
579                         struct monst *carrier;
580                         int holder = 0;
581
582                         container = obj->ocontainer;
583                         carrier = get_container_location(container, &holder,
584                                                         &container_nesting);
585                         switch(holder) {
586                             case OBJ_MINVENT:
587                                 x = carrier->mx; y = carrier->my;
588                                 in_container = TRUE;
589                                 break;
590                             case OBJ_INVENT:
591                                 x = u.ux; y = u.uy;
592                                 in_container = TRUE;
593                                 break;
594                             case OBJ_FLOOR:
595                                 if (!get_obj_location(obj, &x, &y, CONTAINED_TOO))
596                                         return (struct monst *) 0;
597                                 in_container = TRUE;
598                                 break;
599                             default:
600                                 return (struct monst *)0;
601                         }
602                 } else {
603                         /* only for invent, minvent, or floor */
604                         if (!get_obj_location(obj, &x, &y, 0))
605                             return (struct monst *) 0;
606                 }
607                 if (in_container) {
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)
613                         */
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;
618                 }
619
620                 if (MON_AT(x,y)) {
621                     coord new_xy;
622
623                     if (enexto(&new_xy, x, y, &mons[montype]))
624                         x = new_xy.x,  y = new_xy.y;
625                 }
626
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);
631                         if (mtmp) {
632                                 mtmp->mhp = mtmp->mhpmax = 100;
633                                 mon_adjust_speed(mtmp, 2, (struct obj *)0); /* MFAST */
634                         }
635                 } else {
636                     if (obj->oxlth && (obj->oattached == OATTACHED_MONST)) {
637                             coord xy;
638                             xy.x = x; xy.y = y;
639                             mtmp = montraits(obj, &xy);
640                             if (mtmp && mtmp->mtame && !mtmp->isminion)
641                                 wary_dog(mtmp, TRUE);
642                     } else
643                             mtmp = makemon(&mons[montype], x, y,
644                                        NO_MINVENT|MM_NOWAIT|MM_NOCOUNTBIRTH);
645                     if (mtmp) {
646                         if (obj->oxlth && (obj->oattached == OATTACHED_M_ID)) {
647                             unsigned m_id;
648                             struct monst *ghost;
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]) {
653                                     int x2, y2;
654                                     x2 = ghost->mx; y2 = ghost->my;
655                                     if (ghost->mtame)
656                                         savetame = ghost->mtame;
657                                     if (canseemon(ghost))
658                                         pline("%s is suddenly drawn into its former body!",
659                                                 Monnam(ghost));
660                                     mondead(ghost);
661                                     recorporealization = TRUE;
662                                     newsym(x2, y2);
663                             }
664                             /* don't mess with obj->oxlth here */
665                             obj->oattached = OATTACHED_NOTHING;
666                         }
667                         /* Monster retains its name */
668                         if (obj->onamelth)
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;
674                     }
675                 }
676                 if (mtmp) {
677                         if (obj->oeaten)
678                                 mtmp->mhp = eaten_stat(mtmp->mhp, obj);
679                         /* track that this monster was revived at least once */
680                         mtmp->mrevived = 1;
681
682                         if (recorporealization) {
683                                 /* If mtmp is revivification of former tame ghost*/
684                                 if (savetame) {
685                                     struct monst *mtmp2 = tamedog(mtmp, (struct obj *)0);
686                                     if (mtmp2) {
687                                         mtmp2->mtame = savetame;
688                                         mtmp = mtmp2;
689                                     }
690                                 }
691                                 /* was ghost, now alive, it's all very confusing */
692                                 mtmp->mconf = 1;
693                         }
694
695                         switch (obj->where) {
696                             case OBJ_INVENT:
697                                 useup(obj);
698                                 break;
699                             case OBJ_FLOOR:
700                                 /* in case MON_AT+enexto for invisible mon */
701                                 x = obj->ox,  y = obj->oy;
702                                 /* not useupf(), which charges */
703                                 if (obj->quan > 1L)
704                                     obj = splitobj(obj, 1L);
705                                 delobj(obj);
706                                 newsym(x, y);
707                                 break;
708                             case OBJ_MINVENT:
709                                 m_useup(obj->ocarry, obj);
710                                 break;
711                             case OBJ_CONTAINED:
712                                 obj_extract_self(obj);
713                                 obfree(obj, (struct obj *) 0);
714                                 break;
715                             default:
716                                 panic("revive");
717                         }
718                 }
719         }
720         return mtmp;
721 }
722
723 STATIC_OVL void
724 revive_egg(obj)
725 struct obj *obj;
726 {
727         /*
728          * Note: generic eggs with corpsenm set to NON_PM will never hatch.
729          */
730         if (obj->otyp != EGG) return;
731         if (obj->corpsenm != NON_PM && !dead_species(obj->corpsenm, TRUE))
732             attach_egg_hatch_timeout(obj);
733 }
734
735 /* try to revive all corpses and eggs carried by `mon' */
736 int
737 unturn_dead(mon)
738 struct monst *mon;
739 {
740         struct obj *otmp, *otmp2;
741         struct monst *mtmp2;
742         char owner[BUFSZ], corpse[BUFSZ];
743         boolean youseeit;
744         int once = 0, res = 0;
745
746         youseeit = (mon == &youmonst) ? TRUE : canseemon(mon);
747         otmp2 = (mon == &youmonst) ? invent : mon->minvent;
748
749         while ((otmp = otmp2) != 0) {
750             otmp2 = otmp->nobj;
751             if (otmp->otyp == EGG)
752                 revive_egg(otmp);
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));
756
757             /* for a merged group, only one is revived; should this be fixed? */
758             if ((mtmp2 = revive(otmp)) != 0) {
759                 ++res;
760                 if (youseeit) {
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));
767             }
768         }
769         return res;
770 }
771 #endif /*OVL1*/
772
773 #ifdef OVLB
774 static const char charged_objs[] = { WAND_CLASS, WEAPON_CLASS, ARMOR_CLASS, 0 };
775
776 STATIC_OVL void
777 costly_cancel(obj)
778 register struct obj *obj;
779 {
780         char objroom;
781         struct monst *shkp = (struct monst *)0;
782
783         if (obj->no_charge) return;
784
785         switch (obj->where) {
786         case OBJ_INVENT:
787                 if (obj->unpaid) {
788                     shkp = shop_keeper(*u.ushops);
789                     if (!shkp) return;
790                     Norep("You cancel an unpaid object, you pay for it!");
791                     bill_dummy_object(obj);
792                 }
793                 break;
794         case OBJ_FLOOR:
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);
801                 } else
802                     (void) stolen_value(obj, obj->ox, obj->oy, FALSE, FALSE);
803                 break;
804         }
805 }
806
807 /* cancel obj, possibly carried by you or a monster */
808 void
809 cancel_item(obj)
810 register struct obj *obj;
811 {
812         boolean u_ring = (obj == uleft) || (obj == uright);
813         register boolean holy = (obj->otyp == POT_WATER && obj->blessed);
814
815         switch(obj->otyp) {
816                 case RIN_GAIN_STRENGTH:
817                         if ((obj->owornmask & W_RING) && u_ring) {
818                                 ABON(A_STR) -= obj->spe;
819                                 flags.botl = 1;
820                         }
821                         break;
822                 case RIN_GAIN_CONSTITUTION:
823                         if ((obj->owornmask & W_RING) && u_ring) {
824                                 ABON(A_CON) -= obj->spe;
825                                 flags.botl = 1;
826                         }
827                         break;
828                 case RIN_ADORNMENT:
829                         if ((obj->owornmask & W_RING) && u_ring) {
830                                 ABON(A_CHA) -= obj->spe;
831                                 flags.botl = 1;
832                         }
833                         break;
834                 case RIN_INCREASE_ACCURACY:
835                         if ((obj->owornmask & W_RING) && u_ring)
836                                 u.uhitinc -= obj->spe;
837                         break;
838                 case RIN_INCREASE_DAMAGE:
839                         if ((obj->owornmask & W_RING) && u_ring)
840                                 u.udaminc -= obj->spe;
841                         break;
842                 case GAUNTLETS_OF_DEXTERITY:
843                         if ((obj->owornmask & W_ARMG) && (obj == uarmg)) {
844                                 ABON(A_DEX) -= obj->spe;
845                                 flags.botl = 1;
846                         }
847                         break;
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;
852                                 flags.botl = 1;
853                         }
854                         break;
855                 /* case RIN_PROTECTION:  not needed */
856         }
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) {
866                 costly_cancel(obj);
867                 obj->spe = (obj->oclass == WAND_CLASS) ? -1 : 0;
868             }
869             switch (obj->oclass) {
870               case SCROLL_CLASS:
871                 costly_cancel(obj);
872                 obj->otyp = SCR_BLANK_PAPER;
873                 obj->spe = 0;
874                 break;
875               case SPBOOK_CLASS:
876                 if (obj->otyp != SPE_CANCELLATION &&
877                         obj->otyp != SPE_BOOK_OF_THE_DEAD) {
878                     costly_cancel(obj);
879                     obj->otyp = SPE_BLANK_PAPER;
880                 }
881                 break;
882               case POTION_CLASS:
883                 costly_cancel(obj);
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.
889              */
890                     obj->otyp = POT_FRUIT_JUICE;
891                 } else {
892                     obj->otyp = POT_WATER;
893                     obj->odiluted = 0; /* same as any other water */
894                 }
895                 break;
896             }
897         }
898         if (holy) costly_cancel(obj);
899         unbless(obj);
900         uncurse(obj);
901 #ifdef INVISIBLE_OBJECTS
902         if (obj->oinvis) obj->oinvis = 0;
903 #endif
904         return;
905 }
906
907 /* Remove a positive enchantment or charge from obj,
908  * possibly carried by you or a monster
909  */
910 boolean
911 drain_item(obj)
912 register struct obj *obj;
913 {
914         boolean u_ring;
915
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)) ||
920                         obj->spe <= 0)
921             return (FALSE);
922         if (obj_resists(obj, 10, 90))
923             return (FALSE);
924
925         /* Charge for the cost of the object */
926         costly_cancel(obj);     /* The term "cancel" is okay for now */
927
928         /* Drain the object and any implied effects */
929         obj->spe--;
930         u_ring = (obj == uleft) || (obj == uright);
931         switch(obj->otyp) {
932         case RIN_GAIN_STRENGTH:
933             if ((obj->owornmask & W_RING) && u_ring) {
934                 ABON(A_STR)--;
935                 flags.botl = 1;
936             }
937             break;
938         case RIN_GAIN_CONSTITUTION:
939             if ((obj->owornmask & W_RING) && u_ring) {
940                 ABON(A_CON)--;
941                 flags.botl = 1;
942             }
943             break;
944         case RIN_ADORNMENT:
945             if ((obj->owornmask & W_RING) && u_ring) {
946                 ABON(A_CHA)--;
947                 flags.botl = 1;
948             }
949             break;
950         case RIN_INCREASE_ACCURACY:
951             if ((obj->owornmask & W_RING) && u_ring)
952                 u.uhitinc--;
953             break;
954         case RIN_INCREASE_DAMAGE:
955             if ((obj->owornmask & W_RING) && u_ring)
956                 u.udaminc--;
957             break;
958         case HELM_OF_BRILLIANCE:
959             if ((obj->owornmask & W_ARMH) && (obj == uarmh)) {
960                 ABON(A_INT)--;
961                 ABON(A_WIS)--;
962                 flags.botl = 1;
963             }
964             break;
965         case GAUNTLETS_OF_DEXTERITY:
966             if ((obj->owornmask & W_ARMG) && (obj == uarmg)) {
967                 ABON(A_DEX)--;
968                 flags.botl = 1;
969             }
970             break;
971         case RIN_PROTECTION:
972             flags.botl = 1;
973             break;
974         }
975         if (carried(obj)) update_inventory();
976         return (TRUE);
977 }
978
979 #endif /*OVLB*/
980 #ifdef OVL0
981
982 boolean
983 obj_resists(obj, ochance, achance)
984 struct obj *obj;
985 int ochance, achance;   /* percent chance for ordinary objects, artifacts */
986 {
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]))) {
992                 return TRUE;
993         } else {
994                 int chance = rn2(100);
995
996                 return((boolean)(chance < (obj->oartifact ? achance : ochance)));
997         }
998 }
999
1000 boolean
1001 obj_shudders(obj)
1002 struct obj *obj;
1003 {
1004         int     zap_odds;
1005
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 */
1012         else
1013                 zap_odds = 8;   /* half-life = 6 zaps */
1014
1015         /* adjust for "large" quantities of identical things */
1016         if(obj->quan > 4L) zap_odds /= 2;
1017
1018         return((boolean)(! rn2(zap_odds)));
1019 }
1020 #endif /*OVL0*/
1021 #ifdef OVLB
1022
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.
1027  */
1028 STATIC_OVL void
1029 polyuse(objhdr, mat, minwt)
1030     struct obj *objhdr;
1031     int mat, minwt;
1032 {
1033     register struct obj *otmp, *otmp2;
1034
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 */
1039 #ifdef MAIL
1040         if (otmp->otyp == SCR_MAIL) continue;
1041 #endif
1042
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)) {
1047                 if (*u.ushops)
1048                         addtobill(otmp, FALSE, FALSE, FALSE);
1049                 else
1050                         (void)stolen_value(otmp,
1051                                            otmp->ox, otmp->oy, FALSE, FALSE);
1052             }
1053             if (otmp->quan < LARGEST_INT)
1054                 minwt -= (int)otmp->quan;
1055             else
1056                 minwt = 0;
1057             delobj(otmp);
1058         }
1059     }
1060 }
1061
1062 /*
1063  * Polymorph some of the stuff in this pile into a monster, preferably
1064  * a golem of the kind okind.
1065  */
1066 STATIC_OVL void
1067 create_polymon(obj, okind)
1068     struct obj *obj;
1069     int okind;
1070 {
1071         struct permonst *mdat = (struct permonst *)0;
1072         struct monst *mtmp;
1073         const char *material;
1074         int pm_index;
1075
1076         /* no golems if you zap only one object -- not enough stuff */
1077         if(!obj || (!obj->nexthere && obj->quan == 1L)) return;
1078
1079         /* some of these choices are arbitrary */
1080         switch(okind) {
1081         case IRON:
1082         case METAL:
1083         case MITHRIL:
1084             pm_index = PM_IRON_GOLEM;
1085             material = "metal ";
1086             break;
1087         case COPPER:
1088         case SILVER:
1089         case PLATINUM:
1090         case GEMSTONE:
1091         case MINERAL:
1092             pm_index = rn2(2) ? PM_STONE_GOLEM : PM_CLAY_GOLEM;
1093             material = "lithic ";
1094             break;
1095         case 0:
1096         case FLESH:
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 ";
1100             break;
1101         case WOOD:
1102             pm_index = PM_WOOD_GOLEM;
1103             material = "wood ";
1104             break;
1105         case LEATHER:
1106             pm_index = PM_LEATHER_GOLEM;
1107             material = "leather ";
1108             break;
1109         case CLOTH:
1110             pm_index = PM_ROPE_GOLEM;
1111             material = "cloth ";
1112             break;
1113         case BONE:
1114             pm_index = PM_SKELETON;     /* nearest thing to "bone golem" */
1115             material = "bony ";
1116             break;
1117         case GOLD:
1118             pm_index = PM_GOLD_GOLEM;
1119             material = "gold ";
1120             break;
1121         case GLASS:
1122             pm_index = PM_GLASS_GOLEM;
1123             material = "glassy ";
1124             break;
1125         case PAPER:
1126             pm_index = PM_PAPER_GOLEM;
1127             material = "paper ";
1128             break;
1129         default:
1130             /* if all else fails... */
1131             pm_index = PM_STRAW_GOLEM;
1132             material = "";
1133             break;
1134         }
1135
1136         if (!(mvitals[pm_index].mvflags & G_GENOD))
1137                 mdat = &mons[pm_index];
1138
1139         mtmp = makemon(mdat, obj->ox, obj->oy, NO_MM_FLAGS);
1140         polyuse(obj, okind, (int)mons[pm_index].cwt);
1141
1142         if(mtmp && cansee(mtmp->mx, mtmp->my)) {
1143             pline("Some %sobjects meld, and %s arises from the pile!",
1144                   material, a_monnam(mtmp));
1145         }
1146 }
1147
1148 /* Assumes obj is on the floor. */
1149 void
1150 do_osshock(obj)
1151 struct obj *obj;
1152 {
1153         long i;
1154
1155 #ifdef MAIL
1156         if (obj->otyp == SCR_MAIL) return;
1157 #endif
1158         obj_zapped = TRUE;
1159
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;
1165                     break;
1166                 }
1167         }
1168
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));
1173             else
1174                 obj = splitobj(obj, (long)rnd((int)obj->quan - 1));
1175         }
1176
1177         /* appropriately add damage to bill */
1178         if (costly_spot(obj->ox, obj->oy)) {
1179                 if (*u.ushops)
1180                         addtobill(obj, FALSE, FALSE, FALSE);
1181                 else
1182                         (void)stolen_value(obj,
1183                                            obj->ox, obj->oy, FALSE, FALSE);
1184         }
1185
1186         /* zap the object */
1187         delobj(obj);
1188 }
1189
1190 /*
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
1197  * the new object.
1198  *
1199  * This should be safe to call for an object anywhere.
1200  */
1201 struct obj *
1202 poly_obj(obj, id)
1203         struct obj *obj;
1204         int id;
1205 {
1206         struct obj *otmp;
1207         xchar ox, oy;
1208         boolean can_merge = (id == STRANGE_OBJECT);
1209         int obj_location = obj->where;
1210
1211         if (obj->otyp == BOULDER && In_sokoban(&u.uz))
1212             change_luck(-1);    /* Sokoban guilt */
1213         if (id == STRANGE_OBJECT) { /* preserve symbol */
1214             int try_limit = 3;
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;
1218             do {
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);
1223         } else {
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
1231         }
1232
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;
1240 #ifdef MAIL
1241         /* You can't send yourself 100 mail messages and then
1242          * polymorph them into useful scrolls
1243          */
1244         if (obj->otyp == SCR_MAIL) {
1245                 otmp->otyp = SCR_MAIL;
1246                 otmp->spe = 1;
1247         }
1248 #endif
1249
1250         /* avoid abusing eggs laid by you */
1251         if (obj->otyp == EGG && obj->spe) {
1252                 int mnum, tryct = 100;
1253
1254                 /* first, turn into a generic egg */
1255                 if (otmp->otyp == EGG)
1256                     kill_egg(otmp);
1257                 else {
1258                     otmp->otyp = EGG;
1259                     otmp->owt = weight(otmp);
1260                 }
1261                 otmp->corpsenm = NON_PM;
1262                 otmp->spe = 0;
1263
1264                 /* now change it into something layed by the hero */
1265                 while (tryct--) {
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);
1271                         break;
1272                     }
1273                 }
1274         }
1275
1276         /* keep special fields (including charges on wands) */
1277         if (index(charged_objs, otmp->oclass)) otmp->spe = obj->spe;
1278         otmp->recharged = obj->recharged;
1279
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;
1288
1289         /* Keep chest/box traps and poisoned ammo if we may */
1290         if (obj->otrapped && Is_box(otmp)) otmp->otrapped = TRUE;
1291
1292         if (obj->opoisoned && is_poisonable(otmp))
1293                 otmp->opoisoned = TRUE;
1294
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;
1300                 otmp->spe = 0;
1301                 otmp->oeroded = 0;
1302                 otmp->oerodeproof = TRUE;
1303                 otmp->quan = 1L;
1304                 otmp->cursed = FALSE;
1305             }
1306         }
1307
1308         /* no box contents --KAA */
1309         if (Has_contents(otmp)) delete_contents(otmp);
1310
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))))
1314             otmp->quan = 1L;
1315
1316         switch (otmp->oclass) {
1317
1318         case TOOL_CLASS:
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 */
1324             }
1325             /* don't care about the recharge count of other tools */
1326             break;
1327
1328         case WAND_CLASS:
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 */
1334                 otmp->recharged++;
1335             break;
1336
1337         case POTION_CLASS:
1338             while (otmp->otyp == POT_POLYMORPH)
1339                 otmp->otyp = rnd_class(POT_GAIN_ABILITY, POT_WATER);
1340             break;
1341
1342         case SPBOOK_CLASS:
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;
1347             break;
1348
1349         case GEM_CLASS:
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 */
1355             }
1356             break;
1357         }
1358
1359         /* update the weight */
1360         otmp->owt = weight(otmp);
1361
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);
1366             else {
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.
1371                  */
1372                 otmp->owornmask = obj->owornmask;
1373                 remove_worn_item(obj, TRUE);
1374                 setworn(otmp, otmp->owornmask);
1375                 if (otmp->owornmask & LEFT_RING)
1376                     uleft = otmp;
1377                 if (otmp->owornmask & RIGHT_RING)
1378                     uright = otmp;
1379                 if (otmp->owornmask & W_WEP)
1380                     uwep = otmp;
1381                 if (otmp->owornmask & W_SWAPWEP)
1382                     uswapwep = otmp;
1383                 if (otmp->owornmask & W_QUIVER)
1384                     uquiver = otmp;
1385                 goto no_unwear;
1386             }
1387         }
1388
1389         /* preserve the mask in case being used by something else */
1390         otmp->owornmask = obj->owornmask;
1391 no_unwear:
1392
1393         if (obj_location == OBJ_FLOOR && obj->otyp == BOULDER &&
1394                 otmp->otyp != BOULDER)
1395             unblock_point(obj->ox, obj->oy);
1396
1397         /* ** we are now done adjusting the object ** */
1398
1399
1400         /* swap otmp for obj */
1401         replace_object(obj, otmp);
1402         if (obj_location == OBJ_INVENT) {
1403             /*
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.
1408              */
1409             freeinv_core(obj);
1410             addinv_core1(otmp);
1411             addinv_core2(otmp);
1412         }
1413
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));
1419
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);
1429                     else {
1430                         pline("%s gets angry!", Monnam(shkp));
1431                         hot_pursuit(shkp);
1432                     }
1433                 } else Norep("%s is furious!", Monnam(shkp));
1434             }
1435         }
1436         delobj(obj);
1437         return otmp;
1438 }
1439
1440 /*
1441  * Object obj was hit by the effect of the wand/spell otmp.  Return
1442  * non-zero if the wand/spell had any effect.
1443  */
1444 int
1445 bhito(obj, otmp)
1446 struct obj *obj, *otmp;
1447 {
1448         int res = 1;    /* affected object by default */
1449         xchar refresh_x, refresh_y;
1450
1451         if (obj->bypass) {
1452                 /* The bypass bit is currently only used as follows:
1453                  *
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
1461                  *             either.
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.
1465                  *
1466                  * The bypass bit on all objects is reset each turn, whenever
1467                  * flags.bypasses is set.
1468                  *
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.
1472                  */
1473                 if (flags.bypasses)
1474                         return 0;
1475                 else {
1476 #ifdef DEBUG
1477                         pline("%s for a moment.", Tobjnam(obj, "pulsate"));
1478 #endif
1479                         obj->bypass = 0;
1480                 }
1481         }
1482
1483         /*
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.
1487          */
1488         if (!(obj->where == OBJ_FLOOR || otmp->otyp == SPE_STONE_TO_FLESH))
1489             impossible("bhito: obj is not floor or Stone To Flesh spell");
1490
1491         if (obj == uball) {
1492                 res = 0;
1493         } else if (obj == uchain) {
1494                 if (otmp->otyp == WAN_OPENING || otmp->otyp == SPE_KNOCK) {
1495                     unpunish();
1496                     makeknown(otmp->otyp);
1497                 } else
1498                     res = 0;
1499         } else
1500         switch(otmp->otyp) {
1501         case WAN_POLYMORPH:
1502         case SPE_POLYMORPH:
1503                 if (obj->otyp == WAN_POLYMORPH ||
1504                         obj->otyp == SPE_POLYMORPH ||
1505                         obj->otyp == POT_POLYMORPH ||
1506                         obj_resists(obj, 5, 95)) {
1507                     res = 0;
1508                     break;
1509                 }
1510                 /* KMH, conduct */
1511                 u.uconduct.polypiles++;
1512                 /* any saved lock context will be dangerously obsolete */
1513                 if (Is_box(obj)) (void) boxlock(obj, otmp);
1514
1515                 if (obj_shudders(obj)) {
1516                     if (cansee(obj->ox, obj->oy))
1517                         makeknown(otmp->otyp);
1518                     do_osshock(obj);
1519                     break;
1520                 }
1521                 obj = poly_obj(obj, STRANGE_OBJECT);
1522                 newsym(obj->ox,obj->oy);
1523                 break;
1524         case WAN_PROBING:
1525                 res = !obj->dknown;
1526                 /* target object has now been "seen (up close)" */
1527                 obj->dknown = 1;
1528                 if (Is_container(obj) || obj->otyp == STATUE) {
1529                     if (!obj->cobj)
1530                         pline("%s empty.", Tobjnam(obj, "are"));
1531                     else {
1532                         struct obj *o;
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);
1537                     }
1538                     res = 1;
1539                 }
1540                 if (res) makeknown(WAN_PROBING);
1541                 break;
1542         case WAN_STRIKING:
1543         case SPE_FORCE_BOLT:
1544                 if (obj->otyp == BOULDER)
1545                         fracture_rock(obj);
1546                 else if (obj->otyp == STATUE)
1547                         (void) break_statue(obj);
1548                 else {
1549                         if (!flags.mon_moving)
1550                             (void)hero_breaks(obj, obj->ox, obj->oy, FALSE);
1551                         else
1552                             (void)breaks(obj, obj->ox, obj->oy);
1553                         res = 0;
1554                 }
1555                 /* BUG[?]: shouldn't this depend upon you seeing it happen? */
1556                 makeknown(otmp->otyp);
1557                 break;
1558         case WAN_CANCELLATION:
1559         case SPE_CANCELLATION:
1560                 cancel_item(obj);
1561 #ifdef TEXTCOLOR
1562                 newsym(obj->ox,obj->oy);        /* might change color */
1563 #endif
1564                 break;
1565         case SPE_DRAIN_LIFE:
1566                 (void) drain_item(obj);
1567                 break;
1568         case WAN_TELEPORTATION:
1569         case SPE_TELEPORT_AWAY:
1570                 rloco(obj);
1571                 break;
1572         case WAN_MAKE_INVISIBLE:
1573 #ifdef INVISIBLE_OBJECTS
1574                 obj->oinvis = TRUE;
1575                 newsym(obj->ox,obj->oy);        /* make object disappear */
1576 #endif
1577                 break;
1578         case WAN_UNDEAD_TURNING:
1579         case SPE_TURN_UNDEAD:
1580                 if (obj->otyp == EGG)
1581                         revive_egg(obj);
1582                 else
1583                         res = !!revive(obj);
1584                 break;
1585         case WAN_OPENING:
1586         case SPE_KNOCK:
1587         case WAN_LOCKING:
1588         case SPE_WIZARD_LOCK:
1589                 if(Is_box(obj))
1590                         res = boxlock(obj, otmp);
1591                 else
1592                         res = 0;
1593                 if (res /* && otmp->oclass == WAND_CLASS */)
1594                         makeknown(otmp->otyp);
1595                 break;
1596         case WAN_SLOW_MONSTER:          /* no effect on objects */
1597         case SPE_SLOW_MONSTER:
1598         case WAN_SPEED_MONSTER:
1599         case WAN_NOTHING:
1600         case SPE_HEALING:
1601         case SPE_EXTRA_HEALING:
1602                 res = 0;
1603                 break;
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) {
1608                     res = 0;
1609                     break;
1610                 }
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);
1616                             goto smell;
1617                         } else if (obj->otyp == STATUE) {
1618                             xchar oox, ooy;
1619
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);
1625                                 goto smell;
1626                             }
1627                             if (!animate_statue(obj, oox, ooy,
1628                                                 ANIMATE_SPELL, (int *)0)) {
1629                                 struct obj *item;
1630 makecorpse:                     if (mons[obj->corpsenm].geno &
1631                                                         (G_NOCORPSE|G_UNIQ)) {
1632                                     res = 0;
1633                                     break;
1634                                 }
1635                                 /* Unlikely to get here since genociding
1636                                  * monsters also sets the G_NOCORPSE flag.
1637                                  * Drop the contents, poly_obj looses them.
1638                                  */
1639                                 while ((item = obj->cobj) != 0) {
1640                                     obj_extract_self(item);
1641                                     place_object(item, oox, ooy);
1642                                 }
1643                                 obj = poly_obj(obj, CORPSE);
1644                                 break;
1645                             }
1646                         } else { /* new rock class object... */
1647                             /* impossible? */
1648                             res = 0;
1649                         }
1650                         break;
1651                     case TOOL_CLASS:    /* figurine */
1652                     {
1653                         struct monst *mon;
1654                         xchar oox, ooy;
1655
1656                         if (obj->otyp != FIGURINE) {
1657                             res = 0;
1658                             break;
1659                         }
1660                         if (vegetarian(&mons[obj->corpsenm])) {
1661                             /* Don't animate monsters that aren't flesh */
1662                             obj = poly_obj(obj, MEATBALL);
1663                             goto smell;
1664                         }
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);
1669                         if (mon) {
1670                             delobj(obj);
1671                             if (cansee(mon->mx, mon->my))
1672                                 pline_The("figurine animates!");
1673                             break;
1674                         }
1675                         goto makecorpse;
1676                     }
1677                     /* maybe add weird things to become? */
1678                     case RING_CLASS:    /* some of the rings are stone */
1679                         obj = poly_obj(obj, MEAT_RING);
1680                         goto smell;
1681                     case WAND_CLASS:    /* marble wand */
1682                         obj = poly_obj(obj, MEAT_STICK);
1683                         goto smell;
1684                     case GEM_CLASS:     /* rocks & gems */
1685                         obj = poly_obj(obj, MEATBALL);
1686 smell:
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.");
1691                         else
1692                             Norep("You smell a delicious smell.");
1693                         break;
1694                     case WEAPON_CLASS:  /* crysknife */
1695                         /* fall through */
1696                     default:
1697                         res = 0;
1698                         break;
1699                 }
1700                 newsym(refresh_x, refresh_y);
1701                 break;
1702         default:
1703                 impossible("What an interesting effect (%d)", otmp->otyp);
1704                 break;
1705         }
1706         return res;
1707 }
1708
1709 /* returns nonzero if something was hit */
1710 int
1711 bhitpile(obj,fhito,tx,ty)
1712     struct obj *obj;
1713     int FDECL((*fhito), (OBJ_P,OBJ_P));
1714     int tx, ty;
1715 {
1716     int hitanything = 0;
1717     register struct obj *otmp, *next_obj;
1718
1719     if (obj->otyp == SPE_FORCE_BOLT || obj->otyp == WAN_STRIKING) {
1720         struct trap *t = t_at(tx, ty);
1721
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);
1730     }
1731
1732     poly_zapped = -1;
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);
1737     }
1738     if(poly_zapped >= 0)
1739         create_polymon(level.objects[tx][ty], poly_zapped);
1740
1741     return hitanything;
1742 }
1743 #endif /*OVLB*/
1744 #ifdef OVL1
1745
1746 /*
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
1750  */
1751 int
1752 zappable(wand)
1753 register struct obj *wand;
1754 {
1755         if(wand->spe < 0 || (wand->spe == 0 && rn2(121)))
1756                 return 0;
1757         if(wand->spe == 0)
1758                 You("wrest one last charge from the worn-out wand.");
1759         wand->spe--;
1760         return 1;
1761 }
1762
1763 /*
1764  * zapnodir - zaps a NODIR wand/spell.
1765  * added by GAN 11/03/86
1766  */
1767 void
1768 zapnodir(obj)
1769 register struct obj *obj;
1770 {
1771         boolean known = FALSE;
1772
1773         switch(obj->otyp) {
1774                 case WAN_LIGHT:
1775                 case SPE_LIGHT:
1776                         litroom(TRUE,obj);
1777                         if (!Blind) known = TRUE;
1778                         break;
1779                 case WAN_SECRET_DOOR_DETECTION:
1780                 case SPE_DETECT_UNSEEN:
1781                         if(!findit()) return;
1782                         if (!Blind) known = TRUE;
1783                         break;
1784                 case WAN_CREATE_MONSTER:
1785                         known = create_critters(rn2(23) ? 1 : rn1(7,2),
1786                                         (struct permonst *)0);
1787                         break;
1788                 case WAN_WISHING:
1789                         known = TRUE;
1790                         if(Luck + rn2(5) < 0) {
1791                                 pline("Unfortunately, nothing happens.");
1792                                 break;
1793                         }
1794                         makewish();
1795                         break;
1796                 case WAN_ENLIGHTENMENT:
1797                         known = TRUE;
1798                         You_feel("self-knowledgeable...");
1799                         display_nhwindow(WIN_MESSAGE, FALSE);
1800                         enlightenment(FALSE);
1801                         pline_The("feeling subsides.");
1802                         exercise(A_WIS, TRUE);
1803                         break;
1804         }
1805         if (known && !objects[obj->otyp].oc_name_known) {
1806                 makeknown(obj->otyp);
1807                 more_experienced(0,10);
1808         }
1809 }
1810 #endif /*OVL1*/
1811 #ifdef OVL0
1812
1813 STATIC_OVL void
1814 backfire(otmp)
1815 struct obj *otmp;
1816 {
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);
1820         useup(otmp);
1821 }
1822
1823 static NEARDATA const char zap_syms[] = { WAND_CLASS, 0 };
1824
1825 int
1826 dozap()
1827 {
1828         register struct obj *obj;
1829         int     damage;
1830
1831         if(check_capacity((char *)0)) return(0);
1832         obj = getobj(zap_syms, "zap");
1833         if(!obj) return(0);
1834
1835         check_unpaid(obj);
1836
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);
1842                 return(1);
1843         } else if(!(objects[obj->otyp].oc_dir == NODIR) && !getdir((char *)0)) {
1844                 if (!Blind)
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) {
1849                 char buf[BUFSZ];
1850                 Sprintf(buf, "zapped %sself with a wand", uhim());
1851                 losehp(damage, buf, NO_KILLER_PREFIX);
1852             }
1853         } else {
1854
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)
1860                  */
1861                 current_wand = obj;
1862                 weffects(obj);
1863                 obj = current_wand;
1864                 current_wand = 0;
1865         }
1866         if (obj && obj->spe < 0) {
1867             pline("%s to dust.", Tobjnam(obj, "turn"));
1868             useup(obj);
1869         }
1870         update_inventory();     /* maybe used a charge */
1871         return(1);
1872 }
1873
1874 int
1875 zapyourself(obj, ordinary)
1876 struct obj *obj;
1877 boolean ordinary;
1878 {
1879         int     damage = 0;
1880         char buf[BUFSZ];
1881
1882         switch(obj->otyp) {
1883                 case WAN_STRIKING:
1884                     makeknown(WAN_STRIKING);
1885                 case SPE_FORCE_BOLT:
1886                     if(Antimagic) {
1887                         shieldeff(u.ux, u.uy);
1888                         pline("Boing!");
1889                     } else {
1890                         if (ordinary) {
1891                             You("bash yourself!");
1892                             damage = d(2,12);
1893                         } else
1894                             damage = d(1 + obj->spe,6);
1895                         exercise(A_STR, FALSE);
1896                     }
1897                     break;
1898
1899                 case WAN_LIGHTNING:
1900                     makeknown(WAN_LIGHTNING);
1901                     if (!Shock_resistance) {
1902                         You("shock yourself!");
1903                         damage = d(12,6);
1904                         exercise(A_CON, FALSE);
1905                     } else {
1906                         shieldeff(u.ux, u.uy);
1907                         You("zap yourself, but seem unharmed.");
1908                         ugolemeffects(AD_ELEC, d(12,6));
1909                     }
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);
1916                     }
1917                     break;
1918
1919                 case SPE_FIREBALL:
1920                     You("explode a fireball on top of yourself!");
1921                     explode(u.ux, u.uy, 11, d(6,6), WAND_CLASS, EXPL_FIERY);
1922                     break;
1923                 case WAN_FIRE:
1924                     makeknown(WAN_FIRE);
1925                 case FIRE_HORN:
1926                     if (Fire_resistance) {
1927                         shieldeff(u.ux, u.uy);
1928                         You_feel("rather warm.");
1929                         ugolemeffects(AD_FIRE, d(12,6));
1930                     } else {
1931                         pline("You've set yourself afire!");
1932                         damage = d(12,6);
1933                     }
1934                     burn_away_slime();
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);
1939                     break;
1940
1941                 case WAN_COLD:
1942                     makeknown(WAN_COLD);
1943                 case SPE_CONE_OF_COLD:
1944                 case FROST_HORN:
1945                     if (Cold_resistance) {
1946                         shieldeff(u.ux, u.uy);
1947                         You_feel("a little chill.");
1948                         ugolemeffects(AD_COLD, d(12,6));
1949                     } else {
1950                         You("imitate a popsicle!");
1951                         damage = d(12,6);
1952                     }
1953                     destroy_item(POTION_CLASS, AD_COLD);
1954                     break;
1955
1956                 case WAN_MAGIC_MISSILE:
1957                     makeknown(WAN_MAGIC_MISSILE);
1958                 case SPE_MAGIC_MISSILE:
1959                     if(Antimagic) {
1960                         shieldeff(u.ux, u.uy);
1961                         pline_The("missiles bounce!");
1962                     } else {
1963                         damage = d(4,6);
1964                         pline("Idiot!  You've shot yourself!");
1965                     }
1966                     break;
1967
1968                 case WAN_POLYMORPH:
1969                     if (!Unchanging)
1970                         makeknown(WAN_POLYMORPH);
1971                 case SPE_POLYMORPH:
1972                     if (!Unchanging)
1973                         polyself(FALSE);
1974                     break;
1975
1976                 case WAN_CANCELLATION:
1977                 case SPE_CANCELLATION:
1978                     (void) cancel_monst(&youmonst, obj, TRUE, FALSE, TRUE);
1979                     break;
1980
1981                 case SPE_DRAIN_LIFE:
1982                         if (!Drain_resistance) {
1983                                 losexp("life drainage");
1984                                 makeknown(obj->otyp);
1985                         }
1986                         damage = 0;     /* No additional damage */
1987                         break;
1988
1989                 case WAN_MAKE_INVISIBLE: {
1990                     /* have to test before changing HInvis but must change
1991                      * HInvis before doing newsym().
1992                      */
1993                     int msg = !Invis && !Blind && !BInvis;
1994
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));
1998                         break;
1999                     }
2000                     if (ordinary || !rn2(10)) { /* permanent */
2001                         HInvis |= FROMOUTSIDE;
2002                     } else {                    /* temporary */
2003                         incr_itimeout(&HInvis, d(obj->spe, 250));
2004                     }
2005                     if (msg) {
2006                         makeknown(WAN_MAKE_INVISIBLE);
2007                         newsym(u.ux, u.uy);
2008                         self_invis_message();
2009                     }
2010                     break;
2011                 }
2012
2013                 case WAN_SPEED_MONSTER:
2014                     if (!(HFast & INTRINSIC)) {
2015                         if (!Fast)
2016                             You("speed up.");
2017                         else
2018                             Your("quickness feels more natural.");
2019                         makeknown(WAN_SPEED_MONSTER);
2020                         exercise(A_DEX, TRUE);
2021                     }
2022                     HFast |= FROMOUTSIDE;
2023                     break;
2024
2025                 case WAN_SLEEP:
2026                     makeknown(WAN_SLEEP);
2027                 case SPE_SLEEP:
2028                     if(Sleep_resistance) {
2029                         shieldeff(u.ux, u.uy);
2030                         You("don't feel sleepy!");
2031                     } else {
2032                         pline_The("sleep ray hits you!");
2033                         fall_asleep(-rnd(50), TRUE);
2034                     }
2035                     break;
2036
2037                 case WAN_SLOW_MONSTER:
2038                 case SPE_SLOW_MONSTER:
2039                     if(HFast & (TIMEOUT | INTRINSIC)) {
2040                         u_slow_down();
2041                         makeknown(obj->otyp);
2042                     }
2043                     break;
2044
2045                 case WAN_TELEPORTATION:
2046                 case SPE_TELEPORT_AWAY:
2047                     tele();
2048                     break;
2049
2050                 case WAN_DEATH:
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.");
2056                         break;
2057                     }
2058                     Sprintf(buf, "shot %sself with a death ray", uhim());
2059                     killer = buf;
2060                     killer_format = NO_KILLER_PREFIX;
2061                     You("irradiate yourself with pure energy!");
2062                     You("die.");
2063                     makeknown(obj->otyp);
2064                         /* They might survive with an amulet of life saving */
2065                     done(DIED);
2066                     break;
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);
2075                     } else
2076                         You("shudder in dread.");
2077                     break;
2078                 case SPE_HEALING:
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 " : "");
2084                     break;
2085                 case WAN_LIGHT: /* (broken wand) */
2086                  /* assert( !ordinary ); */
2087                     damage = d(obj->spe, 25);
2088 #ifdef TOURIST
2089                 case EXPENSIVE_CAMERA:
2090 #endif
2091                     damage += rnd(25);
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);
2097                     }
2098                     damage = 0; /* reset */
2099                     break;
2100                 case WAN_OPENING:
2101                     if (Punished) makeknown(WAN_OPENING);
2102                 case SPE_KNOCK:
2103                     if (Punished) Your("chain quivers for a moment.");
2104                     break;
2105                 case WAN_DIGGING:
2106                 case SPE_DIG:
2107                 case SPE_DETECT_UNSEEN:
2108                 case WAN_NOTHING:
2109                 case WAN_LOCKING:
2110                 case SPE_WIZARD_LOCK:
2111                     break;
2112                 case WAN_PROBING:
2113                     for (obj = invent; obj; obj = obj->nobj)
2114                         obj->dknown = 1;
2115                     /* note: `obj' reused; doesn't point at wand anymore */
2116                     makeknown(WAN_PROBING);
2117                     ustatusline();
2118                     break;
2119                 case SPE_STONE_TO_FLESH:
2120                     {
2121                     struct obj *otemp, *onext;
2122                     boolean didmerge;
2123
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);
2131                         }
2132                     /*
2133                      * It is possible that we can now merge some inventory.
2134                      * Do a higly paranoid merge.  Restart from the beginning
2135                      * until no merges.
2136                      */
2137                     do {
2138                         didmerge = FALSE;
2139                         for (otemp = invent; !didmerge && otemp; otemp = otemp->nobj)
2140                             for (onext = otemp->nobj; onext; onext = onext->nobj)
2141                                 if (merged(&otemp, &onext)) {
2142                                         didmerge = TRUE;
2143                                         break;
2144                                         }
2145                     } while (didmerge);
2146                     }
2147                     break;
2148                 default: impossible("object %d used?",obj->otyp);
2149                     break;
2150         }
2151         return(damage);
2152 }
2153
2154 #ifdef STEED
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.
2158  */
2159 STATIC_OVL boolean
2160 zap_steed(obj)
2161 struct obj *obj;        /* wand or spell */
2162 {
2163         int steedhit = FALSE;
2164         
2165         switch (obj->otyp) {
2166
2167            /*
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.
2171             */
2172                 case WAN_PROBING:
2173                     probe_monster(u.usteed);
2174                     makeknown(WAN_PROBING);
2175                     steedhit = TRUE;
2176                     break;
2177                 case WAN_TELEPORTATION:
2178                 case SPE_TELEPORT_AWAY:
2179                     /* you go together */
2180                     tele();
2181                     if(Teleport_control || !couldsee(u.ux0, u.uy0) ||
2182                         (distu(u.ux0, u.uy0) >= 16))
2183                                 makeknown(obj->otyp);
2184                     steedhit = TRUE;
2185                     break;
2186
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:
2192                 case WAN_POLYMORPH:
2193                 case SPE_POLYMORPH:
2194                 case WAN_STRIKING:
2195                 case SPE_FORCE_BOLT:
2196                 case WAN_SLOW_MONSTER:
2197                 case SPE_SLOW_MONSTER:
2198                 case WAN_SPEED_MONSTER:
2199                 case SPE_HEALING:
2200                 case SPE_EXTRA_HEALING:
2201                 case SPE_DRAIN_LIFE:
2202                 case WAN_OPENING:
2203                 case SPE_KNOCK:
2204                     (void) bhitm(u.usteed, obj);
2205                     steedhit = TRUE;
2206                     break;
2207
2208                 default:
2209                     steedhit = FALSE;
2210                     break;
2211         }
2212         return steedhit;
2213 }
2214 #endif
2215
2216 #endif /*OVL0*/
2217 #ifdef OVL3
2218
2219 /*
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.
2224  */
2225 boolean
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;
2230 {
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 */
2235
2236         if (youdefend ? (!youattack && Antimagic)
2237                       : resist(mdef, obj->oclass, 0, NOTELL))
2238                 return FALSE;   /* resisted cancellation */
2239
2240         if (self_cancel) {      /* 1st cancel inventory */
2241             struct obj *otmp;
2242
2243             for (otmp = (youdefend ? invent : mdef->minvent);
2244                             otmp; otmp = otmp->nobj)
2245                 cancel_item(otmp);
2246             if (youdefend) {
2247                 flags.botl = 1; /* potential AC change */
2248                 find_ac();
2249             }
2250         }
2251
2252         /* now handle special cases */
2253         if (youdefend) {
2254             if (Upolyd) {
2255                 if ((u.umonnum == PM_CLAY_GOLEM) && !Blind)
2256                     pline(writing_vanishes, your);
2257
2258                 if (Unchanging)
2259                     Your("amulet grows hot for a moment, then cools.");
2260                 else
2261                     rehumanize();
2262             }
2263         } else {
2264             mdef->mcan = TRUE;
2265
2266             if (is_were(mdef->data) && mdef->data->mlet != S_HUMAN)
2267                 were_change(mdef);
2268
2269             if (mdef->data == &mons[PM_CLAY_GOLEM]) {
2270                 if (canseemon(mdef))
2271                     pline(writing_vanishes, s_suffix(mon_nam(mdef)));
2272
2273                 if (allow_cancel_kill) {
2274                     if (youattack)
2275                         killed(mdef);
2276                     else
2277                         monkilled(mdef, "", AD_SPEL);
2278                 }
2279             }
2280         }
2281         return TRUE;
2282 }
2283
2284 /* you've zapped an immediate type wand up or down */
2285 STATIC_OVL boolean
2286 zap_updown(obj)
2287 struct obj *obj;        /* wand or spell */
2288 {
2289         boolean striking = FALSE, disclose = FALSE;
2290         int x, y, xx, yy, ptmp;
2291         struct obj *otmp;
2292         struct engr *e;
2293         struct trap *ttmp;
2294         char buf[BUFSZ];
2295
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 */
2301
2302         switch (obj->otyp) {
2303         case WAN_PROBING:
2304             ptmp = 0;
2305             if (u.dz < 0) {
2306                 You("probe towards the %s.", ceiling(x,y));
2307             } else {
2308                 ptmp += bhitpile(obj, bhito, x, y);
2309                 You("probe beneath the %s.", surface(x,y));
2310                 ptmp += display_binventory(x, y, TRUE);
2311             }
2312             if (!ptmp) Your("probe reveals nothing.");
2313             return TRUE;        /* we've done our own bhitpile */
2314         case WAN_OPENING:
2315         case SPE_KNOCK:
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);
2319                 disclose = TRUE;
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.");
2325                 disclose = TRUE;
2326             }
2327             break;
2328         case WAN_STRIKING:
2329         case SPE_FORCE_BOLT:
2330             striking = TRUE;
2331             /*FALLTHRU*/
2332         case WAN_LOCKING:
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)) {
2338                 if (!striking)
2339                     close_drawbridge(xx, yy);
2340                 else
2341                     destroy_drawbridge(xx, yy);
2342                 disclose = TRUE;
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 */
2353                     stackobj(otmp);
2354                 }
2355                 newsym(x, y);
2356             } else if (!striking && ttmp && ttmp->ttyp == TRAPDOOR && u.dz > 0) {
2357                 if (!Blind) {
2358                         if (ttmp->tseen) {
2359                                 pline("A trap door beneath you closes up then vanishes.");
2360                                 disclose = TRUE;
2361                         } else {
2362                                 You("see a swirl of %s beneath you.",
2363                                         is_ice(x,y) ? "frost" : "dust");
2364                         }
2365                 } else {
2366                         You_hear("a twang followed by a thud.");
2367                 }
2368                 deltrap(ttmp);
2369                 ttmp = (struct trap *)0;
2370                 newsym(x, y);
2371             }
2372             break;
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)) {
2380                 /*
2381                 Print this message only if there wasn't an engraving
2382                 affected here.  If water or ice, act like waterlevel case.
2383                 */
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);
2388                     else
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)));
2393                 }
2394             }
2395             break;
2396         default:
2397             break;
2398         }
2399
2400         if (u.dz > 0) {
2401             /* zapping downward */
2402             (void) bhitpile(obj, bhito, x, y);
2403
2404             /* subset of engraving effects; none sets `disclose' */
2405             if ((e = engr_at(x, y)) != 0 && e->engr_type != HEADSTONE) {
2406                 switch (obj->otyp) {
2407                 case WAN_POLYMORPH:
2408                 case SPE_POLYMORPH:
2409                     del_engr(e);
2410                     make_engr_at(x, y, random_engraving(buf), moves, (xchar)0);
2411                     break;
2412                 case WAN_CANCELLATION:
2413                 case SPE_CANCELLATION:
2414                 case WAN_MAKE_INVISIBLE:
2415                     del_engr(e);
2416                     break;
2417                 case WAN_TELEPORTATION:
2418                 case SPE_TELEPORT_AWAY:
2419                     rloc_engr(e);
2420                     break;
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));
2428                         }
2429                     break;
2430                 case WAN_STRIKING:
2431                 case SPE_FORCE_BOLT:
2432                     wipe_engr_at(x, y, d(2,4));
2433                     break;
2434                 default:
2435                     break;
2436                 }
2437             }
2438         }
2439
2440         return disclose;
2441 }
2442
2443 #endif /*OVL3*/
2444 #ifdef OVLB
2445
2446 /* called for various wand and spell effects - M. Stephenson */
2447 void
2448 weffects(obj)
2449 register struct obj     *obj;
2450 {
2451         int otyp = obj->otyp;
2452         boolean disclose = FALSE, was_unkn = !objects[otyp].oc_name_known;
2453
2454         exercise(A_WIS, TRUE);
2455 #ifdef STEED
2456         if (u.usteed && (objects[otyp].oc_dir != NODIR) &&
2457             !u.dx && !u.dy && (u.dz > 0) && zap_steed(obj)) {
2458                 disclose = TRUE;
2459         } else
2460 #endif
2461         if (objects[otyp].oc_dir == IMMEDIATE) {
2462             obj_zapped = FALSE;
2463
2464             if (u.uswallow) {
2465                 (void) bhitm(u.ustuck, obj);
2466                 /* [how about `bhitpile(u.ustuck->minvent)' effect?] */
2467             } else if (u.dz) {
2468                 disclose = zap_updown(obj);
2469             } else {
2470                 (void) bhit(u.dx,u.dy, rn1(8,6),ZAPPED_WAND, bhitm,bhito, obj);
2471             }
2472             /* give a clue if obj_zapped */
2473             if (obj_zapped)
2474                 You_feel("shuddering vibrations.");
2475
2476         } else if (objects[otyp].oc_dir == NODIR) {
2477             zapnodir(obj);
2478
2479         } else {
2480             /* neither immediate nor directionless */
2481
2482             if (otyp == WAN_DIGGING || otyp == SPE_DIG)
2483                 zap_dig();
2484             else if (otyp >= SPE_MAGIC_MISSILE && otyp <= SPE_FINGER_OF_DEATH)
2485                 buzz(otyp - SPE_MAGIC_MISSILE + 10,
2486                      u.ulevel / 2 + 1,
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);
2492             else
2493                 impossible("weffects: unexpected spell or wand");
2494             disclose = TRUE;
2495         }
2496         if (disclose && was_unkn) {
2497             makeknown(otyp);
2498             more_experienced(0,10);
2499         }
2500         return;
2501 }
2502 #endif /*OVLB*/
2503 #ifdef OVL0
2504
2505 /*
2506  * Generate the to damage bonus for a spell. Based on the hero's intelligence
2507  */
2508 int
2509 spell_damage_bonus()
2510 {
2511     int tmp, intell = ACURR(A_INT);
2512
2513     /* Punish low intellegence before low level else low intellegence
2514        gets punished only when high level */
2515     if (intell < 10)
2516         tmp = -3;
2517     else if (u.ulevel < 5)
2518         tmp = 0;
2519     else if (intell < 14)
2520         tmp = 0;
2521     else if (intell <= 18)
2522         tmp = 1;
2523     else                /* helm of brilliance */
2524         tmp = 2;
2525
2526     return tmp;
2527 }
2528
2529 /*
2530  * Generate the to hit bonus for a spell.  Based on the hero's skill in
2531  * spell class and dexterity.
2532  */
2533 STATIC_OVL int
2534 spell_hit_bonus(skill)
2535 int skill;
2536 {
2537     int hit_bon = 0;
2538     int dex = ACURR(A_DEX);
2539
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;
2546     }
2547
2548     if (dex < 4)
2549         hit_bon -= 3;
2550     else if (dex < 6)
2551         hit_bon -= 2;
2552     else if (dex < 8)
2553         hit_bon -= 1;
2554     else if (dex < 14)
2555         hit_bon -= 0;           /* Will change when print stuff below removed */
2556     else
2557         hit_bon += dex - 14; /* Even increment for dextrous heroes (see weapon.c abon) */
2558
2559     return hit_bon;
2560 }
2561
2562 const char *
2563 exclam(force)
2564 register int force;
2565 {
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) ? "." : "!");
2570 }
2571
2572 void
2573 hit(str,mtmp,force)
2574 register const char *str;
2575 register struct monst *mtmp;
2576 register const char *force;             /* usually either "." or "!" */
2577 {
2578         if((!cansee(bhitpos.x,bhitpos.y) && !canspotmon(mtmp) &&
2579              !(u.uswallow && mtmp == u.ustuck))
2580            || !flags.verbose)
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);
2584 }
2585
2586 void
2587 miss(str,mtmp)
2588 register const char *str;
2589 register struct monst *mtmp;
2590 {
2591         pline("%s %s %s.", The(str), vtense(str, "miss"),
2592               ((cansee(bhitpos.x,bhitpos.y) || canspotmon(mtmp))
2593                && flags.verbose) ?
2594               mon_nam(mtmp) : "it");
2595 }
2596 #endif /*OVL0*/
2597 #ifdef OVL1
2598
2599 /*
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.
2611  *
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().
2616  */
2617 struct monst *
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 */
2624 {
2625         struct monst *mtmp;
2626         uchar typ;
2627         boolean shopdoor = FALSE, point_blank = TRUE;
2628
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;
2633             range--;
2634         } else {
2635             bhitpos.x = u.ux;
2636             bhitpos.y = u.uy;
2637         }
2638
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));
2643
2644         while(range-- > 0) {
2645             int x,y;
2646
2647             bhitpos.x += ddx;
2648             bhitpos.y += ddy;
2649             x = bhitpos.x; y = bhitpos.y;
2650
2651             if(!isok(x, y)) {
2652                 bhitpos.x -= ddx;
2653                 bhitpos.y -= ddy;
2654                 break;
2655             }
2656
2657             if(is_pick(obj) && inside_shop(x, y) &&
2658                                            (mtmp = shkcatch(obj, x, y))) {
2659                 tmp_at(DISP_END, 0);
2660                 return(mtmp);
2661             }
2662
2663             typ = levl[bhitpos.x][bhitpos.y].typ;
2664
2665             /* iron bars will block anything big enough */
2666             if ((weapon == THROWN_WEAPON || weapon == KICKED_WEAPON) &&
2667                     typ == IRONBARS &&
2668                     hits_bars(&obj, x - ddx, y - ddy,
2669                               point_blank ? 0 : !rn2(5), 1)) {
2670                 /* caveat: obj might now be null... */
2671                 bhitpos.x -= ddx;
2672                 bhitpos.y -= ddy;
2673                 break;
2674             }
2675
2676             if (weapon == ZAPPED_WAND && find_drawbridge(&x,&y))
2677                 switch (obj->otyp) {
2678                     case WAN_OPENING:
2679                     case SPE_KNOCK:
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);
2684                         }
2685                         break;
2686                     case WAN_LOCKING:
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);
2692                         break;
2693                     case WAN_STRIKING:
2694                     case SPE_FORCE_BOLT:
2695                         if (typ != DRAWBRIDGE_UP)
2696                             destroy_drawbridge(x,y);
2697                         makeknown(obj->otyp);
2698                         break;
2699                 }
2700
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);
2710                                     return(mtmp);
2711                                 }
2712                             } else
2713                                 return(mtmp);
2714                         }
2715                         if (weapon != INVIS_BEAM) {
2716                             (*fhitm)(mtmp, obj);
2717                             range -= 3;
2718                         }
2719                 } else {
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.*/
2728                     if (mtmp->minvis) {
2729                         obj->ox = u.ux,  obj->oy = u.uy;
2730                         (void) flash_hits_mon(mtmp, obj);
2731                     } else {
2732                         tmp_at(DISP_END, 0);
2733                         return(mtmp);   /* caller will call flash_hits_mon */
2734                     }
2735                 }
2736             } else {
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);
2740                     newsym(x, y);
2741                 }
2742             }
2743             if(fhito) {
2744                 if(bhitpile(obj,fhito,bhitpos.x,bhitpos.y))
2745                     range--;
2746             } else {
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;
2754                 }
2755             }
2756             if(weapon == ZAPPED_WAND && (IS_DOOR(typ) || typ == SDOOR)) {
2757                 switch (obj->otyp) {
2758                 case WAN_OPENING:
2759                 case WAN_LOCKING:
2760                 case WAN_STRIKING:
2761                 case SPE_KNOCK:
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)) {
2770                             shopdoor = TRUE;
2771                             add_damage(bhitpos.x, bhitpos.y, 400L);
2772                         }
2773                     }
2774                     break;
2775                 }
2776             }
2777             if(!ZAP_POS(typ) || closed_door(bhitpos.x, bhitpos.y)) {
2778                 bhitpos.x -= ddx;
2779                 bhitpos.y -= ddy;
2780                 break;
2781             }
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)
2786                         && cansee(x, y)) {
2787                     unmap_object(bhitpos.x, bhitpos.y);
2788                     newsym(x, y);
2789                 }
2790                 tmp_at(bhitpos.x, bhitpos.y);
2791                 delay_output();
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)))
2796                     break;
2797 #ifdef SINKS
2798                 if(IS_SINK(typ) && weapon != FLASHED_LIGHT)
2799                     break;      /* physical objects fall onto sink */
2800 #endif
2801             }
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) {
2805                 struct obj *bobj;
2806                 struct trap *t;
2807                 if ((bobj = sobj_at(BOULDER, x, y)) != 0) {
2808                     if (cansee(x,y))
2809                         pline("%s hits %s.",
2810                               The(distant_name(obj, xname)), an(xname(bobj)));
2811                     range = 0;
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 */
2815                         if (cansee(x,y))
2816                             pline("%s jerks to an abrupt halt.",
2817                                   The(distant_name(obj, xname))); /* lame */
2818                         range = 0;
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 */
2823                         range = 0;
2824                     }
2825                 }
2826             }
2827
2828             /* thrown/kicked missile has moved away from its starting spot */
2829             point_blank = FALSE;        /* affects passing through iron bars */
2830         }
2831
2832         if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM) tmp_at(DISP_END, 0);
2833
2834         if(shopdoor)
2835             pay_for_damage("destroy", FALSE);
2836
2837         return (struct monst *)0;
2838 }
2839
2840 struct monst *
2841 boomhit(dx, dy)
2842 int dx, dy;
2843 {
2844         register int i, ct;
2845         int boom = S_boomleft;  /* showsym[] index  */
2846         struct monst *mtmp;
2847
2848         bhitpos.x = u.ux;
2849         bhitpos.y = u.uy;
2850
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++) {
2854                 if(i == 8) i = 0;
2855                 boom = (boom == S_boomleft) ? S_boomright : S_boomleft;
2856                 tmp_at(DISP_CHANGE, cmap_to_glyph(boom));/* change glyph */
2857                 dx = xdir[i];
2858                 dy = ydir[i];
2859                 bhitpos.x += dx;
2860                 bhitpos.y += dy;
2861                 if(MON_AT(bhitpos.x, bhitpos.y)) {
2862                         mtmp = m_at(bhitpos.x,bhitpos.y);
2863                         m_respond(mtmp);
2864                         tmp_at(DISP_END, 0);
2865                         return(mtmp);
2866                 }
2867                 if(!ZAP_POS(levl[bhitpos.x][bhitpos.y].typ) ||
2868                    closed_door(bhitpos.x, bhitpos.y)) {
2869                         bhitpos.x -= dx;
2870                         bhitpos.y -= dy;
2871                         break;
2872                 }
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,
2877                                         "boomerang");
2878                                 break;
2879                         } else {        /* we catch it */
2880                                 tmp_at(DISP_END, 0);
2881                                 You("skillfully catch the boomerang.");
2882                                 return(&youmonst);
2883                         }
2884                 }
2885                 tmp_at(bhitpos.x, bhitpos.y);
2886                 delay_output();
2887                 if(ct % 5 != 0) i++;
2888 #ifdef SINKS
2889                 if(IS_SINK(levl[bhitpos.x][bhitpos.y].typ))
2890                         break;  /* boomerang falls on sink */
2891 #endif
2892         }
2893         tmp_at(DISP_END, 0);    /* do not leave last symbol */
2894         return (struct monst *)0;
2895 }
2896
2897 STATIC_OVL int
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 */
2902 {
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! */
2907
2908         *ootmp = (struct obj *)0;
2909         switch(abstype) {
2910         case ZT_MAGIC_MISSILE:
2911                 if (resists_magm(mon)) {
2912                     sho_shieldeff = TRUE;
2913                     break;
2914                 }
2915                 tmp = d(nd,6);
2916                 if (spellcaster)
2917                     tmp += spell_damage_bonus();
2918 #ifdef WIZ_PATCH_DEBUG
2919                 if (spellcaster)
2920                     pline("Damage = %d + %d", tmp-spell_damage_bonus(),
2921                         spell_damage_bonus());
2922 #endif
2923                 break;
2924         case ZT_FIRE:
2925                 if (resists_fire(mon)) {
2926                     sho_shieldeff = TRUE;
2927                     break;
2928                 }
2929                 tmp = d(nd,6);
2930                 if (resists_cold(mon)) tmp += 7;
2931                 if (spellcaster)
2932                     tmp += spell_damage_bonus();
2933 #ifdef WIZ_PATCH_DEBUG
2934                 if (spellcaster)
2935                     pline("Damage = %d + %d",tmp-spell_damage_bonus(),
2936                         spell_damage_bonus());
2937 #endif
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);
2942                 }
2943                 break;
2944         case ZT_COLD:
2945                 if (resists_cold(mon)) {
2946                     sho_shieldeff = TRUE;
2947                     break;
2948                 }
2949                 tmp = d(nd,6);
2950                 if (resists_fire(mon)) tmp += d(nd, 3);
2951                 if (spellcaster)
2952                     tmp += spell_damage_bonus();
2953 #ifdef WIZ_PATCH_DEBUG
2954                 if (spellcaster)
2955                     pline("Damage = %d + %d", tmp-spell_damage_bonus(),
2956                         spell_damage_bonus());
2957 #endif
2958                 if (!rn2(3)) (void)destroy_mitem(mon, POTION_CLASS, AD_COLD);
2959                 break;
2960         case ZT_SLEEP:
2961                 tmp = 0;
2962                 (void)sleep_monst(mon, d(nd, 25),
2963                                 type == ZT_WAND(ZT_SLEEP) ? WAND_CLASS : '\0');
2964                 break;
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;
2972                         tmp = 0;
2973                         break;
2974                     }
2975                     if (nonliving(mon->data) || is_demon(mon->data) ||
2976                             resists_magm(mon)) {        /* similar to player */
2977                         sho_shieldeff = TRUE;
2978                         break;
2979                     }
2980                     type = -1; /* so they don't get saving throws */
2981                 } else {
2982                     struct obj *otmp2;
2983
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);
2994                     } else {
2995                         /* no body armor, victim dies; destroy cloak
2996                            and shirt now in case target gets life-saved */
2997                         tmp = MAGIC_COOKIE;
2998                         if ((otmp2 = which_armor(mon, W_ARMC)) != 0)
2999                             m_useup(mon, otmp2);
3000 #ifdef TOURIST
3001                         if ((otmp2 = which_armor(mon, W_ARMU)) != 0)
3002                             m_useup(mon, otmp2);
3003 #endif
3004                     }
3005                     type = -1;  /* no saving throw wanted */
3006                     break;      /* not ordinary damage */
3007                 }
3008                 tmp = mon->mhp+1;
3009                 break;
3010         case ZT_LIGHTNING:
3011                 if (resists_elec(mon)) {
3012                     sho_shieldeff = TRUE;
3013                     tmp = 0;
3014                     /* can still blind the monster */
3015                 } else
3016                     tmp = d(nd,6);
3017                 if (spellcaster)
3018                     tmp += spell_damage_bonus();
3019 #ifdef WIZ_PATCH_DEBUG
3020                 if (spellcaster)
3021                     pline("Damage = %d + %d", tmp-spell_damage_bonus(),
3022                         spell_damage_bonus());
3023 #endif
3024                 if (!resists_blnd(mon) &&
3025                                 !(type > 0 && u.uswallow && mon == u.ustuck)) {
3026                         register unsigned rnd_tmp = rnd(50);
3027                         mon->mcansee = 0;
3028                         if((mon->mblinded + rnd_tmp) > 127)
3029                                 mon->mblinded = 127;
3030                         else mon->mblinded += rnd_tmp;
3031                 }
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);
3035                 break;
3036         case ZT_POISON_GAS:
3037                 if (resists_poison(mon)) {
3038                     sho_shieldeff = TRUE;
3039                     break;
3040                 }
3041                 tmp = d(nd,6);
3042                 break;
3043         case ZT_ACID:
3044                 if (resists_acid(mon)) {
3045                     sho_shieldeff = TRUE;
3046                     break;
3047                 }
3048                 tmp = d(nd,6);
3049                 if (!rn2(6)) erode_obj(MON_WEP(mon), TRUE, TRUE);
3050                 if (!rn2(6)) erode_armor(mon, TRUE);
3051                 break;
3052         }
3053         if (sho_shieldeff) shieldeff(mon->mx, mon->my);
3054         if (is_hero_spell(type) && (Role_if(PM_KNIGHT) && u.uhave.questart))
3055             tmp *= 2;
3056         if (tmp > 0 && type >= 0 &&
3057                 resist(mon, type < ZT_SPELL(0) ? WAND_CLASS : '\0', 0, NOTELL))
3058             tmp /= 2;
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);
3062 #endif
3063         mon->mhp -= tmp;
3064         return(tmp);
3065 }
3066
3067 STATIC_OVL void
3068 zhitu(type, nd, fltxt, sx, sy)
3069 int type, nd;
3070 const char *fltxt;
3071 xchar sx, sy;
3072 {
3073         int dam = 0;
3074
3075         switch (abs(type) % 10) {
3076         case ZT_MAGIC_MISSILE:
3077             if (Antimagic) {
3078                 shieldeff(sx, sy);
3079                 pline_The("missiles bounce off!");
3080             } else {
3081                 dam = d(nd,6);
3082                 exercise(A_STR, FALSE);
3083             }
3084             break;
3085         case ZT_FIRE:
3086             if (Fire_resistance) {
3087                 shieldeff(sx, sy);
3088                 You("don't feel hot!");
3089                 ugolemeffects(AD_FIRE, d(nd, 6));
3090             } else {
3091                 dam = d(nd, 6);
3092             }
3093             burn_away_slime();
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);
3098             }
3099             break;
3100         case ZT_COLD:
3101             if (Cold_resistance) {
3102                 shieldeff(sx, sy);
3103                 You("don't feel cold.");
3104                 ugolemeffects(AD_COLD, d(nd, 6));
3105             } else {
3106                 dam = d(nd, 6);
3107             }
3108             if (!rn2(3)) destroy_item(POTION_CLASS, AD_COLD);
3109             break;
3110         case ZT_SLEEP:
3111             if (Sleep_resistance) {
3112                 shieldeff(u.ux, u.uy);
3113                 You("don't feel sleepy.");
3114             } else {
3115                 fall_asleep(-d(nd,25), TRUE); /* sleep ray */
3116             }
3117             break;
3118         case ZT_DEATH:
3119             if (abs(type) == ZT_BREATH(ZT_DEATH)) {
3120                 if (Disint_resistance) {
3121                     You("are not disintegrated.");
3122                     break;
3123                 } else if (uarms) {
3124                     /* destroy shield; other possessions are safe */
3125                     (void) destroy_arm(uarms);
3126                     break;
3127                 } else if (uarm) {
3128                     /* destroy suit; if present, cloak goes too */
3129                     if (uarmc) (void) destroy_arm(uarmc);
3130                     (void) destroy_arm(uarm);
3131                     break;
3132                 }
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);
3136 #ifdef TOURIST
3137                 if (uarmu) (void) destroy_arm(uarmu);
3138 #endif
3139             } else if (nonliving(youmonst.data) || is_demon(youmonst.data)) {
3140                 shieldeff(sx, sy);
3141                 You("seem unaffected.");
3142                 break;
3143             } else if (Antimagic) {
3144                 shieldeff(sx, sy);
3145                 You("aren't affected.");
3146                 break;
3147             }
3148             killer_format = KILLED_BY_AN;
3149             killer = fltxt;
3150             /* when killed by disintegration breath, don't leave corpse */
3151             u.ugrave_arise = (type == -ZT_BREATH(ZT_DEATH)) ? -3 : NON_PM;
3152             done(DIED);
3153             return; /* lifesaved */
3154         case ZT_LIGHTNING:
3155             if (Shock_resistance) {
3156                 shieldeff(sx, sy);
3157                 You("aren't affected.");
3158                 ugolemeffects(AD_ELEC, d(nd, 6));
3159             } else {
3160                 dam = d(nd, 6);
3161                 exercise(A_CON, FALSE);
3162             }
3163             if (!rn2(3)) destroy_item(WAND_CLASS, AD_ELEC);
3164             if (!rn2(3)) destroy_item(RING_CLASS, AD_ELEC);
3165             break;
3166         case ZT_POISON_GAS:
3167             poisoned("blast", A_DEX, "poisoned blast", 15);
3168             break;
3169         case ZT_ACID:
3170             if (Acid_resistance) {
3171                 dam = 0;
3172             } else {
3173                 pline_The("acid burns!");
3174                 dam = d(nd,6);
3175                 exercise(A_STR, FALSE);
3176             }
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);
3181             break;
3182         }
3183
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);
3188         return;
3189 }
3190
3191 #endif /*OVL1*/
3192 #ifdef OVLB
3193
3194 /*
3195  * burn scrolls and spellbooks on floor at position x,y
3196  * return the number of scrolls and spellbooks burned
3197  */
3198 int
3199 burn_floor_paper(x, y, give_feedback, u_caused)
3200 int x, y;
3201 boolean give_feedback;  /* caller needs to decide about visibility checks */
3202 boolean u_caused;
3203 {
3204         struct obj *obj, *obj2;
3205         long i, scrquan, delquan;
3206         char buf1[BUFSZ], buf2[BUFSZ];
3207         int cnt = 0;
3208
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))
3214                     continue;
3215                 scrquan = obj->quan;    /* number present */
3216                 delquan = 0;            /* number to destroy */
3217                 for (i = scrquan; i > 0; i--)
3218                     if (!rn2(3)) delquan++;
3219                 if (delquan) {
3220                     /* save name before potential delobj() */
3221                     if (give_feedback) {
3222                         obj->quan = 1;
3223                         Strcpy(buf1, (x == u.ux && y == u.uy) ?
3224                                 xname(obj) : distant_name(obj, xname));
3225                         obj->quan = 2;
3226                         Strcpy(buf2, (x == u.ux && y == u.uy) ?
3227                                 xname(obj) : distant_name(obj, xname));
3228                         obj->quan = scrquan;
3229                     }
3230                     /* useupf(), which charges, only if hero caused damage */
3231                     if (u_caused) useupf(obj, delquan);
3232                     else if (delquan < scrquan) obj->quan -= delquan;
3233                     else delobj(obj);
3234                     cnt += delquan;
3235                     if (give_feedback) {
3236                         if (delquan > 1)
3237                             pline("%ld %s burn.", delquan, buf2);
3238                         else
3239                             pline("%s burns.", An(buf1));
3240                     }
3241                 }
3242             }
3243         }
3244         return cnt;
3245 }
3246
3247 /* will zap/spell/breath attack score a hit against armor class `ac'? */
3248 STATIC_OVL int
3249 zap_hit(ac, type)
3250 int ac;
3251 int type;       /* either hero cast spell type or 0 */
3252 {
3253     int chance = rn2(20);
3254     int spell_bonus = type ? spell_hit_bonus(type) : 0;
3255
3256     /* small chance for naked target to avoid being hit */
3257     if (!chance) return rnd(10) < ac+spell_bonus;
3258
3259     /* very high armor protection does not achieve invulnerability */
3260     ac = AC_VALUE(ac);
3261
3262     return (3 - chance) < ac+spell_bonus;
3263 }
3264
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 */
3272 void
3273 buzz(type,nd,sx,sy,dx,dy)
3274 register int type, nd;
3275 register xchar sx,sy;
3276 register int dx,dy;
3277 {
3278     int range, abstype = abs(type) % 10;
3279     struct rm *lev;
3280     register xchar lsx, lsy;
3281     struct monst *mon;
3282     coord save_bhitpos;
3283     boolean shopdamage = FALSE;
3284     register const char *fltxt;
3285     struct obj *otmp;
3286     int spell_type;
3287
3288     /* if its a Hero Spell then get its SPE_TYPE */
3289     spell_type = is_hero_spell(type) ? SPE_MAGIC_MISSILE + abstype : 0;
3290
3291     fltxt = flash_types[(type <= -30) ? abstype : abs(type)];
3292     if(u.uswallow) {
3293         register int tmp;
3294
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)
3302             u.ustuck->mhp = 0;
3303         if (u.ustuck->mhp < 1)
3304             killed(u.ustuck);
3305         return;
3306     }
3307     if(type < 0) newsym(u.ux,u.uy);
3308     range = rn1(7,7);
3309     if(dx == 0 && dy == 0) range = 1;
3310     save_bhitpos = bhitpos;
3311
3312     tmp_at(DISP_BEAM, zapdir_to_glyph(dx, dy, abstype));
3313     while(range-- > 0) {
3314         lsx = sx; sx += dx;
3315         lsy = sy; sy += dy;
3316         if(isok(sx,sy) && (lev = &levl[sx][sy])->typ) {
3317             mon = m_at(sx, sy);
3318             if(cansee(sx,sy)) {
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);
3324                     newsym(sx, sy);
3325                 }
3326                 if(ZAP_POS(lev->typ) || cansee(lsx,lsy))
3327                     tmp_at(sx,sy);
3328                 delay_output(); /* wait a little */
3329             }
3330         } else
3331             goto make_bounce;
3332
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);
3338
3339         if (mon) {
3340             if (type == ZT_SPELL(ZT_FIRE)) break;
3341             if (type >= 0) mon->mstrategy &= ~STRAT_WAITMASK;
3342 #ifdef STEED
3343             buzzmonst:
3344 #endif
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!");
3351                     }
3352                     dx = -dx;
3353                     dy = -dy;
3354                 } else {
3355                     boolean mon_could_move = mon->mcanmove;
3356                     int tmp = zhitm(mon, type, nd, &otmp);
3357
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));
3367                         }
3368                         mon->mhp = mon->mhpmax;
3369                         break; /* Out of while loop */
3370                     }
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) ?
3376                                         "blast" : "ray");
3377                             pline("It seems even stronger than before.");
3378                         }
3379                         break; /* Out of while loop */
3380                     }
3381
3382                     if (tmp == MAGIC_COOKIE) { /* disintegration */
3383                         struct obj *otmp2, *m_amulet = mlifesaver(mon);
3384
3385                         if (canseemon(mon)) {
3386                             if (!m_amulet)
3387                                 pline("%s is disintegrated!", Monnam(mon));
3388                             else
3389                                 hit(fltxt, mon, "!");
3390                         }
3391 #ifndef GOLDOBJ
3392                         mon->mgold = 0L;
3393 #endif
3394
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) || \
3399                  obj == m_amulet)
3400
3401                         for (otmp = mon->minvent; otmp; otmp = otmp2) {
3402                             otmp2 = otmp->nobj;
3403                             if (!oresist_disintegration(otmp)) {
3404                                 obj_extract_self(otmp);
3405                                 obfree(otmp, (struct obj *)0);
3406                             }
3407                         }
3408
3409                         if (type < 0)
3410                             monkilled(mon, (char *)0, -AD_RBRE);
3411                         else
3412                             xkilled(mon, 2);
3413                     } else if(mon->mhp < 1) {
3414                         if(type < 0)
3415                             monkilled(mon, fltxt, AD_RBRE);
3416                         else
3417                             killed(mon);
3418                     } else {
3419                         if (!otmp) {
3420                             /* normal non-fatal hit */
3421                             hit(fltxt, mon, exclam(tmp));
3422                         } else {
3423                             /* some armor was destroyed; no damage done */
3424                             if (canseemon(mon))
3425                                 pline("%s %s is disintegrated!",
3426                                       s_suffix(Monnam(mon)),
3427                                       distant_name(otmp, xname));
3428                             m_useup(mon, otmp);
3429                         }
3430                         if (mon_could_move && !mon->mcanmove)   /* ZT_SLEEP */
3431                             slept_monst(mon);
3432                     }
3433                 }
3434                 range -= 2;
3435             } else {
3436                 miss(fltxt,mon);
3437             }
3438         } else if (sx == u.ux && sy == u.uy && range >= 0) {
3439             nomul(0);
3440 #ifdef STEED
3441             if (u.usteed && !rn2(3) && !mon_reflects(u.usteed, (char *)0)) {
3442                     mon = u.usteed;
3443                     goto buzzmonst;
3444             } else
3445 #endif
3446             if (zap_hit((int) u.uac, 0)) {
3447                 range -= 2;
3448                 pline("%s hits you!", The(fltxt));
3449                 if (Reflecting) {
3450                     if (!Blind) {
3451                         (void) ureflects("But %s reflects from your %s!", "it");
3452                     } else
3453                         pline("For some reason you are not affected.");
3454                     dx = -dx;
3455                     dy = -dy;
3456                     shieldeff(sx, sy);
3457                 } else {
3458                     zhitu(type, nd, fltxt, sx, sy);
3459                 }
3460             } else {
3461                 pline("%s whizzes by you!", The(fltxt));
3462             }
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);
3467             }
3468             stop_occupation();
3469             nomul(0);
3470         }
3471
3472         if(!ZAP_POS(lev->typ) || (closed_door(sx, sy) && (range >= 0))) {
3473             int bounce;
3474             uchar rmn;
3475
3476  make_bounce:
3477             if (type == ZT_SPELL(ZT_FIRE)) {
3478                 sx = lsx;
3479                 sy = lsy;
3480                 break; /* fireballs explode before the wall */
3481             }
3482             bounce = 0;
3483             range--;
3484             if(range && isok(lsx, lsy) && cansee(lsx,lsy))
3485                 pline("%s bounces!", The(fltxt));
3486             if(!dx || !dy || !rn2(20)) {
3487                 dx = -dx;
3488                 dy = -dy;
3489             } else {
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))))
3494                     bounce = 1;
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))
3500                         bounce = 2;
3501
3502                 switch(bounce) {
3503                 case 0: dx = -dx; /* fall into... */
3504                 case 1: dy = -dy; break;
3505                 case 2: dx = -dx; break;
3506                 }
3507                 tmp_at(DISP_CHANGE, zapdir_to_glyph(dx,dy,abstype));
3508             }
3509         }
3510     }
3511     tmp_at(DISP_END,0);
3512     if (type == ZT_SPELL(ZT_FIRE))
3513         explode(sx, sy, type, d(12,6), 0, EXPL_FIERY);
3514     if (shopdamage)
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;
3519 }
3520 #endif /*OVLB*/
3521 #ifdef OVL0
3522
3523 void
3524 melt_ice(x, y)
3525 xchar x, y;
3526 {
3527         struct rm *lev = &levl[x][y];
3528         struct obj *otmp;
3529
3530         if (lev->typ == DRAWBRIDGE_UP)
3531             lev->drawbridgemask &= ~DB_ICE;     /* revert to DB_MOAT */
3532         else {  /* lev->typ == ICE */
3533 #ifdef STUPID
3534             if (lev->icedpool == ICED_POOL) lev->typ = POOL;
3535             else lev->typ = MOAT;
3536 #else
3537             lev->typ = (lev->icedpool == ICED_POOL ? POOL : MOAT);
3538 #endif
3539             lev->icedpool = 0;
3540         }
3541         obj_ice_effects(x, y, FALSE);
3542         unearth_objs(x, y);
3543         if (Underwater) vision_recalc(1);
3544         newsym(x,y);
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)));
3548             do {
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);
3554             newsym(x,y);
3555         }
3556         if (x == u.ux && y == u.uy)
3557                 spoteffects(TRUE);      /* possibly drown, notice objects */
3558 }
3559
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)
3564  */
3565 int
3566 zap_over_floor(x, y, type, shopdamage)
3567 xchar x, y;
3568 int type;
3569 boolean *shopdamage;
3570 {
3571         struct monst *mon;
3572         int abstype = abs(type) % 10;
3573         struct rm *lev = &levl[x][y];
3574         int rangemod = 0;
3575
3576         if(abstype == ZT_FIRE) {
3577             struct trap *t = t_at(x, y);
3578
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);
3584             }
3585             if(is_ice(x, y)) {
3586                 melt_ice(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.";
3591                 } else {
3592                     register struct trap *ttmp;
3593
3594                     rangemod -= 3;
3595                     lev->typ = ROOM;
3596                     ttmp = maketrap(x, y, PIT);
3597                     if (ttmp) ttmp->tseen = 1;
3598                     if (cansee(x,y)) msgtxt = "The water evaporates.";
3599                 }
3600                 Norep(msgtxt);
3601                 if (lev->typ == ROOM) newsym(x,y);
3602             } else if(IS_FOUNTAIN(lev->typ)) {
3603                     if (cansee(x,y))
3604                         pline("Steam billows from the fountain.");
3605                     rangemod -= 1;
3606                     dryup(x, y, type > 0);
3607             }
3608         }
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));
3615
3616                 if (lev->typ == WATER) {
3617                     /* For now, don't let WATER freeze. */
3618                     if (cansee(x,y))
3619                         pline_The("water freezes for a moment.");
3620                     else
3621                         You_hear("a soft crackling.");
3622                     rangemod -= 1000;   /* stop */
3623                 } else {
3624                     rangemod -= 3;
3625                     if (lev->typ == DRAWBRIDGE_UP) {
3626                         lev->drawbridgemask &= ~DB_UNDER;  /* clear lava */
3627                         lev->drawbridgemask |= (lava ? DB_FLOOR : DB_ICE);
3628                     } else {
3629                         if (!lava)
3630                             lev->icedpool =
3631                                     (lev->typ == POOL ? ICED_POOL : ICED_MOAT);
3632                         lev->typ = (lava ? ROOM : ICE);
3633                     }
3634                     bury_objs(x,y);
3635                     if(cansee(x,y)) {
3636                         if(moat)
3637                                 Norep("The moat is bridged with ice!");
3638                         else if(lava)
3639                                 Norep("The lava cools and solidifies.");
3640                         else
3641                                 Norep("The water freezes.");
3642                         newsym(x,y);
3643                     } else if(flags.soundok && !lava)
3644                         You_hear("a crackling sound.");
3645
3646                     if (x == u.ux && y == u.uy) {
3647                         if (u.uinwater) {   /* not just `if (Underwater)' */
3648                             /* leave the no longer existent water */
3649                             u.uinwater = 0;
3650                             u.uundetected = 0;
3651                             docrt();
3652                             vision_full_recalc = 1;
3653                         } else if (u.utrap && u.utraptype == TT_LAVA) {
3654                             if (Passes_walls) {
3655                                 You("pass through the now-solid rock.");
3656                             } else {
3657                                 u.utrap = rn1(50,20);
3658                                 u.utraptype = TT_INFLOOR;
3659                                 You("are firmly stuck in the cooling rock.");
3660                             }
3661                         }
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;
3668                             newsym(x,y);
3669                         }
3670                     }
3671                 }
3672                 obj_ice_effects(x,y,TRUE);
3673         }
3674         if(closed_door(x, y)) {
3675                 int new_doormask = -1;
3676                 const char *see_txt = 0, *sense_txt = 0, *hear_txt = 0;
3677                 rangemod = -1000;
3678                 switch(abstype) {
3679                 case ZT_FIRE:
3680                     new_doormask = D_NODOOR;
3681                     see_txt = "The door is consumed in flames!";
3682                     sense_txt = "smell smoke.";
3683                     break;
3684                 case ZT_COLD:
3685                     new_doormask = D_NODOOR;
3686                     see_txt = "The door freezes and shatters!";
3687                     sense_txt = "feel cold.";
3688                     break;
3689                 case ZT_DEATH:
3690                     /* death spells/wands don't disintegrate */
3691                     if(abs(type) != ZT_BREATH(ZT_DEATH))
3692                         goto def_case;
3693                     new_doormask = D_NODOOR;
3694                     see_txt = "The door disintegrates!";
3695                     hear_txt = "crashing wood.";
3696                     break;
3697                 case ZT_LIGHTNING:
3698                     new_doormask = D_BROKEN;
3699                     see_txt = "The door splinters!";
3700                     hear_txt = "crackling.";
3701                     break;
3702                 default:
3703                 def_case:
3704                     if(cansee(x,y)) {
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" :
3709                               "blast");
3710                     } else You_feel("vibrations.");
3711                     break;
3712                 }
3713                 if (new_doormask >= 0) {        /* door gets broken */
3714                     if (*in_rooms(x, y, SHOPBASE)) {
3715                         if (type >= 0) {
3716                             add_damage(x, y, 400L);
3717                             *shopdamage = TRUE;
3718                         } else  /* caused by monster */
3719                             add_damage(x, y, 0L);
3720                     }
3721                     lev->doormask = new_doormask;
3722                     unblock_point(x, y);        /* vision */
3723                     if (cansee(x, y)) {
3724                         pline(see_txt);
3725                         newsym(x, y);
3726                     } else if (sense_txt) {
3727                         You(sense_txt);
3728                     } else if (hear_txt) {
3729                         if (flags.soundok) You_hear(hear_txt);
3730                     }
3731                     if (picking_at(x, y)) {
3732                         stop_occupation();
3733                         reset_pick();
3734                     }
3735                 }
3736         }
3737
3738         if(OBJ_AT(x, y) && abstype == ZT_FIRE)
3739                 if (burn_floor_paper(x, y, FALSE, type > 0) && couldsee(x, y)) {
3740                     newsym(x,y);
3741                     You("%s of smoke.",
3742                         !Blind ? "see a puff" : "smell a whiff");
3743                 }
3744         if ((mon = m_at(x,y)) != 0) {
3745                 /* Cannot use wakeup() which also angers the monster */
3746                 mon->msleeping = 0;
3747                 if(mon->m_ap_type) seemimic(mon);
3748                 if(type >= 0) {
3749                     setmangry(mon);
3750                     if(mon->ispriest && *in_rooms(mon->mx, mon->my, TEMPLE))
3751                         ghod_hitsu(mon);
3752                     if(mon->isshk && !*u.ushops)
3753                         hot_pursuit(mon);
3754                 }
3755         }
3756         return rangemod;
3757 }
3758
3759 #endif /*OVL0*/
3760 #ifdef OVL3
3761
3762 void
3763 fracture_rock(obj)      /* fractured by pick-axe or wand of striking */
3764 register struct obj *obj;                  /* no texts here! */
3765 {
3766         /* A little Sokoban guilt... */
3767         if (obj->otyp == BOULDER && In_sokoban(&u.uz) && !flags.mon_moving)
3768             change_luck(-1);
3769
3770         obj->otyp = ROCK;
3771         obj->quan = (long) rn1(60, 7);
3772         obj->owt = weight(obj);
3773         obj->oclass = GEM_CLASS;
3774         obj->known = FALSE;
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);
3785         }
3786 }
3787
3788 /* handle statue hit by striking/force bolt/pick-axe */
3789 boolean
3790 break_statue(obj)
3791 register struct obj *obj;
3792 {
3793         /* [obj is assumed to be on floor, so no get_obj_location() needed] */
3794         struct trap *trap = t_at(obj->ox, obj->oy);
3795         struct obj *item;
3796
3797         if (trap && trap->ttyp == STATUE_TRAP &&
3798                 activate_statue_trap(trap, obj->ox, obj->oy, TRUE))
3799             return FALSE;
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);
3804         }
3805         if (Role_if(PM_ARCHEOLOGIST) && !flags.mon_moving && (obj->spe & STATUE_HISTORIC)) {
3806             You_feel("guilty about damaging such a historic statue.");
3807             adjalign(-1);
3808         }
3809         obj->spe = 0;
3810         fracture_rock(obj);
3811         return TRUE;
3812 }
3813
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"
3821 };
3822
3823 void
3824 destroy_item(osym, dmgtyp)
3825 register int osym, dmgtyp;
3826 {
3827         register struct obj *obj, *obj2;
3828         register int dmg, xresist, skip;
3829         register long i, cnt, quan;
3830         register int dindx;
3831         const char *mult;
3832
3833         for(obj = invent; obj; obj = obj2) {
3834             obj2 = obj->nobj;
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 */
3838             xresist = skip = 0;
3839 #ifdef GCC_WARN
3840             dmg = dindx = 0;
3841             quan = 0L;
3842 #endif
3843             switch(dmgtyp) {
3844                 case AD_COLD:
3845                     if(osym == POTION_CLASS && obj->otyp != POT_OIL) {
3846                         quan = obj->quan;
3847                         dindx = 0;
3848                         dmg = rnd(4);
3849                     } else skip++;
3850                     break;
3851                 case AD_FIRE:
3852                     xresist = (Fire_resistance && obj->oclass != POTION_CLASS);
3853
3854                     if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL)
3855                         skip++;
3856                     if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
3857                         skip++;
3858                         if (!Blind)
3859                             pline("%s glows a strange %s, but remains intact.",
3860                                 The(xname(obj)), hcolor("dark red"));
3861                     }
3862                     quan = obj->quan;
3863                     switch(osym) {
3864                         case POTION_CLASS:
3865                             dindx = 1;
3866                             dmg = rnd(6);
3867                             break;
3868                         case SCROLL_CLASS:
3869                             dindx = 2;
3870                             dmg = 1;
3871                             break;
3872                         case SPBOOK_CLASS:
3873                             dindx = 3;
3874                             dmg = 1;
3875                             break;
3876                         default:
3877                             skip++;
3878                             break;
3879                     }
3880                     break;
3881                 case AD_ELEC:
3882                     xresist = (Shock_resistance && obj->oclass != RING_CLASS);
3883                     quan = obj->quan;
3884                     switch(osym) {
3885                         case RING_CLASS:
3886                             if(obj->otyp == RIN_SHOCK_RESISTANCE)
3887                                     { skip++; break; }
3888                             dindx = 4;
3889                             dmg = 0;
3890                             break;
3891                         case WAND_CLASS:
3892                             if(obj->otyp == WAN_LIGHTNING) { skip++; break; }
3893 #if 0
3894                             if (obj == current_wand) { skip++; break; }
3895 #endif
3896                             dindx = 5;
3897                             dmg = rnd(10);
3898                             break;
3899                         default:
3900                             skip++;
3901                             break;
3902                     }
3903                     break;
3904                 default:
3905                     skip++;
3906                     break;
3907             }
3908             if(!skip) {
3909                 if (obj->in_use) --quan; /* one will be used up elsewhere */
3910                 for(i = cnt = 0L; i < quan; i++)
3911                     if(!rn2(3)) cnt++;
3912
3913                 if(!cnt) continue;
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))
3921                         potionbreathe(obj);
3922                 }
3923                 if (obj->owornmask) {
3924                     if (obj->owornmask & W_RING) /* ring being worn */
3925                         Ring_gone(obj);
3926                     else
3927                         setnotworn(obj);
3928                 }
3929                 if (obj == current_wand) current_wand = 0;      /* destroyed */
3930                 for (i = 0; i < cnt; i++)
3931                     useup(obj);
3932                 if(dmg) {
3933                     if(xresist) You("aren't hurt!");
3934                     else {
3935                         const char *how = destroy_strings[dindx * 3 + 2];
3936                         boolean one = (cnt == 1L);
3937
3938                         losehp(dmg, one ? how : (const char *)makeplural(how),
3939                                one ? KILLED_BY_AN : KILLED_BY);
3940                         exercise(A_STR, FALSE);
3941                     }
3942                 }
3943             }
3944         }
3945         return;
3946 }
3947
3948 int
3949 destroy_mitem(mtmp, osym, dmgtyp)
3950 struct monst *mtmp;
3951 int osym, dmgtyp;
3952 {
3953         struct obj *obj, *obj2;
3954         int skip, tmp = 0;
3955         long i, cnt, quan;
3956         int dindx;
3957         boolean vis;
3958
3959         if (mtmp == &youmonst) {        /* this simplifies artifact_hit() */
3960             destroy_item(osym, dmgtyp);
3961             return 0;   /* arbitrary; value doesn't matter to artifact_hit() */
3962         }
3963
3964         vis = canseemon(mtmp);
3965         for(obj = mtmp->minvent; obj; obj = obj2) {
3966             obj2 = obj->nobj;
3967             if(obj->oclass != osym) continue; /* test only objs of type osym */
3968             skip = 0;
3969             quan = 0L;
3970             dindx = 0;
3971
3972             switch(dmgtyp) {
3973                 case AD_COLD:
3974                     if(osym == POTION_CLASS && obj->otyp != POT_OIL) {
3975                         quan = obj->quan;
3976                         dindx = 0;
3977                         tmp++;
3978                     } else skip++;
3979                     break;
3980                 case AD_FIRE:
3981                     if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL)
3982                         skip++;
3983                     if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
3984                         skip++;
3985                         if (vis)
3986                             pline("%s glows a strange %s, but remains intact.",
3987                                 The(distant_name(obj, xname)),
3988                                 hcolor("dark red"));
3989                     }
3990                     quan = obj->quan;
3991                     switch(osym) {
3992                         case POTION_CLASS:
3993                             dindx = 1;
3994                             tmp++;
3995                             break;
3996                         case SCROLL_CLASS:
3997                             dindx = 2;
3998                             tmp++;
3999                             break;
4000                         case SPBOOK_CLASS:
4001                             dindx = 3;
4002                             tmp++;
4003                             break;
4004                         default:
4005                             skip++;
4006                             break;
4007                     }
4008                     break;
4009                 case AD_ELEC:
4010                     quan = obj->quan;
4011                     switch(osym) {
4012                         case RING_CLASS:
4013                             if(obj->otyp == RIN_SHOCK_RESISTANCE)
4014                                     { skip++; break; }
4015                             dindx = 4;
4016                             break;
4017                         case WAND_CLASS:
4018                             if(obj->otyp == WAN_LIGHTNING) { skip++; break; }
4019                             dindx = 5;
4020                             tmp++;
4021                             break;
4022                         default:
4023                             skip++;
4024                             break;
4025                     }
4026                     break;
4027                 default:
4028                     skip++;
4029                     break;
4030             }
4031             if(!skip) {
4032                 for(i = cnt = 0L; i < quan; i++)
4033                     if(!rn2(3)) cnt++;
4034
4035                 if(!cnt) continue;
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);
4041             }
4042         }
4043         return(tmp);
4044 }
4045
4046 #endif /*OVL3*/
4047 #ifdef OVL2
4048
4049 int
4050 resist(mtmp, oclass, damage, tell)
4051 struct monst *mtmp;
4052 char oclass;
4053 int damage, tell;
4054 {
4055         int resisted;
4056         int alev, dlev;
4057
4058         /* attack level */
4059         switch (oclass) {
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 */
4067         }
4068         /* defense level */
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;
4072
4073         resisted = rn2(100 + alev - dlev) < mtmp->data->mr;
4074         if (resisted) {
4075             if (tell) {
4076                 shieldeff(mtmp->mx, mtmp->my);
4077                 pline("%s resists!", Monnam(mtmp));
4078             }
4079             damage = (damage + 1) / 2;
4080         }
4081
4082         if (damage) {
4083             mtmp->mhp -= damage;
4084             if (mtmp->mhp < 1) {
4085                 if(m_using) monkilled(mtmp, "", AD_RBRE);
4086                 else killed(mtmp);
4087             }
4088         }
4089         return(resisted);
4090 }
4091
4092 void
4093 makewish()
4094 {
4095         char buf[BUFSZ];
4096         struct obj *otmp, nothing;
4097         int tries = 0;
4098
4099         nothing = zeroobj;  /* lint suppression; only its address matters */
4100         if (flags.verbose) You("may wish for an object.");
4101 retry:
4102         getlin("For what do you wish?", buf);
4103         if(buf[0] == '\033') buf[0] = 0;
4104         /*
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.
4109          */
4110         otmp = readobjnam(buf, &nothing, TRUE);
4111         if (!otmp) {
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 == &nothing) {
4118             /* explicitly wished for "nothing", presumeably attempting
4119                to retain wishless conduct */
4120             return;
4121         }
4122
4123         /* KMH, conduct */
4124         u.uconduct.wishes++;
4125
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!",
4136                                        The(aobjnam(otmp,
4137                                              Is_airlevel(&u.uz) || u.uinwater ?
4138                                                    "slip" : "drop")),
4139                                        (const char *)0);
4140             u.ublesscnt += rn1(100,50);  /* the gods take notice */
4141         }
4142 }
4143
4144 #endif /*OVL2*/
4145
4146 /*zap.c*/