Wikia

Wikihack

Source:SLASH'EM 0.0.7E7F2/explode.c

2,032pages on
this wiki
Talk0

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.
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*/

Around Wikia's network

Random Wiki