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-2016 */
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 boolean shopdamage = FALSE, generic = FALSE, physical_dmg = FALSE,
50 do_hallu = FALSE, inside_engulfer, grabbed, grabbing;
52 char hallu_buf[BUFSZ], killr_buf[BUFSZ];
53 short exploding_wand_typ = 0;
55 if (olet == WAND_CLASS) { /* retributive strike */
56 /* 'type' is passed as (wand's object type * -1); save
57 object type and convert 'type' itself to zap-type */
60 exploding_wand_typ = (short) type;
61 /* most attack wands produce specific explosions;
62 other types produce a generic magical explosion */
63 if (objects[type].oc_dir == RAY
64 && type != WAN_DIGGING && type != WAN_SLEEP) {
65 type -= WAN_MAGIC_MISSILE;
66 if (type < 0 || type > 9) {
67 impossible("explode: wand has bad zap type (%d).", type);
73 switch (Role_switch) {
87 /* muse_unslime: SCR_FIRE */
89 /* hero gets credit/blame for killing this monster, not others */
93 /* if hero is engulfed and caused the explosion, only hero and
94 engulfer will be affected */
95 inside_engulfer = (u.uswallow && type >= 0);
96 /* held but not engulfed implies holder is reaching into second spot
97 so might get hit by double damage */
98 grabbed = grabbing = FALSE;
99 if (u.ustuck && !u.uswallow) {
100 if (Upolyd && sticks(youmonst.data))
104 grabxy.x = u.ustuck->mx;
105 grabxy.y = u.ustuck->my;
107 grabxy.x = grabxy.y = 0; /* lint suppression */
109 * It is possible for a grabber to be outside the explosion
110 * radius and reaching inside to hold the hero. If so, it ought
111 * to take damage (the extra half of double damage). It is also
112 * possible for poly'd hero to be outside the radius and reaching
113 * in to hold a monster. Hero should take damage in that situation.
115 * Probably the simplest way to handle this would be to expand
116 * the radius used when collecting targets but exclude everything
117 * beyond the regular radius which isn't reaching inside. Then
118 * skip harm to gear of any extended targets when inflicting damage.
121 if (olet == MON_EXPLODE) {
122 /* when explode() is called recursively, killer.name might change so
123 we need to retain a copy of the current value for this explosion */
124 str = strcpy(killr_buf, killer.name);
125 do_hallu = (Hallucination
126 && (strstri(str, "'s explosion")
127 || strstri(str, "s' explosion")));
130 switch (abs(type) % 10) {
133 str = "magical blast";
135 str = "
\96\82\96@
\82Ì
\95\97";
140 str = (olet == BURNING_OIL) ? "burning oil"
141 : (olet == SCROLL_CLASS) ? "tower of flame" : "fireball";
143 str = (olet == BURNING_OIL) ? "
\94R
\82¦
\82Ä
\82¢
\82é
\96û"
144 : (olet == SCROLL_CLASS) ? "
\89Î
\92\8c" : "
\89Î
\82Ì
\8bÊ";
146 /* fire damage, not physical damage */
151 str = "ball of cold";
153 str = "
\95X
\82Ì
\8bÊ";
158 str = (olet == WAND_CLASS) ? "death field"
159 : "disintegration field";
161 str = (olet == WAND_CLASS) ? "
\8e\80\82Ì
\95\97"
162 : "
\95ª
\89ð
\82Ì
\95\97";
168 str = "ball of lightning";
175 str = "poison gas cloud";
177 str = "
\93Å
\82Ì
\89_";
182 str = "splash of acid";
184 str = "
\8e_
\82Ì
\82µ
\82Ô
\82«";
188 impossible("explosion base type %d?", type);
192 any_shield = visible = FALSE;
193 for (i = 0; i < 3; i++)
194 for (j = 0; j < 3; j++) {
195 if (!isok(i + x - 1, j + y - 1)) {
201 if (i + x - 1 == u.ux && j + y - 1 == u.uy) {
207 explmask[i][j] = !!Antimagic;
210 explmask[i][j] = !!Fire_resistance;
213 explmask[i][j] = !!Cold_resistance;
216 explmask[i][j] = (olet == WAND_CLASS)
217 ? !!(nonliving(youmonst.data)
218 || is_demon(youmonst.data))
219 : !!Disint_resistance;
222 explmask[i][j] = !!Shock_resistance;
225 explmask[i][j] = !!Poison_resistance;
228 explmask[i][j] = !!Acid_resistance;
232 impossible("explosion type %d?", adtyp);
236 /* can be both you and mtmp if you're swallowed or riding */
237 mtmp = m_at(i + x - 1, j + y - 1);
238 if (!mtmp && i + x - 1 == u.ux && j + y - 1 == u.uy)
248 explmask[i][j] |= resists_magm(mtmp);
251 explmask[i][j] |= resists_fire(mtmp);
254 explmask[i][j] |= resists_cold(mtmp);
257 explmask[i][j] |= (olet == WAND_CLASS)
258 ? (nonliving(mtmp->data)
259 || is_demon(mtmp->data)
260 || is_vampshifter(mtmp))
261 : resists_disint(mtmp);
264 explmask[i][j] |= resists_elec(mtmp);
267 explmask[i][j] |= resists_poison(mtmp);
270 explmask[i][j] |= resists_acid(mtmp);
273 impossible("explosion type %d?", adtyp);
277 if (mtmp && cansee(i + x - 1, j + y - 1) && !canspotmon(mtmp))
278 map_invisible(i + x - 1, j + y - 1);
280 (void) unmap_invisible(i + x - 1, j + y - 1);
281 if (cansee(i + x - 1, j + y - 1))
283 if (explmask[i][j] == 1)
288 /* Start the explosion */
289 for (i = 0; i < 3; i++)
290 for (j = 0; j < 3; j++) {
291 if (explmask[i][j] == 2)
293 tmp_at(starting ? DISP_BEAM : DISP_CHANGE,
294 explosion_to_glyph(expltype, explosion[i][j]));
295 tmp_at(i + x - 1, j + y - 1);
298 curs_on_u(); /* will flush screen and output */
300 if (any_shield && flags.sparkle) { /* simulate shield effect */
301 for (k = 0; k < SHIELD_COUNT; k++) {
302 for (i = 0; i < 3; i++)
303 for (j = 0; j < 3; j++) {
304 if (explmask[i][j] == 1)
306 * Bypass tmp_at() and send the shield glyphs
307 * directly to the buffered screen. tmp_at()
308 * will clean up the location for us later.
310 show_glyph(i + x - 1, j + y - 1,
311 cmap_to_glyph(shield_static[k]));
313 curs_on_u(); /* will flush screen and output */
317 /* Cover last shield glyph with blast symbol. */
318 for (i = 0; i < 3; i++)
319 for (j = 0; j < 3; j++) {
320 if (explmask[i][j] == 1)
322 i + x - 1, j + y - 1,
323 explosion_to_glyph(expltype, explosion[i][j]));
326 } else { /* delay a little bit. */
331 tmp_at(DISP_END, 0); /* clear the explosion */
333 if (olet == MON_EXPLODE) {
340 if (!Deaf && olet != SCROLL_CLASS)
342 You_hear("a blast.");
344 You_hear("
\94\9a\94
\89¹
\82ð
\95·
\82¢
\82½
\81D");
348 for (i = 0; i < 3; i++)
349 for (j = 0; j < 3; j++) {
350 if (explmask[i][j] == 2)
352 if (i + x - 1 == u.ux && j + y - 1 == u.uy)
353 uhurt = (explmask[i][j] == 1) ? 1 : 2;
354 /* for inside_engulfer, only <u.ux,u.uy> is affected */
355 else if (inside_engulfer)
357 idamres = idamnonres = 0;
358 if (type >= 0 && !u.uswallow)
359 (void) zap_over_floor((xchar) (i + x - 1),
360 (xchar) (j + y - 1), type,
361 &shopdamage, exploding_wand_typ);
363 mtmp = m_at(i + x - 1, j + y - 1);
364 if (!mtmp && i + x - 1 == u.ux && j + y - 1 == u.uy)
369 /* replace "gas spore" with a different description
370 for each target (we can't distinguish personal names
371 like "Barney" here in order to suppress "the" below,
372 so avoid any which begins with a capital letter) */
374 Sprintf(hallu_buf, "%s explosion",
375 s_suffix(rndmonnam((char *) 0)));
376 } while (*hallu_buf != lowc(*hallu_buf));
379 if (u.uswallow && mtmp == u.ustuck) {
380 const char *adj = (char *) 0;
382 if (is_animal(u.ustuck->data)) {
388 adj = "
\94R
\82¦
\82½";
394 adj = "
\93\80\82ç
\82³
\82ê
\82½";
397 if (olet == WAND_CLASS)
399 adj = "irradiated by pure energy";
401 adj = "
\8fò
\89»
\82Ì
\97Í
\82ð
\97\81\82Ñ
\82½";
406 adj = "
\8c\8a\82ð
\82 \82¯
\82ç
\82ê
\82½";
412 adj = "
\93d
\8c\82\82ð
\82
\82ç
\82Á
\82½";
418 adj = "
\93Å
\82ð
\82
\82ç
\82Á
\82½";
422 adj = "an upset stomach";
424 adj = "
\8e_
\82ð
\82
\82ç
\82Á
\82½";
430 adj = "
\83p
\83\8a\83p
\83\8a\82É
\82È
\82Á
\82½";
434 pline("%s gets %s!", Monnam(u.ustuck), adj);
436 pline("%s
\82Í%s
\81I", Monnam(u.ustuck), adj);
443 adj = "
\8fÅ
\82°
\82½";
449 adj = "
\93\80\82Á
\82½";
452 if (olet == WAND_CLASS)
454 adj = "overwhelmed by pure energy";
456 adj = "
\8fò
\89»
\82Ì
\97Í
\82ð
\97\81\82Ñ
\82½";
461 adj = "
\8c\8a\82ð
\82 \82¯
\82ç
\82ê
\82½";
467 adj = "
\93d
\8c\82\82ð
\82
\82ç
\82Á
\82½";
473 adj = "
\93Å
\82ð
\82
\82ç
\82Á
\82½";
479 adj = "
\8e_
\82ð
\82
\82ç
\82Á
\82½";
485 adj = "
\83p
\83\8a\83p
\83\8a\82É
\82È
\82Á
\82½";
489 pline("%s gets slightly %s!", Monnam(u.ustuck), adj);
491 pline("%s
\82Í
\8f
\82µ
\82¾
\82¯%s
\81I", Monnam(u.ustuck), adj);
493 } else if (cansee(i + x - 1, j + y - 1)) {
497 pline("%s is caught in the %s!", Monnam(mtmp), str);
499 pline("%s
\82Í%s
\82É
\82Â
\82Â
\82Ü
\82ê
\82½
\81I", Monnam(mtmp), str);
502 idamres += destroy_mitem(mtmp, SCROLL_CLASS, (int) adtyp);
503 idamres += destroy_mitem(mtmp, SPBOOK_CLASS, (int) adtyp);
504 idamnonres += destroy_mitem(mtmp, POTION_CLASS, (int) adtyp);
505 idamnonres += destroy_mitem(mtmp, WAND_CLASS, (int) adtyp);
506 idamnonres += destroy_mitem(mtmp, RING_CLASS, (int) adtyp);
508 if (explmask[i][j] == 1) {
509 golemeffects(mtmp, (int) adtyp, dam + idamres);
510 mtmp->mhp -= idamnonres;
512 /* call resist with 0 and do damage manually so 1) we can
513 * get out the message before doing the damage, and 2) we
514 * can call mondied, not killed, if it's not your blast
518 if (resist(mtmp, olet, 0, FALSE)) {
519 /* inside_engulfer: <i+x-1,j+y-1> == <u.ux,u.uy> */
520 if (cansee(i + x - 1, j + y - 1) || inside_engulfer)
522 pline("%s resists the %s!", Monnam(mtmp), str);
524 pline("%s
\82Í%s
\82É
\92ï
\8dR
\82µ
\82½
\81I", Monnam(mtmp), str);
525 mdam = (dam + 1) / 2;
527 /* if grabber is reaching into hero's spot and
528 hero's spot is within explosion radius, grabber
529 gets hit by double damage */
530 if (grabbed && mtmp == u.ustuck && distu(x, y) <= 2)
532 /* being resistant to opposite type of damage makes
533 target more vulnerable to current type of damage
534 (when target is also resistant to current type,
535 we won't get here) */
536 if (resists_cold(mtmp) && adtyp == AD_FIRE)
538 else if (resists_fire(mtmp) && adtyp == AD_COLD)
541 mtmp->mhp -= (idamres + idamnonres);
543 if (mtmp->mhp <= 0) {
544 int xkflg = ((adtyp == AD_FIRE
545 && completelyburns(mtmp->data))
546 ? XKILL_NOCORPSE : 0);
548 if (!context.mon_moving) {
549 xkilled(mtmp, XKILL_GIVEMSG | xkflg);
550 } else if (mdef && mtmp == mdef) {
551 /* 'mdef' killed self trying to cure being turned
552 * into slime due to some action by the player.
553 * Hero gets the credit (experience) and most of
554 * the blame (possible loss of alignment and/or
555 * luck and/or telepathy depending on mtmp) but
556 * doesn't break pacifism. xkilled()'s message
557 * would be "you killed <mdef>" so give our own.
559 if (cansee(mtmp->mx, mtmp->my) || canspotmon(mtmp))
560 pline("%s is %s!", Monnam(mtmp),
561 xkflg ? "burned completely"
562 : nonliving(mtmp->data) ? "destroyed"
564 xkilled(mtmp, XKILL_NOMSG | XKILL_NOCONDUCT | xkflg);
567 adtyp = AD_RBRE; /* no corpse */
568 monkilled(mtmp, "", (int) adtyp);
570 } else if (!context.mon_moving) {
571 /* all affected monsters, even if mdef is set */
572 setmangry(mtmp, TRUE);
576 /* Do your injury last */
578 /* give message for any monster-induced explosion
579 or player-induced one other than scroll of fire */
580 if (flags.verbose && (type < 0 || olet != SCROLL_CLASS)) {
581 if (do_hallu) { /* (see explanation above) */
583 Sprintf(hallu_buf, "%s explosion",
584 s_suffix(rndmonnam((char *) 0)));
585 } while (*hallu_buf != lowc(*hallu_buf));
589 You("are caught in the %s!", str);
591 You("%s
\82É
\82Â
\82Â
\82Ü
\82ê
\82½
\81I", str);
592 iflags.last_msg = PLNMSG_CAUGHT_IN_EXPLOSION;
594 /* do property damage first, in case we end up leaving bones */
595 if (adtyp == AD_FIRE)
600 You("are unharmed!");
602 You("
\8f\9d\82Â
\82©
\82È
\82¢
\81I");
603 } else if (adtyp == AD_PHYS || physical_dmg)
604 damu = Maybe_Half_Phys(damu);
605 if (adtyp == AD_FIRE)
606 (void) burnarmor(&youmonst);
607 destroy_item(SCROLL_CLASS, (int) adtyp);
608 destroy_item(SPBOOK_CLASS, (int) adtyp);
609 destroy_item(POTION_CLASS, (int) adtyp);
610 destroy_item(RING_CLASS, (int) adtyp);
611 destroy_item(WAND_CLASS, (int) adtyp);
613 ugolemeffects((int) adtyp, damu);
615 /* if poly'd hero is grabbing another victim, hero takes
616 double damage (note: don't rely on u.ustuck here because
617 that victim might have been killed when hit by the blast) */
618 if (grabbing && dist2((int) grabxy.x, (int) grabxy.y, x, y) <= 2)
620 /* hero does not get same fire-resistant vs cold and
621 cold-resistant vs fire double damage as monsters [why not?] */
629 if (u.uhp <= 0 || (Upolyd && u.mh <= 0)) {
633 if (olet == MON_EXPLODE) {
634 if (generic) /* explosion was unseen; str=="explosion", */
635 ; /* killer.name=="gas spore's explosion" */
636 else if (str != killer.name && str != hallu_buf)
637 Strcpy(killer.name, str);
638 killer.format = KILLED_BY_AN;
640 Strcat(killer.name, "
\82Å");
642 } else if (type >= 0 && olet != SCROLL_CLASS) {
644 killer.format = NO_KILLER_PREFIX;
645 Sprintf(killer.name, "caught %sself in %s own %s", uhim(),
648 killer.format = KILLED_BY;
649 Sprintf(killer.name, "
\8e©
\95ª
\8e©
\90g
\82Ì%s
\82É
\82Â
\82Â
\82Ü
\82ê
\82Ä",
653 #if 0 /*JP*//* an
\82ð
\82Â
\82¯
\82é
\82©
\82Ç
\82¤
\82©
\82Í
\8aÖ
\8cW
\82È
\82¢ */
654 killer.format = (!strcmpi(str, "tower of flame")
655 || !strcmpi(str, "fireball"))
658 Strcpy(killer.name, str);
660 killer.format = KILLED_BY;
661 Strcpy(killer.name, str);
662 Strcat(killer.name, "
\82Å");
665 if (iflags.last_msg == PLNMSG_CAUGHT_IN_EXPLOSION
666 || iflags.last_msg == PLNMSG_TOWER_OF_FLAME) /*seffects()*/
668 pline("It is fatal.");
670 pline("
\82»
\82ê
\82Í
\92v
\96½
\93I
\82¾
\81D");
673 pline_The("%s is fatal.", str);
675 pline_The("%s
\82Í
\92v
\96½
\93I
\82¾
\81D", str);
676 /* Known BUG: BURNING suppresses corpse in bones data,
677 but done does not handle killer reason correctly */
678 done((adtyp == AD_FIRE) ? BURNING : DIED);
681 exercise(A_STR, FALSE);
686 pay_for_damage((adtyp == AD_FIRE) ? "burn away"
687 : (adtyp == AD_COLD) ? "shatter"
688 : (adtyp == AD_DISN) ? "disintegrate"
692 pay_for_damage(adtyp == AD_FIRE
695 ? "
\95²
\81X
\82É
\82·
\82é"
696 : adtyp == AD_DISN ? "
\95²
\8dÓ
\82·
\82é"
697 : "
\94j
\89ó
\82·
\82é",
702 /* explosions are noisy */
705 i = 50; /* in case random damage is very small */
708 wake_nearto(x, y, i);
711 struct scatter_chain {
712 struct scatter_chain *next; /* pointer to next scatter item */
713 struct obj *obj; /* pointer to the object */
714 xchar ox; /* location of */
716 schar dx; /* direction of */
717 schar dy; /* travel */
718 int range; /* range of object */
719 boolean stopped; /* flag for in-motion/stopped */
724 * VIS_EFFECTS Add visual effects to display
725 * MAY_HITMON Objects may hit monsters
726 * MAY_HITYOU Objects may hit hero
727 * MAY_HIT Objects may hit you or monsters
728 * MAY_DESTROY Objects may be destroyed at random
729 * MAY_FRACTURE Stone objects can be fractured (statues, boulders)
732 /* returns number of scattered objects */
734 scatter(sx, sy, blastforce, scflags, obj)
735 int sx, sy; /* location of objects to scatter */
736 int blastforce; /* force behind the scattering */
737 unsigned int scflags;
738 struct obj *obj; /* only scatter this obj */
740 register struct obj *otmp;
746 boolean individual_object = obj ? TRUE : FALSE;
748 struct scatter_chain *stmp, *stmp2 = 0;
749 struct scatter_chain *schain = (struct scatter_chain *) 0;
752 while ((otmp = (individual_object ? obj : level.objects[sx][sy])) != 0) {
753 if (otmp->quan > 1L) {
754 qtmp = otmp->quan - 1L;
755 if (qtmp > LARGEST_INT)
757 qtmp = (long) rnd((int) qtmp);
758 otmp = splitobj(otmp, qtmp);
760 obj = (struct obj *) 0; /* all used */
762 obj_extract_self(otmp);
765 /* 9 in 10 chance of fracturing boulders or statues */
766 if ((scflags & MAY_FRACTURE) != 0
767 && (otmp->otyp == BOULDER || otmp->otyp == STATUE)
769 if (otmp->otyp == BOULDER) {
772 pline("%s apart.", Tobjnam(otmp, "break"));
774 pline("%s
\82Í
\88ê
\95\94\95ª
\82ª
\8dÓ
\82¯
\82½
\81D",xname(otmp));
776 You_hear("stone breaking.");
778 place_object(otmp, sx, sy);
779 if ((otmp = sobj_at(BOULDER, sx, sy)) != 0) {
780 /* another boulder here, restack it to the top */
781 obj_extract_self(otmp);
782 place_object(otmp, sx, sy);
787 if ((trap = t_at(sx, sy)) && trap->ttyp == STATUE_TRAP)
791 pline("%s.", Tobjnam(otmp, "crumble"));
793 pline("%s
\82Í
\82±
\82È
\82²
\82È
\82É
\82È
\82Á
\82½
\81D",xname(otmp));
795 You_hear("stone crumbling.");
796 (void) break_statue(otmp);
797 #ifndef FIX_BUG_C340_2
798 place_object(otmp, sx, sy); /* put fragments on floor */
803 /* 1 in 10 chance of destruction of obj; glass, egg destruction */
804 } else if ((scflags & MAY_DESTROY) != 0
805 && (!rn2(10) || (objects[otmp->otyp].oc_material == GLASS
806 || otmp->otyp == EGG))) {
807 if (breaks(otmp, (xchar) sx, (xchar) sy))
812 stmp = (struct scatter_chain *) alloc(sizeof *stmp);
813 stmp->next = (struct scatter_chain *) 0;
817 tmp = rn2(8); /* get the direction */
818 stmp->dx = xdir[tmp];
819 stmp->dy = ydir[tmp];
820 tmp = blastforce - (otmp->owt / 40);
823 stmp->range = rnd(tmp); /* anywhere up to that determ. by wt */
824 if (farthest < stmp->range)
825 farthest = stmp->range;
826 stmp->stopped = FALSE;
835 while (farthest-- > 0) {
836 for (stmp = schain; stmp; stmp = stmp->next) {
837 if ((stmp->range-- > 0) && (!stmp->stopped)) {
838 bhitpos.x = stmp->ox + stmp->dx;
839 bhitpos.y = stmp->oy + stmp->dy;
840 typ = levl[bhitpos.x][bhitpos.y].typ;
841 if (!isok(bhitpos.x, bhitpos.y)) {
842 bhitpos.x -= stmp->dx;
843 bhitpos.y -= stmp->dy;
844 stmp->stopped = TRUE;
845 } else if (!ZAP_POS(typ)
846 || closed_door(bhitpos.x, bhitpos.y)) {
847 bhitpos.x -= stmp->dx;
848 bhitpos.y -= stmp->dy;
849 stmp->stopped = TRUE;
850 } else if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
851 if (scflags & MAY_HITMON) {
853 if (ohitmon(mtmp, stmp->obj, 1, FALSE)) {
854 stmp->obj = (struct obj *) 0;
855 stmp->stopped = TRUE;
858 } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) {
859 if (scflags & MAY_HITYOU) {
864 hitvalu = 8 + stmp->obj->spe;
865 if (bigmonst(youmonst.data))
867 hitu = thitu(hitvalu, dmgval(stmp->obj, &youmonst),
868 &stmp->obj, (char *) 0);
870 stmp->stopped = TRUE;
877 if (scflags & VIS_EFFECTS) {
878 /* tmp_at(bhitpos.x, bhitpos.y); */
879 /* delay_output(); */
882 stmp->ox = bhitpos.x;
883 stmp->oy = bhitpos.y;
887 for (stmp = schain; stmp; stmp = stmp2) {
894 if (x != sx || y != sy)
895 total += stmp->obj->quan;
896 place_object(stmp->obj, x, y);
899 free((genericptr_t) stmp);
907 * Splatter burning oil from x,y to the surrounding area.
909 * This routine should really take a how and direction parameters.
910 * The how is how it was caused, e.g. kicked verses thrown. The
911 * direction is which way to spread the flaming oil. Different
912 * "how"s would give different dispersal patterns. For example,
913 * kicking a burning flask will splatter differently from a thrown
914 * flask hitting the ground.
916 * For now, just perform a "regular" explosion.
919 splatter_burning_oil(x, y)
922 /* ZT_SPELL(ZT_FIRE) = ZT_SPELL(AD_FIRE-1) = 10+(2-1) = 11 */
923 #define ZT_SPELL_O_FIRE 11 /* value kludge, see zap.c */
924 explode(x, y, ZT_SPELL_O_FIRE, d(4, 4), BURNING_OIL, EXPL_FIERY);
927 /* lit potion of oil is exploding; extinguish it as a light source before
928 possibly killing the hero and attempting to save bones */
930 explode_oil(obj, x, y)
935 impossible("exploding unlit oil");
937 splatter_burning_oil(x, y);