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;
57 char hallu_buf[BUFSZ], killr_buf[BUFSZ];
58 short exploding_wand_typ = 0;
60 if (olet == WAND_CLASS) { /* retributive strike */
61 /* 'type' is passed as (wand's object type * -1); save
62 object type and convert 'type' itself to zap-type */
65 exploding_wand_typ = (short) type;
66 /* most attack wands produce specific explosions;
67 other types produce a generic magical explosion */
68 if (objects[type].oc_dir == RAY
69 && type != WAN_DIGGING && type != WAN_SLEEP) {
70 type -= WAN_MAGIC_MISSILE;
71 if (type < 0 || type > 9) {
72 impossible("explode: wand has bad zap type (%d).", type);
78 switch (Role_switch) {
92 /* muse_unslime: SCR_FIRE */
94 /* hero gets credit/blame for killing this monster, not others */
98 /* if hero is engulfed and caused the explosion, only hero and
99 engulfer will be affected */
100 inside_engulfer = (u.uswallow && type >= 0);
101 /* held but not engulfed implies holder is reaching into second spot
102 so might get hit by double damage */
103 grabbed = grabbing = FALSE;
104 if (u.ustuck && !u.uswallow) {
105 if (Upolyd && sticks(youmonst.data))
109 grabxy.x = u.ustuck->mx;
110 grabxy.y = u.ustuck->my;
112 grabxy.x = grabxy.y = 0; /* lint suppression */
114 * It is possible for a grabber to be outside the explosion
115 * radius and reaching inside to hold the hero. If so, it ought
116 * to take damage (the extra half of double damage). It is also
117 * possible for poly'd hero to be outside the radius and reaching
118 * in to hold a monster. Hero should take damage in that situation.
120 * Probably the simplest way to handle this would be to expand
121 * the radius used when collecting targets but exclude everything
122 * beyond the regular radius which isn't reaching inside. Then
123 * skip harm to gear of any extended targets when inflicting damage.
126 #if 0 /*JP*//*do_hallu
\82Ì
\8f\88\97\9d\82Í
\82Æ
\82è
\82 \82¦
\82¸
\8aO
\82·*/
127 if (olet == MON_EXPLODE) {
128 /* when explode() is called recursively, killer.name might change so
129 we need to retain a copy of the current value for this explosion */
130 str = strcpy(killr_buf, killer.name);
131 do_hallu = (Hallucination
132 && (strstri(str, "'s explosion")
133 || strstri(str, "s' explosion")));
137 switch (abs(type) % 10) {
140 str = "magical blast";
142 str = "
\96\82\96@
\82Ì
\95\97";
147 str = (olet == BURNING_OIL) ? "burning oil"
148 : (olet == SCROLL_CLASS) ? "tower of flame" : "fireball";
150 str = (olet == BURNING_OIL) ? "
\94R
\82¦
\82Ä
\82¢
\82é
\96û"
151 : (olet == SCROLL_CLASS) ? "
\89Î
\92\8c" : "
\89Î
\82Ì
\8bÊ";
153 /* fire damage, not physical damage */
158 str = "ball of cold";
160 str = "
\95X
\82Ì
\8bÊ";
165 str = (olet == WAND_CLASS) ? "death field"
166 : "disintegration field";
168 str = (olet == WAND_CLASS) ? "
\8e\80\82Ì
\95\97"
169 : "
\95ª
\89ð
\82Ì
\95\97";
175 str = "ball of lightning";
182 str = "poison gas cloud";
184 str = "
\93Å
\82Ì
\89_";
189 str = "splash of acid";
191 str = "
\8e_
\82Ì
\82µ
\82Ô
\82«";
195 impossible("explosion base type %d?", type);
199 any_shield = visible = FALSE;
200 for (i = 0; i < 3; i++)
201 for (j = 0; j < 3; j++) {
202 if (!isok(i + x - 1, j + y - 1)) {
208 if (i + x - 1 == u.ux && j + y - 1 == u.uy) {
214 explmask[i][j] = !!Antimagic;
217 explmask[i][j] = !!Fire_resistance;
220 explmask[i][j] = !!Cold_resistance;
223 explmask[i][j] = (olet == WAND_CLASS)
224 ? !!(nonliving(youmonst.data)
225 || is_demon(youmonst.data))
226 : !!Disint_resistance;
229 explmask[i][j] = !!Shock_resistance;
232 explmask[i][j] = !!Poison_resistance;
235 explmask[i][j] = !!Acid_resistance;
239 impossible("explosion type %d?", adtyp);
243 /* can be both you and mtmp if you're swallowed or riding */
244 mtmp = m_at(i + x - 1, j + y - 1);
245 if (!mtmp && i + x - 1 == u.ux && j + y - 1 == u.uy)
255 explmask[i][j] |= resists_magm(mtmp);
258 explmask[i][j] |= resists_fire(mtmp);
261 explmask[i][j] |= resists_cold(mtmp);
264 explmask[i][j] |= (olet == WAND_CLASS)
265 ? (nonliving(mtmp->data)
266 || is_demon(mtmp->data)
267 || is_vampshifter(mtmp))
268 : resists_disint(mtmp);
271 explmask[i][j] |= resists_elec(mtmp);
274 explmask[i][j] |= resists_poison(mtmp);
277 explmask[i][j] |= resists_acid(mtmp);
280 impossible("explosion type %d?", adtyp);
284 if (mtmp && cansee(i + x - 1, j + y - 1) && !canspotmon(mtmp))
285 map_invisible(i + x - 1, j + y - 1);
287 (void) unmap_invisible(i + x - 1, j + y - 1);
288 if (cansee(i + x - 1, j + y - 1))
290 if (explmask[i][j] == 1)
295 /* Start the explosion */
296 for (i = 0; i < 3; i++)
297 for (j = 0; j < 3; j++) {
298 if (explmask[i][j] == 2)
300 tmp_at(starting ? DISP_BEAM : DISP_CHANGE,
301 explosion_to_glyph(expltype, explosion[i][j]));
302 tmp_at(i + x - 1, j + y - 1);
305 curs_on_u(); /* will flush screen and output */
307 if (any_shield && flags.sparkle) { /* simulate shield effect */
308 for (k = 0; k < SHIELD_COUNT; k++) {
309 for (i = 0; i < 3; i++)
310 for (j = 0; j < 3; j++) {
311 if (explmask[i][j] == 1)
313 * Bypass tmp_at() and send the shield glyphs
314 * directly to the buffered screen. tmp_at()
315 * will clean up the location for us later.
317 show_glyph(i + x - 1, j + y - 1,
318 cmap_to_glyph(shield_static[k]));
320 curs_on_u(); /* will flush screen and output */
324 /* Cover last shield glyph with blast symbol. */
325 for (i = 0; i < 3; i++)
326 for (j = 0; j < 3; j++) {
327 if (explmask[i][j] == 1)
329 i + x - 1, j + y - 1,
330 explosion_to_glyph(expltype, explosion[i][j]));
333 } else { /* delay a little bit. */
338 tmp_at(DISP_END, 0); /* clear the explosion */
340 if (olet == MON_EXPLODE) {
347 if (!Deaf && olet != SCROLL_CLASS)
349 You_hear("a blast.");
351 You_hear("
\94\9a\94
\89¹
\82ð
\95·
\82¢
\82½
\81D");
355 for (i = 0; i < 3; i++)
356 for (j = 0; j < 3; j++) {
357 if (explmask[i][j] == 2)
359 if (i + x - 1 == u.ux && j + y - 1 == u.uy)
360 uhurt = (explmask[i][j] == 1) ? 1 : 2;
361 /* for inside_engulfer, only <u.ux,u.uy> is affected */
362 else if (inside_engulfer)
364 idamres = idamnonres = 0;
365 if (type >= 0 && !u.uswallow)
366 (void) zap_over_floor((xchar) (i + x - 1),
367 (xchar) (j + y - 1), type,
368 &shopdamage, exploding_wand_typ);
370 mtmp = m_at(i + x - 1, j + y - 1);
371 if (!mtmp && i + x - 1 == u.ux && j + y - 1 == u.uy)
375 #if 0 /*JP*//*do_hallu
\82Ì
\8f\88\97\9d\82Í
\82Æ
\82è
\82 \82¦
\82¸
\8aO
\82·*/
377 /* replace "gas spore" with a different description
378 for each target (we can't distinguish personal names
379 like "Barney" here in order to suppress "the" below,
380 so avoid any which begins with a capital letter) */
382 Sprintf(hallu_buf, "%s explosion",
383 s_suffix(rndmonnam((char *) 0)));
384 } while (*hallu_buf != lowc(*hallu_buf));
388 if (u.uswallow && mtmp == u.ustuck) {
389 const char *adj = (char *) 0;
391 if (is_animal(u.ustuck->data)) {
397 adj = "
\94R
\82¦
\82½";
403 adj = "
\93\80\82ç
\82³
\82ê
\82½";
406 if (olet == WAND_CLASS)
408 adj = "irradiated by pure energy";
410 adj = "
\8fò
\89»
\82Ì
\97Í
\82ð
\97\81\82Ñ
\82½";
415 adj = "
\8c\8a\82ð
\82 \82¯
\82ç
\82ê
\82½";
421 adj = "
\93d
\8c\82\82ð
\82
\82ç
\82Á
\82½";
427 adj = "
\93Å
\82ð
\82
\82ç
\82Á
\82½";
431 adj = "an upset stomach";
433 adj = "
\8e_
\82ð
\82
\82ç
\82Á
\82½";
439 adj = "
\83p
\83\8a\83p
\83\8a\82É
\82È
\82Á
\82½";
443 pline("%s gets %s!", Monnam(u.ustuck), adj);
445 pline("%s
\82Í%s
\81I", Monnam(u.ustuck), adj);
452 adj = "
\8fÅ
\82°
\82½";
458 adj = "
\93\80\82Á
\82½";
461 if (olet == WAND_CLASS)
463 adj = "overwhelmed by pure energy";
465 adj = "
\8fò
\89»
\82Ì
\97Í
\82ð
\97\81\82Ñ
\82½";
470 adj = "
\8c\8a\82ð
\82 \82¯
\82ç
\82ê
\82½";
476 adj = "
\93d
\8c\82\82ð
\82
\82ç
\82Á
\82½";
482 adj = "
\93Å
\82ð
\82
\82ç
\82Á
\82½";
488 adj = "
\8e_
\82ð
\82
\82ç
\82Á
\82½";
494 adj = "
\83p
\83\8a\83p
\83\8a\82É
\82È
\82Á
\82½";
498 pline("%s gets slightly %s!", Monnam(u.ustuck), adj);
500 pline("%s
\82Í
\8f
\82µ
\82¾
\82¯%s
\81I", Monnam(u.ustuck), adj);
502 } else if (cansee(i + x - 1, j + y - 1)) {
506 pline("%s is caught in the %s!", Monnam(mtmp), str);
508 pline("%s
\82Í%s
\82É
\82Â
\82Â
\82Ü
\82ê
\82½
\81I", Monnam(mtmp), str);
511 idamres += destroy_mitem(mtmp, SCROLL_CLASS, (int) adtyp);
512 idamres += destroy_mitem(mtmp, SPBOOK_CLASS, (int) adtyp);
513 idamnonres += destroy_mitem(mtmp, POTION_CLASS, (int) adtyp);
514 idamnonres += destroy_mitem(mtmp, WAND_CLASS, (int) adtyp);
515 idamnonres += destroy_mitem(mtmp, RING_CLASS, (int) adtyp);
517 if (explmask[i][j] == 1) {
518 golemeffects(mtmp, (int) adtyp, dam + idamres);
519 mtmp->mhp -= idamnonres;
521 /* call resist with 0 and do damage manually so 1) we can
522 * get out the message before doing the damage, and 2) we
523 * can call mondied, not killed, if it's not your blast
527 if (resist(mtmp, olet, 0, FALSE)) {
528 /* inside_engulfer: <i+x-1,j+y-1> == <u.ux,u.uy> */
529 if (cansee(i + x - 1, j + y - 1) || inside_engulfer)
531 pline("%s resists the %s!", Monnam(mtmp), str);
533 pline("%s
\82Í%s
\82É
\92ï
\8dR
\82µ
\82½
\81I", Monnam(mtmp), str);
534 mdam = (dam + 1) / 2;
536 /* if grabber is reaching into hero's spot and
537 hero's spot is within explosion radius, grabber
538 gets hit by double damage */
539 if (grabbed && mtmp == u.ustuck && distu(x, y) <= 2)
541 /* being resistant to opposite type of damage makes
542 target more vulnerable to current type of damage
543 (when target is also resistant to current type,
544 we won't get here) */
545 if (resists_cold(mtmp) && adtyp == AD_FIRE)
547 else if (resists_fire(mtmp) && adtyp == AD_COLD)
550 mtmp->mhp -= (idamres + idamnonres);
552 if (mtmp->mhp <= 0) {
553 int xkflg = ((adtyp == AD_FIRE
554 && completelyburns(mtmp->data))
555 ? XKILL_NOCORPSE : 0);
557 if (!context.mon_moving) {
558 xkilled(mtmp, XKILL_GIVEMSG | xkflg);
559 } else if (mdef && mtmp == mdef) {
560 /* 'mdef' killed self trying to cure being turned
561 * into slime due to some action by the player.
562 * Hero gets the credit (experience) and most of
563 * the blame (possible loss of alignment and/or
564 * luck and/or telepathy depending on mtmp) but
565 * doesn't break pacifism. xkilled()'s message
566 * would be "you killed <mdef>" so give our own.
568 if (cansee(mtmp->mx, mtmp->my) || canspotmon(mtmp))
570 pline("%s is %s!", Monnam(mtmp),
571 xkflg ? "burned completely"
572 : nonliving(mtmp->data) ? "destroyed"
575 pline("%s
\82Í%s
\81I", Monnam(mtmp),
576 xkflg ? "
\94R
\82¦
\82Â
\82«
\82½"
577 : nonliving(mtmp->data) ? "
\93|
\82³
\82ê
\82½"
578 : "
\8eE
\82³
\82ê
\82½");
580 xkilled(mtmp, XKILL_NOMSG | XKILL_NOCONDUCT | xkflg);
583 adtyp = AD_RBRE; /* no corpse */
584 monkilled(mtmp, "", (int) adtyp);
586 } else if (!context.mon_moving) {
587 /* all affected monsters, even if mdef is set */
588 setmangry(mtmp, TRUE);
592 /* Do your injury last */
594 /* give message for any monster-induced explosion
595 or player-induced one other than scroll of fire */
596 if (flags.verbose && (type < 0 || olet != SCROLL_CLASS)) {
597 #if 0 /*JP*//*do_hallu
\82Ì
\8f\88\97\9d\82Í
\82Æ
\82è
\82 \82¦
\82¸
\8aO
\82·*/
598 if (do_hallu) { /* (see explanation above) */
600 Sprintf(hallu_buf, "%s explosion",
601 s_suffix(rndmonnam((char *) 0)));
602 } while (*hallu_buf != lowc(*hallu_buf));
607 You("are caught in the %s!", str);
609 You("%s
\82É
\82Â
\82Â
\82Ü
\82ê
\82½
\81I", str);
610 iflags.last_msg = PLNMSG_CAUGHT_IN_EXPLOSION;
612 /* do property damage first, in case we end up leaving bones */
613 if (adtyp == AD_FIRE)
618 You("are unharmed!");
620 You("
\8f\9d\82Â
\82©
\82È
\82¢
\81I");
621 } else if (adtyp == AD_PHYS || physical_dmg)
622 damu = Maybe_Half_Phys(damu);
623 if (adtyp == AD_FIRE)
624 (void) burnarmor(&youmonst);
625 destroy_item(SCROLL_CLASS, (int) adtyp);
626 destroy_item(SPBOOK_CLASS, (int) adtyp);
627 destroy_item(POTION_CLASS, (int) adtyp);
628 destroy_item(RING_CLASS, (int) adtyp);
629 destroy_item(WAND_CLASS, (int) adtyp);
631 ugolemeffects((int) adtyp, damu);
633 /* if poly'd hero is grabbing another victim, hero takes
634 double damage (note: don't rely on u.ustuck here because
635 that victim might have been killed when hit by the blast) */
636 if (grabbing && dist2((int) grabxy.x, (int) grabxy.y, x, y) <= 2)
638 /* hero does not get same fire-resistant vs cold and
639 cold-resistant vs fire double damage as monsters [why not?] */
647 if (u.uhp <= 0 || (Upolyd && u.mh <= 0)) {
651 if (olet == MON_EXPLODE) {
652 if (generic) /* explosion was unseen; str=="explosion", */
653 ; /* killer.name=="gas spore's explosion" */
654 else if (str != killer.name && str != hallu_buf)
655 Strcpy(killer.name, str);
656 killer.format = KILLED_BY_AN;
658 Strcat(killer.name, "
\82Å");
660 } else if (type >= 0 && olet != SCROLL_CLASS) {
662 killer.format = NO_KILLER_PREFIX;
663 Sprintf(killer.name, "caught %sself in %s own %s", uhim(),
666 killer.format = KILLED_BY;
667 Sprintf(killer.name, "
\8e©
\95ª
\8e©
\90g
\82Ì%s
\82É
\82Â
\82Â
\82Ü
\82ê
\82Ä",
671 #if 0 /*JP*//* an
\82ð
\82Â
\82¯
\82é
\82©
\82Ç
\82¤
\82©
\82Í
\8aÖ
\8cW
\82È
\82¢ */
672 killer.format = (!strcmpi(str, "tower of flame")
673 || !strcmpi(str, "fireball"))
676 Strcpy(killer.name, str);
678 killer.format = KILLED_BY;
679 Strcpy(killer.name, str);
680 Strcat(killer.name, "
\82Å");
683 if (iflags.last_msg == PLNMSG_CAUGHT_IN_EXPLOSION
684 || iflags.last_msg == PLNMSG_TOWER_OF_FLAME) /*seffects()*/
686 pline("It is fatal.");
688 pline("
\82»
\82ê
\82Í
\92v
\96½
\93I
\82¾
\81D");
691 pline_The("%s is fatal.", str);
693 pline_The("%s
\82Í
\92v
\96½
\93I
\82¾
\81D", str);
694 /* Known BUG: BURNING suppresses corpse in bones data,
695 but done does not handle killer reason correctly */
696 done((adtyp == AD_FIRE) ? BURNING : DIED);
699 exercise(A_STR, FALSE);
704 pay_for_damage((adtyp == AD_FIRE) ? "burn away"
705 : (adtyp == AD_COLD) ? "shatter"
706 : (adtyp == AD_DISN) ? "disintegrate"
710 pay_for_damage(adtyp == AD_FIRE
713 ? "
\95²
\81X
\82É
\82·
\82é"
714 : adtyp == AD_DISN ? "
\95²
\8dÓ
\82·
\82é"
715 : "
\94j
\89ó
\82·
\82é",
720 /* explosions are noisy */
723 i = 50; /* in case random damage is very small */
726 wake_nearto(x, y, i);
729 struct scatter_chain {
730 struct scatter_chain *next; /* pointer to next scatter item */
731 struct obj *obj; /* pointer to the object */
732 xchar ox; /* location of */
734 schar dx; /* direction of */
735 schar dy; /* travel */
736 int range; /* range of object */
737 boolean stopped; /* flag for in-motion/stopped */
742 * VIS_EFFECTS Add visual effects to display
743 * MAY_HITMON Objects may hit monsters
744 * MAY_HITYOU Objects may hit hero
745 * MAY_HIT Objects may hit you or monsters
746 * MAY_DESTROY Objects may be destroyed at random
747 * MAY_FRACTURE Stone objects can be fractured (statues, boulders)
750 /* returns number of scattered objects */
752 scatter(sx, sy, blastforce, scflags, obj)
753 int sx, sy; /* location of objects to scatter */
754 int blastforce; /* force behind the scattering */
755 unsigned int scflags;
756 struct obj *obj; /* only scatter this obj */
758 register struct obj *otmp;
764 boolean individual_object = obj ? TRUE : FALSE;
766 struct scatter_chain *stmp, *stmp2 = 0;
767 struct scatter_chain *schain = (struct scatter_chain *) 0;
770 while ((otmp = (individual_object ? obj : level.objects[sx][sy])) != 0) {
771 if (otmp->quan > 1L) {
772 qtmp = otmp->quan - 1L;
773 if (qtmp > LARGEST_INT)
775 qtmp = (long) rnd((int) qtmp);
776 otmp = splitobj(otmp, qtmp);
778 obj = (struct obj *) 0; /* all used */
780 obj_extract_self(otmp);
783 /* 9 in 10 chance of fracturing boulders or statues */
784 if ((scflags & MAY_FRACTURE) != 0
785 && (otmp->otyp == BOULDER || otmp->otyp == STATUE)
787 if (otmp->otyp == BOULDER) {
790 pline("%s apart.", Tobjnam(otmp, "break"));
792 pline("%s
\82Í
\88ê
\95\94\95ª
\82ª
\8dÓ
\82¯
\82½
\81D",xname(otmp));
795 You_hear("stone breaking.");
797 You_hear("
\90Î
\82ª
\8dÓ
\82¯
\82é
\89¹
\82ð
\95·
\82¢
\82½
\81D");
799 place_object(otmp, sx, sy);
800 if ((otmp = sobj_at(BOULDER, sx, sy)) != 0) {
801 /* another boulder here, restack it to the top */
802 obj_extract_self(otmp);
803 place_object(otmp, sx, sy);
808 if ((trap = t_at(sx, sy)) && trap->ttyp == STATUE_TRAP)
812 pline("%s.", Tobjnam(otmp, "crumble"));
814 pline("%s
\82Í
\82±
\82È
\82²
\82È
\82É
\82È
\82Á
\82½
\81D",xname(otmp));
817 You_hear("stone crumbling.");
819 You_hear("
\90Î
\82ª
\82±
\82È
\82²
\82È
\82É
\82È
\82é
\89¹
\82ð
\95·
\82¢
\82½
\81D");
820 (void) break_statue(otmp);
821 #ifndef FIX_BUG_C340_2
822 place_object(otmp, sx, sy); /* put fragments on floor */
827 /* 1 in 10 chance of destruction of obj; glass, egg destruction */
828 } else if ((scflags & MAY_DESTROY) != 0
829 && (!rn2(10) || (objects[otmp->otyp].oc_material == GLASS
830 || otmp->otyp == EGG))) {
831 if (breaks(otmp, (xchar) sx, (xchar) sy))
836 stmp = (struct scatter_chain *) alloc(sizeof *stmp);
837 stmp->next = (struct scatter_chain *) 0;
841 tmp = rn2(8); /* get the direction */
842 stmp->dx = xdir[tmp];
843 stmp->dy = ydir[tmp];
844 tmp = blastforce - (otmp->owt / 40);
847 stmp->range = rnd(tmp); /* anywhere up to that determ. by wt */
848 if (farthest < stmp->range)
849 farthest = stmp->range;
850 stmp->stopped = FALSE;
859 while (farthest-- > 0) {
860 for (stmp = schain; stmp; stmp = stmp->next) {
861 if ((stmp->range-- > 0) && (!stmp->stopped)) {
862 bhitpos.x = stmp->ox + stmp->dx;
863 bhitpos.y = stmp->oy + stmp->dy;
864 typ = levl[bhitpos.x][bhitpos.y].typ;
865 if (!isok(bhitpos.x, bhitpos.y)) {
866 bhitpos.x -= stmp->dx;
867 bhitpos.y -= stmp->dy;
868 stmp->stopped = TRUE;
869 } else if (!ZAP_POS(typ)
870 || closed_door(bhitpos.x, bhitpos.y)) {
871 bhitpos.x -= stmp->dx;
872 bhitpos.y -= stmp->dy;
873 stmp->stopped = TRUE;
874 } else if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
875 if (scflags & MAY_HITMON) {
877 if (ohitmon(mtmp, stmp->obj, 1, FALSE)) {
878 stmp->obj = (struct obj *) 0;
879 stmp->stopped = TRUE;
882 } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) {
883 if (scflags & MAY_HITYOU) {
888 hitvalu = 8 + stmp->obj->spe;
889 if (bigmonst(youmonst.data))
891 hitu = thitu(hitvalu, dmgval(stmp->obj, &youmonst),
892 &stmp->obj, (char *) 0);
894 stmp->stopped = TRUE;
901 if (scflags & VIS_EFFECTS) {
902 /* tmp_at(bhitpos.x, bhitpos.y); */
903 /* delay_output(); */
906 stmp->ox = bhitpos.x;
907 stmp->oy = bhitpos.y;
911 for (stmp = schain; stmp; stmp = stmp2) {
918 if (x != sx || y != sy)
919 total += stmp->obj->quan;
920 place_object(stmp->obj, x, y);
923 free((genericptr_t) stmp);
931 * Splatter burning oil from x,y to the surrounding area.
933 * This routine should really take a how and direction parameters.
934 * The how is how it was caused, e.g. kicked verses thrown. The
935 * direction is which way to spread the flaming oil. Different
936 * "how"s would give different dispersal patterns. For example,
937 * kicking a burning flask will splatter differently from a thrown
938 * flask hitting the ground.
940 * For now, just perform a "regular" explosion.
943 splatter_burning_oil(x, y)
946 /* ZT_SPELL(ZT_FIRE) = ZT_SPELL(AD_FIRE-1) = 10+(2-1) = 11 */
947 #define ZT_SPELL_O_FIRE 11 /* value kludge, see zap.c */
948 explode(x, y, ZT_SPELL_O_FIRE, d(4, 4), BURNING_OIL, EXPL_FIERY);
951 /* lit potion of oil is exploding; extinguish it as a light source before
952 possibly killing the hero and attempting to save bones */
954 explode_oil(obj, x, y)
959 impossible("exploding unlit oil");
961 splatter_burning_oil(x, y);