Source:SLASH'EM 0.0.7E7F2/explode.c

From NetHackWiki
Revision as of 19:05, 7 March 2008 by Kernigh bot (talk | contribs) (SLASH'EM 0.0.7E7F2/explode.c moved to Source:SLASH'EM 0.0.7E7F2/explode.c: Robot: moved page)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Below is the full text to explode.c from the source code of SLASH'EM 0.0.7E7F2. To link to a particular line, write [[SLASH'EM 0.0.7E7F2/explode.c#line123]], for example.

The latest source code for vanilla NetHack is at Source code.


The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

1.    /*	SCCS Id: @(#)explode.c	3.4	2002/11/10	*/
2.    /*	Copyright (C) 1990 by Ken Arromdee */
3.    /* NetHack may be freely redistributed.  See license for details. */
4.    
5.    #include "hack.h"
6.    
7.    #ifdef OVL0
8.    
9.    /* ExplodeRegions share some commonalities with NhRegions, but not enough to
10.    * make it worth trying to create a common implementation.
11.    */
12.   typedef struct {
13.       xchar x, y;
14.       xchar blast;	/* blast symbol */
15.       xchar shielded;	/* True if this location is shielded */
16.   } ExplodeLocation;
17.   
18.   typedef struct {
19.       ExplodeLocation *locations;
20.       short nlocations, alocations;
21.   } ExplodeRegion;
22.   
23.   STATIC_DCL ExplodeRegion *
24.   create_explode_region()
25.   {
26.       ExplodeRegion *reg;
27.   
28.       reg = (ExplodeRegion *)alloc(sizeof(ExplodeRegion));
29.       reg->locations = (ExplodeLocation *)0;
30.       reg->nlocations = 0;
31.       reg->alocations = 0;
32.       return reg;
33.   }
34.   
35.   STATIC_DCL void
36.   add_location_to_explode_region(reg, x, y)
37.   ExplodeRegion *reg;
38.   xchar x, y;
39.   {
40.       int i;
41.       ExplodeLocation *new;
42.       for(i = 0; i < reg->nlocations; i++)
43.   	if (reg->locations[i].x == x && reg->locations[i].y == y)
44.   	    return;
45.       if (reg->nlocations == reg->alocations) {
46.   	reg->alocations = reg->alocations ? 2 * reg->alocations : 32;
47.   	new = (ExplodeLocation *)
48.   		alloc(reg->alocations * sizeof(ExplodeLocation));
49.   	(void) memcpy((genericptr_t)new, (genericptr_t)reg->locations,
50.   		reg->nlocations * sizeof(ExplodeLocation));
51.   	free((genericptr_t)reg->locations);
52.   	reg->locations = new;
53.       }
54.       reg->locations[reg->nlocations].x = x;
55.       reg->locations[reg->nlocations].y = y;
56.       /* reg->locations[reg->nlocations].blast = 0; */
57.       /* reg->locations[reg->nlocations].shielded = 0; */
58.       reg->nlocations++;
59.   }
60.   
61.   STATIC_DCL int
62.   compare_explode_location(loc1, loc2)
63.   ExplodeLocation *loc1, *loc2;
64.   {
65.       return loc1->y == loc2->y ? loc1->x - loc2->x : loc1->y - loc2->y;
66.   }
67.   
68.   STATIC_DCL void
69.   set_blast_symbols(reg)
70.   ExplodeRegion *reg;
71.   {
72.       int i, j, bitmask;
73.       /* The index into the blast symbol array is a bitmask containing 4 bits:
74.        * bit 3: True if the location immediately to the north is present
75.        * bit 2: True if the location immediately to the south is present
76.        * bit 1: True if the location immediately to the east is present
77.        * bit 0: True if the location immediately to the west is present
78.        */
79.       static int blast_symbols[16] = {
80.   	S_explode5, S_explode6, S_explode4, S_explode5,
81.   	S_explode2, S_explode3, S_explode1, S_explode2,
82.   	S_explode8, S_explode9, S_explode7, S_explode8,
83.   	S_explode5, S_explode6, S_explode4, S_explode5,
84.       };
85.       /* Sort in order of North -> South, West -> East */
86.       qsort(reg->locations, reg->nlocations, sizeof(ExplodeLocation),
87.   	    compare_explode_location);
88.       /* Pass 1: Build the bitmasks in the blast field */
89.       for(i = 0; i < reg->nlocations; i++)
90.   	reg->locations[i].blast = 0;
91.       for(i = 0; i < reg->nlocations; i++) {
92.   	bitmask = 0;
93.   	if (i && reg->locations[i-1].y == reg->locations[i].y &&
94.   		reg->locations[i-1].x == reg->locations[i].x-1) {
95.   	    reg->locations[i].blast |= 1;	/* Location to the west */
96.   	    reg->locations[i-1].blast |= 2;	/* Location to the east */
97.   	}
98.   	for(j = i-1; j >= 0; j--) {
99.   	    if (reg->locations[j].y < reg->locations[i].y-1)
100.  		break;
101.  	    else if (reg->locations[j].y == reg->locations[i].y-1 &&
102.  		    reg->locations[j].x == reg->locations[i].x) {
103.  		reg->locations[i].blast |= 8;	/* Location to the north */
104.  		reg->locations[j].blast |= 4;	/* Location to the south */
105.  		break;
106.  	    }
107.  	}
108.      }
109.      /* Pass 2: Set the blast symbols */
110.      for(i = 0; i < reg->nlocations; i++)
111.  	reg->locations[i].blast = blast_symbols[reg->locations[i].blast];
112.  }
113.  
114.  STATIC_DCL void
115.  free_explode_region(reg)
116.  ExplodeRegion *reg;
117.  {
118.      free((genericptr_t)reg->locations);
119.      free((genericptr_t)reg);
120.  }
121.  
122.  /* This is the "do-it-all" explosion command */
123.  STATIC_DCL void FDECL(do_explode,
124.  	(int,int,ExplodeRegion *,int,int,CHAR_P,int,int,BOOLEAN_P));
125.  
126.  /* Note: I had to choose one of three possible kinds of "type" when writing
127.   * this function: a wand type (like in zap.c), an adtyp, or an object type.
128.   * Wand types get complex because they must be converted to adtyps for
129.   * determining such things as fire resistance.  Adtyps get complex in that
130.   * they don't supply enough information--was it a player or a monster that
131.   * did it, and with a wand, spell, or breath weapon?  Object types share both
132.   * these disadvantages....
133.   *
134.   * Explosions derived from vanilla NetHack:
135.   *
136.   * src         nature          olet        expl    Comment
137.   * Your wand   MAGIC_MISSILE   WAND        FROSTY  Exploding wands of cold
138.   * Your wand   MAGIC_MISSILE   WAND        FIERY   Exploding wands of fire/
139.   *                                                 fireball
140.   * Your wand   MAGIC_MISSILE   WAND        MAGICAL Other explosive wands
141.   * Your spell  FIRE            BURNING_OIL FIERY   Splattered buring oil
142.   * Mon's ?     -               MON_EXPLODE NOXIOUS Exploding gas spore
143.   * Your spell  FIRE            0           FIERY   Filling a lamp with oil
144.   *                                                 when lit
145.   * Your spell  FIRE            SCROLL      FIERY   Reading a scroll of fire
146.   * Your spell  FIRE            WAND        FIERY   Zap yourself with wand/
147.   *                                                 spell of fireball
148.   * Your spell  FIRE            0           FIERY   Your fireball
149.   *
150.   * Slash'EM specific explosions:
151.   *
152.   * src         nature          olet        expl    Comment
153.   * Your spell  FIRE            WEAPON      FIERY   Explosive projectile
154.   * Your spell  FIRE            WEAPON      FIERY   Bolts shot by Hellfire
155.   * Mon's spell FIRE            FIERY       WEAPON  Explosive projectile (BUG)
156.   * Mon's spell FIRE            FIERY       WEAPON  Bolts shot by Hellfire (BUG)
157.   * Your spell  MAGIC_MISSILE   WAND        MAGICAL Spirit bomb technique
158.   * Mon's spell FIRE            0           FIERY   Monster's fireball
159.   *
160.   * Sigil of tempest:
161.   *
162.   * src         nature          olet        expl    Comment
163.   * Your spell  MAGIC_MISSILE   0           MAGICAL Hero casts magic missile
164.   * Your spell  DEATH           0           MAGICAL Hero casts finger of death
165.   * Your spell  FIRE            0           FIERY   Hero casts fireball
166.   * Your spell  LIGHTNING       0           FIERY   Hero casts lightning
167.   * Your spell  COLD            0           FROSTY  Hero casts cone of cold
168.   * Your spell  SLEEP           0           NOXIOUS Hero casts sleep
169.   * Your spell  POISON_GAS      0           NOXIOUS Hero casts poison blast
170.   * Your spell  ACID            0           NOXIOUS Hero casts acid stream
171.   *
172.   * Mega spells:
173.   *
174.   * src         nature          olet        expl    Comment
175.   * Your mega   FIRE            0           FIERY   
176.   * Your mega   COLD            0           FROSTY  
177.   * Your mega   MAGIC_MISSLE    0           MAGICAL 
178.   *
179.   * Notes:
180.   *	Nature is encoded as (abs(type) % 10) and src is determined using the
181.   *	following table:
182.   *		Types		Src
183.   *		-30 - -39	Mon's wand
184.   *		-20 - -29	Mon's breath
185.   *		-10 - -19	Mon's spell
186.   *		 -1 -  -9	Special
187.   *		  0 -   9	Your wand
188.   *		 10 -  19	Your spell
189.   *		 20 -  29	Your breath
190.   *		 30 -  39	Your mega
191.   *	There is only one special type currently defined:
192.   *		-1		Exploding gas spore
193.   */
194.  void
195.  explode(x, y, type, dam, olet, expltype)
196.  xchar x, y; /* WAC was int...i think it's supposed to be xchar */
197.  int type; /* the same as in zap.c */
198.  int dam;
199.  char olet;
200.  int expltype;
201.  {
202.      int i, j;
203.      ExplodeRegion *area;
204.      area = create_explode_region();
205.      for(i = 0; i < 3; i++)
206.  	for(j = 0; j < 3; j++)
207.  	    if (isok(i+x-1,j+y-1) && ZAP_POS((&levl[i+x-1][j+y-1])->typ))
208.  		add_location_to_explode_region(area, i+x-1, j+y-1);
209.      do_explode(x, y, area, type, dam, olet, expltype, 0, !flags.mon_moving);
210.      free_explode_region(area);
211.  }
212.  
213.  void
214.  do_explode(x, y, area, type, dam, olet, expltype, dest, yours)
215.  xchar x, y; /* WAC was int...i think it's supposed to be xchar */
216.  ExplodeRegion *area;
217.  int type; /* the same as in zap.c */
218.  int dam;
219.  char olet;
220.  int expltype;
221.  int dest; /* 0 = normal, 1 = silent, 2 = silent/remote */	
222.  boolean yours; /* is it your fault (for killing monsters) */
223.  {
224.  	int i, k, damu = dam;
225.  	boolean starting = 1;
226.  	boolean visible, any_shield;
227.  	int uhurt = 0; /* 0=unhurt, 1=items damaged, 2=you and items damaged */
228.  	const char *str;
229.  	int idamres, idamnonres;
230.  	struct monst *mtmp;
231.  	uchar adtyp;
232.  	boolean explmask;
233.  	boolean shopdamage = FALSE;
234.  	boolean generic = FALSE;
235.  	boolean silent = FALSE, remote = FALSE;
236.  	xchar xi, yi;
237.  
238.  	if (dest > 0) silent = TRUE;	
239.  	if (dest == 2) remote = TRUE;
240.  
241.  	if (olet == WAND_CLASS)		/* retributive strike */
242.  		switch (Role_switch) {
243.  			case PM_PRIEST:
244.  			/*WAC add Flame,  Ice mages,  Necromancer */
245.  			case PM_FLAME_MAGE:
246.  			case PM_ICE_MAGE:
247.  			case PM_NECROMANCER:
248.  			case PM_WIZARD: damu /= 5;
249.  				  break;
250.  			case PM_HEALER:
251.  			case PM_KNIGHT: damu /= 2;
252.  				  break;
253.  			default:  break;
254.  		}
255.  
256.  	if (olet == MON_EXPLODE) {
257.  	    str = killer;
258.  	    killer = 0;		/* set again later as needed */
259.  	    adtyp = AD_PHYS;
260.  	} else
261.  	switch (abs(type) % 10) {
262.  		case 0: str = "magical blast";
263.  			adtyp = AD_MAGM;
264.  			break;
265.  		case 1: str =   olet == BURNING_OIL ?	"burning oil" :
266.  				olet == SCROLL_CLASS ?	"tower of flame" :
267.  							"fireball";
268.  			adtyp = AD_FIRE;
269.  			break;
270.  		case 2: str = "ball of cold";
271.  			adtyp = AD_COLD;
272.  			break;
273.  /* Assume that wands are death, others are disintegration */
274.  		case 4: str =  (olet == WAND_CLASS) ? "death field" :
275.  							"disintegration field";
276.  			adtyp = AD_DISN;
277.  			break;
278.  		case 5: str = "ball of lightning";
279.  			adtyp = AD_ELEC;
280.  			break;
281.  		case 6: str = "poison gas cloud";
282.  			adtyp = AD_DRST;
283.  			break;
284.  		case 7: str = "splash of acid";
285.  			adtyp = AD_ACID;
286.  			break;
287.  		default: impossible("explosion base type %d?", type); return;
288.  	}
289.  
290.  /*WAC add light source for fire*/
291.  #ifdef LIGHT_SRC_SPELL
292.          if ((!remote) && ((adtyp == AD_FIRE) || (adtyp == AD_ELEC))) {
293.                  new_light_source(x, y, 2, LS_TEMP, (genericptr_t) 1);
294.                  vision_recalc(0);
295.          }
296.  #endif
297.  
298.  	any_shield = visible = FALSE;
299.  	for(i = 0; i < area->nlocations; i++) {
300.  		explmask = FALSE;
301.  		xi = area->locations[i].x;
302.  		yi = area->locations[i].y;
303.  		if (xi == u.ux && yi == u.uy) {
304.  		    switch(adtyp) {
305.  			case AD_PHYS:                        
306.  				break;
307.  			case AD_MAGM:
308.  				explmask = !!Antimagic;
309.  				break;
310.  			case AD_FIRE:
311.  				explmask = !!Fire_resistance;
312.  				break;
313.  			case AD_COLD:
314.  				explmask = !!Cold_resistance;
315.  				break;
316.  			case AD_DISN:
317.  				explmask = (olet == WAND_CLASS) ?
318.  						!!(nonliving(youmonst.data) || is_demon(youmonst.data)) :
319.  						!!Disint_resistance;
320.  				break;
321.  			case AD_ELEC:
322.  				explmask = !!Shock_resistance;
323.  				break;
324.  			case AD_DRST:
325.  				explmask = !!Poison_resistance;
326.  				break;
327.  			case AD_ACID:
328.  				explmask = !!Acid_resistance;
329.  				break;
330.  			default:
331.  				impossible("explosion type %d?", adtyp);
332.  				break;
333.  		    }
334.  		}
335.  
336.  		mtmp = m_at(xi, yi);
337.  #ifdef STEED
338.  		if (!mtmp && xi == u.ux && yi == u.uy)
339.  			mtmp = u.usteed;
340.  #endif
341.  		if (mtmp) {
342.  		    switch(adtyp) {
343.  			case AD_PHYS:                        
344.  				break;
345.  			case AD_MAGM:
346.  				explmask |= resists_magm(mtmp);
347.  				break;
348.  			case AD_FIRE:
349.  				explmask |= resists_fire(mtmp);
350.  				break;
351.  			case AD_COLD:
352.  				explmask |= resists_cold(mtmp);
353.  				break;
354.  			case AD_DISN:
355.  				explmask |= (olet == WAND_CLASS) ?
356.  					(nonliving(mtmp->data) || is_demon(mtmp->data)) :
357.  					resists_disint(mtmp);
358.  				break;
359.  			case AD_ELEC:
360.  				explmask |= resists_elec(mtmp);
361.  				break;
362.  			case AD_DRST:
363.  				explmask |= resists_poison(mtmp);
364.  				break;
365.  			case AD_ACID:
366.  				explmask |= resists_acid(mtmp);
367.  				break;
368.  			default:
369.  				impossible("explosion type %d?", adtyp);
370.  				break;
371.  		    }
372.  		}
373.  		if (mtmp && cansee(xi,yi) && !canspotmon(mtmp))
374.  		    map_invisible(xi, yi);
375.  		else if (!mtmp && memory_is_invisible(xi, yi)) {
376.  		    unmap_object(xi, yi);
377.  		    newsym(xi, yi);
378.  		}
379.  		if (cansee(xi, yi)) visible = TRUE;
380.  		if (explmask) any_shield = TRUE;
381.  		area->locations[i].shielded = explmask;
382.  	}
383.  
384.  	/* Not visible if remote */
385.  	if (remote) visible = FALSE;
386.  	
387.  	if (visible) {
388.  #ifdef ALLEG_FX
389.  	    if (iflags.usealleg) {
390.  		alleg_explode(x, y, adtyp);
391.  		if (any_shield)		/* simulate a shield effect */
392.  		    for(i = 0; i < area->nlocations; i++) {
393.  			if (area->locations[i].shielded)
394.  			    shieldeff(area->locations[i].x,
395.  				    area->locations[i].y);
396.  		    }
397.  	    } else {
398.  #endif
399.  		set_blast_symbols(area);
400.  		/* Start the explosion */
401.  		for(i = 0; i < area->nlocations; i++) {
402.  		    tmp_at(starting ? DISP_BEAM : DISP_CHANGE,
403.  			    explosion_to_glyph(expltype,
404.  			    area->locations[i].blast));
405.  		    tmp_at(area->locations[i].x, area->locations[i].y);
406.  		    starting = 0;
407.  		}
408.  		curs_on_u();	/* will flush screen and output */
409.  
410.  		if (any_shield && flags.sparkle) { /* simulate shield effect */
411.  		    for (k = 0; k < SHIELD_COUNT; k++) {
412.  			for(i = 0; i < area->nlocations; i++) {
413.  			    if (area->locations[i].shielded)
414.  				/*
415.  				 * Bypass tmp_at() and send the shield glyphs
416.  				 * directly to the buffered screen.  tmp_at()
417.  				 * will clean up the location for us later.
418.  				 */
419.  				show_glyph(area->locations[i].x,
420.  					area->locations[i].y,
421.  					cmap_to_glyph(shield_static[k]));
422.  			}
423.  			curs_on_u();	/* will flush screen and output */
424.  			delay_output();
425.  		    }
426.  
427.  		    /* Cover last shield glyph with blast symbol. */
428.  		    for(i = 0; i < area->nlocations; i++) {
429.  			if (area->locations[i].shielded)
430.  			    show_glyph(area->locations[i].x,
431.  				    area->locations[i].y,
432.  				    explosion_to_glyph(expltype,
433.  				    area->locations[i].blast));
434.  		    }
435.  
436.  		} else {		/* delay a little bit. */
437.  		    delay_output();
438.  		    delay_output();
439.  		}
440.  		tmp_at(DISP_END, 0); /* clear the explosion */
441.  #ifdef ALLEG_FX
442.  	    }
443.  #endif
444.  	} else if (!remote) {
445.  	    if (olet == MON_EXPLODE) {
446.  		str = "explosion";
447.  		generic = TRUE;
448.  	    }
449.  	    if (flags.soundok)
450.  		You_hear(is_pool(x, y) ? "a muffled explosion." : "a blast.");
451.  	}
452.  
453.  	    if (dam) for(i = 0; i < area->nlocations; i++) {
454.  		xi = area->locations[i].x;
455.  		yi = area->locations[i].y;
456.  		if (xi == u.ux && yi == u.uy)
457.  		    uhurt = area->locations[i].shielded ? 1 : 2;
458.  		idamres = idamnonres = 0;
459.  
460.  		/* DS: Allow monster induced explosions also */
461.  		if (type >= 0 || type <= -10)
462.  		    (void)zap_over_floor(xi, yi, type, &shopdamage);
463.  
464.  		mtmp = m_at(xi, yi);
465.  #ifdef STEED
466.  		if (!mtmp && xi == u.ux && yi == u.uy)
467.  			mtmp = u.usteed;
468.  #endif
469.  		if (!mtmp) continue;
470.  		if (DEADMONSTER(mtmp)) continue;
471.  		if (u.uswallow && mtmp == u.ustuck) {
472.  			if (is_animal(u.ustuck->data))
473.  				if (!silent) pline("%s gets %s!",
474.  				      Monnam(u.ustuck),
475.  				      (adtyp == AD_FIRE) ? "heartburn" :
476.  				      (adtyp == AD_COLD) ? "chilly" :
477.  				      (adtyp == AD_DISN) ? ((olet == WAND_CLASS) ?
478.  				       "irradiated by pure energy" : "perforated") :
479.  				      (adtyp == AD_ELEC) ? "shocked" :
480.  				      (adtyp == AD_DRST) ? "poisoned" :
481.  				      (adtyp == AD_ACID) ? "an upset stomach" :
482.  				       "fried");
483.  			else
484.  				if (!silent) pline("%s gets slightly %s!",
485.  				      Monnam(u.ustuck),
486.  				      (adtyp == AD_FIRE) ? "toasted" :
487.  				      (adtyp == AD_COLD) ? "chilly" :
488.  				      (adtyp == AD_DISN) ? ((olet == WAND_CLASS) ?
489.  				       "overwhelmed by pure energy" : "perforated") :
490.  				      (adtyp == AD_ELEC) ? "shocked" :
491.  				      (adtyp == AD_DRST) ? "intoxicated" :
492.  				      (adtyp == AD_ACID) ? "burned" :
493.  				       "fried");
494.  		} else if (!silent && cansee(xi, yi)) {
495.  		    if(mtmp->m_ap_type) seemimic(mtmp);
496.  		    pline("%s is caught in the %s!", Monnam(mtmp), str);
497.  		}
498.  
499.  		idamres += destroy_mitem(mtmp, SCROLL_CLASS, (int) adtyp);
500.  		idamres += destroy_mitem(mtmp, SPBOOK_CLASS, (int) adtyp);
501.  		idamnonres += destroy_mitem(mtmp, POTION_CLASS, (int) adtyp);
502.  		idamnonres += destroy_mitem(mtmp, WAND_CLASS, (int) adtyp);
503.  		idamnonres += destroy_mitem(mtmp, RING_CLASS, (int) adtyp);
504.  
505.  		if (area->locations[i].shielded) {
506.  			golemeffects(mtmp, (int) adtyp, dam + idamres);
507.  			mtmp->mhp -= idamnonres;
508.  		} else {
509.  		/* call resist with 0 and do damage manually so 1) we can
510.  		 * get out the message before doing the damage, and 2) we can
511.  		 * call mondied, not killed, if it's not your blast
512.  		 */
513.  			int mdam = dam;
514.  
515.  			if (resist(mtmp, olet, 0, FALSE)) {
516.  			    if (!silent && cansee(xi,yi))
517.  				pline("%s resists the %s!", Monnam(mtmp), str);
518.  			    mdam = dam/2;
519.  			}
520.  			if (mtmp == u.ustuck)
521.  				mdam *= 2;
522.  			if (resists_cold(mtmp) && adtyp == AD_FIRE)
523.  				mdam *= 2;
524.  			else if (resists_fire(mtmp) && adtyp == AD_COLD)
525.  				mdam *= 2;
526.  			mtmp->mhp -= mdam;
527.  			mtmp->mhp -= (idamres + idamnonres);
528.  #ifdef SHOW_DMG
529.  			if (mtmp->mhp > 0 && !remote)
530.  				showdmg(mdam + idamres + idamnonres);
531.  #endif
532.  		}
533.  		if (mtmp->mhp <= 0) {
534.  			/* KMH -- Don't blame the player for pets killing gas spores */
535.  			if (yours) xkilled(mtmp, (silent ? 0 : 1));
536.  			else monkilled(mtmp, "", (int)adtyp);
537.  		} else if (!flags.mon_moving && yours) setmangry(mtmp);
538.  	}
539.  
540.  #ifdef LIGHT_SRC_SPELL
541.          /*WAC kill the light source*/
542.          if ((!remote) && ((adtyp == AD_FIRE) || (adtyp == AD_ELEC))) {
543.              del_light_source(LS_TEMP, (genericptr_t) 1);
544.  	}
545.  #endif
546.  
547.  	/* Do your injury last */
548.  	
549.  	/* You are not hurt if this is remote */
550.  	if (remote) uhurt = FALSE;
551.  	
552.  	if (uhurt) {
553.  		/* [ALI] Give message if it's a weapon (grenade) exploding */
554.  		if ((type >= 0 || adtyp == AD_PHYS || olet == WEAPON_CLASS) &&
555.  		    /* gas spores */
556.  				flags.verbose && olet != SCROLL_CLASS)
557.  			You("are caught in the %s!", str);
558.  		/* do property damage first, in case we end up leaving bones */
559.  		if (adtyp == AD_FIRE) burn_away_slime();
560.  		if (Invulnerable) {
561.  		    damu = 0;
562.  		    You("are unharmed!");
563.  		} else if (Half_physical_damage && adtyp == AD_PHYS)
564.  		    damu = (damu+1) / 2;
565.  		if (adtyp == AD_FIRE) (void) burnarmor(&youmonst);
566.  		destroy_item(SCROLL_CLASS, (int) adtyp);
567.  		destroy_item(SPBOOK_CLASS, (int) adtyp);
568.  		destroy_item(POTION_CLASS, (int) adtyp);
569.  		destroy_item(RING_CLASS, (int) adtyp);
570.  		destroy_item(WAND_CLASS, (int) adtyp);
571.  
572.  		ugolemeffects((int) adtyp, damu);
573.  
574.  		if (uhurt == 2) {
575.  		    if (Upolyd)
576.  		    	u.mh  -= damu;
577.  		    else
578.  			u.uhp -= damu;
579.  		    flags.botl = 1;
580.  #ifdef SHOW_DMG                
581.  		    if (flags.showdmg) pline("[%d pts.]", damu);
582.  #endif
583.  		}
584.  
585.  		if (u.uhp <= 0 || (Upolyd && u.mh <= 0)) {
586.  		    if (Upolyd) {
587.  			if (Polymorph_control || !rn2(3)) {
588.  			    u.uhp -= mons[u.umonnum].mlevel;
589.  			    u.uhpmax -= mons[u.umonnum].mlevel;
590.  			    if (u.uhpmax < 1) u.uhpmax = 1;
591.  			}
592.  			rehumanize();
593.  		    } else {
594.  			if (olet == MON_EXPLODE) {
595.  			    /* killer handled by caller */
596.  			    if (str != killer_buf && !generic)
597.  				Strcpy(killer_buf, str);
598.  			    killer_format = KILLED_BY_AN;
599.  			} else if (type >= 0 && olet != SCROLL_CLASS && yours) {
600.  			    killer_format = NO_KILLER_PREFIX;
601.  			    Sprintf(killer_buf, "caught %sself in %s own %s",
602.  				    uhim(), uhis(), str);
603.  			} else if (olet != BURNING_OIL) {
604.  			    killer_format = KILLED_BY_AN;
605.  			    Strcpy(killer_buf, str);
606.  			} else {
607.  			    killer_format = KILLED_BY;
608.  			    Strcpy(killer_buf, str);
609.  			}
610.  			killer = killer_buf;
611.  			/* Known BUG: BURNING suppresses corpse in bones data,
612.  			   but done does not handle killer reason correctly */
613.  			done((adtyp == AD_FIRE) ? BURNING : DIED);
614.  		    }
615.  		}
616.  		exercise(A_STR, FALSE);
617.  	}
618.  
619.  	if (shopdamage) {
620.  		pay_for_damage(adtyp == AD_FIRE ? "burn away" :
621.  			       adtyp == AD_COLD ? "shatter" :
622.  			       adtyp == AD_DISN ? "disintegrate" : "destroy",
623.  			       FALSE);
624.  	}
625.  
626.  	/* explosions are noisy */
627.  	i = dam * dam;
628.  	if (i < 50) i = 50;	/* in case random damage is very small */
629.  	wake_nearto(x, y, i);
630.  #ifdef ALLEG_FX
631.          if (iflags.usealleg) cleanup_explosions();
632.  #endif
633.  }
634.  #endif /* OVL0 */
635.  #ifdef OVL1
636.  
637.  struct scatter_chain {
638.  	struct scatter_chain *next;	/* pointer to next scatter item	*/
639.  	struct obj *obj;		/* pointer to the object	*/
640.  	xchar ox;			/* location of			*/
641.  	xchar oy;			/*	item			*/
642.  	schar dx;			/* direction of			*/
643.  	schar dy;			/*	travel			*/
644.  	int range;			/* range of object		*/
645.  	boolean stopped;		/* flag for in-motion/stopped	*/
646.  };
647.  
648.  /*
649.   * scflags:
650.   *	VIS_EFFECTS	Add visual effects to display
651.   *	MAY_HITMON	Objects may hit monsters
652.   *	MAY_HITYOU	Objects may hit hero
653.   *	MAY_HIT		Objects may hit you or monsters
654.   *	MAY_DESTROY	Objects may be destroyed at random
655.   *	MAY_FRACTURE	Stone objects can be fractured (statues, boulders)
656.   */
657.  
658.  /* returns number of scattered objects */
659.  long
660.  scatter(sx,sy,blastforce,scflags, obj)
661.  int sx,sy;				/* location of objects to scatter */
662.  int blastforce;				/* force behind the scattering	*/
663.  unsigned int scflags;
664.  struct obj *obj;			/* only scatter this obj        */
665.  {
666.  	register struct obj *otmp;
667.  	register int tmp;
668.  	int farthest = 0;
669.  	uchar typ;
670.  	long qtmp;
671.  	boolean used_up;
672.  	boolean individual_object = obj ? TRUE : FALSE;
673.  	struct monst *mtmp;
674.  	struct scatter_chain *stmp, *stmp2 = 0;
675.  	struct scatter_chain *schain = (struct scatter_chain *)0;
676.  	long total = 0L;
677.  
678.  	while ((otmp = individual_object ? obj : level.objects[sx][sy]) != 0) {
679.  	    if (otmp->quan > 1L) {
680.  		qtmp = otmp->quan - 1;
681.  		if (qtmp > LARGEST_INT) qtmp = LARGEST_INT;
682.  		qtmp = (long)rnd((int)qtmp);
683.  		otmp = splitobj(otmp, qtmp);
684.  	    } else {
685.  		obj = (struct obj *)0; /* all used */
686.  	    }
687.  	    obj_extract_self(otmp);
688.  	    used_up = FALSE;
689.  
690.  	    /* 9 in 10 chance of fracturing boulders or statues */
691.  	    if ((scflags & MAY_FRACTURE)
692.  			&& ((otmp->otyp == BOULDER) || (otmp->otyp == STATUE))
693.  			&& rn2(10)) {
694.  		if (otmp->otyp == BOULDER) {
695.  		    pline("%s apart.", Tobjnam(otmp, "break"));
696.  		    fracture_rock(otmp);
697.  		    place_object(otmp, sx, sy);
698.  		    if ((otmp = sobj_at(BOULDER, sx, sy)) != 0) {
699.  			/* another boulder here, restack it to the top */
700.  			obj_extract_self(otmp);
701.  			place_object(otmp, sx, sy);
702.  		    }
703.  		} else {
704.  		    struct trap *trap;
705.  
706.  		    if ((trap = t_at(sx,sy)) && trap->ttyp == STATUE_TRAP)
707.  			    deltrap(trap);
708.  		    pline("%s.", Tobjnam(otmp, "crumble"));
709.  		    (void) break_statue(otmp);
710.  		    place_object(otmp, sx, sy);	/* put fragments on floor */
711.  		}
712.  		used_up = TRUE;
713.  
714.  	    /* 1 in 10 chance of destruction of obj; glass, egg destruction */
715.  	    } else if ((scflags & MAY_DESTROY) && (!rn2(10)
716.  			|| (objects[otmp->otyp].oc_material == GLASS
717.  			|| otmp->otyp == EGG))) {
718.  		if (breaks(otmp, (xchar)sx, (xchar)sy)) used_up = TRUE;
719.  	    }
720.  
721.  	    if (!used_up) {
722.  		stmp = (struct scatter_chain *)
723.  					alloc(sizeof(struct scatter_chain));
724.  		stmp->next = (struct scatter_chain *)0;
725.  		stmp->obj = otmp;
726.  		stmp->ox = sx;
727.  		stmp->oy = sy;
728.  		tmp = rn2(8);		/* get the direction */
729.  		stmp->dx = xdir[tmp];
730.  		stmp->dy = ydir[tmp];
731.  		tmp = blastforce - (otmp->owt/40);
732.  		if (tmp < 1) tmp = 1;
733.  		stmp->range = rnd(tmp); /* anywhere up to that determ. by wt */
734.  		if (farthest < stmp->range) farthest = stmp->range;
735.  		stmp->stopped = FALSE;
736.  		if (!schain)
737.  		    schain = stmp;
738.  		else
739.  		    stmp2->next = stmp;
740.  		stmp2 = stmp;
741.  	    }
742.  	}
743.  
744.  	while (farthest-- > 0) {
745.  		for (stmp = schain; stmp; stmp = stmp->next) {
746.  		   if ((stmp->range-- > 0) && (!stmp->stopped)) {
747.  			bhitpos.x = stmp->ox + stmp->dx;
748.  			bhitpos.y = stmp->oy + stmp->dy;
749.  			typ = levl[bhitpos.x][bhitpos.y].typ;
750.  			if(!isok(bhitpos.x, bhitpos.y)) {
751.  				bhitpos.x -= stmp->dx;
752.  				bhitpos.y -= stmp->dy;
753.  				stmp->stopped = TRUE;
754.  			} else if(!ZAP_POS(typ) ||
755.  					closed_door(bhitpos.x, bhitpos.y)) {
756.  				bhitpos.x -= stmp->dx;
757.  				bhitpos.y -= stmp->dy;
758.  				stmp->stopped = TRUE;
759.  			} else if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
760.  				if (scflags & MAY_HITMON) {
761.  				    stmp->range--;
762.  				    if (ohitmon((struct monst *)0, mtmp, stmp->obj, 1, FALSE)) {
763.  					stmp->obj = (struct obj *)0;
764.  					stmp->stopped = TRUE;
765.  				    }
766.  				}
767.  			} else if (bhitpos.x==u.ux && bhitpos.y==u.uy) {
768.  				if (scflags & MAY_HITYOU) {
769.  				    int hitvalu, hitu;
770.  
771.  				    if (multi) nomul(0);
772.  				    hitvalu = 8 + stmp->obj->spe;
773.  				    if (bigmonst(youmonst.data)) hitvalu++;
774.  				    hitu = thitu(hitvalu,
775.  						 dmgval(stmp->obj, &youmonst),
776.  						 stmp->obj, (char *)0);
777.  				    if (hitu) {
778.  					stmp->range -= 3;
779.  					stop_occupation();
780.  				    }
781.  				}
782.  			} else {
783.  				if (scflags & VIS_EFFECTS) {
784.  				    /* tmp_at(bhitpos.x, bhitpos.y); */
785.  				    /* delay_output(); */
786.  				}
787.  			}
788.  			stmp->ox = bhitpos.x;
789.  			stmp->oy = bhitpos.y;
790.  		   }
791.  		}
792.  	}
793.  	for (stmp = schain; stmp; stmp = stmp2) {
794.  		int x,y;
795.  
796.  		stmp2 = stmp->next;
797.  		x = stmp->ox; y = stmp->oy;
798.  		if (stmp->obj) {
799.  			if ( x!=sx || y!=sy )
800.  			    total += stmp->obj->quan;
801.  			place_object(stmp->obj, x, y);
802.  			stackobj(stmp->obj);
803.  		}
804.  		free((genericptr_t)stmp);
805.  		newsym(x,y);
806.  	}
807.  
808.  	return total;
809.  }
810.  
811.  
812.  /*
813.   * Splatter burning oil from x,y to the surrounding area.
814.   *
815.   * This routine should really take a how and direction parameters.
816.   * The how is how it was caused, e.g. kicked verses thrown.  The
817.   * direction is which way to spread the flaming oil.  Different
818.   * "how"s would give different dispersal patterns.  For example,
819.   * kicking a burning flask will splatter differently from a thrown
820.   * flask hitting the ground.
821.   *
822.   * For now, just perform a "regular" explosion.
823.   */
824.  void
825.  splatter_burning_oil(x, y)
826.      int x, y;
827.  {
828.      explode(x, y, ZT_SPELL(ZT_FIRE), d(4,4), BURNING_OIL, EXPL_FIERY);
829.  }
830.  
831.  #ifdef FIREARMS
832.  
833.  #define BY_OBJECT       ((struct monst *)0)
834.  
835.  STATIC_DCL int
836.  dp(n, p)		/* 0 <= dp(n, p) <= n */
837.  int n, p;
838.  {
839.      int tmp = 0;
840.      while (n--) tmp += !rn2(p);
841.      return tmp;
842.  }
843.  
844.  #define GRENADE_TRIGGER(obj)	\
845.      if ((obj)->otyp == FRAG_GRENADE) { \
846.  	delquan = dp((obj)->quan, 10); \
847.  	no_fiery += delquan; \
848.      } else if ((obj)->otyp == GAS_GRENADE) { \
849.  	delquan = dp((obj)->quan, 10); \
850.  	no_gas += delquan; \
851.      } else if ((obj)->otyp == STICK_OF_DYNAMITE) { \
852.  	delquan = (obj)->quan; \
853.  	no_fiery += (obj)->quan * 2; \
854.  	no_dig += (obj)->quan; \
855.      } else if (is_bullet(obj)) \
856.  	delquan = (obj)->quan; \
857.      else \
858.  	delquan = 0
859.  
860.  struct grenade_callback {
861.      ExplodeRegion *fiery_area, *gas_area, *dig_area;
862.      boolean isyou;
863.  };
864.  
865.  STATIC_DCL void FDECL(grenade_effects, (struct obj *,XCHAR_P,XCHAR_P,
866.  	ExplodeRegion *,ExplodeRegion *,ExplodeRegion *,BOOLEAN_P));
867.  
868.  STATIC_DCL int
869.  grenade_fiery_callback(data, x, y)
870.  genericptr_t data;
871.  int x, y;
872.  {
873.      int is_accessible = ZAP_POS(levl[x][y].typ);
874.      struct grenade_callback *gc = (struct grenade_callback *)data;
875.      if (is_accessible) {
876.  	add_location_to_explode_region(gc->fiery_area, x, y);
877.  	grenade_effects((struct obj *)0, x, y,
878.  		gc->fiery_area, gc->gas_area, gc->dig_area, gc->isyou);
879.      }
880.      return !is_accessible;
881.  }
882.  
883.  STATIC_DCL int
884.  grenade_gas_callback(data, x, y)
885.  genericptr_t data;
886.  int x, y;
887.  {
888.      int is_accessible = ZAP_POS(levl[x][y].typ);
889.      struct grenade_callback *gc = (struct grenade_callback *)data;
890.      if (is_accessible)
891.  	add_location_to_explode_region(gc->gas_area, x, y);
892.      return !is_accessible;
893.  }
894.  
895.  STATIC_DCL int
896.  grenade_dig_callback(data, x, y)
897.  genericptr_t data;
898.  int x, y;
899.  {
900.      struct grenade_callback *gc = (struct grenade_callback *)data;
901.      if (dig_check(BY_OBJECT, FALSE, x, y))
902.  	add_location_to_explode_region(gc->dig_area, x, y);
903.      return !ZAP_POS(levl[x][y].typ);
904.  }
905.  
906.  STATIC_DCL void
907.  grenade_effects(source, x, y, fiery_area, gas_area, dig_area, isyou)
908.  struct obj *source;
909.  xchar x, y;
910.  ExplodeRegion *fiery_area, *gas_area, *dig_area;
911.  boolean isyou;
912.  {
913.      int i, r;
914.      struct obj *obj, *obj2;
915.      struct monst *mon;
916.      /*
917.       * Note: These count explosive charges in arbitary units. Grenades
918.       *       are counted as 1 and sticks of dynamite as 2 fiery and 1 dig.
919.       */
920.      int no_gas = 0, no_fiery = 0, no_dig = 0;
921.      int delquan;
922.      boolean shielded = FALSE, redraw;
923.      struct grenade_callback gc;
924.  
925.      if (source) {
926.  	if (source->otyp == GAS_GRENADE)
927.  	    no_gas += source->quan;
928.  	else if (source->otyp == FRAG_GRENADE)
929.  	    no_fiery += source->quan;
930.  	else if (source->otyp == STICK_OF_DYNAMITE) {
931.  	    no_fiery += source->quan * 2;
932.  	    no_dig += source->quan;
933.  	}
934.  	redraw = source->where == OBJ_FLOOR;
935.  	obj_extract_self(source);
936.  	obfree(source, (struct obj *)0);
937.  	if (redraw) newsym(x, y);
938.      }
939.      mon = m_at(x, y);
940.  #ifdef STEED
941.      if (!mon && x == u.ux && y == u.uy)
942.  	mon = u.usteed;
943.  #endif
944.      if (mon && !DEADMONSTER(mon))
945.  	if (resists_fire(mon))
946.  	    shielded = TRUE;
947.  	else
948.  	    for(obj = mon->minvent; obj; obj = obj2) {
949.  		obj2 = obj->nobj;
950.  		GRENADE_TRIGGER(obj);
951.  		for(i = 0; i < delquan; i++)
952.  		    m_useup(mon, obj);
953.  	    }
954.      if (x == u.ux && y == u.uy)
955.  	if (Fire_resistance)
956.  	    shielded = TRUE;
957.  	else
958.  	    for(obj = invent; obj; obj = obj2) {
959.  		obj2 = obj->nobj;
960.  		GRENADE_TRIGGER(obj);
961.  		for(i = 0; i < delquan; i++)
962.  		    useup(obj);
963.  	    }
964.      if (!shielded)
965.  	for(obj = level.objects[x][y]; obj; obj = obj2) {
966.  	    obj2 = obj->nexthere;
967.  	    GRENADE_TRIGGER(obj);
968.  	    if (delquan) {
969.  		if (isyou)
970.  		    useupf(obj, delquan);
971.  		else if (delquan < obj->quan)
972.  		    obj->quan -= delquan;
973.  		else
974.  		    delobj(obj);
975.  	    }
976.  	}
977.      gc.fiery_area = fiery_area;
978.      gc.gas_area = gas_area;
979.      gc.dig_area = dig_area;
980.      gc.isyou = isyou;
981.      if (no_gas) {
982.  	/* r = floor(log2(n))+1 */
983.  	r = 0;
984.  	while(no_gas) {
985.  	    r++;
986.  	    no_gas /= 2;
987.  	}
988.  	xpathto(r, x, y, grenade_gas_callback, (genericptr_t)&gc);
989.      }
990.      if (no_fiery) {
991.  	/* r = floor(log2(n))+1 */
992.  	r = 0;
993.  	while(no_fiery) {
994.  	    r++;
995.  	    no_fiery /= 2;
996.  	}
997.  	xpathto(r, x, y, grenade_fiery_callback, (genericptr_t)&gc);
998.      }
999.      if (no_dig) {
1000. 	/* r = floor(log2(n))+1 */
1001. 	r = 0;
1002. 	while(no_dig) {
1003. 	    r++;
1004. 	    no_dig /= 2;
1005. 	}
1006. 	xpathto(r, x, y, grenade_dig_callback, (genericptr_t)&gc);
1007.     }
1008. }
1009. 
1010. /*
1011.  * Note: obj is not valid after return
1012.  */
1013. 
1014. void
1015. grenade_explode(obj, x, y, isyou, dest)
1016. struct obj *obj;
1017. int x, y;
1018. boolean isyou;
1019. int dest;
1020. {
1021.     int i, ztype;
1022.     boolean shop_damage = FALSE;
1023.     int ox, oy;
1024.     ExplodeRegion *fiery_area, *gas_area, *dig_area;
1025.     struct trap *trap;
1026.     
1027.     fiery_area = create_explode_region();
1028.     gas_area = create_explode_region();
1029.     dig_area = create_explode_region();
1030.     grenade_effects(obj, x, y, fiery_area, gas_area, dig_area, isyou);
1031.     if (fiery_area->nlocations) {
1032. 	ztype = isyou ? ZT_SPELL(ZT_FIRE) : -ZT_SPELL(ZT_FIRE);
1033. 	do_explode(x, y, fiery_area, ztype, d(3,6), WEAPON_CLASS,
1034. 	  EXPL_FIERY, dest, isyou);
1035.     }
1036.     wake_nearto(x, y, 400);
1037.     /* Like cartoons - the explosion first, then
1038.      * the world deals with the holes produced ;)
1039.      */
1040.     for(i = 0; i < dig_area->nlocations; i++) {
1041. 	ox = dig_area->locations[i].x;
1042. 	oy = dig_area->locations[i].y;
1043. 	if (IS_WALL(levl[ox][oy].typ) || IS_DOOR(levl[ox][oy].typ)) {
1044. 	    watch_dig((struct monst *)0, ox, oy, TRUE);
1045. 	    if (*in_rooms(ox, oy, SHOPBASE)) shop_damage = TRUE;
1046. 	}
1047. 	digactualhole(ox, oy, BY_OBJECT, PIT);
1048.     }
1049.     free_explode_region(dig_area);
1050.     for(i = 0; i < fiery_area->nlocations; i++) {
1051. 	ox = fiery_area->locations[i].x;
1052. 	oy = fiery_area->locations[i].y;
1053. 	if ((trap = t_at(ox, oy)) != 0 && trap->ttyp == LANDMINE)
1054. 	    blow_up_landmine(trap);
1055.     }
1056.     free_explode_region(fiery_area);
1057.     if (gas_area->nlocations) {
1058. 	ztype = isyou ? ZT_SPELL(ZT_POISON_GAS) : -ZT_SPELL(ZT_POISON_GAS);
1059. 	do_explode(x, y, gas_area, ztype, d(3,6), WEAPON_CLASS,
1060. 	  EXPL_NOXIOUS, dest, isyou);
1061.     }
1062.     free_explode_region(gas_area);
1063.     if (shop_damage) pay_for_damage("damage", FALSE);
1064. }
1065. 
1066. void arm_bomb(obj, yours)
1067. struct obj *obj;
1068. boolean yours;
1069. {
1070. 	if (is_grenade(obj)) {
1071. 		attach_bomb_blow_timeout(obj, 
1072. 			    (obj->cursed ? rn2(5) + 2 : obj->blessed ? 4 : 
1073. 			    	rn2(2) + 3)
1074. 			     , yours);			
1075. 	}
1076. 	/* Otherwise, do nothing */
1077. }
1078. 
1079. #endif /* FIREARMS */
1080. 
1081. #endif /* OVL1 */
1082. 
1083. /*explode.c*/