1 /* NetHack 3.6 explode.c $NHDT-Date: 1545182146 2018/12/19 01:15:46 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.60 $ */
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-2020 */
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)
252 if (DEADMONSTER(mtmp))
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 (DEADMONSTER(mtmp)) {
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 if (individual_object && (obj->ox != sx || obj->oy != sy))
775 impossible("scattered object <%d,%d> not at scatter site <%d,%d>",
776 obj->ox, obj->oy, sx, sy);
778 while ((otmp = (individual_object ? obj : level.objects[sx][sy])) != 0) {
779 if (otmp == uball || otmp == uchain) {
780 boolean waschain = (otmp == uchain);
782 pline_The("chain shatters!");
784 pline("
\8d½
\82Í
\82Î
\82ç
\82Î
\82ç
\82É
\82È
\82Á
\82½
\81I");
789 if (otmp->quan > 1L) {
790 qtmp = otmp->quan - 1L;
791 if (qtmp > LARGEST_INT)
793 qtmp = (long) rnd((int) qtmp);
794 otmp = splitobj(otmp, qtmp);
796 obj = (struct obj *) 0; /* all used */
798 obj_extract_self(otmp);
801 /* 9 in 10 chance of fracturing boulders or statues */
802 if ((scflags & MAY_FRACTURE) != 0
803 && (otmp->otyp == BOULDER || otmp->otyp == STATUE)
805 if (otmp->otyp == BOULDER) {
808 pline("%s apart.", Tobjnam(otmp, "break"));
810 pline("%s
\82Í
\88ê
\95\94\95ª
\82ª
\8dÓ
\82¯
\82½
\81D",xname(otmp));
813 You_hear("stone breaking.");
815 You_hear("
\90Î
\82ª
\8dÓ
\82¯
\82é
\89¹
\82ð
\95·
\82¢
\82½
\81D");
817 place_object(otmp, sx, sy);
818 if ((otmp = sobj_at(BOULDER, sx, sy)) != 0) {
819 /* another boulder here, restack it to the top */
820 obj_extract_self(otmp);
821 place_object(otmp, sx, sy);
826 if ((trap = t_at(sx, sy)) && trap->ttyp == STATUE_TRAP)
830 pline("%s.", Tobjnam(otmp, "crumble"));
832 pline("%s
\82Í
\82±
\82È
\82²
\82È
\82É
\82È
\82Á
\82½
\81D",xname(otmp));
835 You_hear("stone crumbling.");
837 You_hear("
\90Î
\82ª
\82±
\82È
\82²
\82È
\82É
\82È
\82é
\89¹
\82ð
\95·
\82¢
\82½
\81D");
838 (void) break_statue(otmp);
839 #ifndef FIX_BUG_C340_2
840 place_object(otmp, sx, sy); /* put fragments on floor */
843 newsym(sx, sy); /* in case it's beyond radius of 'farthest' */
846 /* 1 in 10 chance of destruction of obj; glass, egg destruction */
847 } else if ((scflags & MAY_DESTROY) != 0
848 && (!rn2(10) || (objects[otmp->otyp].oc_material == GLASS
849 || otmp->otyp == EGG))) {
850 if (breaks(otmp, (xchar) sx, (xchar) sy))
855 stmp = (struct scatter_chain *) alloc(sizeof *stmp);
856 stmp->next = (struct scatter_chain *) 0;
860 tmp = rn2(8); /* get the direction */
861 stmp->dx = xdir[tmp];
862 stmp->dy = ydir[tmp];
863 tmp = blastforce - (otmp->owt / 40);
866 stmp->range = rnd(tmp); /* anywhere up to that determ. by wt */
867 if (farthest < stmp->range)
868 farthest = stmp->range;
869 stmp->stopped = FALSE;
878 while (farthest-- > 0) {
879 for (stmp = schain; stmp; stmp = stmp->next) {
880 if ((stmp->range-- > 0) && (!stmp->stopped)) {
881 bhitpos.x = stmp->ox + stmp->dx;
882 bhitpos.y = stmp->oy + stmp->dy;
883 typ = levl[bhitpos.x][bhitpos.y].typ;
884 if (!isok(bhitpos.x, bhitpos.y)) {
885 bhitpos.x -= stmp->dx;
886 bhitpos.y -= stmp->dy;
887 stmp->stopped = TRUE;
888 } else if (!ZAP_POS(typ)
889 || closed_door(bhitpos.x, bhitpos.y)) {
890 bhitpos.x -= stmp->dx;
891 bhitpos.y -= stmp->dy;
892 stmp->stopped = TRUE;
893 } else if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
894 if (scflags & MAY_HITMON) {
896 if (ohitmon(mtmp, stmp->obj, 1, FALSE)) {
897 stmp->obj = (struct obj *) 0;
898 stmp->stopped = TRUE;
901 } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) {
902 if (scflags & MAY_HITYOU) {
907 hitvalu = 8 + stmp->obj->spe;
908 if (bigmonst(youmonst.data))
910 hitu = thitu(hitvalu, dmgval(stmp->obj, &youmonst),
911 &stmp->obj, (char *) 0);
913 stmp->stopped = TRUE;
920 if (scflags & VIS_EFFECTS) {
921 /* tmp_at(bhitpos.x, bhitpos.y); */
922 /* delay_output(); */
925 stmp->ox = bhitpos.x;
926 stmp->oy = bhitpos.y;
930 for (stmp = schain; stmp; stmp = stmp2) {
937 if (x != sx || y != sy)
938 total += stmp->obj->quan;
939 place_object(stmp->obj, x, y);
942 free((genericptr_t) stmp);
946 if (sx == u.ux && sy == u.uy && u.uundetected
947 && hides_under(youmonst.data))
948 (void) hideunder(&youmonst);
953 * Splatter burning oil from x,y to the surrounding area.
955 * This routine should really take a how and direction parameters.
956 * The how is how it was caused, e.g. kicked verses thrown. The
957 * direction is which way to spread the flaming oil. Different
958 * "how"s would give different dispersal patterns. For example,
959 * kicking a burning flask will splatter differently from a thrown
960 * flask hitting the ground.
962 * For now, just perform a "regular" explosion.
965 splatter_burning_oil(x, y, diluted_oil)
969 int dmg = d(diluted_oil ? 3 : 4, 4);
971 /* ZT_SPELL(ZT_FIRE) = ZT_SPELL(AD_FIRE-1) = 10+(2-1) = 11 */
972 #define ZT_SPELL_O_FIRE 11 /* value kludge, see zap.c */
973 explode(x, y, ZT_SPELL_O_FIRE, dmg, BURNING_OIL, EXPL_FIERY);
976 /* lit potion of oil is exploding; extinguish it as a light source before
977 possibly killing the hero and attempting to save bones */
979 explode_oil(obj, x, y)
983 boolean diluted_oil = obj->odiluted;
986 impossible("exploding unlit oil");
988 splatter_burning_oil(x, y, diluted_oil);