OSDN Git Service

import nethack-3.6.0
[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 #include "hack.h"
6
7 /* Note: Arrays are column first, while the screen is row first */
8 static int explosion[3][3] = { { S_explode1, S_explode4, S_explode7 },
9                                { S_explode2, S_explode5, S_explode8 },
10                                { S_explode3, S_explode6, S_explode9 } };
11
12 /* Note: I had to choose one of three possible kinds of "type" when writing
13  * this function: a wand type (like in zap.c), an adtyp, or an object type.
14  * Wand types get complex because they must be converted to adtyps for
15  * determining such things as fire resistance.  Adtyps get complex in that
16  * they don't supply enough information--was it a player or a monster that
17  * did it, and with a wand, spell, or breath weapon?  Object types share both
18  * these disadvantages....
19  *
20  * Important note about Half_physical_damage:
21  *      Unlike losehp(), explode() makes the Half_physical_damage adjustments
22  *      itself, so the caller should never have done that ahead of time.
23  *      It has to be done this way because the damage value is applied to
24  *      things beside the player. Care is taken within explode() to ensure
25  *      that Half_physical_damage only affects the damage applied to the hero.
26  */
27 void
28 explode(x, y, type, dam, olet, expltype)
29 int x, y;
30 int type; /* the same as in zap.c; passes -(wand typ) for some WAND_CLASS */
31 int dam;
32 char olet;
33 int expltype;
34 {
35     int i, j, k, damu = dam;
36     boolean starting = 1;
37     boolean visible, any_shield;
38     int uhurt = 0; /* 0=unhurt, 1=items damaged, 2=you and items damaged */
39     const char *str = (const char *) 0;
40     int idamres, idamnonres;
41     struct monst *mtmp, *mdef = 0;
42     uchar adtyp;
43     int explmask[3][3];
44     /* 0=normal explosion, 1=do shieldeff, 2=do nothing */
45     boolean shopdamage = FALSE, generic = FALSE, physical_dmg = FALSE,
46             do_hallu = FALSE, inside_engulfer;
47     char hallu_buf[BUFSZ];
48     short exploding_wand_typ = 0;
49
50     if (olet == WAND_CLASS) { /* retributive strike */
51         /* 'type' is passed as (wand's object type * -1); save
52            object type and convert 'type' itself to zap-type */
53         if (type < 0) {
54             type = -type;
55             exploding_wand_typ = (short) type;
56             /* most attack wands produce specific explosions;
57                other types produce a generic magical explosion */
58             if (objects[type].oc_dir == RAY
59                 && type != WAN_DIGGING && type != WAN_SLEEP) {
60                 type -= WAN_MAGIC_MISSILE;
61                 if (type < 0 || type > 9) {
62                     impossible("explode: wand has bad zap type (%d).", type);
63                     type = 0;
64                 }
65             } else
66                 type = 0;
67         }
68         switch (Role_switch) {
69         case PM_PRIEST:
70         case PM_MONK:
71         case PM_WIZARD:
72             damu /= 5;
73             break;
74         case PM_HEALER:
75         case PM_KNIGHT:
76             damu /= 2;
77             break;
78         default:
79             break;
80         }
81     }
82     /* muse_unslime: SCR_FIRE */
83     if (expltype < 0) {
84         /* hero gets credit/blame for killing this monster, not others */
85         mdef = m_at(x, y);
86         expltype = -expltype;
87     }
88     /* if hero is engulfed and caused the explosion, only hero and
89        engulfer will be affected */
90     inside_engulfer = (u.uswallow && type >= 0);
91
92     if (olet == MON_EXPLODE) {
93         str = killer.name;
94         do_hallu = Hallucination && strstri(str, "'s explosion");
95         adtyp = AD_PHYS;
96     } else
97         switch (abs(type) % 10) {
98         case 0:
99             str = "magical blast";
100             adtyp = AD_MAGM;
101             break;
102         case 1:
103             str = (olet == BURNING_OIL) ? "burning oil"
104                      : (olet == SCROLL_CLASS) ? "tower of flame" : "fireball";
105             /* fire damage, not physical damage */
106             adtyp = AD_FIRE;
107             break;
108         case 2:
109             str = "ball of cold";
110             adtyp = AD_COLD;
111             break;
112         case 4:
113             str = (olet == WAND_CLASS) ? "death field"
114                                        : "disintegration field";
115             adtyp = AD_DISN;
116             break;
117         case 5:
118             str = "ball of lightning";
119             adtyp = AD_ELEC;
120             break;
121         case 6:
122             str = "poison gas cloud";
123             adtyp = AD_DRST;
124             break;
125         case 7:
126             str = "splash of acid";
127             adtyp = AD_ACID;
128             break;
129         default:
130             impossible("explosion base type %d?", type);
131             return;
132         }
133
134     any_shield = visible = FALSE;
135     for (i = 0; i < 3; i++)
136         for (j = 0; j < 3; j++) {
137             if (!isok(i + x - 1, j + y - 1)) {
138                 explmask[i][j] = 2;
139                 continue;
140             } else
141                 explmask[i][j] = 0;
142
143             if (i + x - 1 == u.ux && j + y - 1 == u.uy) {
144                 switch (adtyp) {
145                 case AD_PHYS:
146                     explmask[i][j] = 0;
147                     break;
148                 case AD_MAGM:
149                     explmask[i][j] = !!Antimagic;
150                     break;
151                 case AD_FIRE:
152                     explmask[i][j] = !!Fire_resistance;
153                     break;
154                 case AD_COLD:
155                     explmask[i][j] = !!Cold_resistance;
156                     break;
157                 case AD_DISN:
158                     explmask[i][j] = (olet == WAND_CLASS)
159                                          ? !!(nonliving(youmonst.data)
160                                               || is_demon(youmonst.data))
161                                          : !!Disint_resistance;
162                     break;
163                 case AD_ELEC:
164                     explmask[i][j] = !!Shock_resistance;
165                     break;
166                 case AD_DRST:
167                     explmask[i][j] = !!Poison_resistance;
168                     break;
169                 case AD_ACID:
170                     explmask[i][j] = !!Acid_resistance;
171                     physical_dmg = TRUE;
172                     break;
173                 default:
174                     impossible("explosion type %d?", adtyp);
175                     break;
176                 }
177             }
178             /* can be both you and mtmp if you're swallowed */
179             mtmp = m_at(i + x - 1, j + y - 1);
180             if (!mtmp && i + x - 1 == u.ux && j + y - 1 == u.uy)
181                 mtmp = u.usteed;
182             if (mtmp) {
183                 if (mtmp->mhp < 1)
184                     explmask[i][j] = 2;
185                 else
186                     switch (adtyp) {
187                     case AD_PHYS:
188                         break;
189                     case AD_MAGM:
190                         explmask[i][j] |= resists_magm(mtmp);
191                         break;
192                     case AD_FIRE:
193                         explmask[i][j] |= resists_fire(mtmp);
194                         break;
195                     case AD_COLD:
196                         explmask[i][j] |= resists_cold(mtmp);
197                         break;
198                     case AD_DISN:
199                         explmask[i][j] |= (olet == WAND_CLASS)
200                                               ? (nonliving(mtmp->data)
201                                                  || is_demon(mtmp->data)
202                                                  || is_vampshifter(mtmp))
203                                               : resists_disint(mtmp);
204                         break;
205                     case AD_ELEC:
206                         explmask[i][j] |= resists_elec(mtmp);
207                         break;
208                     case AD_DRST:
209                         explmask[i][j] |= resists_poison(mtmp);
210                         break;
211                     case AD_ACID:
212                         explmask[i][j] |= resists_acid(mtmp);
213                         break;
214                     default:
215                         impossible("explosion type %d?", adtyp);
216                         break;
217                     }
218             }
219             if (mtmp && cansee(i + x - 1, j + y - 1) && !canspotmon(mtmp))
220                 map_invisible(i + x - 1, j + y - 1);
221             else if (!mtmp && glyph_is_invisible(
222                                   levl[i + x - 1][j + y - 1].glyph)) {
223                 unmap_object(i + x - 1, j + y - 1);
224                 newsym(i + x - 1, j + y - 1);
225             }
226             if (cansee(i + x - 1, j + y - 1))
227                 visible = TRUE;
228             if (explmask[i][j] == 1)
229                 any_shield = TRUE;
230         }
231
232     if (visible) {
233         /* Start the explosion */
234         for (i = 0; i < 3; i++)
235             for (j = 0; j < 3; j++) {
236                 if (explmask[i][j] == 2)
237                     continue;
238                 tmp_at(starting ? DISP_BEAM : DISP_CHANGE,
239                        explosion_to_glyph(expltype, explosion[i][j]));
240                 tmp_at(i + x - 1, j + y - 1);
241                 starting = 0;
242             }
243         curs_on_u(); /* will flush screen and output */
244
245         if (any_shield && flags.sparkle) { /* simulate shield effect */
246             for (k = 0; k < SHIELD_COUNT; k++) {
247                 for (i = 0; i < 3; i++)
248                     for (j = 0; j < 3; j++) {
249                         if (explmask[i][j] == 1)
250                             /*
251                              * Bypass tmp_at() and send the shield glyphs
252                              * directly to the buffered screen.  tmp_at()
253                              * will clean up the location for us later.
254                              */
255                             show_glyph(i + x - 1, j + y - 1,
256                                        cmap_to_glyph(shield_static[k]));
257                     }
258                 curs_on_u(); /* will flush screen and output */
259                 delay_output();
260             }
261
262             /* Cover last shield glyph with blast symbol. */
263             for (i = 0; i < 3; i++)
264                 for (j = 0; j < 3; j++) {
265                     if (explmask[i][j] == 1)
266                         show_glyph(
267                             i + x - 1, j + y - 1,
268                             explosion_to_glyph(expltype, explosion[i][j]));
269                 }
270
271         } else { /* delay a little bit. */
272             delay_output();
273             delay_output();
274         }
275
276         tmp_at(DISP_END, 0); /* clear the explosion */
277     } else {
278         if (olet == MON_EXPLODE) {
279             str = "explosion";
280             generic = TRUE;
281         }
282         if (!Deaf && olet != SCROLL_CLASS)
283             You_hear("a blast.");
284     }
285
286     if (dam)
287         for (i = 0; i < 3; i++)
288             for (j = 0; j < 3; j++) {
289                 if (explmask[i][j] == 2)
290                     continue;
291                 if (i + x - 1 == u.ux && j + y - 1 == u.uy)
292                     uhurt = (explmask[i][j] == 1) ? 1 : 2;
293                 /* for inside_engulfer, only <u.ux,u.uy> is affected */
294                 else if (inside_engulfer)
295                     continue;
296                 idamres = idamnonres = 0;
297                 if (type >= 0 && !u.uswallow)
298                     (void) zap_over_floor((xchar) (i + x - 1),
299                                           (xchar) (j + y - 1), type,
300                                           &shopdamage, exploding_wand_typ);
301
302                 mtmp = m_at(i + x - 1, j + y - 1);
303                 if (!mtmp && i + x - 1 == u.ux && j + y - 1 == u.uy)
304                     mtmp = u.usteed;
305                 if (!mtmp)
306                     continue;
307                 if (do_hallu) {
308                     /* replace "gas spore" with a different description
309                        for each target (we can't distinguish personal names
310                        like "Barney" here in order to suppress "the" below,
311                        so avoid any which begins with a capital letter) */
312                     do {
313                         Sprintf(hallu_buf, "%s explosion",
314                                 s_suffix(rndmonnam(NULL)));
315                     } while (*hallu_buf != lowc(*hallu_buf));
316                     str = hallu_buf;
317                 }
318                 if (u.uswallow && mtmp == u.ustuck) {
319                     const char *adj = NULL;
320                     if (is_animal(u.ustuck->data)) {
321                         switch (adtyp) {
322                         case AD_FIRE:
323                             adj = "heartburn";
324                             break;
325                         case AD_COLD:
326                             adj = "chilly";
327                             break;
328                         case AD_DISN:
329                             if (olet == WAND_CLASS)
330                                 adj = "irradiated by pure energy";
331                             else
332                                 adj = "perforated";
333                             break;
334                         case AD_ELEC:
335                             adj = "shocked";
336                             break;
337                         case AD_DRST:
338                             adj = "poisoned";
339                             break;
340                         case AD_ACID:
341                             adj = "an upset stomach";
342                             break;
343                         default:
344                             adj = "fried";
345                             break;
346                         }
347                         pline("%s gets %s!", Monnam(u.ustuck), adj);
348                     } else {
349                         switch (adtyp) {
350                         case AD_FIRE:
351                             adj = "toasted";
352                             break;
353                         case AD_COLD:
354                             adj = "chilly";
355                             break;
356                         case AD_DISN:
357                             if (olet == WAND_CLASS)
358                                 adj = "overwhelmed by pure energy";
359                             else
360                                 adj = "perforated";
361                             break;
362                         case AD_ELEC:
363                             adj = "shocked";
364                             break;
365                         case AD_DRST:
366                             adj = "intoxicated";
367                             break;
368                         case AD_ACID:
369                             adj = "burned";
370                             break;
371                         default:
372                             adj = "fried";
373                             break;
374                         }
375                         pline("%s gets slightly %s!", Monnam(u.ustuck), adj);
376                     }
377                 } else if (cansee(i + x - 1, j + y - 1)) {
378                     if (mtmp->m_ap_type)
379                         seemimic(mtmp);
380                     pline("%s is caught in the %s!", Monnam(mtmp), str);
381                 }
382
383                 idamres += destroy_mitem(mtmp, SCROLL_CLASS, (int) adtyp);
384                 idamres += destroy_mitem(mtmp, SPBOOK_CLASS, (int) adtyp);
385                 idamnonres += destroy_mitem(mtmp, POTION_CLASS, (int) adtyp);
386                 idamnonres += destroy_mitem(mtmp, WAND_CLASS, (int) adtyp);
387                 idamnonres += destroy_mitem(mtmp, RING_CLASS, (int) adtyp);
388
389                 if (explmask[i][j] == 1) {
390                     golemeffects(mtmp, (int) adtyp, dam + idamres);
391                     mtmp->mhp -= idamnonres;
392                 } else {
393                     /* call resist with 0 and do damage manually so 1) we can
394                      * get out the message before doing the damage, and 2) we
395                      * can
396                      * call mondied, not killed, if it's not your blast
397                      */
398                     int mdam = dam;
399
400                     if (resist(mtmp, olet, 0, FALSE)) {
401                         /* inside_engulfer: <i+x-1,j+y-1> == <u.ux,u.uy> */
402                         if (cansee(i + x - 1, j + y - 1) || inside_engulfer)
403                             pline("%s resists the %s!", Monnam(mtmp), str);
404                         mdam = (dam + 1) / 2;
405                     }
406                     if (mtmp == u.ustuck)
407                         mdam *= 2;
408                     if (resists_cold(mtmp) && adtyp == AD_FIRE)
409                         mdam *= 2;
410                     else if (resists_fire(mtmp) && adtyp == AD_COLD)
411                         mdam *= 2;
412                     mtmp->mhp -= mdam;
413                     mtmp->mhp -= (idamres + idamnonres);
414                 }
415                 if (mtmp->mhp <= 0) {
416                     if (mdef ? (mtmp == mdef) : !context.mon_moving)
417                         killed(mtmp);
418                     else
419                         monkilled(mtmp, "", (int) adtyp);
420                 } else if (!context.mon_moving) {
421                     /* all affected monsters, even if mdef is set */
422                     setmangry(mtmp);
423                 }
424             }
425
426     /* Do your injury last */
427     if (uhurt) {
428         /* give message for any monster-induced explosion
429            or player-induced one other than scroll of fire */
430         if (flags.verbose && (type < 0 || olet != SCROLL_CLASS)) {
431             if (do_hallu) { /* (see explanation above) */
432                 do {
433                     Sprintf(hallu_buf, "%s explosion",
434                             s_suffix(rndmonnam(NULL)));
435                 } while (*hallu_buf != lowc(*hallu_buf));
436                 str = hallu_buf;
437             }
438             You("are caught in the %s!", str);
439             iflags.last_msg = PLNMSG_CAUGHT_IN_EXPLOSION;
440         }
441         /* do property damage first, in case we end up leaving bones */
442         if (adtyp == AD_FIRE)
443             burn_away_slime();
444         if (Invulnerable) {
445             damu = 0;
446             You("are unharmed!");
447         } else if (adtyp == AD_PHYS || physical_dmg)
448             damu = Maybe_Half_Phys(damu);
449         if (adtyp == AD_FIRE)
450             (void) burnarmor(&youmonst);
451         destroy_item(SCROLL_CLASS, (int) adtyp);
452         destroy_item(SPBOOK_CLASS, (int) adtyp);
453         destroy_item(POTION_CLASS, (int) adtyp);
454         destroy_item(RING_CLASS, (int) adtyp);
455         destroy_item(WAND_CLASS, (int) adtyp);
456
457         ugolemeffects((int) adtyp, damu);
458         if (uhurt == 2) {
459             if (Upolyd)
460                 u.mh -= damu;
461             else
462                 u.uhp -= damu;
463             context.botl = 1;
464         }
465
466         if (u.uhp <= 0 || (Upolyd && u.mh <= 0)) {
467             if (Upolyd) {
468                 rehumanize();
469             } else {
470                 if (olet == MON_EXPLODE) {
471                     /* killer handled by caller */
472                     if (generic)
473                         killer.name[0] = 0;
474                     else if (str != killer.name && str != hallu_buf)
475                         Strcpy(killer.name, str);
476                     killer.format = KILLED_BY_AN;
477                 } else if (type >= 0 && olet != SCROLL_CLASS) {
478                     killer.format = NO_KILLER_PREFIX;
479                     Sprintf(killer.name, "caught %sself in %s own %s", uhim(),
480                             uhis(), str);
481                 } else {
482                     killer.format = (!strcmpi(str, "tower of flame")
483                                      || !strcmpi(str, "fireball"))
484                                         ? KILLED_BY_AN
485                                         : KILLED_BY;
486                     Strcpy(killer.name, str);
487                 }
488                 if (iflags.last_msg == PLNMSG_CAUGHT_IN_EXPLOSION
489                     || iflags.last_msg
490                            == PLNMSG_TOWER_OF_FLAME) /*seffects()*/
491                     pline("It is fatal.");
492                 else
493                     pline_The("%s is fatal.", str);
494                 /* Known BUG: BURNING suppresses corpse in bones data,
495                    but done does not handle killer reason correctly */
496                 done((adtyp == AD_FIRE) ? BURNING : DIED);
497             }
498         }
499         exercise(A_STR, FALSE);
500     }
501
502     if (shopdamage) {
503         pay_for_damage(adtyp == AD_FIRE
504                            ? "burn away"
505                            : adtyp == AD_COLD
506                                  ? "shatter"
507                                  : adtyp == AD_DISN ? "disintegrate"
508                                                     : "destroy",
509                        FALSE);
510     }
511
512     /* explosions are noisy */
513     i = dam * dam;
514     if (i < 50)
515         i = 50; /* in case random damage is very small */
516     if (inside_engulfer)
517         i = (i + 3) / 4;
518     wake_nearto(x, y, i);
519 }
520
521 struct scatter_chain {
522     struct scatter_chain *next; /* pointer to next scatter item */
523     struct obj *obj;            /* pointer to the object        */
524     xchar ox;                   /* location of                  */
525     xchar oy;                   /*      item                    */
526     schar dx;                   /* direction of                 */
527     schar dy;                   /*      travel                  */
528     int range;                  /* range of object              */
529     boolean stopped;            /* flag for in-motion/stopped   */
530 };
531
532 /*
533  * scflags:
534  *      VIS_EFFECTS     Add visual effects to display
535  *      MAY_HITMON      Objects may hit monsters
536  *      MAY_HITYOU      Objects may hit hero
537  *      MAY_HIT         Objects may hit you or monsters
538  *      MAY_DESTROY     Objects may be destroyed at random
539  *      MAY_FRACTURE    Stone objects can be fractured (statues, boulders)
540  */
541
542 /* returns number of scattered objects */
543 long
544 scatter(sx, sy, blastforce, scflags, obj)
545 int sx, sy;     /* location of objects to scatter */
546 int blastforce; /* force behind the scattering */
547 unsigned int scflags;
548 struct obj *obj; /* only scatter this obj        */
549 {
550     register struct obj *otmp;
551     register int tmp;
552     int farthest = 0;
553     uchar typ;
554     long qtmp;
555     boolean used_up;
556     boolean individual_object = obj ? TRUE : FALSE;
557     struct monst *mtmp;
558     struct scatter_chain *stmp, *stmp2 = 0;
559     struct scatter_chain *schain = (struct scatter_chain *) 0;
560     long total = 0L;
561
562     while ((otmp = individual_object ? obj : level.objects[sx][sy]) != 0) {
563         if (otmp->quan > 1L) {
564             qtmp = otmp->quan - 1L;
565             if (qtmp > LARGEST_INT)
566                 qtmp = LARGEST_INT;
567             qtmp = (long) rnd((int) qtmp);
568             otmp = splitobj(otmp, qtmp);
569         } else {
570             obj = (struct obj *) 0; /* all used */
571         }
572         obj_extract_self(otmp);
573         used_up = FALSE;
574
575         /* 9 in 10 chance of fracturing boulders or statues */
576         if ((scflags & MAY_FRACTURE)
577             && ((otmp->otyp == BOULDER) || (otmp->otyp == STATUE))
578             && rn2(10)) {
579             if (otmp->otyp == BOULDER) {
580                 pline("%s apart.", Tobjnam(otmp, "break"));
581                 fracture_rock(otmp);
582                 place_object(otmp, sx, sy);
583                 if ((otmp = sobj_at(BOULDER, sx, sy)) != 0) {
584                     /* another boulder here, restack it to the top */
585                     obj_extract_self(otmp);
586                     place_object(otmp, sx, sy);
587                 }
588             } else {
589                 struct trap *trap;
590
591                 if ((trap = t_at(sx, sy)) && trap->ttyp == STATUE_TRAP)
592                     deltrap(trap);
593                 pline("%s.", Tobjnam(otmp, "crumble"));
594                 (void) break_statue(otmp);
595                 place_object(otmp, sx, sy); /* put fragments on floor */
596             }
597             used_up = TRUE;
598
599             /* 1 in 10 chance of destruction of obj; glass, egg destruction */
600         } else if ((scflags & MAY_DESTROY)
601                    && (!rn2(10) || (objects[otmp->otyp].oc_material == GLASS
602                                     || otmp->otyp == EGG))) {
603             if (breaks(otmp, (xchar) sx, (xchar) sy))
604                 used_up = TRUE;
605         }
606
607         if (!used_up) {
608             stmp =
609                 (struct scatter_chain *) alloc(sizeof(struct scatter_chain));
610             stmp->next = (struct scatter_chain *) 0;
611             stmp->obj = otmp;
612             stmp->ox = sx;
613             stmp->oy = sy;
614             tmp = rn2(8); /* get the direction */
615             stmp->dx = xdir[tmp];
616             stmp->dy = ydir[tmp];
617             tmp = blastforce - (otmp->owt / 40);
618             if (tmp < 1)
619                 tmp = 1;
620             stmp->range = rnd(tmp); /* anywhere up to that determ. by wt */
621             if (farthest < stmp->range)
622                 farthest = stmp->range;
623             stmp->stopped = FALSE;
624             if (!schain)
625                 schain = stmp;
626             else
627                 stmp2->next = stmp;
628             stmp2 = stmp;
629         }
630     }
631
632     while (farthest-- > 0) {
633         for (stmp = schain; stmp; stmp = stmp->next) {
634             if ((stmp->range-- > 0) && (!stmp->stopped)) {
635                 bhitpos.x = stmp->ox + stmp->dx;
636                 bhitpos.y = stmp->oy + stmp->dy;
637                 typ = levl[bhitpos.x][bhitpos.y].typ;
638                 if (!isok(bhitpos.x, bhitpos.y)) {
639                     bhitpos.x -= stmp->dx;
640                     bhitpos.y -= stmp->dy;
641                     stmp->stopped = TRUE;
642                 } else if (!ZAP_POS(typ)
643                            || closed_door(bhitpos.x, bhitpos.y)) {
644                     bhitpos.x -= stmp->dx;
645                     bhitpos.y -= stmp->dy;
646                     stmp->stopped = TRUE;
647                 } else if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
648                     if (scflags & MAY_HITMON) {
649                         stmp->range--;
650                         if (ohitmon(mtmp, stmp->obj, 1, FALSE)) {
651                             stmp->obj = (struct obj *) 0;
652                             stmp->stopped = TRUE;
653                         }
654                     }
655                 } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) {
656                     if (scflags & MAY_HITYOU) {
657                         int hitvalu, hitu;
658
659                         if (multi)
660                             nomul(0);
661                         hitvalu = 8 + stmp->obj->spe;
662                         if (bigmonst(youmonst.data))
663                             hitvalu++;
664                         hitu = thitu(hitvalu, dmgval(stmp->obj, &youmonst),
665                                      stmp->obj, (char *) 0);
666                         if (hitu) {
667                             stmp->range -= 3;
668                             stop_occupation();
669                         }
670                     }
671                 } else {
672                     if (scflags & VIS_EFFECTS) {
673                         /* tmp_at(bhitpos.x, bhitpos.y); */
674                         /* delay_output(); */
675                     }
676                 }
677                 stmp->ox = bhitpos.x;
678                 stmp->oy = bhitpos.y;
679             }
680         }
681     }
682     for (stmp = schain; stmp; stmp = stmp2) {
683         int x, y;
684
685         stmp2 = stmp->next;
686         x = stmp->ox;
687         y = stmp->oy;
688         if (stmp->obj) {
689             if (x != sx || y != sy)
690                 total += stmp->obj->quan;
691             place_object(stmp->obj, x, y);
692             stackobj(stmp->obj);
693         }
694         free((genericptr_t) stmp);
695         newsym(x, y);
696     }
697
698     return total;
699 }
700
701 /*
702  * Splatter burning oil from x,y to the surrounding area.
703  *
704  * This routine should really take a how and direction parameters.
705  * The how is how it was caused, e.g. kicked verses thrown.  The
706  * direction is which way to spread the flaming oil.  Different
707  * "how"s would give different dispersal patterns.  For example,
708  * kicking a burning flask will splatter differently from a thrown
709  * flask hitting the ground.
710  *
711  * For now, just perform a "regular" explosion.
712  */
713 void
714 splatter_burning_oil(x, y)
715 int x, y;
716 {
717 /* ZT_SPELL(ZT_FIRE) = ZT_SPELL(AD_FIRE-1) = 10+(2-1) = 11 */
718 #define ZT_SPELL_O_FIRE 11 /* value kludge, see zap.c */
719     explode(x, y, ZT_SPELL_O_FIRE, d(4, 4), BURNING_OIL, EXPL_FIERY);
720 }
721
722 /* lit potion of oil is exploding; extinguish it as a light source before
723    possibly killing the hero and attempting to save bones */
724 void
725 explode_oil(obj, x, y)
726 struct obj *obj;
727 int x, y;
728 {
729     if (!obj->lamplit)
730         impossible("exploding unlit oil");
731     end_burn(obj, TRUE);
732     splatter_burning_oil(x, y);
733 }
734
735 /*explode.c*/