Source:SLASH'EM 0.0.7E7F2/explode.c

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.

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