Source:NetHack 3.3.0/explode.c

Below is the full text to explode.c from the source code of NetHack 3.3.0. To link to a particular line, write [[NetHack 3.3.0/explode.c#line123 ]], for example.

Warning! This is the source code from an old release. For the latest release, see Source code

1.   /*	SCCS Id: @(#)explode.c	3.3	97/06/14	*/ 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.  	    adtyp = AD_PHYS; 58.  	} else 59.  	switch (abs(type) % 10) { 60.  		case 0: str = "magical blast"; 61.  			adtyp = AD_MAGM; 62.  			break; 63.  		case 1: str =   olet == BURNING_OIL ? "burning oil" : 64.  				olet == SCROLL_CLASS ? "tower of flame" : 65.  							"fireball"; 66.  			adtyp = AD_FIRE; 67.  			break; 68.  		case 2: str = "ball of cold"; 69.  			adtyp = AD_COLD; 70.  			break; 71.  		case 4: str =  (olet == WAND_CLASS) ? "death field" : 72.  							"disintegration field"; 73.  			adtyp = AD_DISN; 74.  			break; 75.  		case 5: str = "ball lightning"; 76.  			adtyp = AD_ELEC; 77.  			break; 78.  		case 6: str = "poison gas cloud"; 79.  			adtyp = AD_DRST; 80.  			break; 81.  		case 7: str = "splash of acid"; 82.  			adtyp = AD_ACID; 83.  			break; 84.  		default: impossible("explosion base type %d?", type); return; 85.  	}  86.    87.   	any_shield = visible = FALSE; 88.  	for (i=0; i<3; i++) for (j=0; j<3; j++) { 89.  		if (!isok(i+x-1, j+y-1)) { 90.  			explmask[i][j] = 2; 91.  			continue; 92.  		} else 93.  			explmask[i][j] = 0; 94.   95.   		if (i+x-1 == u.ux && j+y-1 == u.uy) { 96.  		    switch(adtyp) { 97.  			case AD_PHYS: 98.  				explmask[i][j] = 0; 99.  				break; 100. 			case AD_MAGM: 101. 				explmask[i][j] = !!Antimagic; 102. 				break; 103. 			case AD_FIRE: 104. 				explmask[i][j] = !!Fire_resistance; 105. 				break; 106. 			case AD_COLD: 107. 				explmask[i][j] = !!Cold_resistance; 108. 				break; 109. 			case AD_DISN: 110. 				explmask[i][j] = (olet == WAND_CLASS) ? 111. 						!!(nonliving(youmonst.data) || is_demon(youmonst.data)) : 112. 						!!Disint_resistance; 113. 				break; 114. 			case AD_ELEC: 115. 				explmask[i][j] = !!Shock_resistance; 116. 				break; 117. 			case AD_DRST: 118. 				explmask[i][j] = !!Poison_resistance; 119. 				break; 120. 			case AD_ACID: 121. 				explmask[i][j] = !!Acid_resistance; 122. 				break; 123. 			default: 124. 				impossible("explosion type %d?", adtyp); 125. 				break; 126. 		    }  127.  		}  128.  		/* can be both you and mtmp if you're swallowed */ 129. 		mtmp = m_at(i+x-1, j+y-1); 130. #ifdef STEED 131. 		if (!mtmp && i+x-1 == u.ux && j+y-1 == u.uy) 132. 			mtmp = u.usteed; 133. #endif 134. 		if (mtmp) { 135. 		    if (mtmp->mhp < 1) explmask[i][j] = 2; 136. 		    else switch(adtyp) { 137. 			case AD_PHYS: 138. 				break; 139. 			case AD_MAGM: 140. 				explmask[i][j] |= resists_magm(mtmp); 141. 				break; 142. 			case AD_FIRE: 143. 				explmask[i][j] |= resists_fire(mtmp); 144. 				break; 145. 			case AD_COLD: 146. 				explmask[i][j] |= resists_cold(mtmp); 147. 				break; 148. 			case AD_DISN: 149. 				explmask[i][j] |= (olet == WAND_CLASS) ? 150. 					(nonliving(mtmp->data) || is_demon(mtmp->data)) : 151. 					resists_disint(mtmp); 152. 				break; 153. 			case AD_ELEC: 154. 				explmask[i][j] |= resists_elec(mtmp); 155. 				break; 156. 			case AD_DRST: 157. 				explmask[i][j] |= resists_poison(mtmp); 158. 				break; 159. 			case AD_ACID: 160. 				explmask[i][j] |= resists_acid(mtmp); 161. 				break; 162. 			default: 163. 				impossible("explosion type %d?", adtyp); 164. 				break; 165. 		    }  166.  		}  167.  		if (mtmp && cansee(i,j) && !canspotmon(mtmp)) 168. 		    map_invisible(i, j); 169. 		else if (!mtmp && glyph_is_invisible(levl[i][j].glyph)) { 170. 		    unmap_object(i, j); 171. 		    newsym(i, j); 172. 		}  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.  	} else { 217. 		if (flags.soundok) You_hear("a blast."); 218. 	}  219.   220.      if (dam) 221. 	for (i=0; i<3; i++) for (j=0; j<3; j++) { 222. 		if (explmask[i][j] == 2) continue; 223. 		if (i+x-1 == u.ux && j+y-1 == u.uy) 224. 			uhurt = (explmask[i][j] == 1) ? 1 : 2; 225.  		idamres = idamnonres = 0; 226. 		if (type >= 0) 227. 		    (void)zap_over_floor((xchar)(i+x-1), (xchar)(j+y-1),  228.  		    		type, &shopdamage); 229.  230.  		mtmp = m_at(i+x-1, j+y-1); 231. #ifdef STEED 232. 		if (!mtmp && i+x-1 == u.ux && j+y-1 == u.uy) 233. 			mtmp = u.usteed; 234. #endif 235. 		if (!mtmp) continue; 236. 		if (u.uswallow && mtmp == u.ustuck) { 237. 			if (is_animal(u.ustuck->data)) 238. 				pline("%s gets %s!",  239.  				      Monnam(u.ustuck),  240.  				      (adtyp == AD_FIRE) ? "heartburn" :  241.  				      (adtyp == AD_COLD) ? "chilly" :  242.  				      (adtyp == AD_DISN) ? ((olet == WAND_CLASS) ? 243. 				       "irradiated by pure energy" : "perforated") :  244.  				      (adtyp == AD_ELEC) ? "shocked" :  245.  				      (adtyp == AD_DRST) ? "poisoned" :  246.  				      (adtyp == AD_ACID) ? "an upset stomach" :  247.  				       "fried"); 248. 			else 249. 				pline("%s gets slightly %s!",  250.  				      Monnam(u.ustuck),  251.  				      (adtyp == AD_FIRE) ? "toasted" :  252.  				      (adtyp == AD_COLD) ? "chilly" :  253.  				      (adtyp == AD_DISN) ? ((olet == WAND_CLASS) ? 254. 				       "overwhelmed by pure energy" : "perforated") :  255.  				      (adtyp == AD_ELEC) ? "shocked" :  256.  				      (adtyp == AD_DRST) ? "intoxicated" :  257.  				      (adtyp == AD_ACID) ? "burned" :  258.  				       "fried"); 259. 		} else 260. 		pline("%s is caught in the %s!",  261.  			cansee(i+x-1, j+y-1) ? Monnam(mtmp) : "It", 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. 				pline("%s resists the %s!",  281.  					cansee(i+x-1,j+y-1) ? Monnam(mtmp) : "It",  282.  					str); 283. 				mdam = dam/2; 284. 			}  285.  			if (mtmp == u.ustuck) 286. 				mdam *= 2; 287. 			if (resists_cold(mtmp) && adtyp == AD_FIRE) 288. 				mdam *= 2; 289. 			else if (resists_fire(mtmp) && adtyp == AD_COLD) 290. 				mdam *= 2; 291. 			mtmp->mhp -= mdam; 292. 			mtmp->mhp -= (idamres + idamnonres); 293. 		}  294.  		if (mtmp->mhp <= 0) { 295. 			/* KMH -- Don't blame the player for pets killing gas spores */ 296. 			if (!flags.mon_moving) killed(mtmp); 297. 			else monkilled(mtmp, "", (int)adtyp); 298. 		}  299.  	}  300.   301.  	if (visible) tmp_at(DISP_END, 0); /* clear the explosion */ 302.  303.  	/* Do your injury last */ 304. 	if (uhurt) { 305. 		if ((type >= 0 || adtyp == AD_PHYS) &&	/* gas spores */  306.  				flags.verbose && olet != SCROLL_CLASS) 307. 			You("are caught in the %s!", str); 308. 		/* do property damage first, in case we end up leaving bones */ 309. 		if (adtyp == AD_FIRE) burn_away_slime; 310. 		if (Invulnerable) { 311. 		    damu = 0; 312. 		    pline("You are unharmed!"); 313. 		}  314.  		if (adtyp == AD_FIRE) (void) burnarmor(&youmonst); 315. 		destroy_item(SCROLL_CLASS, (int) adtyp); 316. 		destroy_item(SPBOOK_CLASS, (int) adtyp); 317. 		destroy_item(POTION_CLASS, (int) adtyp); 318. 		destroy_item(RING_CLASS, (int) adtyp); 319. 		destroy_item(WAND_CLASS, (int) adtyp); 320.  321.  		ugolemeffects((int) adtyp, damu); 322. 		if (uhurt == 2) u.uhp -= damu, flags.botl = 1; 323.  324.  		if (u.uhp <= 0) { 325. 			char buf[BUFSZ]; 326.  327.  			if (olet == MON_EXPLODE) { 328. 			    /* killer handled by caller */ 329. 			    Strcpy(buf, str); 330. 			    killer_format = KILLED_BY_AN; 331. 			} else if (type >= 0 && olet != SCROLL_CLASS) { 332. 			    killer_format = NO_KILLER_PREFIX; 333. 			    Sprintf(buf, "caught %sself in %s own %s.",  334.  				    him[flags.female], his[flags.female], str); 335. 			} else { 336. 			    killer_format = KILLED_BY; 337. 			    Strcpy(buf, str); 338. 			}  339.  			killer = buf; 340. 			/* Known BUG: BURNING suppresses corpse in bones data, 341. 			   but done does not handle killer reason correctly */ 342. 			/* done(adtyp == AD_FIRE ? BURNING : DIED); */ 343. 			done(BURNING); 344. 		}  345.  		exercise(A_STR, FALSE); 346. 	}  347.   348.  	if (shopdamage) { 349. 		pay_for_damage(adtyp == AD_FIRE ? "burn away" :  350.  			       adtyp == AD_COLD ? "shatter" :  351.  			       adtyp == AD_DISN ? "disintegrate" : "destroy"); 352. 	}  353.  }  354.  #endif /* OVL0 */ 355. #ifdef OVL1 356.  357.  struct scatter_chain { 358. 	struct scatter_chain *next;	/* pointer to next scatter item	*/ 359. 	struct obj *obj;		/* pointer to the object	*/ 360. 	xchar ox;			/* location of			*/ 361. 	xchar oy;			/*	item			*/ 362. 	schar dx;			/* direction of			*/ 363. 	schar dy;			/*	travel			*/ 364. 	int range;			/* range of object		*/ 365. 	boolean stopped;		/* flag for in-motion/stopped	*/ 366. };  367.   368.  /*  369.   * scflags: 370.  *	VIS_EFFECTS	Add visual effects to display 371.  *	MAY_HITMON	Objects may hit monsters 372.  *	MAY_HITYOU	Objects may hit hero 373.  *	MAY_HIT		Objects may hit you or monsters 374.  *	MAY_DESTROY	Objects may be destroyed at random 375.  *	MAY_FRACTURE	Stone objects can be fractured (statues, boulders) 376.  */  377.   378.  void 379. scatter(sx,sy,blastforce,scflags, obj) 380. int sx,sy;				/* location of objects to scatter */ 381. int blastforce;				/* force behind the scattering	*/ 382. unsigned int scflags; 383. struct obj *obj;			/* only scatter this obj        */ 384. {  385.  	register struct obj *otmp; 386. 	register int tmp; 387. 	int farthest = 0; 388. 	uchar typ; 389. 	long qtmp; 390. 	boolean used_up; 391. 	boolean split_up = FALSE; 392. 	boolean individual_object = obj ? TRUE : FALSE; 393. 	struct monst *mtmp; 394. 	struct scatter_chain *stmp, *stmp2 = 0; 395. 	struct scatter_chain *schain = (struct scatter_chain *)0; 396.  397.  	while ((otmp = individual_object ? obj : level.objects[sx][sy]) != 0) { 398. 	    if (otmp->quan > 1L) { 399. 		qtmp = otmp->quan - 1; 400. 		if (qtmp > LARGEST_INT) qtmp = LARGEST_INT; 401. 		qtmp = (long)rnd((int)qtmp); 402. 		(void) splitobj(otmp, qtmp); 403. 		if (qtmp < otmp->quan) 404. 			split_up = TRUE; 405. 		else 406. 			split_up = FALSE; 407. 	    }  408.  	    if (individual_object) { 409. 		if (split_up) { 410. 			if (otmp->where == OBJ_FLOOR) 411. 				obj = otmp->nexthere; 412. 			else 413. 				obj = otmp->nobj; 414. 		} else 415. 			obj = (struct obj *)0; 416. 	    }  417.  	    obj_extract_self(otmp); 418. 	    used_up = FALSE; 419.  420.  	    /* 9 in 10 chance of fracturing boulders or statues */ 421. 	    if ((scflags & MAY_FRACTURE)  422.  			&& ((otmp->otyp == BOULDER) || (otmp->otyp == STATUE))  423.  			&& rn2(10)) { 424. 		if (otmp->otyp == BOULDER) { 425. 		    pline("%s breaks apart.",The(xname(otmp))); 426. 		    fracture_rock(otmp); 427. 		    place_object(otmp, sx, sy);	/* put fragments on floor */ 428. 		} else { 429. 		    struct trap *trap; 430.  431.  		    if ((trap = t_at(sx,sy)) && trap->ttyp == STATUE_TRAP) 432. 			    deltrap(trap); 433. 		    pline("%s crumbles.",The(xname(otmp))); 434. 		    (void) break_statue(otmp); 435. 		    place_object(otmp, sx, sy);	/* put fragments on floor */ 436. 		}  437.  		used_up = TRUE; 438.  439.  	    /* 1 in 10 chance of destruction of obj; glass, egg destruction */ 440. 	    } else if ((scflags & MAY_DESTROY) && (!rn2(10) 441. 			|| (objects[otmp->otyp].oc_material == GLASS  442.  			|| otmp->otyp == EGG))) { 443. 		if (breaks(otmp, (xchar)sx, (xchar)sy)) used_up = TRUE; 444. 	    }  445.   446.  	    if (!used_up) { 447. 		stmp = (struct scatter_chain *) 448. 					alloc(sizeof(struct scatter_chain)); 449. 		stmp->next = (struct scatter_chain *)0; 450. 		stmp->obj = otmp; 451. 		stmp->ox = sx; 452. 		stmp->oy = sy; 453. 		tmp = rn2(8);		/* get the direction */ 454. 		stmp->dx = xdir[tmp]; 455. 		stmp->dy = ydir[tmp]; 456. 		tmp = blastforce - (otmp->owt/40); 457. 		if (tmp < 1) tmp = 1; 458. 		stmp->range = rnd(tmp); /* anywhere up to that determ. by wt */ 459. 		if (farthest < stmp->range) farthest = stmp->range; 460. 		stmp->stopped = FALSE; 461. 		if (!schain) 462. 		    schain = stmp; 463. 		else 464. 		    stmp2->next = stmp; 465. 		stmp2 = stmp; 466. 	    }  467.  	}  468.   469.  	while (farthest-- > 0) { 470. 		for (stmp = schain; stmp; stmp = stmp->next) { 471. 		   if ((stmp->range-- > 0) && (!stmp->stopped)) { 472. 			bhitpos.x = stmp->ox + stmp->dx; 473. 			bhitpos.y = stmp->oy + stmp->dy; 474. 			typ = levl[bhitpos.x][bhitpos.y].typ; 475. 			if(!isok(bhitpos.x, bhitpos.y)) { 476. 				bhitpos.x -= stmp->dx; 477. 				bhitpos.y -= stmp->dy; 478. 				stmp->stopped = TRUE; 479. 			} else if(!ZAP_POS(typ) ||  480.  					closed_door(bhitpos.x, bhitpos.y)) { 481. 				bhitpos.x -= stmp->dx; 482. 				bhitpos.y -= stmp->dy; 483. 				stmp->stopped = TRUE; 484. 			} else if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) { 485. 				if (scflags & MAY_HITMON) { 486. 				    stmp->range--; 487. 				    if (ohitmon(mtmp, stmp->obj, 1, FALSE)) { 488. 					stmp->obj = (struct obj *)0; 489. 					stmp->stopped = TRUE; 490. 				    }  491.  				}  492.  			} else if (bhitpos.x==u.ux && bhitpos.y==u.uy) { 493. 				if (scflags & MAY_HITYOU) { 494. 				    int hitvalu, hitu; 495.  496.  				    if (multi) nomul(0); 497. 				    hitvalu = 8 + stmp->obj->spe; 498. 				    if (bigmonst(youmonst.data)) hitvalu++; 499. 				    /* could just use doname all the time, 500. 				     * except thitu adds "an" to the front 501. 				     */  502.  				    hitu = thitu(hitvalu,  503.  					dmgval(stmp->obj, &youmonst),  504.  					stmp->obj,  505.  					(stmp->obj->quan>1) ? doname(stmp->obj)  506.  						: xname(stmp->obj)); 507. 				    if (hitu) { 508. 					stmp->range -= 3; 509. 					stop_occupation; 510. 				    }  511.  				}  512.  			} else { 513. 				if (scflags & VIS_EFFECTS) { 514. 				    /* tmp_at(bhitpos.x, bhitpos.y); */ 515. 				    /* delay_output; */ 516. 				}  517.  			}  518.  			stmp->ox = bhitpos.x;  519. stmp->oy = bhitpos.y; 520. } 521.  		}  522.  	}  523.  	for (stmp = schain; stmp; stmp = stmp2) { 524. 		int x,y; 525.  526.  		stmp2 = stmp->next; 527. 		x = stmp->ox; y = stmp->oy; 528. 		if (stmp->obj) { 529. 			place_object(stmp->obj, x, y); 530. 			stackobj(stmp->obj); 531. 		}  532.  		free((genericptr_t)stmp); 533. 		newsym(x,y); 534. 	}  535.  }  536.   537.   538.  /*  539.   * Splatter burning oil from x,y to the surrounding area. 540.  *  541.   * This routine should really take a how and direction parameters. 542.  * The how is how it was caused, e.g. kicked verses thrown. The 543.  * direction is which way to spread the flaming oil. Different 544.  * "how"s would give different dispersal patterns. For example, 545.  * kicking a burning flask will splatter differently from a thrown 546.  * flask hitting the ground. 547.  *  548.   * For now, just perform a "regular" explosion. 549.  */  550.  void 551. splatter_burning_oil(x, y)  552. int x, y; 553. { 554.  /* ZT_SPELL(ZT_FIRE) = ZT_SPELL(AD_FIRE-1) = 10+(2-1) = 11 */ 555. #define ZT_SPELL_O_FIRE 11 /* value kludge, see zap.c */ 556.     explode(x, y, ZT_SPELL_O_FIRE, d(4,4), BURNING_OIL); 557. }  558.   559.  #endif /* OVL1 */ 560.  561.  /*explode.c*/