1    | /*	SCCS Id: @(#)explode.c	3.3	2000/07/07	*/
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    | /* Note: Arrays are column first, while the screen is row first */
10   | static int expl[3][3] = {
11   | 	{ S_explode1, S_explode4, S_explode7 },
12   | 	{ S_explode2, S_explode5, S_explode8 },
13   | 	{ S_explode3, S_explode6, S_explode9 }
14   | };
15   | 
16   | /* Note: I had to choose one of three possible kinds of "type" when writing
17   |  * this function: a wand type (like in zap.c), an adtyp, or an object type.
18   |  * Wand types get complex because they must be converted to adtyps for
19   |  * determining such things as fire resistance.  Adtyps get complex in that
20   |  * they don't supply enough information--was it a player or a monster that
21   |  * did it, and with a wand, spell, or breath weapon?  Object types share both
22   |  * these disadvantages....
23   |  */
24   | void
25   | explode(x, y, type, dam, olet)
26   | int x, y;
27   | int type; /* the same as in zap.c */
28   | int dam;
29   | char olet;
30   | {
31   | 	int i, j, k, damu = dam;
32   | 	boolean starting = 1;
33   | 	boolean visible, any_shield;
34   | 	int uhurt = 0; /* 0=unhurt, 1=items damaged, 2=you and items damaged */
35   | 	const char *str;
36   | 	int idamres, idamnonres;
37   | 	struct monst *mtmp;
38   | 	uchar adtyp;
39   | 	int explmask[3][3];
40   | 		/* 0=normal explosion, 1=do shieldeff, 2=do nothing */
41   | 	boolean shopdamage = FALSE;
42   | 
43   | 	if (olet == WAND_CLASS)		/* retributive strike */
44   | 		switch (Role_switch) {
45   | 			case PM_PRIEST:
46   | 			case PM_MONK:
47   | 			case PM_WIZARD: damu /= 5;
48   | 				  break;
49   | 			case PM_HEALER:
50   | 			case PM_KNIGHT: damu /= 2;
51   | 				  break;
52   | 			default:  break;
53   | 		}
54   | 
55   | 	if (olet == MON_EXPLODE) {
56   | 	    str = killer;
57   | 	    killer = 0;		/* set again later as needed */
58   | 	    adtyp = AD_PHYS;
59   | 	} else
60   | 	switch (abs(type) % 10) {
61   | 		case 0: str = "magical blast";
62   | 			adtyp = AD_MAGM;
63   | 			break;
64   | 		case 1: str =   olet == BURNING_OIL ?	"burning oil" :
65   | 				olet == SCROLL_CLASS ?	"tower of flame" :
66   | 							"fireball";
67   | 			adtyp = AD_FIRE;
68   | 			break;
69   | 		case 2: str = "ball of cold";
70   | 			adtyp = AD_COLD;
71   | 			break;
72   | 		case 4: str =  (olet == WAND_CLASS) ? "death field" :
73   | 							"disintegration field";
74   | 			adtyp = AD_DISN;
75   | 			break;
76   | 		case 5: str = "ball of lightning";
77   | 			adtyp = AD_ELEC;
78   | 			break;
79   | 		case 6: str = "poison gas cloud";
80   | 			adtyp = AD_DRST;
81   | 			break;
82   | 		case 7: str = "splash of acid";
83   | 			adtyp = AD_ACID;
84   | 			break;
85   | 		default: impossible("explosion base type %d?", type); return;
86   | 	}
87   | 
88   | 	any_shield = visible = FALSE;
89   | 	for (i=0; i<3; i++) for (j=0; j<3; j++) {
90   | 		if (!isok(i+x-1, j+y-1)) {
91   | 			explmask[i][j] = 2;
92   | 			continue;
93   | 		} else
94   | 			explmask[i][j] = 0;
95   | 
96   | 		if (i+x-1 == u.ux && j+y-1 == u.uy) {
97   | 		    switch(adtyp) {
98   | 			case AD_PHYS:                        
99   | 				explmask[i][j] = 0;
100  | 				break;
101  | 			case AD_MAGM:
102  | 				explmask[i][j] = !!Antimagic;
103  | 				break;
104  | 			case AD_FIRE:
105  | 				explmask[i][j] = !!Fire_resistance;
106  | 				break;
107  | 			case AD_COLD:
108  | 				explmask[i][j] = !!Cold_resistance;
109  | 				break;
110  | 			case AD_DISN:
111  | 				explmask[i][j] = (olet == WAND_CLASS) ?
112  | 						!!(nonliving(youmonst.data) || is_demon(youmonst.data)) :
113  | 						!!Disint_resistance;
114  | 				break;
115  | 			case AD_ELEC:
116  | 				explmask[i][j] = !!Shock_resistance;
117  | 				break;
118  | 			case AD_DRST:
119  | 				explmask[i][j] = !!Poison_resistance;
120  | 				break;
121  | 			case AD_ACID:
122  | 				explmask[i][j] = !!Acid_resistance;
123  | 				break;
124  | 			default:
125  | 				impossible("explosion type %d?", adtyp);
126  | 				break;
127  | 		    }
128  | 		}
129  | 		/* can be both you and mtmp if you're swallowed */
130  | 		mtmp = m_at(i+x-1, j+y-1);
131  | #ifdef STEED
132  | 		if (!mtmp && i+x-1 == u.ux && j+y-1 == u.uy)
133  | 			mtmp = u.usteed;
134  | #endif
135  | 		if (mtmp) {
136  | 		    if (mtmp->mhp < 1) explmask[i][j] = 2;
137  | 		    else switch(adtyp) {
138  | 			case AD_PHYS:                        
139  | 				break;
140  | 			case AD_MAGM:
141  | 				explmask[i][j] |= resists_magm(mtmp);
142  | 				break;
143  | 			case AD_FIRE:
144  | 				explmask[i][j] |= resists_fire(mtmp);
145  | 				break;
146  | 			case AD_COLD:
147  | 				explmask[i][j] |= resists_cold(mtmp);
148  | 				break;
149  | 			case AD_DISN:
150  | 				explmask[i][j] |= (olet == WAND_CLASS) ?
151  | 					(nonliving(mtmp->data) || is_demon(mtmp->data)) :
152  | 					resists_disint(mtmp);
153  | 				break;
154  | 			case AD_ELEC:
155  | 				explmask[i][j] |= resists_elec(mtmp);
156  | 				break;
157  | 			case AD_DRST:
158  | 				explmask[i][j] |= resists_poison(mtmp);
159  | 				break;
160  | 			case AD_ACID:
161  | 				explmask[i][j] |= resists_acid(mtmp);
162  | 				break;
163  | 			default:
164  | 				impossible("explosion type %d?", adtyp);
165  | 				break;
166  | 		    }
167  | 		}
168  | 		if (mtmp && cansee(i+x-1,j+y-1) && !canspotmon(mtmp))
169  | 		    map_invisible(i+x-1, j+y-1);
170  | 		else if (!mtmp && glyph_is_invisible(levl[i+x-1][j+y-1].glyph)) {
171  | 		    unmap_object(i+x-1, j+y-1);
172  | 		    newsym(i+x-1, j+y-1);
173  | 		}
174  | 		if (cansee(i+x-1, j+y-1)) visible = TRUE;
175  | 		if (explmask[i][j] == 1) any_shield = TRUE;
176  | 	}
177  | 
178  | 	if (visible) {
179  | 		/* Start the explosion */
180  | 		for (i=0; i<3; i++) for (j=0; j<3; j++) {
181  | 			if (explmask[i][j] == 2) continue;
182  | 			tmp_at(starting ? DISP_BEAM : DISP_CHANGE,
183  | 					    cmap_to_glyph(expl[i][j]));
184  | 			tmp_at(i+x-1, j+y-1);
185  | 			starting = 0;
186  | 		}
187  | 		curs_on_u();	/* will flush screen and output */
188  | 
189  | 		if (any_shield) {	/* simulate a shield effect */
190  | 		    for (k = 0; k < SHIELD_COUNT; k++) {
191  | 			for (i=0; i<3; i++) for (j=0; j<3; j++) {
192  | 			    if (explmask[i][j] == 1)
193  | 				/*
194  | 				 * Bypass tmp_at() and send the shield glyphs
195  | 				 * directly to the buffered screen.  tmp_at()
196  | 				 * will clean up the location for us later.
197  | 				 */
198  | 				show_glyph(i+x-1, j+y-1,
199  | 					cmap_to_glyph(shield_static[k]));
200  | 			}
201  | 			curs_on_u();	/* will flush screen and output */
202  | 			delay_output();
203  | 		    }
204  | 
205  | 		    /* Cover last shield glyph with blast symbol. */
206  | 		    for (i=0; i<3; i++) for (j=0; j<3; j++) {
207  | 			if (explmask[i][j] == 1)
208  | 			    show_glyph(i+x-1,j+y-1,cmap_to_glyph(expl[i][j]));
209  | 		    }
210  | 
211  | 		} else {		/* delay a little bit. */
212  | 		    delay_output();
213  | 		    delay_output();
214  | 		}
215  | 
216  | 		tmp_at(DISP_END, 0); /* clear the explosion */
217  | 	} else {
218  | 		if (flags.soundok) You_hear("a blast.");
219  | 	}
220  | 
221  |     if (dam)
222  | 	for (i=0; i<3; i++) for (j=0; j<3; j++) {
223  | 		if (explmask[i][j] == 2) continue;
224  | 		if (i+x-1 == u.ux && j+y-1 == u.uy)
225  | 			uhurt = (explmask[i][j] == 1) ? 1 : 2;
226  | 		idamres = idamnonres = 0;
227  | 		if (type >= 0)
228  | 		    (void)zap_over_floor((xchar)(i+x-1), (xchar)(j+y-1),
229  | 		    		type, &shopdamage);
230  | 
231  | 		mtmp = m_at(i+x-1, j+y-1);
232  | #ifdef STEED
233  | 		if (!mtmp && i+x-1 == u.ux && j+y-1 == u.uy)
234  | 			mtmp = u.usteed;
235  | #endif
236  | 		if (!mtmp) continue;
237  | 		if (u.uswallow && mtmp == u.ustuck) {
238  | 			if (is_animal(u.ustuck->data))
239  | 				pline("%s gets %s!",
240  | 				      Monnam(u.ustuck),
241  | 				      (adtyp == AD_FIRE) ? "heartburn" :
242  | 				      (adtyp == AD_COLD) ? "chilly" :
243  | 				      (adtyp == AD_DISN) ? ((olet == WAND_CLASS) ?
244  | 				       "irradiated by pure energy" : "perforated") :
245  | 				      (adtyp == AD_ELEC) ? "shocked" :
246  | 				      (adtyp == AD_DRST) ? "poisoned" :
247  | 				      (adtyp == AD_ACID) ? "an upset stomach" :
248  | 				       "fried");
249  | 			else
250  | 				pline("%s gets slightly %s!",
251  | 				      Monnam(u.ustuck),
252  | 				      (adtyp == AD_FIRE) ? "toasted" :
253  | 				      (adtyp == AD_COLD) ? "chilly" :
254  | 				      (adtyp == AD_DISN) ? ((olet == WAND_CLASS) ?
255  | 				       "overwhelmed by pure energy" : "perforated") :
256  | 				      (adtyp == AD_ELEC) ? "shocked" :
257  | 				      (adtyp == AD_DRST) ? "intoxicated" :
258  | 				      (adtyp == AD_ACID) ? "burned" :
259  | 				       "fried");
260  | 		} else if (cansee(i+x-1, j+y-1))
261  | 		pline("%s is caught in the %s!", Monnam(mtmp), str);
262  | 
263  | 		idamres += destroy_mitem(mtmp, SCROLL_CLASS, (int) adtyp);
264  | 		idamres += destroy_mitem(mtmp, SPBOOK_CLASS, (int) adtyp);
265  | 		idamnonres += destroy_mitem(mtmp, POTION_CLASS, (int) adtyp);
266  | 		idamnonres += destroy_mitem(mtmp, WAND_CLASS, (int) adtyp);
267  | 		idamnonres += destroy_mitem(mtmp, RING_CLASS, (int) adtyp);
268  | 
269  | 		if (explmask[i][j] == 1) {
270  | 			golemeffects(mtmp, (int) adtyp, dam + idamres);
271  | 			mtmp->mhp -= idamnonres;
272  | 		} else {
273  | 		/* call resist with 0 and do damage manually so 1) we can
274  | 		 * get out the message before doing the damage, and 2) we can
275  | 		 * call mondied, not killed, if it's not your blast
276  | 		 */
277  | 			int mdam = dam;
278  | 
279  | 			if (resist(mtmp, olet, 0, FALSE)) {
280  | 				if (cansee(i+x-1,j+y-1))
281  | 				    pline("%s resists the %s!", Monnam(mtmp), str);
282  | 				mdam = dam/2;
283  | 			}
284  | 			if (mtmp == u.ustuck)
285  | 				mdam *= 2;
286  | 			if (resists_cold(mtmp) && adtyp == AD_FIRE)
287  | 				mdam *= 2;
288  | 			else if (resists_fire(mtmp) && adtyp == AD_COLD)
289  | 				mdam *= 2;
290  | 			mtmp->mhp -= mdam;
291  | 			mtmp->mhp -= (idamres + idamnonres);
292  | 		}
293  | 		if (mtmp->mhp <= 0) {
294  | 			/* KMH -- Don't blame the player for pets killing gas spores */
295  | 			if (!flags.mon_moving) killed(mtmp);
296  | 			else monkilled(mtmp, "", (int)adtyp);
297  | 		}
298  | 	}
299  | 
300  | 	/* Do your injury last */
301  | 	if (uhurt) {
302  | 		if ((type >= 0 || adtyp == AD_PHYS) &&	/* gas spores */
303  | 				flags.verbose && olet != SCROLL_CLASS)
304  | 			You("are caught in the %s!", str);
305  | 		/* do property damage first, in case we end up leaving bones */
306  | 		if (adtyp == AD_FIRE) burn_away_slime();
307  | 		if (Invulnerable) {
308  | 		    damu = 0;
309  | 		    You("are unharmed!");
310  | 		}
311  | 		if (adtyp == AD_FIRE) (void) burnarmor(&youmonst);
312  | 		destroy_item(SCROLL_CLASS, (int) adtyp);
313  | 		destroy_item(SPBOOK_CLASS, (int) adtyp);
314  | 		destroy_item(POTION_CLASS, (int) adtyp);
315  | 		destroy_item(RING_CLASS, (int) adtyp);
316  | 		destroy_item(WAND_CLASS, (int) adtyp);
317  | 
318  | 		ugolemeffects((int) adtyp, damu);
319  | 		if (uhurt == 2) u.uhp -= damu, flags.botl = 1;
320  | 
321  | 		if (u.uhp <= 0) {
322  | 			if (olet == MON_EXPLODE) {
323  | 			    /* killer handled by caller */
324  | 			    if (str != killer_buf)
325  | 				Strcpy(killer_buf, str);
326  | 			    killer_format = KILLED_BY_AN;
327  | 			} else if (type >= 0 && olet != SCROLL_CLASS) {
328  | 			    killer_format = NO_KILLER_PREFIX;
329  | 			    Sprintf(killer_buf, "caught %sself in %s own %s",
330  | 				    him[flags.female], his[flags.female], str);
331  | 			} else {
332  | 			    killer_format = KILLED_BY;
333  | 			    Strcpy(killer_buf, str);
334  | 			}
335  | 			killer = killer_buf;
336  | 			/* Known BUG: BURNING suppresses corpse in bones data,
337  | 			   but done does not handle killer reason correctly */
338  | 			done((adtyp == AD_FIRE) ? BURNING : DIED);
339  | 		}
340  | 		exercise(A_STR, FALSE);
341  | 	}
342  | 
343  | 	if (shopdamage) {
344  | 		pay_for_damage(adtyp == AD_FIRE ? "burn away" :
345  | 			       adtyp == AD_COLD ? "shatter" :
346  | 			       adtyp == AD_DISN ? "disintegrate" : "destroy");
347  | 	}
348  | }
349  | #endif /* OVL0 */
350  | #ifdef OVL1
351  | 
352  | struct scatter_chain {
353  | 	struct scatter_chain *next;	/* pointer to next scatter item	*/
354  | 	struct obj *obj;		/* pointer to the object	*/
355  | 	xchar ox;			/* location of			*/
356  | 	xchar oy;			/*	item			*/
357  | 	schar dx;			/* direction of			*/
358  | 	schar dy;			/*	travel			*/
359  | 	int range;			/* range of object		*/
360  | 	boolean stopped;		/* flag for in-motion/stopped	*/
361  | };
362  | 
363  | /*
364  |  * scflags:
365  |  *	VIS_EFFECTS	Add visual effects to display
366  |  *	MAY_HITMON	Objects may hit monsters
367  |  *	MAY_HITYOU	Objects may hit hero
368  |  *	MAY_HIT		Objects may hit you or monsters
369  |  *	MAY_DESTROY	Objects may be destroyed at random
370  |  *	MAY_FRACTURE	Stone objects can be fractured (statues, boulders)
371  |  */
372  | 
373  | void
374  | scatter(sx,sy,blastforce,scflags, obj)
375  | int sx,sy;				/* location of objects to scatter */
376  | int blastforce;				/* force behind the scattering	*/
377  | unsigned int scflags;
378  | struct obj *obj;			/* only scatter this obj        */
379  | {
380  | 	register struct obj *otmp;
381  | 	register int tmp;
382  | 	int farthest = 0;
383  | 	uchar typ;
384  | 	long qtmp;
385  | 	boolean used_up;
386  | 	boolean split_up = FALSE;
387  | 	boolean individual_object = obj ? TRUE : FALSE;
388  | 	struct monst *mtmp;
389  | 	struct scatter_chain *stmp, *stmp2 = 0;
390  | 	struct scatter_chain *schain = (struct scatter_chain *)0;
391  | 
392  | 	while ((otmp = individual_object ? obj : level.objects[sx][sy]) != 0) {
393  | 	    if (otmp->quan > 1L) {
394  | 		qtmp = otmp->quan - 1;
395  | 		if (qtmp > LARGEST_INT) qtmp = LARGEST_INT;
396  | 		qtmp = (long)rnd((int)qtmp);
397  | 		(void) splitobj(otmp, qtmp);
398  | 		if (qtmp < otmp->quan)
399  | 			split_up = TRUE;
400  | 		else
401  | 			split_up = FALSE;
402  | 	    }
403  | 	    if (individual_object) {
404  | 		if (split_up) {
405  | 			if (otmp->where == OBJ_FLOOR)
406  | 				obj = otmp->nexthere;
407  | 			else
408  | 				obj = otmp->nobj;
409  | 		} else
410  | 			obj = (struct obj *)0;
411  | 	    }
412  | 	    obj_extract_self(otmp);
413  | 	    used_up = FALSE;
414  | 
415  | 	    /* 9 in 10 chance of fracturing boulders or statues */
416  | 	    if ((scflags & MAY_FRACTURE)
417  | 			&& ((otmp->otyp == BOULDER) || (otmp->otyp == STATUE))
418  | 			&& rn2(10)) {
419  | 		if (otmp->otyp == BOULDER) {
420  | 		    pline("%s breaks apart.",The(xname(otmp)));
421  | 		    fracture_rock(otmp);
422  | 		    place_object(otmp, sx, sy);	/* put fragments on floor */
423  | 		} else {
424  | 		    struct trap *trap;
425  | 
426  | 		    if ((trap = t_at(sx,sy)) && trap->ttyp == STATUE_TRAP)
427  | 			    deltrap(trap);
428  | 		    pline("%s crumbles.",The(xname(otmp)));
429  | 		    (void) break_statue(otmp);
430  | 		    place_object(otmp, sx, sy);	/* put fragments on floor */
431  | 		}
432  | 		used_up = TRUE;
433  | 
434  | 	    /* 1 in 10 chance of destruction of obj; glass, egg destruction */
435  | 	    } else if ((scflags & MAY_DESTROY) && (!rn2(10)
436  | 			|| (objects[otmp->otyp].oc_material == GLASS
437  | 			|| otmp->otyp == EGG))) {
438  | 		if (breaks(otmp, (xchar)sx, (xchar)sy)) used_up = TRUE;
439  | 	    }
440  | 
441  | 	    if (!used_up) {
442  | 		stmp = (struct scatter_chain *)
443  | 					alloc(sizeof(struct scatter_chain));
444  | 		stmp->next = (struct scatter_chain *)0;
445  | 		stmp->obj = otmp;
446  | 		stmp->ox = sx;
447  | 		stmp->oy = sy;
448  | 		tmp = rn2(8);		/* get the direction */
449  | 		stmp->dx = xdir[tmp];
450  | 		stmp->dy = ydir[tmp];
451  | 		tmp = blastforce - (otmp->owt/40);
452  | 		if (tmp < 1) tmp = 1;
453  | 		stmp->range = rnd(tmp); /* anywhere up to that determ. by wt */
454  | 		if (farthest < stmp->range) farthest = stmp->range;
455  | 		stmp->stopped = FALSE;
456  | 		if (!schain)
457  | 		    schain = stmp;
458  | 		else
459  | 		    stmp2->next = stmp;
460  | 		stmp2 = stmp;
461  | 	    }
462  | 	}
463  | 
464  | 	while (farthest-- > 0) {
465  | 		for (stmp = schain; stmp; stmp = stmp->next) {
466  | 		   if ((stmp->range-- > 0) && (!stmp->stopped)) {
467  | 			bhitpos.x = stmp->ox + stmp->dx;
468  | 			bhitpos.y = stmp->oy + stmp->dy;
469  | 			typ = levl[bhitpos.x][bhitpos.y].typ;
470  | 			if(!isok(bhitpos.x, bhitpos.y)) {
471  | 				bhitpos.x -= stmp->dx;
472  | 				bhitpos.y -= stmp->dy;
473  | 				stmp->stopped = TRUE;
474  | 			} else if(!ZAP_POS(typ) ||
475  | 					closed_door(bhitpos.x, bhitpos.y)) {
476  | 				bhitpos.x -= stmp->dx;
477  | 				bhitpos.y -= stmp->dy;
478  | 				stmp->stopped = TRUE;
479  | 			} else if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
480  | 				if (scflags & MAY_HITMON) {
481  | 				    stmp->range--;
482  | 				    if (ohitmon(mtmp, stmp->obj, 1, FALSE)) {
483  | 					stmp->obj = (struct obj *)0;
484  | 					stmp->stopped = TRUE;
485  | 				    }
486  | 				}
487  | 			} else if (bhitpos.x==u.ux && bhitpos.y==u.uy) {
488  | 				if (scflags & MAY_HITYOU) {
489  | 				    int hitvalu, hitu;
490  | 
491  | 				    if (multi) nomul(0);
492  | 				    hitvalu = 8 + stmp->obj->spe;
493  | 				    if (bigmonst(youmonst.data)) hitvalu++;
494  | 				    hitu = thitu(hitvalu,
495  | 						 dmgval(stmp->obj, &youmonst),
496  | 						 stmp->obj, (char *)0);
497  | 				    if (hitu) {
498  | 					stmp->range -= 3;
499  | 					stop_occupation();
500  | 				    }
501  | 				}
502  | 			} else {
503  | 				if (scflags & VIS_EFFECTS) {
504  | 				    /* tmp_at(bhitpos.x, bhitpos.y); */
505  | 				    /* delay_output(); */
506  | 				}
507  | 			}
508  | 			stmp->ox = bhitpos.x;
509  | 			stmp->oy = bhitpos.y;
510  | 		   }
511  | 		}
512  | 	}
513  | 	for (stmp = schain; stmp; stmp = stmp2) {
514  | 		int x,y;
515  | 
516  | 		stmp2 = stmp->next;
517  | 		x = stmp->ox; y = stmp->oy;
518  | 		if (stmp->obj) {
519  | 			place_object(stmp->obj, x, y);
520  | 			stackobj(stmp->obj);
521  | 		}
522  | 		free((genericptr_t)stmp);
523  | 		newsym(x,y);
524  | 	}
525  | }
526  | 
527  | 
528  | /*
529  |  * Splatter burning oil from x,y to the surrounding area.
530  |  *
531  |  * This routine should really take a how and direction parameters.
532  |  * The how is how it was caused, e.g. kicked verses thrown.  The
533  |  * direction is which way to spread the flaming oil.  Different
534  |  * "how"s would give different dispersal patterns.  For example,
535  |  * kicking a burning flask will splatter differently from a thrown
536  |  * flask hitting the ground.
537  |  *
538  |  * For now, just perform a "regular" explosion.
539  |  */
540  | void
541  | splatter_burning_oil(x, y)
542  |     int x, y;
543  | {
544  | /* ZT_SPELL(ZT_FIRE) = ZT_SPELL(AD_FIRE-1) = 10+(2-1) = 11 */
545  | #define ZT_SPELL_O_FIRE 11 /* value kludge, see zap.c */
546  |     explode(x, y, ZT_SPELL_O_FIRE, d(4,4), BURNING_OIL);
547  | }
548  | 
549  | #endif /* OVL1 */
550  | 
551  | /*explode.c*/