OSDN Git Service

adjust for patch
[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 /*JP
609                     pline("It is fatal.");
610 */
611                     pline("\82»\82ê\82Í\92v\96½\93I\82¾\81D");
612                 else
613 /*JP
614                     pline_The("%s is fatal.", str);
615 */
616                     pline_The("%s\82Í\92v\96½\93I\82¾\81D", str);
617                 /* Known BUG: BURNING suppresses corpse in bones data,
618                    but done does not handle killer reason correctly */
619                 done((adtyp == AD_FIRE) ? BURNING : DIED);
620             }
621         }
622         exercise(A_STR, FALSE);
623     }
624
625     if (shopdamage) {
626 #if 0 /*JP*/
627         pay_for_damage(adtyp == AD_FIRE
628                            ? "burn away"
629                            : adtyp == AD_COLD
630                                  ? "shatter"
631                                  : adtyp == AD_DISN ? "disintegrate"
632                                                     : "destroy",
633                        FALSE);
634 #else
635         pay_for_damage(adtyp == AD_FIRE
636                            ? "\94R\82â\82·"
637                            : adtyp == AD_COLD
638                                  ? "\95²\81X\82É\82·\82é"
639                                  : adtyp == AD_DISN ? "\95²\8dÓ\82·\82é"
640                                                     : "\94j\89ó\82·\82é",
641                        FALSE);
642 #endif
643     }
644
645     /* explosions are noisy */
646     i = dam * dam;
647     if (i < 50)
648         i = 50; /* in case random damage is very small */
649     if (inside_engulfer)
650         i = (i + 3) / 4;
651     wake_nearto(x, y, i);
652 }
653
654 struct scatter_chain {
655     struct scatter_chain *next; /* pointer to next scatter item */
656     struct obj *obj;            /* pointer to the object        */
657     xchar ox;                   /* location of                  */
658     xchar oy;                   /*      item                    */
659     schar dx;                   /* direction of                 */
660     schar dy;                   /*      travel                  */
661     int range;                  /* range of object              */
662     boolean stopped;            /* flag for in-motion/stopped   */
663 };
664
665 /*
666  * scflags:
667  *      VIS_EFFECTS     Add visual effects to display
668  *      MAY_HITMON      Objects may hit monsters
669  *      MAY_HITYOU      Objects may hit hero
670  *      MAY_HIT         Objects may hit you or monsters
671  *      MAY_DESTROY     Objects may be destroyed at random
672  *      MAY_FRACTURE    Stone objects can be fractured (statues, boulders)
673  */
674
675 /* returns number of scattered objects */
676 long
677 scatter(sx, sy, blastforce, scflags, obj)
678 int sx, sy;     /* location of objects to scatter */
679 int blastforce; /* force behind the scattering */
680 unsigned int scflags;
681 struct obj *obj; /* only scatter this obj        */
682 {
683     register struct obj *otmp;
684     register int tmp;
685     int farthest = 0;
686     uchar typ;
687     long qtmp;
688     boolean used_up;
689     boolean individual_object = obj ? TRUE : FALSE;
690     struct monst *mtmp;
691     struct scatter_chain *stmp, *stmp2 = 0;
692     struct scatter_chain *schain = (struct scatter_chain *) 0;
693     long total = 0L;
694
695     while ((otmp = individual_object ? obj : level.objects[sx][sy]) != 0) {
696         if (otmp->quan > 1L) {
697             qtmp = otmp->quan - 1L;
698             if (qtmp > LARGEST_INT)
699                 qtmp = LARGEST_INT;
700             qtmp = (long) rnd((int) qtmp);
701             otmp = splitobj(otmp, qtmp);
702         } else {
703             obj = (struct obj *) 0; /* all used */
704         }
705         obj_extract_self(otmp);
706         used_up = FALSE;
707
708         /* 9 in 10 chance of fracturing boulders or statues */
709         if ((scflags & MAY_FRACTURE)
710             && ((otmp->otyp == BOULDER) || (otmp->otyp == STATUE))
711             && rn2(10)) {
712             if (otmp->otyp == BOULDER) {
713 /*JP
714                 pline("%s apart.", Tobjnam(otmp, "break"));
715 */
716                 pline("%s\82Í\88ê\95\94\95ª\82ª\8dÓ\82¯\82½\81D",xname(otmp));
717                 fracture_rock(otmp);
718                 place_object(otmp, sx, sy);
719                 if ((otmp = sobj_at(BOULDER, sx, sy)) != 0) {
720                     /* another boulder here, restack it to the top */
721                     obj_extract_self(otmp);
722                     place_object(otmp, sx, sy);
723                 }
724             } else {
725                 struct trap *trap;
726
727                 if ((trap = t_at(sx, sy)) && trap->ttyp == STATUE_TRAP)
728                     deltrap(trap);
729 /*JP
730                 pline("%s.", Tobjnam(otmp, "crumble"));
731 */
732                 pline("%s\82Í\82±\82È\82²\82È\82É\82È\82Á\82½\81D",xname(otmp));
733                 (void) break_statue(otmp);
734 #ifndef FIX_BUG_C340_2
735                 place_object(otmp, sx, sy); /* put fragments on floor */
736 #endif
737             }
738             used_up = TRUE;
739
740             /* 1 in 10 chance of destruction of obj; glass, egg destruction */
741         } else if ((scflags & MAY_DESTROY)
742                    && (!rn2(10) || (objects[otmp->otyp].oc_material == GLASS
743                                     || otmp->otyp == EGG))) {
744             if (breaks(otmp, (xchar) sx, (xchar) sy))
745                 used_up = TRUE;
746         }
747
748         if (!used_up) {
749             stmp =
750                 (struct scatter_chain *) alloc(sizeof(struct scatter_chain));
751             stmp->next = (struct scatter_chain *) 0;
752             stmp->obj = otmp;
753             stmp->ox = sx;
754             stmp->oy = sy;
755             tmp = rn2(8); /* get the direction */
756             stmp->dx = xdir[tmp];
757             stmp->dy = ydir[tmp];
758             tmp = blastforce - (otmp->owt / 40);
759             if (tmp < 1)
760                 tmp = 1;
761             stmp->range = rnd(tmp); /* anywhere up to that determ. by wt */
762             if (farthest < stmp->range)
763                 farthest = stmp->range;
764             stmp->stopped = FALSE;
765             if (!schain)
766                 schain = stmp;
767             else
768                 stmp2->next = stmp;
769             stmp2 = stmp;
770         }
771     }
772
773     while (farthest-- > 0) {
774         for (stmp = schain; stmp; stmp = stmp->next) {
775             if ((stmp->range-- > 0) && (!stmp->stopped)) {
776                 bhitpos.x = stmp->ox + stmp->dx;
777                 bhitpos.y = stmp->oy + stmp->dy;
778                 typ = levl[bhitpos.x][bhitpos.y].typ;
779                 if (!isok(bhitpos.x, bhitpos.y)) {
780                     bhitpos.x -= stmp->dx;
781                     bhitpos.y -= stmp->dy;
782                     stmp->stopped = TRUE;
783                 } else if (!ZAP_POS(typ)
784                            || closed_door(bhitpos.x, bhitpos.y)) {
785                     bhitpos.x -= stmp->dx;
786                     bhitpos.y -= stmp->dy;
787                     stmp->stopped = TRUE;
788                 } else if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
789                     if (scflags & MAY_HITMON) {
790                         stmp->range--;
791                         if (ohitmon(mtmp, stmp->obj, 1, FALSE)) {
792                             stmp->obj = (struct obj *) 0;
793                             stmp->stopped = TRUE;
794                         }
795                     }
796                 } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) {
797                     if (scflags & MAY_HITYOU) {
798                         int hitvalu, hitu;
799
800                         if (multi)
801                             nomul(0);
802                         hitvalu = 8 + stmp->obj->spe;
803                         if (bigmonst(youmonst.data))
804                             hitvalu++;
805                         hitu = thitu(hitvalu, dmgval(stmp->obj, &youmonst),
806                                      stmp->obj, (char *) 0);
807                         if (hitu) {
808                             stmp->range -= 3;
809                             stop_occupation();
810                         }
811                     }
812                 } else {
813                     if (scflags & VIS_EFFECTS) {
814                         /* tmp_at(bhitpos.x, bhitpos.y); */
815                         /* delay_output(); */
816                     }
817                 }
818                 stmp->ox = bhitpos.x;
819                 stmp->oy = bhitpos.y;
820             }
821         }
822     }
823     for (stmp = schain; stmp; stmp = stmp2) {
824         int x, y;
825
826         stmp2 = stmp->next;
827         x = stmp->ox;
828         y = stmp->oy;
829         if (stmp->obj) {
830             if (x != sx || y != sy)
831                 total += stmp->obj->quan;
832             place_object(stmp->obj, x, y);
833             stackobj(stmp->obj);
834         }
835         free((genericptr_t) stmp);
836         newsym(x, y);
837     }
838
839     return total;
840 }
841
842 /*
843  * Splatter burning oil from x,y to the surrounding area.
844  *
845  * This routine should really take a how and direction parameters.
846  * The how is how it was caused, e.g. kicked verses thrown.  The
847  * direction is which way to spread the flaming oil.  Different
848  * "how"s would give different dispersal patterns.  For example,
849  * kicking a burning flask will splatter differently from a thrown
850  * flask hitting the ground.
851  *
852  * For now, just perform a "regular" explosion.
853  */
854 void
855 splatter_burning_oil(x, y)
856 int x, y;
857 {
858 /* ZT_SPELL(ZT_FIRE) = ZT_SPELL(AD_FIRE-1) = 10+(2-1) = 11 */
859 #define ZT_SPELL_O_FIRE 11 /* value kludge, see zap.c */
860     explode(x, y, ZT_SPELL_O_FIRE, d(4, 4), BURNING_OIL, EXPL_FIERY);
861 }
862
863 /* lit potion of oil is exploding; extinguish it as a light source before
864    possibly killing the hero and attempting to save bones */
865 void
866 explode_oil(obj, x, y)
867 struct obj *obj;
868 int x, y;
869 {
870     if (!obj->lamplit)
871         impossible("exploding unlit oil");
872     end_burn(obj, TRUE);
873     splatter_burning_oil(x, y);
874 }
875
876 /*explode.c*/