OSDN Git Service

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