Use define for iron ball weight increment
[aNetHack.git] / src / explode.c
blob0c736a7f95614bb7cedd96a513447531a9c942f3
1 /* NetHack 3.6 explode.c $NHDT-Date: 1450915435 2015/12/24 00:03:55 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.45 $ */
2 /* Copyright (C) 1990 by Ken Arromdee */
3 /* NetHack may be freely redistributed. See license for details. */
5 #include "hack.h"
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 } };
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....
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.
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;
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;
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;
65 } else
66 type = 0;
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;
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;
88 /* if hero is engulfed and caused the explosion, only hero and
89 engulfer will be affected */
90 inside_engulfer = (u.uswallow && type >= 0);
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;
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;
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;
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;
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);
226 if (cansee(i + x - 1, j + y - 1))
227 visible = TRUE;
228 if (explmask[i][j] == 1)
229 any_shield = TRUE;
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;
243 curs_on_u(); /* will flush screen and output */
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)
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.
255 show_glyph(i + x - 1, j + y - 1,
256 cmap_to_glyph(shield_static[k]));
258 curs_on_u(); /* will flush screen and output */
259 delay_output();
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]));
271 } else { /* delay a little bit. */
272 delay_output();
273 delay_output();
276 tmp_at(DISP_END, 0); /* clear the explosion */
277 } else {
278 if (olet == MON_EXPLODE) {
279 str = "explosion";
280 generic = TRUE;
282 if (!Deaf && olet != SCROLL_CLASS)
283 You_hear("a blast.");
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);
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((char *) 0)));
315 } while (*hallu_buf != lowc(*hallu_buf));
316 str = hallu_buf;
318 if (u.uswallow && mtmp == u.ustuck) {
319 const char *adj = (char *) 0;
321 if (is_animal(u.ustuck->data)) {
322 switch (adtyp) {
323 case AD_FIRE:
324 adj = "heartburn";
325 break;
326 case AD_COLD:
327 adj = "chilly";
328 break;
329 case AD_DISN:
330 if (olet == WAND_CLASS)
331 adj = "irradiated by pure energy";
332 else
333 adj = "perforated";
334 break;
335 case AD_ELEC:
336 adj = "shocked";
337 break;
338 case AD_DRST:
339 adj = "poisoned";
340 break;
341 case AD_ACID:
342 adj = "an upset stomach";
343 break;
344 default:
345 adj = "fried";
346 break;
348 pline("%s gets %s!", Monnam(u.ustuck), adj);
349 } else {
350 switch (adtyp) {
351 case AD_FIRE:
352 adj = "toasted";
353 break;
354 case AD_COLD:
355 adj = "chilly";
356 break;
357 case AD_DISN:
358 if (olet == WAND_CLASS)
359 adj = "overwhelmed by pure energy";
360 else
361 adj = "perforated";
362 break;
363 case AD_ELEC:
364 adj = "shocked";
365 break;
366 case AD_DRST:
367 adj = "intoxicated";
368 break;
369 case AD_ACID:
370 adj = "burned";
371 break;
372 default:
373 adj = "fried";
374 break;
376 pline("%s gets slightly %s!", Monnam(u.ustuck), adj);
378 } else if (cansee(i + x - 1, j + y - 1)) {
379 if (mtmp->m_ap_type)
380 seemimic(mtmp);
381 pline("%s is caught in the %s!", Monnam(mtmp), str);
384 idamres += destroy_mitem(mtmp, SCROLL_CLASS, (int) adtyp);
385 idamres += destroy_mitem(mtmp, SPBOOK_CLASS, (int) adtyp);
386 idamnonres += destroy_mitem(mtmp, POTION_CLASS, (int) adtyp);
387 idamnonres += destroy_mitem(mtmp, WAND_CLASS, (int) adtyp);
388 idamnonres += destroy_mitem(mtmp, RING_CLASS, (int) adtyp);
390 if (explmask[i][j] == 1) {
391 golemeffects(mtmp, (int) adtyp, dam + idamres);
392 mtmp->mhp -= idamnonres;
393 } else {
394 /* call resist with 0 and do damage manually so 1) we can
395 * get out the message before doing the damage, and 2) we
396 * can
397 * call mondied, not killed, if it's not your blast
399 int mdam = dam;
401 if (resist(mtmp, olet, 0, FALSE)) {
402 /* inside_engulfer: <i+x-1,j+y-1> == <u.ux,u.uy> */
403 if (cansee(i + x - 1, j + y - 1) || inside_engulfer)
404 pline("%s resists the %s!", Monnam(mtmp), str);
405 mdam = (dam + 1) / 2;
407 if (mtmp == u.ustuck)
408 mdam *= 2;
409 if (resists_cold(mtmp) && adtyp == AD_FIRE)
410 mdam *= 2;
411 else if (resists_fire(mtmp) && adtyp == AD_COLD)
412 mdam *= 2;
413 mtmp->mhp -= mdam;
414 mtmp->mhp -= (idamres + idamnonres);
416 if (mtmp->mhp <= 0) {
417 if (mdef ? (mtmp == mdef) : !context.mon_moving)
418 killed(mtmp);
419 else
420 monkilled(mtmp, "", (int) adtyp);
421 } else if (!context.mon_moving) {
422 /* all affected monsters, even if mdef is set */
423 setmangry(mtmp);
427 /* Do your injury last */
428 if (uhurt) {
429 /* give message for any monster-induced explosion
430 or player-induced one other than scroll of fire */
431 if (flags.verbose && (type < 0 || olet != SCROLL_CLASS)) {
432 if (do_hallu) { /* (see explanation above) */
433 do {
434 Sprintf(hallu_buf, "%s explosion",
435 s_suffix(rndmonnam((char *) 0)));
436 } while (*hallu_buf != lowc(*hallu_buf));
437 str = hallu_buf;
439 You("are caught in the %s!", str);
440 iflags.last_msg = PLNMSG_CAUGHT_IN_EXPLOSION;
442 /* do property damage first, in case we end up leaving bones */
443 if (adtyp == AD_FIRE)
444 burn_away_slime();
445 if (Invulnerable) {
446 damu = 0;
447 You("are unharmed!");
448 } else if (adtyp == AD_PHYS || physical_dmg)
449 damu = Maybe_Half_Phys(damu);
450 if (adtyp == AD_FIRE)
451 (void) burnarmor(&youmonst);
452 destroy_item(SCROLL_CLASS, (int) adtyp);
453 destroy_item(SPBOOK_CLASS, (int) adtyp);
454 destroy_item(POTION_CLASS, (int) adtyp);
455 destroy_item(RING_CLASS, (int) adtyp);
456 destroy_item(WAND_CLASS, (int) adtyp);
458 ugolemeffects((int) adtyp, damu);
459 if (uhurt == 2) {
460 if (Upolyd)
461 u.mh -= damu;
462 else
463 u.uhp -= damu;
464 context.botl = 1;
467 if (u.uhp <= 0 || (Upolyd && u.mh <= 0)) {
468 if (Upolyd) {
469 rehumanize();
470 } else {
471 if (olet == MON_EXPLODE) {
472 if (generic) /* explosion was unseen; str=="explosion", */
473 ; /* killer.name=="gas spore's explosion" */
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);
488 if (iflags.last_msg == PLNMSG_CAUGHT_IN_EXPLOSION
489 || iflags.last_msg == PLNMSG_TOWER_OF_FLAME) /*seffects()*/
490 pline("It is fatal.");
491 else
492 pline_The("%s is fatal.", str);
493 /* Known BUG: BURNING suppresses corpse in bones data,
494 but done does not handle killer reason correctly */
495 done((adtyp == AD_FIRE) ? BURNING : DIED);
498 exercise(A_STR, FALSE);
501 if (shopdamage) {
502 pay_for_damage(adtyp == AD_FIRE
503 ? "burn away"
504 : adtyp == AD_COLD
505 ? "shatter"
506 : adtyp == AD_DISN ? "disintegrate"
507 : "destroy",
508 FALSE);
511 /* explosions are noisy */
512 i = dam * dam;
513 if (i < 50)
514 i = 50; /* in case random damage is very small */
515 if (inside_engulfer)
516 i = (i + 3) / 4;
517 wake_nearto(x, y, i);
520 struct scatter_chain {
521 struct scatter_chain *next; /* pointer to next scatter item */
522 struct obj *obj; /* pointer to the object */
523 xchar ox; /* location of */
524 xchar oy; /* item */
525 schar dx; /* direction of */
526 schar dy; /* travel */
527 int range; /* range of object */
528 boolean stopped; /* flag for in-motion/stopped */
532 * scflags:
533 * VIS_EFFECTS Add visual effects to display
534 * MAY_HITMON Objects may hit monsters
535 * MAY_HITYOU Objects may hit hero
536 * MAY_HIT Objects may hit you or monsters
537 * MAY_DESTROY Objects may be destroyed at random
538 * MAY_FRACTURE Stone objects can be fractured (statues, boulders)
541 /* returns number of scattered objects */
542 long
543 scatter(sx, sy, blastforce, scflags, obj)
544 int sx, sy; /* location of objects to scatter */
545 int blastforce; /* force behind the scattering */
546 unsigned int scflags;
547 struct obj *obj; /* only scatter this obj */
549 register struct obj *otmp;
550 register int tmp;
551 int farthest = 0;
552 uchar typ;
553 long qtmp;
554 boolean used_up;
555 boolean individual_object = obj ? TRUE : FALSE;
556 struct monst *mtmp;
557 struct scatter_chain *stmp, *stmp2 = 0;
558 struct scatter_chain *schain = (struct scatter_chain *) 0;
559 long total = 0L;
561 while ((otmp = individual_object ? obj : level.objects[sx][sy]) != 0) {
562 if (otmp->quan > 1L) {
563 qtmp = otmp->quan - 1L;
564 if (qtmp > LARGEST_INT)
565 qtmp = LARGEST_INT;
566 qtmp = (long) rnd((int) qtmp);
567 otmp = splitobj(otmp, qtmp);
568 } else {
569 obj = (struct obj *) 0; /* all used */
571 obj_extract_self(otmp);
572 used_up = FALSE;
574 /* 9 in 10 chance of fracturing boulders or statues */
575 if ((scflags & MAY_FRACTURE)
576 && ((otmp->otyp == BOULDER) || (otmp->otyp == STATUE))
577 && rn2(10)) {
578 if (otmp->otyp == BOULDER) {
579 pline("%s apart.", Tobjnam(otmp, "break"));
580 fracture_rock(otmp);
581 place_object(otmp, sx, sy);
582 if ((otmp = sobj_at(BOULDER, sx, sy)) != 0) {
583 /* another boulder here, restack it to the top */
584 obj_extract_self(otmp);
585 place_object(otmp, sx, sy);
587 } else {
588 struct trap *trap;
590 if ((trap = t_at(sx, sy)) && trap->ttyp == STATUE_TRAP)
591 deltrap(trap);
592 pline("%s.", Tobjnam(otmp, "crumble"));
593 (void) break_statue(otmp);
594 place_object(otmp, sx, sy); /* put fragments on floor */
596 used_up = TRUE;
598 /* 1 in 10 chance of destruction of obj; glass, egg destruction */
599 } else if ((scflags & MAY_DESTROY)
600 && (!rn2(10) || (objects[otmp->otyp].oc_material == GLASS
601 || otmp->otyp == EGG))) {
602 if (breaks(otmp, (xchar) sx, (xchar) sy))
603 used_up = TRUE;
606 if (!used_up) {
607 stmp =
608 (struct scatter_chain *) alloc(sizeof(struct scatter_chain));
609 stmp->next = (struct scatter_chain *) 0;
610 stmp->obj = otmp;
611 stmp->ox = sx;
612 stmp->oy = sy;
613 tmp = rn2(8); /* get the direction */
614 stmp->dx = xdir[tmp];
615 stmp->dy = ydir[tmp];
616 tmp = blastforce - (otmp->owt / 40);
617 if (tmp < 1)
618 tmp = 1;
619 stmp->range = rnd(tmp); /* anywhere up to that determ. by wt */
620 if (farthest < stmp->range)
621 farthest = stmp->range;
622 stmp->stopped = FALSE;
623 if (!schain)
624 schain = stmp;
625 else
626 stmp2->next = stmp;
627 stmp2 = stmp;
631 while (farthest-- > 0) {
632 for (stmp = schain; stmp; stmp = stmp->next) {
633 if ((stmp->range-- > 0) && (!stmp->stopped)) {
634 bhitpos.x = stmp->ox + stmp->dx;
635 bhitpos.y = stmp->oy + stmp->dy;
636 typ = levl[bhitpos.x][bhitpos.y].typ;
637 if (!isok(bhitpos.x, bhitpos.y)) {
638 bhitpos.x -= stmp->dx;
639 bhitpos.y -= stmp->dy;
640 stmp->stopped = TRUE;
641 } else if (!ZAP_POS(typ)
642 || closed_door(bhitpos.x, bhitpos.y)) {
643 bhitpos.x -= stmp->dx;
644 bhitpos.y -= stmp->dy;
645 stmp->stopped = TRUE;
646 } else if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
647 if (scflags & MAY_HITMON) {
648 stmp->range--;
649 if (ohitmon(mtmp, stmp->obj, 1, FALSE)) {
650 stmp->obj = (struct obj *) 0;
651 stmp->stopped = TRUE;
654 } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) {
655 if (scflags & MAY_HITYOU) {
656 int hitvalu, hitu;
658 if (multi)
659 nomul(0);
660 hitvalu = 8 + stmp->obj->spe;
661 if (bigmonst(youmonst.data))
662 hitvalu++;
663 hitu = thitu(hitvalu, dmgval(stmp->obj, &youmonst),
664 stmp->obj, (char *) 0);
665 if (hitu) {
666 stmp->range -= 3;
667 stop_occupation();
670 } else {
671 if (scflags & VIS_EFFECTS) {
672 /* tmp_at(bhitpos.x, bhitpos.y); */
673 /* delay_output(); */
676 stmp->ox = bhitpos.x;
677 stmp->oy = bhitpos.y;
681 for (stmp = schain; stmp; stmp = stmp2) {
682 int x, y;
684 stmp2 = stmp->next;
685 x = stmp->ox;
686 y = stmp->oy;
687 if (stmp->obj) {
688 if (x != sx || y != sy)
689 total += stmp->obj->quan;
690 place_object(stmp->obj, x, y);
691 stackobj(stmp->obj);
693 free((genericptr_t) stmp);
694 newsym(x, y);
697 return total;
701 * Splatter burning oil from x,y to the surrounding area.
703 * This routine should really take a how and direction parameters.
704 * The how is how it was caused, e.g. kicked verses thrown. The
705 * direction is which way to spread the flaming oil. Different
706 * "how"s would give different dispersal patterns. For example,
707 * kicking a burning flask will splatter differently from a thrown
708 * flask hitting the ground.
710 * For now, just perform a "regular" explosion.
712 void
713 splatter_burning_oil(x, y)
714 int x, y;
716 /* ZT_SPELL(ZT_FIRE) = ZT_SPELL(AD_FIRE-1) = 10+(2-1) = 11 */
717 #define ZT_SPELL_O_FIRE 11 /* value kludge, see zap.c */
718 explode(x, y, ZT_SPELL_O_FIRE, d(4, 4), BURNING_OIL, EXPL_FIERY);
721 /* lit potion of oil is exploding; extinguish it as a light source before
722 possibly killing the hero and attempting to save bones */
723 void
724 explode_oil(obj, x, y)
725 struct obj *obj;
726 int x, y;
728 if (!obj->lamplit)
729 impossible("exploding unlit oil");
730 end_burn(obj, TRUE);
731 splatter_burning_oil(x, y);
734 /*explode.c*/