1 /* NetHack 3.6 explode.c $NHDT-Date: 1522454717 2018/03/31 00:05:17 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.56 $ */
2 /* Copyright (C) 1990 by Ken Arromdee */
3 /* NetHack may be freely redistributed. See license for details. */
5 /* JNetHack Copyright */
6 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
7 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2018 */
8 /* JNetHack may be freely redistributed. See license for details. */
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 } };
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....
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.
33 explode(x, y, type, dam, olet, expltype)
35 int type; /* the same as in zap.c; passes -(wand typ) for some WAND_CLASS */
40 int i, j, k, damu = dam;
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;
48 int explmask[3][3]; /* 0=normal explosion, 1=do shieldeff, 2=do nothing */
49 #if 0 /*JP*//*do_hallu
\82Ì
\8f\88\97\9d\82Í
\82Æ
\82è
\82 \82¦
\82¸
\8aO
\82·*/
50 boolean shopdamage = FALSE, generic = FALSE, physical_dmg = FALSE,
51 do_hallu = FALSE, inside_engulfer, grabbed, grabbing;
53 boolean shopdamage = FALSE, generic = FALSE, physical_dmg = FALSE,
54 inside_engulfer, grabbed, grabbing;
58 char hallu_buf[BUFSZ], killr_buf[BUFSZ];
60 char hallu_buf[BUFSZ];
62 short exploding_wand_typ = 0;
64 if (olet == WAND_CLASS) { /* retributive strike */
65 /* 'type' is passed as (wand's object type * -1); save
66 object type and convert 'type' itself to zap-type */
69 exploding_wand_typ = (short) type;
70 /* most attack wands produce specific explosions;
71 other types produce a generic magical explosion */
72 if (objects[type].oc_dir == RAY
73 && type != WAN_DIGGING && type != WAN_SLEEP) {
74 type -= WAN_MAGIC_MISSILE;
75 if (type < 0 || type > 9) {
76 impossible("explode: wand has bad zap type (%d).", type);
82 switch (Role_switch) {
96 /* muse_unslime: SCR_FIRE */
98 /* hero gets credit/blame for killing this monster, not others */
100 expltype = -expltype;
102 /* if hero is engulfed and caused the explosion, only hero and
103 engulfer will be affected */
104 inside_engulfer = (u.uswallow && type >= 0);
105 /* held but not engulfed implies holder is reaching into second spot
106 so might get hit by double damage */
107 grabbed = grabbing = FALSE;
108 if (u.ustuck && !u.uswallow) {
109 if (Upolyd && sticks(youmonst.data))
113 grabxy.x = u.ustuck->mx;
114 grabxy.y = u.ustuck->my;
116 grabxy.x = grabxy.y = 0; /* lint suppression */
118 * It is possible for a grabber to be outside the explosion
119 * radius and reaching inside to hold the hero. If so, it ought
120 * to take damage (the extra half of double damage). It is also
121 * possible for poly'd hero to be outside the radius and reaching
122 * in to hold a monster. Hero should take damage in that situation.
124 * Probably the simplest way to handle this would be to expand
125 * the radius used when collecting targets but exclude everything
126 * beyond the regular radius which isn't reaching inside. Then
127 * skip harm to gear of any extended targets when inflicting damage.
130 #if 0 /*JP*//*do_hallu
\82Ì
\8f\88\97\9d\82Í
\82Æ
\82è
\82 \82¦
\82¸
\8aO
\82·*/
131 if (olet == MON_EXPLODE) {
132 /* when explode() is called recursively, killer.name might change so
133 we need to retain a copy of the current value for this explosion */
134 str = strcpy(killr_buf, killer.name);
135 do_hallu = (Hallucination
136 && (strstri(str, "'s explosion")
137 || strstri(str, "s' explosion")));
141 switch (abs(type) % 10) {
144 str = "magical blast";
146 str = "
\96\82\96@
\82Ì
\95\97";
151 str = (olet == BURNING_OIL) ? "burning oil"
152 : (olet == SCROLL_CLASS) ? "tower of flame" : "fireball";
154 str = (olet == BURNING_OIL) ? "
\94R
\82¦
\82Ä
\82¢
\82é
\96û"
155 : (olet == SCROLL_CLASS) ? "
\89Î
\92\8c" : "
\89Î
\82Ì
\8bÊ";
157 /* fire damage, not physical damage */
162 str = "ball of cold";
164 str = "
\95X
\82Ì
\8bÊ";
169 str = (olet == WAND_CLASS) ? "death field"
170 : "disintegration field";
172 str = (olet == WAND_CLASS) ? "
\8e\80\82Ì
\95\97"
173 : "
\95ª
\89ð
\82Ì
\95\97";
179 str = "ball of lightning";
186 str = "poison gas cloud";
188 str = "
\93Å
\82Ì
\89_";
193 str = "splash of acid";
195 str = "
\8e_
\82Ì
\82µ
\82Ô
\82«";
199 impossible("explosion base type %d?", type);
203 any_shield = visible = FALSE;
204 for (i = 0; i < 3; i++)
205 for (j = 0; j < 3; j++) {
206 if (!isok(i + x - 1, j + y - 1)) {
212 if (i + x - 1 == u.ux && j + y - 1 == u.uy) {
218 explmask[i][j] = !!Antimagic;
221 explmask[i][j] = !!Fire_resistance;
224 explmask[i][j] = !!Cold_resistance;
227 explmask[i][j] = (olet == WAND_CLASS)
228 ? !!(nonliving(youmonst.data)
229 || is_demon(youmonst.data))
230 : !!Disint_resistance;
233 explmask[i][j] = !!Shock_resistance;
236 explmask[i][j] = !!Poison_resistance;
239 explmask[i][j] = !!Acid_resistance;
243 impossible("explosion type %d?", adtyp);
247 /* can be both you and mtmp if you're swallowed or riding */
248 mtmp = m_at(i + x - 1, j + y - 1);
249 if (!mtmp && i + x - 1 == u.ux && j + y - 1 == u.uy)
259 explmask[i][j] |= resists_magm(mtmp);
262 explmask[i][j] |= resists_fire(mtmp);
265 explmask[i][j] |= resists_cold(mtmp);
268 explmask[i][j] |= (olet == WAND_CLASS)
269 ? (nonliving(mtmp->data)
270 || is_demon(mtmp->data)
271 || is_vampshifter(mtmp))
272 : resists_disint(mtmp);
275 explmask[i][j] |= resists_elec(mtmp);
278 explmask[i][j] |= resists_poison(mtmp);
281 explmask[i][j] |= resists_acid(mtmp);
284 impossible("explosion type %d?", adtyp);
288 if (mtmp && cansee(i + x - 1, j + y - 1) && !canspotmon(mtmp))
289 map_invisible(i + x - 1, j + y - 1);
291 (void) unmap_invisible(i + x - 1, j + y - 1);
292 if (cansee(i + x - 1, j + y - 1))
294 if (explmask[i][j] == 1)
299 /* Start the explosion */
300 for (i = 0; i < 3; i++)
301 for (j = 0; j < 3; j++) {
302 if (explmask[i][j] == 2)
304 tmp_at(starting ? DISP_BEAM : DISP_CHANGE,
305 explosion_to_glyph(expltype, explosion[i][j]));
306 tmp_at(i + x - 1, j + y - 1);
309 curs_on_u(); /* will flush screen and output */
311 if (any_shield && flags.sparkle) { /* simulate shield effect */
312 for (k = 0; k < SHIELD_COUNT; k++) {
313 for (i = 0; i < 3; i++)
314 for (j = 0; j < 3; j++) {
315 if (explmask[i][j] == 1)
317 * Bypass tmp_at() and send the shield glyphs
318 * directly to the buffered screen. tmp_at()
319 * will clean up the location for us later.
321 show_glyph(i + x - 1, j + y - 1,
322 cmap_to_glyph(shield_static[k]));
324 curs_on_u(); /* will flush screen and output */
328 /* Cover last shield glyph with blast symbol. */
329 for (i = 0; i < 3; i++)
330 for (j = 0; j < 3; j++) {
331 if (explmask[i][j] == 1)
333 i + x - 1, j + y - 1,
334 explosion_to_glyph(expltype, explosion[i][j]));
337 } else { /* delay a little bit. */
342 tmp_at(DISP_END, 0); /* clear the explosion */
344 if (olet == MON_EXPLODE) {
351 if (!Deaf && olet != SCROLL_CLASS)
353 You_hear("a blast.");
355 You_hear("
\94\9a\94
\89¹
\82ð
\95·
\82¢
\82½
\81D");
359 for (i = 0; i < 3; i++)
360 for (j = 0; j < 3; j++) {
361 if (explmask[i][j] == 2)
363 if (i + x - 1 == u.ux && j + y - 1 == u.uy)
364 uhurt = (explmask[i][j] == 1) ? 1 : 2;
365 /* for inside_engulfer, only <u.ux,u.uy> is affected */
366 else if (inside_engulfer)
368 idamres = idamnonres = 0;
369 if (type >= 0 && !u.uswallow)
370 (void) zap_over_floor((xchar) (i + x - 1),
371 (xchar) (j + y - 1), type,
372 &shopdamage, exploding_wand_typ);
374 mtmp = m_at(i + x - 1, j + y - 1);
375 if (!mtmp && i + x - 1 == u.ux && j + y - 1 == u.uy)
379 #if 0 /*JP*//*do_hallu
\82Ì
\8f\88\97\9d\82Í
\82Æ
\82è
\82 \82¦
\82¸
\8aO
\82·*/
381 /* replace "gas spore" with a different description
382 for each target (we can't distinguish personal names
383 like "Barney" here in order to suppress "the" below,
384 so avoid any which begins with a capital letter) */
386 Sprintf(hallu_buf, "%s explosion",
387 s_suffix(rndmonnam((char *) 0)));
388 } while (*hallu_buf != lowc(*hallu_buf));
392 if (u.uswallow && mtmp == u.ustuck) {
393 const char *adj = (char *) 0;
395 if (is_animal(u.ustuck->data)) {
401 adj = "
\94R
\82¦
\82½";
407 adj = "
\93\80\82ç
\82³
\82ê
\82½";
410 if (olet == WAND_CLASS)
412 adj = "irradiated by pure energy";
414 adj = "
\8fò
\89»
\82Ì
\97Í
\82ð
\97\81\82Ñ
\82½";
419 adj = "
\8c\8a\82ð
\82 \82¯
\82ç
\82ê
\82½";
425 adj = "
\93d
\8c\82\82ð
\82
\82ç
\82Á
\82½";
431 adj = "
\93Å
\82ð
\82
\82ç
\82Á
\82½";
435 adj = "an upset stomach";
437 adj = "
\8e_
\82ð
\82
\82ç
\82Á
\82½";
443 adj = "
\83p
\83\8a\83p
\83\8a\82É
\82È
\82Á
\82½";
447 pline("%s gets %s!", Monnam(u.ustuck), adj);
449 pline("%s
\82Í%s
\81I", Monnam(u.ustuck), adj);
456 adj = "
\8fÅ
\82°
\82½";
462 adj = "
\93\80\82Á
\82½";
465 if (olet == WAND_CLASS)
467 adj = "overwhelmed by pure energy";
469 adj = "
\8fò
\89»
\82Ì
\97Í
\82ð
\97\81\82Ñ
\82½";
474 adj = "
\8c\8a\82ð
\82 \82¯
\82ç
\82ê
\82½";
480 adj = "
\93d
\8c\82\82ð
\82
\82ç
\82Á
\82½";
486 adj = "
\93Å
\82ð
\82
\82ç
\82Á
\82½";
492 adj = "
\8e_
\82ð
\82
\82ç
\82Á
\82½";
498 adj = "
\83p
\83\8a\83p
\83\8a\82É
\82È
\82Á
\82½";
502 pline("%s gets slightly %s!", Monnam(u.ustuck), adj);
504 pline("%s
\82Í
\8f
\82µ
\82¾
\82¯%s
\81I", Monnam(u.ustuck), adj);
506 } else if (cansee(i + x - 1, j + y - 1)) {
510 pline("%s is caught in the %s!", Monnam(mtmp), str);
512 pline("%s
\82Í%s
\82É
\82Â
\82Â
\82Ü
\82ê
\82½
\81I", Monnam(mtmp), str);
515 idamres += destroy_mitem(mtmp, SCROLL_CLASS, (int) adtyp);
516 idamres += destroy_mitem(mtmp, SPBOOK_CLASS, (int) adtyp);
517 idamnonres += destroy_mitem(mtmp, POTION_CLASS, (int) adtyp);
518 idamnonres += destroy_mitem(mtmp, WAND_CLASS, (int) adtyp);
519 idamnonres += destroy_mitem(mtmp, RING_CLASS, (int) adtyp);
521 if (explmask[i][j] == 1) {
522 golemeffects(mtmp, (int) adtyp, dam + idamres);
523 mtmp->mhp -= idamnonres;
525 /* call resist with 0 and do damage manually so 1) we can
526 * get out the message before doing the damage, and 2) we
527 * can call mondied, not killed, if it's not your blast
531 if (resist(mtmp, olet, 0, FALSE)) {
532 /* inside_engulfer: <i+x-1,j+y-1> == <u.ux,u.uy> */
533 if (cansee(i + x - 1, j + y - 1) || inside_engulfer)
535 pline("%s resists the %s!", Monnam(mtmp), str);
537 pline("%s
\82Í%s
\82É
\92ï
\8dR
\82µ
\82½
\81I", Monnam(mtmp), str);
538 mdam = (dam + 1) / 2;
540 /* if grabber is reaching into hero's spot and
541 hero's spot is within explosion radius, grabber
542 gets hit by double damage */
543 if (grabbed && mtmp == u.ustuck && distu(x, y) <= 2)
545 /* being resistant to opposite type of damage makes
546 target more vulnerable to current type of damage
547 (when target is also resistant to current type,
548 we won't get here) */
549 if (resists_cold(mtmp) && adtyp == AD_FIRE)
551 else if (resists_fire(mtmp) && adtyp == AD_COLD)
554 mtmp->mhp -= (idamres + idamnonres);
556 if (mtmp->mhp <= 0) {
557 int xkflg = ((adtyp == AD_FIRE
558 && completelyburns(mtmp->data))
559 ? XKILL_NOCORPSE : 0);
561 if (!context.mon_moving) {
562 xkilled(mtmp, XKILL_GIVEMSG | xkflg);
563 } else if (mdef && mtmp == mdef) {
564 /* 'mdef' killed self trying to cure being turned
565 * into slime due to some action by the player.
566 * Hero gets the credit (experience) and most of
567 * the blame (possible loss of alignment and/or
568 * luck and/or telepathy depending on mtmp) but
569 * doesn't break pacifism. xkilled()'s message
570 * would be "you killed <mdef>" so give our own.
572 if (cansee(mtmp->mx, mtmp->my) || canspotmon(mtmp))
574 pline("%s is %s!", Monnam(mtmp),
575 xkflg ? "burned completely"
576 : nonliving(mtmp->data) ? "destroyed"
579 pline("%s
\82Í%s
\81I", Monnam(mtmp),
580 xkflg ? "
\94R
\82¦
\82Â
\82«
\82½"
581 : nonliving(mtmp->data) ? "
\93|
\82³
\82ê
\82½"
582 : "
\8eE
\82³
\82ê
\82½");
584 xkilled(mtmp, XKILL_NOMSG | XKILL_NOCONDUCT | xkflg);
587 adtyp = AD_RBRE; /* no corpse */
588 monkilled(mtmp, "", (int) adtyp);
590 } else if (!context.mon_moving) {
591 /* all affected monsters, even if mdef is set */
592 setmangry(mtmp, TRUE);
596 /* Do your injury last */
598 /* give message for any monster-induced explosion
599 or player-induced one other than scroll of fire */
600 if (flags.verbose && (type < 0 || olet != SCROLL_CLASS)) {
601 #if 0 /*JP*//*do_hallu
\82Ì
\8f\88\97\9d\82Í
\82Æ
\82è
\82 \82¦
\82¸
\8aO
\82·*/
602 if (do_hallu) { /* (see explanation above) */
604 Sprintf(hallu_buf, "%s explosion",
605 s_suffix(rndmonnam((char *) 0)));
606 } while (*hallu_buf != lowc(*hallu_buf));
611 You("are caught in the %s!", str);
613 You("%s
\82É
\82Â
\82Â
\82Ü
\82ê
\82½
\81I", str);
614 iflags.last_msg = PLNMSG_CAUGHT_IN_EXPLOSION;
616 /* do property damage first, in case we end up leaving bones */
617 if (adtyp == AD_FIRE)
622 You("are unharmed!");
624 You("
\8f\9d\82Â
\82©
\82È
\82¢
\81I");
625 } else if (adtyp == AD_PHYS || physical_dmg)
626 damu = Maybe_Half_Phys(damu);
627 if (adtyp == AD_FIRE)
628 (void) burnarmor(&youmonst);
629 destroy_item(SCROLL_CLASS, (int) adtyp);
630 destroy_item(SPBOOK_CLASS, (int) adtyp);
631 destroy_item(POTION_CLASS, (int) adtyp);
632 destroy_item(RING_CLASS, (int) adtyp);
633 destroy_item(WAND_CLASS, (int) adtyp);
635 ugolemeffects((int) adtyp, damu);
637 /* if poly'd hero is grabbing another victim, hero takes
638 double damage (note: don't rely on u.ustuck here because
639 that victim might have been killed when hit by the blast) */
640 if (grabbing && dist2((int) grabxy.x, (int) grabxy.y, x, y) <= 2)
642 /* hero does not get same fire-resistant vs cold and
643 cold-resistant vs fire double damage as monsters [why not?] */
651 if (u.uhp <= 0 || (Upolyd && u.mh <= 0)) {
655 if (olet == MON_EXPLODE) {
656 if (generic) /* explosion was unseen; str=="explosion", */
657 ; /* killer.name=="gas spore's explosion" */
658 else if (str != killer.name && str != hallu_buf)
659 Strcpy(killer.name, str);
660 killer.format = KILLED_BY_AN;
662 Strcat(killer.name, "
\82Å");
664 } else if (type >= 0 && olet != SCROLL_CLASS) {
666 killer.format = NO_KILLER_PREFIX;
667 Sprintf(killer.name, "caught %sself in %s own %s", uhim(),
670 killer.format = KILLED_BY;
671 Sprintf(killer.name, "
\8e©
\95ª
\8e©
\90g
\82Ì%s
\82É
\82Â
\82Â
\82Ü
\82ê
\82Ä",
675 #if 0 /*JP*//* an
\82ð
\82Â
\82¯
\82é
\82©
\82Ç
\82¤
\82©
\82Í
\8aÖ
\8cW
\82È
\82¢ */
676 killer.format = (!strcmpi(str, "tower of flame")
677 || !strcmpi(str, "fireball"))
680 Strcpy(killer.name, str);
682 killer.format = KILLED_BY;
683 Strcpy(killer.name, str);
684 Strcat(killer.name, "
\82Å");
687 if (iflags.last_msg == PLNMSG_CAUGHT_IN_EXPLOSION
688 || iflags.last_msg == PLNMSG_TOWER_OF_FLAME) /*seffects()*/
690 pline("It is fatal.");
692 pline("
\82»
\82ê
\82Í
\92v
\96½
\93I
\82¾
\81D");
695 pline_The("%s is fatal.", str);
697 pline_The("%s
\82Í
\92v
\96½
\93I
\82¾
\81D", str);
698 /* Known BUG: BURNING suppresses corpse in bones data,
699 but done does not handle killer reason correctly */
700 done((adtyp == AD_FIRE) ? BURNING : DIED);
703 exercise(A_STR, FALSE);
708 pay_for_damage((adtyp == AD_FIRE) ? "burn away"
709 : (adtyp == AD_COLD) ? "shatter"
710 : (adtyp == AD_DISN) ? "disintegrate"
714 pay_for_damage(adtyp == AD_FIRE
717 ? "
\95²
\81X
\82É
\82·
\82é"
718 : adtyp == AD_DISN ? "
\95²
\8dÓ
\82·
\82é"
719 : "
\94j
\89ó
\82·
\82é",
724 /* explosions are noisy */
727 i = 50; /* in case random damage is very small */
730 wake_nearto(x, y, i);
733 struct scatter_chain {
734 struct scatter_chain *next; /* pointer to next scatter item */
735 struct obj *obj; /* pointer to the object */
736 xchar ox; /* location of */
738 schar dx; /* direction of */
739 schar dy; /* travel */
740 int range; /* range of object */
741 boolean stopped; /* flag for in-motion/stopped */
746 * VIS_EFFECTS Add visual effects to display
747 * MAY_HITMON Objects may hit monsters
748 * MAY_HITYOU Objects may hit hero
749 * MAY_HIT Objects may hit you or monsters
750 * MAY_DESTROY Objects may be destroyed at random
751 * MAY_FRACTURE Stone objects can be fractured (statues, boulders)
754 /* returns number of scattered objects */
756 scatter(sx, sy, blastforce, scflags, obj)
757 int sx, sy; /* location of objects to scatter */
758 int blastforce; /* force behind the scattering */
759 unsigned int scflags;
760 struct obj *obj; /* only scatter this obj */
762 register struct obj *otmp;
768 boolean individual_object = obj ? TRUE : FALSE;
770 struct scatter_chain *stmp, *stmp2 = 0;
771 struct scatter_chain *schain = (struct scatter_chain *) 0;
774 while ((otmp = (individual_object ? obj : level.objects[sx][sy])) != 0) {
775 if (otmp->quan > 1L) {
776 qtmp = otmp->quan - 1L;
777 if (qtmp > LARGEST_INT)
779 qtmp = (long) rnd((int) qtmp);
780 otmp = splitobj(otmp, qtmp);
782 obj = (struct obj *) 0; /* all used */
784 obj_extract_self(otmp);
787 /* 9 in 10 chance of fracturing boulders or statues */
788 if ((scflags & MAY_FRACTURE) != 0
789 && (otmp->otyp == BOULDER || otmp->otyp == STATUE)
791 if (otmp->otyp == BOULDER) {
794 pline("%s apart.", Tobjnam(otmp, "break"));
796 pline("%s
\82Í
\88ê
\95\94\95ª
\82ª
\8dÓ
\82¯
\82½
\81D",xname(otmp));
799 You_hear("stone breaking.");
801 You_hear("
\90Î
\82ª
\8dÓ
\82¯
\82é
\89¹
\82ð
\95·
\82¢
\82½
\81D");
803 place_object(otmp, sx, sy);
804 if ((otmp = sobj_at(BOULDER, sx, sy)) != 0) {
805 /* another boulder here, restack it to the top */
806 obj_extract_self(otmp);
807 place_object(otmp, sx, sy);
812 if ((trap = t_at(sx, sy)) && trap->ttyp == STATUE_TRAP)
816 pline("%s.", Tobjnam(otmp, "crumble"));
818 pline("%s
\82Í
\82±
\82È
\82²
\82È
\82É
\82È
\82Á
\82½
\81D",xname(otmp));
821 You_hear("stone crumbling.");
823 You_hear("
\90Î
\82ª
\82±
\82È
\82²
\82È
\82É
\82È
\82é
\89¹
\82ð
\95·
\82¢
\82½
\81D");
824 (void) break_statue(otmp);
825 #ifndef FIX_BUG_C340_2
826 place_object(otmp, sx, sy); /* put fragments on floor */
831 /* 1 in 10 chance of destruction of obj; glass, egg destruction */
832 } else if ((scflags & MAY_DESTROY) != 0
833 && (!rn2(10) || (objects[otmp->otyp].oc_material == GLASS
834 || otmp->otyp == EGG))) {
835 if (breaks(otmp, (xchar) sx, (xchar) sy))
840 stmp = (struct scatter_chain *) alloc(sizeof *stmp);
841 stmp->next = (struct scatter_chain *) 0;
845 tmp = rn2(8); /* get the direction */
846 stmp->dx = xdir[tmp];
847 stmp->dy = ydir[tmp];
848 tmp = blastforce - (otmp->owt / 40);
851 stmp->range = rnd(tmp); /* anywhere up to that determ. by wt */
852 if (farthest < stmp->range)
853 farthest = stmp->range;
854 stmp->stopped = FALSE;
863 while (farthest-- > 0) {
864 for (stmp = schain; stmp; stmp = stmp->next) {
865 if ((stmp->range-- > 0) && (!stmp->stopped)) {
866 bhitpos.x = stmp->ox + stmp->dx;
867 bhitpos.y = stmp->oy + stmp->dy;
868 typ = levl[bhitpos.x][bhitpos.y].typ;
869 if (!isok(bhitpos.x, bhitpos.y)) {
870 bhitpos.x -= stmp->dx;
871 bhitpos.y -= stmp->dy;
872 stmp->stopped = TRUE;
873 } else if (!ZAP_POS(typ)
874 || closed_door(bhitpos.x, bhitpos.y)) {
875 bhitpos.x -= stmp->dx;
876 bhitpos.y -= stmp->dy;
877 stmp->stopped = TRUE;
878 } else if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
879 if (scflags & MAY_HITMON) {
881 if (ohitmon(mtmp, stmp->obj, 1, FALSE)) {
882 stmp->obj = (struct obj *) 0;
883 stmp->stopped = TRUE;
886 } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) {
887 if (scflags & MAY_HITYOU) {
892 hitvalu = 8 + stmp->obj->spe;
893 if (bigmonst(youmonst.data))
895 hitu = thitu(hitvalu, dmgval(stmp->obj, &youmonst),
896 &stmp->obj, (char *) 0);
898 stmp->stopped = TRUE;
905 if (scflags & VIS_EFFECTS) {
906 /* tmp_at(bhitpos.x, bhitpos.y); */
907 /* delay_output(); */
910 stmp->ox = bhitpos.x;
911 stmp->oy = bhitpos.y;
915 for (stmp = schain; stmp; stmp = stmp2) {
922 if (x != sx || y != sy)
923 total += stmp->obj->quan;
924 place_object(stmp->obj, x, y);
927 free((genericptr_t) stmp);
935 * Splatter burning oil from x,y to the surrounding area.
937 * This routine should really take a how and direction parameters.
938 * The how is how it was caused, e.g. kicked verses thrown. The
939 * direction is which way to spread the flaming oil. Different
940 * "how"s would give different dispersal patterns. For example,
941 * kicking a burning flask will splatter differently from a thrown
942 * flask hitting the ground.
944 * For now, just perform a "regular" explosion.
947 splatter_burning_oil(x, y)
950 /* ZT_SPELL(ZT_FIRE) = ZT_SPELL(AD_FIRE-1) = 10+(2-1) = 11 */
951 #define ZT_SPELL_O_FIRE 11 /* value kludge, see zap.c */
952 explode(x, y, ZT_SPELL_O_FIRE, d(4, 4), BURNING_OIL, EXPL_FIERY);
955 /* lit potion of oil is exploding; extinguish it as a light source before
956 possibly killing the hero and attempting to save bones */
958 explode_oil(obj, x, y)
963 impossible("exploding unlit oil");
965 splatter_burning_oil(x, y);