OSDN Git Service

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