OSDN Git Service

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