OSDN Git Service

update year to 2020
[jnethack/source.git] / src / explode.c
1 /* NetHack 3.6  explode.c       $NHDT-Date: 1545182146 2018/12/19 01:15:46 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.60 $ */
2 /*      Copyright (C) 1990 by Ken Arromdee */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 /* JNetHack Copyright */
6 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000  */
7 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2020            */
8 /* JNetHack may be freely redistributed.  See license for details. */
9
10 #include "hack.h"
11
12 /* Note: Arrays are column first, while the screen is row first */
13 static int explosion[3][3] = { { S_explode1, S_explode4, S_explode7 },
14                                { S_explode2, S_explode5, S_explode8 },
15                                { S_explode3, S_explode6, S_explode9 } };
16
17 /* Note: I had to choose one of three possible kinds of "type" when writing
18  * this function: a wand type (like in zap.c), an adtyp, or an object type.
19  * Wand types get complex because they must be converted to adtyps for
20  * determining such things as fire resistance.  Adtyps get complex in that
21  * they don't supply enough information--was it a player or a monster that
22  * did it, and with a wand, spell, or breath weapon?  Object types share both
23  * these disadvantages....
24  *
25  * Important note about Half_physical_damage:
26  *      Unlike losehp(), explode() makes the Half_physical_damage adjustments
27  *      itself, so the caller should never have done that ahead of time.
28  *      It has to be done this way because the damage value is applied to
29  *      things beside the player. Care is taken within explode() to ensure
30  *      that Half_physical_damage only affects the damage applied to the hero.
31  */
32 void
33 explode(x, y, type, dam, olet, expltype)
34 int x, y;
35 int type; /* the same as in zap.c; passes -(wand typ) for some WAND_CLASS */
36 int dam;
37 char olet;
38 int expltype;
39 {
40     int i, j, k, damu = dam;
41     boolean starting = 1;
42     boolean visible, any_shield;
43     int uhurt = 0; /* 0=unhurt, 1=items damaged, 2=you and items damaged */
44     const char *str = (const char *) 0;
45     int idamres, idamnonres;
46     struct monst *mtmp, *mdef = 0;
47     uchar adtyp;
48     int explmask[3][3]; /* 0=normal explosion, 1=do shieldeff, 2=do nothing */
49 #if 0 /*JP*//*do_hallu\82Ì\8f\88\97\9d\82Í\82Æ\82è\82 \82¦\82¸\8aO\82·*/
50     boolean shopdamage = FALSE, generic = FALSE, physical_dmg = FALSE,
51             do_hallu = FALSE, inside_engulfer, grabbed, grabbing;
52 #else
53     boolean shopdamage = FALSE, generic = FALSE, physical_dmg = FALSE,
54             inside_engulfer, grabbed, grabbing;
55 #endif
56     coord grabxy;
57 #if 0 /*JP*/
58     char hallu_buf[BUFSZ], killr_buf[BUFSZ];
59 #else
60     char hallu_buf[BUFSZ];
61 #endif
62     short exploding_wand_typ = 0;
63
64     if (olet == WAND_CLASS) { /* retributive strike */
65         /* 'type' is passed as (wand's object type * -1); save
66            object type and convert 'type' itself to zap-type */
67         if (type < 0) {
68             type = -type;
69             exploding_wand_typ = (short) type;
70             /* most attack wands produce specific explosions;
71                other types produce a generic magical explosion */
72             if (objects[type].oc_dir == RAY
73                 && type != WAN_DIGGING && type != WAN_SLEEP) {
74                 type -= WAN_MAGIC_MISSILE;
75                 if (type < 0 || type > 9) {
76                     impossible("explode: wand has bad zap type (%d).", type);
77                     type = 0;
78                 }
79             } else
80                 type = 0;
81         }
82         switch (Role_switch) {
83         case PM_PRIEST:
84         case PM_MONK:
85         case PM_WIZARD:
86             damu /= 5;
87             break;
88         case PM_HEALER:
89         case PM_KNIGHT:
90             damu /= 2;
91             break;
92         default:
93             break;
94         }
95     }
96     /* muse_unslime: SCR_FIRE */
97     if (expltype < 0) {
98         /* hero gets credit/blame for killing this monster, not others */
99         mdef = m_at(x, y);
100         expltype = -expltype;
101     }
102     /* if hero is engulfed and caused the explosion, only hero and
103        engulfer will be affected */
104     inside_engulfer = (u.uswallow && type >= 0);
105     /* held but not engulfed implies holder is reaching into second spot
106        so might get hit by double damage */
107     grabbed = grabbing = FALSE;
108     if (u.ustuck && !u.uswallow) {
109         if (Upolyd && sticks(youmonst.data))
110             grabbing = TRUE;
111         else
112             grabbed = TRUE;
113         grabxy.x = u.ustuck->mx;
114         grabxy.y = u.ustuck->my;
115     } else
116         grabxy.x = grabxy.y = 0; /* lint suppression */
117     /* FIXME:
118      *  It is possible for a grabber to be outside the explosion
119      *  radius and reaching inside to hold the hero.  If so, it ought
120      *  to take damage (the extra half of double damage).  It is also
121      *  possible for poly'd hero to be outside the radius and reaching
122      *  in to hold a monster.  Hero should take damage in that situation.
123      *
124      *  Probably the simplest way to handle this would be to expand
125      *  the radius used when collecting targets but exclude everything
126      *  beyond the regular radius which isn't reaching inside.  Then
127      *  skip harm to gear of any extended targets when inflicting damage.
128      */
129
130 #if 0 /*JP*//*do_hallu\82Ì\8f\88\97\9d\82Í\82Æ\82è\82 \82¦\82¸\8aO\82·*/
131     if (olet == MON_EXPLODE) {
132         /* when explode() is called recursively, killer.name might change so
133            we need to retain a copy of the current value for this explosion */
134         str = strcpy(killr_buf, killer.name);
135         do_hallu = (Hallucination
136                     && (strstri(str, "'s explosion")
137                         || strstri(str, "s' explosion")));
138         adtyp = AD_PHYS;
139     } else
140 #endif
141         switch (abs(type) % 10) {
142         case 0:
143 /*JP
144             str = "magical blast";
145 */
146             str = "\96\82\96@\82Ì\95\97";
147             adtyp = AD_MAGM;
148             break;
149         case 1:
150 #if 0 /*JP:T*/
151             str = (olet == BURNING_OIL) ? "burning oil"
152                      : (olet == SCROLL_CLASS) ? "tower of flame" : "fireball";
153 #else
154             str = (olet == BURNING_OIL) ? "\94R\82¦\82Ä\82¢\82é\96û"
155                      : (olet == SCROLL_CLASS) ? "\89Î\92\8c" : "\89Î\82Ì\8bÊ";
156 #endif
157             /* fire damage, not physical damage */
158             adtyp = AD_FIRE;
159             break;
160         case 2:
161 /*JP
162             str = "ball of cold";
163 */
164             str = "\95X\82Ì\8bÊ";
165             adtyp = AD_COLD;
166             break;
167         case 4:
168 #if 0 /*JP:T*/
169             str = (olet == WAND_CLASS) ? "death field"
170                                        : "disintegration field";
171 #else
172             str = (olet == WAND_CLASS) ? "\8e\80\82Ì\95\97"
173                                        : "\95ª\89ð\82Ì\95\97";
174 #endif
175             adtyp = AD_DISN;
176             break;
177         case 5:
178 /*JP
179             str = "ball of lightning";
180 */
181             str = "\97\8b\8bÊ";
182             adtyp = AD_ELEC;
183             break;
184         case 6:
185 /*JP
186             str = "poison gas cloud";
187 */
188             str = "\93Å\82Ì\89_";
189             adtyp = AD_DRST;
190             break;
191         case 7:
192 /*JP
193             str = "splash of acid";
194 */
195             str = "\8e_\82Ì\82µ\82Ô\82«";
196             adtyp = AD_ACID;
197             break;
198         default:
199             impossible("explosion base type %d?", type);
200             return;
201         }
202
203     any_shield = visible = FALSE;
204     for (i = 0; i < 3; i++)
205         for (j = 0; j < 3; j++) {
206             if (!isok(i + x - 1, j + y - 1)) {
207                 explmask[i][j] = 2;
208                 continue;
209             } else
210                 explmask[i][j] = 0;
211
212             if (i + x - 1 == u.ux && j + y - 1 == u.uy) {
213                 switch (adtyp) {
214                 case AD_PHYS:
215                     explmask[i][j] = 0;
216                     break;
217                 case AD_MAGM:
218                     explmask[i][j] = !!Antimagic;
219                     break;
220                 case AD_FIRE:
221                     explmask[i][j] = !!Fire_resistance;
222                     break;
223                 case AD_COLD:
224                     explmask[i][j] = !!Cold_resistance;
225                     break;
226                 case AD_DISN:
227                     explmask[i][j] = (olet == WAND_CLASS)
228                                          ? !!(nonliving(youmonst.data)
229                                               || is_demon(youmonst.data))
230                                          : !!Disint_resistance;
231                     break;
232                 case AD_ELEC:
233                     explmask[i][j] = !!Shock_resistance;
234                     break;
235                 case AD_DRST:
236                     explmask[i][j] = !!Poison_resistance;
237                     break;
238                 case AD_ACID:
239                     explmask[i][j] = !!Acid_resistance;
240                     physical_dmg = TRUE;
241                     break;
242                 default:
243                     impossible("explosion type %d?", adtyp);
244                     break;
245                 }
246             }
247             /* can be both you and mtmp if you're swallowed or riding */
248             mtmp = m_at(i + x - 1, j + y - 1);
249             if (!mtmp && i + x - 1 == u.ux && j + y - 1 == u.uy)
250                 mtmp = u.usteed;
251             if (mtmp) {
252                 if (DEADMONSTER(mtmp))
253                     explmask[i][j] = 2;
254                 else
255                     switch (adtyp) {
256                     case AD_PHYS:
257                         break;
258                     case AD_MAGM:
259                         explmask[i][j] |= resists_magm(mtmp);
260                         break;
261                     case AD_FIRE:
262                         explmask[i][j] |= resists_fire(mtmp);
263                         break;
264                     case AD_COLD:
265                         explmask[i][j] |= resists_cold(mtmp);
266                         break;
267                     case AD_DISN:
268                         explmask[i][j] |= (olet == WAND_CLASS)
269                                               ? (nonliving(mtmp->data)
270                                                  || is_demon(mtmp->data)
271                                                  || is_vampshifter(mtmp))
272                                               : resists_disint(mtmp);
273                         break;
274                     case AD_ELEC:
275                         explmask[i][j] |= resists_elec(mtmp);
276                         break;
277                     case AD_DRST:
278                         explmask[i][j] |= resists_poison(mtmp);
279                         break;
280                     case AD_ACID:
281                         explmask[i][j] |= resists_acid(mtmp);
282                         break;
283                     default:
284                         impossible("explosion type %d?", adtyp);
285                         break;
286                     }
287             }
288             if (mtmp && cansee(i + x - 1, j + y - 1) && !canspotmon(mtmp))
289                 map_invisible(i + x - 1, j + y - 1);
290             else if (!mtmp)
291                 (void) unmap_invisible(i + x - 1, j + y - 1);
292             if (cansee(i + x - 1, j + y - 1))
293                 visible = TRUE;
294             if (explmask[i][j] == 1)
295                 any_shield = TRUE;
296         }
297
298     if (visible) {
299         /* Start the explosion */
300         for (i = 0; i < 3; i++)
301             for (j = 0; j < 3; j++) {
302                 if (explmask[i][j] == 2)
303                     continue;
304                 tmp_at(starting ? DISP_BEAM : DISP_CHANGE,
305                        explosion_to_glyph(expltype, explosion[i][j]));
306                 tmp_at(i + x - 1, j + y - 1);
307                 starting = 0;
308             }
309         curs_on_u(); /* will flush screen and output */
310
311         if (any_shield && flags.sparkle) { /* simulate shield effect */
312             for (k = 0; k < SHIELD_COUNT; k++) {
313                 for (i = 0; i < 3; i++)
314                     for (j = 0; j < 3; j++) {
315                         if (explmask[i][j] == 1)
316                             /*
317                              * Bypass tmp_at() and send the shield glyphs
318                              * directly to the buffered screen.  tmp_at()
319                              * will clean up the location for us later.
320                              */
321                             show_glyph(i + x - 1, j + y - 1,
322                                        cmap_to_glyph(shield_static[k]));
323                     }
324                 curs_on_u(); /* will flush screen and output */
325                 delay_output();
326             }
327
328             /* Cover last shield glyph with blast symbol. */
329             for (i = 0; i < 3; i++)
330                 for (j = 0; j < 3; j++) {
331                     if (explmask[i][j] == 1)
332                         show_glyph(
333                             i + x - 1, j + y - 1,
334                             explosion_to_glyph(expltype, explosion[i][j]));
335                 }
336
337         } else { /* delay a little bit. */
338             delay_output();
339             delay_output();
340         }
341
342         tmp_at(DISP_END, 0); /* clear the explosion */
343     } else {
344         if (olet == MON_EXPLODE) {
345 /*JP
346             str = "explosion";
347 */
348             str = "\94\9a\94­";
349             generic = TRUE;
350         }
351         if (!Deaf && olet != SCROLL_CLASS)
352 /*JP
353             You_hear("a blast.");
354 */
355             You_hear("\94\9a\94­\89¹\82ð\95·\82¢\82½\81D");
356     }
357
358     if (dam)
359         for (i = 0; i < 3; i++)
360             for (j = 0; j < 3; j++) {
361                 if (explmask[i][j] == 2)
362                     continue;
363                 if (i + x - 1 == u.ux && j + y - 1 == u.uy)
364                     uhurt = (explmask[i][j] == 1) ? 1 : 2;
365                 /* for inside_engulfer, only <u.ux,u.uy> is affected */
366                 else if (inside_engulfer)
367                     continue;
368                 idamres = idamnonres = 0;
369                 if (type >= 0 && !u.uswallow)
370                     (void) zap_over_floor((xchar) (i + x - 1),
371                                           (xchar) (j + y - 1), type,
372                                           &shopdamage, exploding_wand_typ);
373
374                 mtmp = m_at(i + x - 1, j + y - 1);
375                 if (!mtmp && i + x - 1 == u.ux && j + y - 1 == u.uy)
376                     mtmp = u.usteed;
377                 if (!mtmp)
378                     continue;
379 #if 0 /*JP*//*do_hallu\82Ì\8f\88\97\9d\82Í\82Æ\82è\82 \82¦\82¸\8aO\82·*/
380                 if (do_hallu) {
381                     /* replace "gas spore" with a different description
382                        for each target (we can't distinguish personal names
383                        like "Barney" here in order to suppress "the" below,
384                        so avoid any which begins with a capital letter) */
385                     do {
386                         Sprintf(hallu_buf, "%s explosion",
387                                 s_suffix(rndmonnam((char *) 0)));
388                     } while (*hallu_buf != lowc(*hallu_buf));
389                     str = hallu_buf;
390                 }
391 #endif
392                 if (u.uswallow && mtmp == u.ustuck) {
393                     const char *adj = (char *) 0;
394
395                     if (is_animal(u.ustuck->data)) {
396                         switch (adtyp) {
397                         case AD_FIRE:
398 /*JP
399                             adj = "heartburn";
400 */
401                             adj = "\94R\82¦\82½";
402                             break;
403                         case AD_COLD:
404 /*JP
405                             adj = "chilly";
406 */
407                             adj = "\93\80\82ç\82³\82ê\82½";
408                             break;
409                         case AD_DISN:
410                             if (olet == WAND_CLASS)
411 /*JP
412                                 adj = "irradiated by pure energy";
413 */
414                                 adj = "\8fò\89»\82Ì\97Í\82ð\97\81\82Ñ\82½";
415                             else
416 /*JP
417                                 adj = "perforated";
418 */
419                                 adj = "\8c\8a\82ð\82 \82¯\82ç\82ê\82½";
420                             break;
421                         case AD_ELEC:
422 /*JP
423                             adj = "shocked";
424 */
425                             adj = "\93d\8c\82\82ð\82­\82ç\82Á\82½";
426                             break;
427                         case AD_DRST:
428 /*JP
429                             adj = "poisoned";
430 */
431                             adj = "\93Å\82ð\82­\82ç\82Á\82½";
432                             break;
433                         case AD_ACID:
434 /*JP
435                             adj = "an upset stomach";
436 */
437                             adj = "\8e_\82ð\82­\82ç\82Á\82½";
438                             break;
439                         default:
440 /*JP
441                             adj = "fried";
442 */
443                             adj = "\83p\83\8a\83p\83\8a\82É\82È\82Á\82½";
444                             break;
445                         }
446 /*JP
447                         pline("%s gets %s!", Monnam(u.ustuck), adj);
448 */
449                         pline("%s\82Í%s\81I", Monnam(u.ustuck), adj);
450                     } else {
451                         switch (adtyp) {
452                         case AD_FIRE:
453 /*JP
454                             adj = "toasted";
455 */
456                             adj = "\8fÅ\82°\82½";
457                             break;
458                         case AD_COLD:
459 /*JP
460                             adj = "chilly";
461 */
462                             adj = "\93\80\82Á\82½";
463                             break;
464                         case AD_DISN:
465                             if (olet == WAND_CLASS)
466 /*JP
467                                 adj = "overwhelmed by pure energy";
468 */
469                                 adj = "\8fò\89»\82Ì\97Í\82ð\97\81\82Ñ\82½";
470                             else
471 /*JP
472                                 adj = "perforated";
473 */
474                                 adj = "\8c\8a\82ð\82 \82¯\82ç\82ê\82½";
475                             break;
476                         case AD_ELEC:
477 /*JP
478                             adj = "shocked";
479 */
480                             adj = "\93d\8c\82\82ð\82­\82ç\82Á\82½";
481                             break;
482                         case AD_DRST:
483 /*JP
484                             adj = "intoxicated";
485 */
486                             adj = "\93Å\82ð\82­\82ç\82Á\82½";
487                             break;
488                         case AD_ACID:
489 /*JP
490                             adj = "burned";
491 */
492                             adj = "\8e_\82ð\82­\82ç\82Á\82½";
493                             break;
494                         default:
495 /*JP
496                             adj = "fried";
497 */
498                             adj = "\83p\83\8a\83p\83\8a\82É\82È\82Á\82½";
499                             break;
500                         }
501 /*JP
502                         pline("%s gets slightly %s!", Monnam(u.ustuck), adj);
503 */
504                         pline("%s\82Í\8f­\82µ\82¾\82¯%s\81I", Monnam(u.ustuck), adj);
505                     }
506                 } else if (cansee(i + x - 1, j + y - 1)) {
507                     if (mtmp->m_ap_type)
508                         seemimic(mtmp);
509 /*JP
510                     pline("%s is caught in the %s!", Monnam(mtmp), str);
511 */
512                     pline("%s\82Í%s\82É\82Â\82Â\82Ü\82ê\82½\81I", Monnam(mtmp), str);
513                 }
514
515                 idamres += destroy_mitem(mtmp, SCROLL_CLASS, (int) adtyp);
516                 idamres += destroy_mitem(mtmp, SPBOOK_CLASS, (int) adtyp);
517                 idamnonres += destroy_mitem(mtmp, POTION_CLASS, (int) adtyp);
518                 idamnonres += destroy_mitem(mtmp, WAND_CLASS, (int) adtyp);
519                 idamnonres += destroy_mitem(mtmp, RING_CLASS, (int) adtyp);
520
521                 if (explmask[i][j] == 1) {
522                     golemeffects(mtmp, (int) adtyp, dam + idamres);
523                     mtmp->mhp -= idamnonres;
524                 } else {
525                     /* call resist with 0 and do damage manually so 1) we can
526                      * get out the message before doing the damage, and 2) we
527                      * can call mondied, not killed, if it's not your blast
528                      */
529                     int mdam = dam;
530
531                     if (resist(mtmp, olet, 0, FALSE)) {
532                         /* inside_engulfer: <i+x-1,j+y-1> == <u.ux,u.uy> */
533                         if (cansee(i + x - 1, j + y - 1) || inside_engulfer)
534 /*JP
535                             pline("%s resists the %s!", Monnam(mtmp), str);
536 */
537                             pline("%s\82Í%s\82É\92ï\8dR\82µ\82½\81I", Monnam(mtmp), str);
538                         mdam = (dam + 1) / 2;
539                     }
540                     /* if grabber is reaching into hero's spot and
541                        hero's spot is within explosion radius, grabber
542                        gets hit by double damage */
543                     if (grabbed && mtmp == u.ustuck && distu(x, y) <= 2)
544                         mdam *= 2;
545                     /* being resistant to opposite type of damage makes
546                        target more vulnerable to current type of damage
547                        (when target is also resistant to current type,
548                        we won't get here) */
549                     if (resists_cold(mtmp) && adtyp == AD_FIRE)
550                         mdam *= 2;
551                     else if (resists_fire(mtmp) && adtyp == AD_COLD)
552                         mdam *= 2;
553                     mtmp->mhp -= mdam;
554                     mtmp->mhp -= (idamres + idamnonres);
555                 }
556                 if (DEADMONSTER(mtmp)) {
557                     int xkflg = ((adtyp == AD_FIRE
558                                   && completelyburns(mtmp->data))
559                                  ? XKILL_NOCORPSE : 0);
560
561                     if (!context.mon_moving) {
562                         xkilled(mtmp, XKILL_GIVEMSG | xkflg);
563                     } else if (mdef && mtmp == mdef) {
564                         /* 'mdef' killed self trying to cure being turned
565                          * into slime due to some action by the player.
566                          * Hero gets the credit (experience) and most of
567                          * the blame (possible loss of alignment and/or
568                          * luck and/or telepathy depending on mtmp) but
569                          * doesn't break pacifism.  xkilled()'s message
570                          * would be "you killed <mdef>" so give our own.
571                          */
572                         if (cansee(mtmp->mx, mtmp->my) || canspotmon(mtmp))
573 #if 0 /*JP:T*/
574                             pline("%s is %s!", Monnam(mtmp),
575                                   xkflg ? "burned completely"
576                                         : nonliving(mtmp->data) ? "destroyed"
577                                                                 : "killed");
578 #else
579                             pline("%s\82Í%s\81I", Monnam(mtmp),
580                                   xkflg ? "\94R\82¦\82Â\82«\82½"
581                                         : nonliving(mtmp->data) ? "\93|\82³\82ê\82½"
582                                                                 : "\8eE\82³\82ê\82½");
583 #endif
584                         xkilled(mtmp, XKILL_NOMSG | XKILL_NOCONDUCT | xkflg);
585                     } else {
586                         if (xkflg)
587                             adtyp = AD_RBRE; /* no corpse */
588                         monkilled(mtmp, "", (int) adtyp);
589                     }
590                 } else if (!context.mon_moving) {
591                     /* all affected monsters, even if mdef is set */
592                     setmangry(mtmp, TRUE);
593                 }
594             }
595
596     /* Do your injury last */
597     if (uhurt) {
598         /* give message for any monster-induced explosion
599            or player-induced one other than scroll of fire */
600         if (flags.verbose && (type < 0 || olet != SCROLL_CLASS)) {
601 #if 0 /*JP*//*do_hallu\82Ì\8f\88\97\9d\82Í\82Æ\82è\82 \82¦\82¸\8aO\82·*/
602             if (do_hallu) { /* (see explanation above) */
603                 do {
604                     Sprintf(hallu_buf, "%s explosion",
605                             s_suffix(rndmonnam((char *) 0)));
606                 } while (*hallu_buf != lowc(*hallu_buf));
607                 str = hallu_buf;
608             }
609 #endif
610 /*JP
611             You("are caught in the %s!", str);
612 */
613             You("%s\82É\82Â\82Â\82Ü\82ê\82½\81I", str);
614             iflags.last_msg = PLNMSG_CAUGHT_IN_EXPLOSION;
615         }
616         /* do property damage first, in case we end up leaving bones */
617         if (adtyp == AD_FIRE)
618             burn_away_slime();
619         if (Invulnerable) {
620             damu = 0;
621 /*JP
622             You("are unharmed!");
623 */
624             You("\8f\9d\82Â\82©\82È\82¢\81I");
625         } else if (adtyp == AD_PHYS || physical_dmg)
626             damu = Maybe_Half_Phys(damu);
627         if (adtyp == AD_FIRE)
628             (void) burnarmor(&youmonst);
629         destroy_item(SCROLL_CLASS, (int) adtyp);
630         destroy_item(SPBOOK_CLASS, (int) adtyp);
631         destroy_item(POTION_CLASS, (int) adtyp);
632         destroy_item(RING_CLASS, (int) adtyp);
633         destroy_item(WAND_CLASS, (int) adtyp);
634
635         ugolemeffects((int) adtyp, damu);
636         if (uhurt == 2) {
637             /* if poly'd hero is grabbing another victim, hero takes
638                double damage (note: don't rely on u.ustuck here because
639                that victim might have been killed when hit by the blast) */
640             if (grabbing && dist2((int) grabxy.x, (int) grabxy.y, x, y) <= 2)
641                 damu *= 2;
642             /* hero does not get same fire-resistant vs cold and
643                cold-resistant vs fire double damage as monsters [why not?] */
644             if (Upolyd)
645                 u.mh -= damu;
646             else
647                 u.uhp -= damu;
648             context.botl = 1;
649         }
650
651         if (u.uhp <= 0 || (Upolyd && u.mh <= 0)) {
652             if (Upolyd) {
653                 rehumanize();
654             } else {
655                 if (olet == MON_EXPLODE) {
656                     if (generic) /* explosion was unseen; str=="explosion", */
657                         ;        /* killer.name=="gas spore's explosion"    */
658                     else if (str != killer.name && str != hallu_buf)
659                         Strcpy(killer.name, str);
660                     killer.format = KILLED_BY_AN;
661 #if 1 /*JP*/
662                     Strcat(killer.name, "\82Å");
663 #endif
664                 } else if (type >= 0 && olet != SCROLL_CLASS) {
665 #if 0 /*JP:T*/
666                     killer.format = NO_KILLER_PREFIX;
667                     Sprintf(killer.name, "caught %sself in %s own %s", uhim(),
668                             uhis(), str);
669 #else
670                     killer.format = KILLED_BY;
671                     Sprintf(killer.name, "\8e©\95ª\8e©\90g\82Ì%s\82É\82Â\82Â\82Ü\82ê\82Ä",
672                             str);
673 #endif
674                 } else {
675 #if 0 /*JP*//* an \82ð\82Â\82¯\82é\82©\82Ç\82¤\82©\82Í\8aÖ\8cW\82È\82¢ */
676                     killer.format = (!strcmpi(str, "tower of flame")
677                                      || !strcmpi(str, "fireball"))
678                                         ? KILLED_BY_AN
679                                         : KILLED_BY;
680                     Strcpy(killer.name, str);
681 #else
682                     killer.format = KILLED_BY;
683                     Strcpy(killer.name, str);
684                     Strcat(killer.name, "\82Å");
685 #endif
686                 }
687                 if (iflags.last_msg == PLNMSG_CAUGHT_IN_EXPLOSION
688                     || iflags.last_msg == PLNMSG_TOWER_OF_FLAME) /*seffects()*/
689 /*JP
690                     pline("It is fatal.");
691 */
692                     pline("\82»\82ê\82Í\92v\96½\93I\82¾\81D");
693                 else
694 /*JP
695                     pline_The("%s is fatal.", str);
696 */
697                     pline_The("%s\82Í\92v\96½\93I\82¾\81D", str);
698                 /* Known BUG: BURNING suppresses corpse in bones data,
699                    but done does not handle killer reason correctly */
700                 done((adtyp == AD_FIRE) ? BURNING : DIED);
701             }
702         }
703         exercise(A_STR, FALSE);
704     }
705
706     if (shopdamage) {
707 #if 0 /*JP:T*/
708         pay_for_damage((adtyp == AD_FIRE) ? "burn away"
709                           : (adtyp == AD_COLD) ? "shatter"
710                              : (adtyp == AD_DISN) ? "disintegrate"
711                                 : "destroy",
712                        FALSE);
713 #else
714         pay_for_damage(adtyp == AD_FIRE
715                            ? "\94R\82â\82·"
716                            : adtyp == AD_COLD
717                                  ? "\95²\81X\82É\82·\82é"
718                                  : adtyp == AD_DISN ? "\95²\8dÓ\82·\82é"
719                                                     : "\94j\89ó\82·\82é",
720                        FALSE);
721 #endif
722     }
723
724     /* explosions are noisy */
725     i = dam * dam;
726     if (i < 50)
727         i = 50; /* in case random damage is very small */
728     if (inside_engulfer)
729         i = (i + 3) / 4;
730     wake_nearto(x, y, i);
731 }
732
733 struct scatter_chain {
734     struct scatter_chain *next; /* pointer to next scatter item */
735     struct obj *obj;            /* pointer to the object        */
736     xchar ox;                   /* location of                  */
737     xchar oy;                   /*      item                    */
738     schar dx;                   /* direction of                 */
739     schar dy;                   /*      travel                  */
740     int range;                  /* range of object              */
741     boolean stopped;            /* flag for in-motion/stopped   */
742 };
743
744 /*
745  * scflags:
746  *      VIS_EFFECTS     Add visual effects to display
747  *      MAY_HITMON      Objects may hit monsters
748  *      MAY_HITYOU      Objects may hit hero
749  *      MAY_HIT         Objects may hit you or monsters
750  *      MAY_DESTROY     Objects may be destroyed at random
751  *      MAY_FRACTURE    Stone objects can be fractured (statues, boulders)
752  */
753
754 /* returns number of scattered objects */
755 long
756 scatter(sx, sy, blastforce, scflags, obj)
757 int sx, sy;     /* location of objects to scatter */
758 int blastforce; /* force behind the scattering */
759 unsigned int scflags;
760 struct obj *obj; /* only scatter this obj        */
761 {
762     register struct obj *otmp;
763     register int tmp;
764     int farthest = 0;
765     uchar typ;
766     long qtmp;
767     boolean used_up;
768     boolean individual_object = obj ? TRUE : FALSE;
769     struct monst *mtmp;
770     struct scatter_chain *stmp, *stmp2 = 0;
771     struct scatter_chain *schain = (struct scatter_chain *) 0;
772     long total = 0L;
773
774     if (individual_object && (obj->ox != sx || obj->oy != sy))
775         impossible("scattered object <%d,%d> not at scatter site <%d,%d>",
776                    obj->ox, obj->oy, sx, sy);
777
778     while ((otmp = (individual_object ? obj : level.objects[sx][sy])) != 0) {
779         if (otmp == uball || otmp == uchain) {
780             boolean waschain = (otmp == uchain);
781 /*JP
782             pline_The("chain shatters!");
783 */
784             pline("\8d½\82Í\82Î\82ç\82Î\82ç\82É\82È\82Á\82½\81I");
785             unpunish();
786             if (waschain)
787                 continue;
788         }
789         if (otmp->quan > 1L) {
790             qtmp = otmp->quan - 1L;
791             if (qtmp > LARGEST_INT)
792                 qtmp = LARGEST_INT;
793             qtmp = (long) rnd((int) qtmp);
794             otmp = splitobj(otmp, qtmp);
795         } else {
796             obj = (struct obj *) 0; /* all used */
797         }
798         obj_extract_self(otmp);
799         used_up = FALSE;
800
801         /* 9 in 10 chance of fracturing boulders or statues */
802         if ((scflags & MAY_FRACTURE) != 0
803             && (otmp->otyp == BOULDER || otmp->otyp == STATUE)
804             && rn2(10)) {
805             if (otmp->otyp == BOULDER) {
806                 if (cansee(sx, sy))
807 /*JP
808                     pline("%s apart.", Tobjnam(otmp, "break"));
809 */
810                     pline("%s\82Í\88ê\95\94\95ª\82ª\8dÓ\82¯\82½\81D",xname(otmp));
811                 else
812 /*JP
813                     You_hear("stone breaking.");
814 */
815                     You_hear("\90Î\82ª\8dÓ\82¯\82é\89¹\82ð\95·\82¢\82½\81D");
816                 fracture_rock(otmp);
817                 place_object(otmp, sx, sy);
818                 if ((otmp = sobj_at(BOULDER, sx, sy)) != 0) {
819                     /* another boulder here, restack it to the top */
820                     obj_extract_self(otmp);
821                     place_object(otmp, sx, sy);
822                 }
823             } else {
824                 struct trap *trap;
825
826                 if ((trap = t_at(sx, sy)) && trap->ttyp == STATUE_TRAP)
827                     deltrap(trap);
828                 if (cansee(sx, sy))
829 /*JP
830                     pline("%s.", Tobjnam(otmp, "crumble"));
831 */
832                     pline("%s\82Í\82±\82È\82²\82È\82É\82È\82Á\82½\81D",xname(otmp));
833                 else
834 /*JP
835                     You_hear("stone crumbling.");
836 */
837                     You_hear("\90Î\82ª\82±\82È\82²\82È\82É\82È\82é\89¹\82ð\95·\82¢\82½\81D");
838                 (void) break_statue(otmp);
839 #ifndef FIX_BUG_C340_2
840                 place_object(otmp, sx, sy); /* put fragments on floor */
841 #endif
842             }
843             newsym(sx, sy); /* in case it's beyond radius of 'farthest' */
844             used_up = TRUE;
845
846             /* 1 in 10 chance of destruction of obj; glass, egg destruction */
847         } else if ((scflags & MAY_DESTROY) != 0
848                    && (!rn2(10) || (objects[otmp->otyp].oc_material == GLASS
849                                     || otmp->otyp == EGG))) {
850             if (breaks(otmp, (xchar) sx, (xchar) sy))
851                 used_up = TRUE;
852         }
853
854         if (!used_up) {
855             stmp = (struct scatter_chain *) alloc(sizeof *stmp);
856             stmp->next = (struct scatter_chain *) 0;
857             stmp->obj = otmp;
858             stmp->ox = sx;
859             stmp->oy = sy;
860             tmp = rn2(8); /* get the direction */
861             stmp->dx = xdir[tmp];
862             stmp->dy = ydir[tmp];
863             tmp = blastforce - (otmp->owt / 40);
864             if (tmp < 1)
865                 tmp = 1;
866             stmp->range = rnd(tmp); /* anywhere up to that determ. by wt */
867             if (farthest < stmp->range)
868                 farthest = stmp->range;
869             stmp->stopped = FALSE;
870             if (!schain)
871                 schain = stmp;
872             else
873                 stmp2->next = stmp;
874             stmp2 = stmp;
875         }
876     }
877
878     while (farthest-- > 0) {
879         for (stmp = schain; stmp; stmp = stmp->next) {
880             if ((stmp->range-- > 0) && (!stmp->stopped)) {
881                 bhitpos.x = stmp->ox + stmp->dx;
882                 bhitpos.y = stmp->oy + stmp->dy;
883                 typ = levl[bhitpos.x][bhitpos.y].typ;
884                 if (!isok(bhitpos.x, bhitpos.y)) {
885                     bhitpos.x -= stmp->dx;
886                     bhitpos.y -= stmp->dy;
887                     stmp->stopped = TRUE;
888                 } else if (!ZAP_POS(typ)
889                            || closed_door(bhitpos.x, bhitpos.y)) {
890                     bhitpos.x -= stmp->dx;
891                     bhitpos.y -= stmp->dy;
892                     stmp->stopped = TRUE;
893                 } else if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
894                     if (scflags & MAY_HITMON) {
895                         stmp->range--;
896                         if (ohitmon(mtmp, stmp->obj, 1, FALSE)) {
897                             stmp->obj = (struct obj *) 0;
898                             stmp->stopped = TRUE;
899                         }
900                     }
901                 } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) {
902                     if (scflags & MAY_HITYOU) {
903                         int hitvalu, hitu;
904
905                         if (multi)
906                             nomul(0);
907                         hitvalu = 8 + stmp->obj->spe;
908                         if (bigmonst(youmonst.data))
909                             hitvalu++;
910                         hitu = thitu(hitvalu, dmgval(stmp->obj, &youmonst),
911                                      &stmp->obj, (char *) 0);
912                         if (!stmp->obj)
913                             stmp->stopped = TRUE;
914                         if (hitu) {
915                             stmp->range -= 3;
916                             stop_occupation();
917                         }
918                     }
919                 } else {
920                     if (scflags & VIS_EFFECTS) {
921                         /* tmp_at(bhitpos.x, bhitpos.y); */
922                         /* delay_output(); */
923                     }
924                 }
925                 stmp->ox = bhitpos.x;
926                 stmp->oy = bhitpos.y;
927             }
928         }
929     }
930     for (stmp = schain; stmp; stmp = stmp2) {
931         int x, y;
932
933         stmp2 = stmp->next;
934         x = stmp->ox;
935         y = stmp->oy;
936         if (stmp->obj) {
937             if (x != sx || y != sy)
938                 total += stmp->obj->quan;
939             place_object(stmp->obj, x, y);
940             stackobj(stmp->obj);
941         }
942         free((genericptr_t) stmp);
943         newsym(x, y);
944     }
945     newsym(sx, sy);
946     if (sx == u.ux && sy == u.uy && u.uundetected
947         && hides_under(youmonst.data))
948         (void) hideunder(&youmonst);
949     return total;
950 }
951
952 /*
953  * Splatter burning oil from x,y to the surrounding area.
954  *
955  * This routine should really take a how and direction parameters.
956  * The how is how it was caused, e.g. kicked verses thrown.  The
957  * direction is which way to spread the flaming oil.  Different
958  * "how"s would give different dispersal patterns.  For example,
959  * kicking a burning flask will splatter differently from a thrown
960  * flask hitting the ground.
961  *
962  * For now, just perform a "regular" explosion.
963  */
964 void
965 splatter_burning_oil(x, y, diluted_oil)
966 int x, y;
967 boolean diluted_oil;
968 {
969     int dmg = d(diluted_oil ? 3 : 4, 4);
970
971 /* ZT_SPELL(ZT_FIRE) = ZT_SPELL(AD_FIRE-1) = 10+(2-1) = 11 */
972 #define ZT_SPELL_O_FIRE 11 /* value kludge, see zap.c */
973     explode(x, y, ZT_SPELL_O_FIRE, dmg, BURNING_OIL, EXPL_FIERY);
974 }
975
976 /* lit potion of oil is exploding; extinguish it as a light source before
977    possibly killing the hero and attempting to save bones */
978 void
979 explode_oil(obj, x, y)
980 struct obj *obj;
981 int x, y;
982 {
983     boolean diluted_oil = obj->odiluted;
984
985     if (!obj->lamplit)
986         impossible("exploding unlit oil");
987     end_burn(obj, TRUE);
988     splatter_burning_oil(x, y, diluted_oil);
989 }
990
991 /*explode.c*/