Source:NetHack 3.2.0/explode.c

Below is the full text to explode.c from the source code of NetHack 3.2.0. To link to a particular line, write [[NetHack 3.2.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.2	96/01/06	*/ 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 (u.role) { 45.  			case 'P': 46.  			case 'W': damu /= 5; 47.  				  break; 48.  			case 'H': 49.  			case 'K': damu /= 2; 50.  				  break; 51.  			default:  break; 52.  		}  53.    54.   	switch (abs(type) % 10) { 55.  		case 0: str = "magical blast"; 56.  			adtyp = AD_MAGM; 57.  			break; 58.  		case 1: str =   olet == BURNING_OIL ? "burning oil" : 59.  				olet == SCROLL_CLASS ? "tower of flame" : 60.  							"fireball"; 61.  			adtyp = AD_FIRE; 62.  			break; 63.  		case 2: str = "ball of cold"; 64.  			adtyp = AD_COLD; 65.  			break; 66.  		case 4: str = "disintegration field"; 67.  			adtyp = AD_DISN; 68.  			break; 69.  		case 5: str = "ball lightning"; 70.  			adtyp = AD_ELEC; 71.  			break; 72.  		default: impossible("explosion base type %d?", type); return; 73.  	}  74.    75.   	any_shield = visible = FALSE; 76.  	for (i=0; i<3; i++) for (j=0; j<3; j++) { 77.  		if (!isok(i+x-1, j+y-1)) { 78.  			explmask[i][j] = 2; 79.  			continue; 80.  		} else 81.  			explmask[i][j] = 0; 82.   83.   		if (i+x-1 == u.ux && j+y-1 == u.uy) { 84.  		    switch(adtyp) { 85.  			case AD_MAGM: 86.  				explmask[i][j] = !!Antimagic; 87.  				break; 88.  			case AD_FIRE: 89.  				explmask[i][j] = !!Fire_resistance; 90.  				break; 91.  			case AD_COLD: 92.  				explmask[i][j] = !!Cold_resistance; 93.  				break; 94.  			case AD_DISN: 95.  				explmask[i][j] = !!Disint_resistance; 96.  				break; 97.  			case AD_ELEC: 98.  				explmask[i][j] = !!Shock_resistance; 99.  				break; 100. 			default: 101. 				impossible("explosion type %d?", adtyp); 102. 				break; 103. 		    }  104.  		}  105.  		/* can be both you and mtmp if you're swallowed */ 106. 		if ((mtmp = m_at(i+x-1, j+y-1)) != 0) { 107. 		    switch(adtyp) { 108. 			case AD_MAGM: 109. 				explmask[i][j] |= resists_magm(mtmp); 110. 				break; 111. 			case AD_FIRE: 112. 				explmask[i][j] |= resists_fire(mtmp); 113. 				break; 114. 			case AD_COLD: 115. 				explmask[i][j] |= resists_cold(mtmp); 116. 				break; 117. 			case AD_DISN: 118. 				explmask[i][j] |= resists_disint(mtmp); 119. 				break; 120. 			case AD_ELEC: 121. 				explmask[i][j] |= resists_elec(mtmp); 122. 				break; 123. 			default: 124. 				impossible("explosion type %d?", adtyp); 125. 				break; 126. 		    }  127.  		}  128.   129.  		if (cansee(i+x-1, j+y-1)) visible = TRUE; 130. 		if (explmask[i][j] == 1) any_shield = TRUE; 131. 	}  132.   133.  	if (visible) { 134. 		/* Start the explosion */ 135. 		for (i=0; i<3; i++) for (j=0; j<3; j++) { 136. 			if (explmask[i][j] == 2) continue; 137. 			tmp_at(starting ? DISP_BEAM : DISP_CHANGE,  138.  					    cmap_to_glyph(expl[i][j])); 139. 			tmp_at(i+x-1, j+y-1); 140. 			starting = 0; 141. 		}  142.  		curs_on_u;	/* will flush screen and output */ 143.  144.  		if (any_shield) {	/* simulate a shield effect */ 145. 		    for (k = 0; k < SHIELD_COUNT; k++) { 146. 			for (i=0; i<3; i++) for (j=0; j<3; j++) { 147. 			    if (explmask[i][j] == 1) 148. 				/*  149.  				 * Bypass tmp_at and send the shield glyphs 150. 				 * directly to the buffered screen. tmp_at 151. 				 * will clean up the location for us later. 152. 				 */  153.  				show_glyph(i+x-1, j+y-1,  154.  					cmap_to_glyph(shield_static[k])); 155. 			}  156.  			curs_on_u;	/* will flush screen and output */ 157. 			delay_output; 158. 		    }  159.   160.  		    /* Cover last shield glyph with blast symbol. */ 161.  		    for (i=0; i<3; i++) for (j=0; j<3; j++) { 162. 			if (explmask[i][j] == 1) 163. 			    show_glyph(i+x-1,j+y-1,cmap_to_glyph(expl[i][j])); 164. 		    }  165.   166.  		} else {		/* delay a little bit. */ 167.  		    delay_output; 168. 		    delay_output; 169. 		}  170.   171.  	} else { 172. 		if (flags.soundok) You_hear("a blast."); 173. 	}  174.   175.      if (dam) 176. 	for (i=0; i<3; i++) for (j=0; j<3; j++) { 177. 		if (explmask[i][j] == 2) continue; 178. 		if (i+x-1 == u.ux && j+y-1 == u.uy) 179. 			uhurt = (explmask[i][j] == 1) ? 1 : 2; 180.  		idamres = idamnonres = 0; 181. 		(void)zap_over_floor((xchar)(i+x-1), (xchar)(j+y-1),  182.  				     type, &shopdamage); 183.  184.  		mtmp = m_at(i+x-1, j+y-1); 185. 		if (!mtmp) continue; 186. 		if (u.uswallow && mtmp == u.ustuck) { 187. 			if (is_animal(u.ustuck->data)) 188. 				pline("%s gets %s!",  189.  				      Monnam(u.ustuck),  190.  				      (adtyp == AD_FIRE) ? "heartburn" :  191.  				      (adtyp == AD_COLD) ? "chilly" :  192.  				      (adtyp == AD_DISN) ? "perforated" :  193.  				      (adtyp == AD_ELEC) ? "shocked" :  194.  				       "fried"); 195. 			else 196. 				pline("%s gets slightly %s!",  197.  				      Monnam(u.ustuck),  198.  				      (adtyp == AD_FIRE) ? "toasted" :  199.  				      (adtyp == AD_COLD) ? "chilly" :  200.  				      (adtyp == AD_DISN) ? "perforated" :  201.  				      (adtyp == AD_ELEC) ? "shocked" :  202.  				       "fried"); 203. 		} else 204. 		pline("%s is caught in the %s!",  205.  			cansee(i+x-1, j+y-1) ? Monnam(mtmp) : "It", str); 206.  207.  		idamres += destroy_mitem(mtmp, SCROLL_CLASS, (int) adtyp); 208. 		idamres += destroy_mitem(mtmp, SPBOOK_CLASS, (int) adtyp); 209. 		idamnonres += destroy_mitem(mtmp, POTION_CLASS, (int) adtyp); 210. 		idamnonres += destroy_mitem(mtmp, WAND_CLASS, (int) adtyp); 211. 		idamnonres += destroy_mitem(mtmp, RING_CLASS, (int) adtyp); 212.  213.  		if (explmask[i][j] == 1) { 214. 			golemeffects(mtmp, (int) adtyp, dam + idamres); 215. 			mtmp->mhp -= idamnonres; 216. 		} else { 217. 		/* call resist with 0 and do damage manually so 1) we can  218.  		 * get out the message before doing the damage, and 2) we can 219. 		 * call mondied, not killed, if it's not your blast 220. 		 */  221.  			int mdam = dam; 222.  223.  			if (resist(mtmp, olet, 0, FALSE)) { 224. 				pline("%s resists the magical blast!",  225.  					cansee(i+x-1,j+y-1) ? Monnam(mtmp)  226.  					: "It"); 227. 				mdam = dam/2; 228. 			}  229.  			if (mtmp == u.ustuck) 230. 				mdam *= 2; 231. 			if (resists_cold(mtmp) && adtyp == AD_FIRE) 232. 				mdam *= 2; 233. 			else if (resists_fire(mtmp) && adtyp == AD_COLD) 234. 				mdam *= 2; 235. 			mtmp->mhp -= mdam; 236. 			mtmp->mhp -= (idamres + idamnonres); 237. 		}  238.  		if (mtmp->mhp <= 0) { 239. 			if (type >= 0) killed(mtmp); 240. 			else mondied(mtmp); 241. 		}  242.  	}  243.   244.  	if (visible) tmp_at(DISP_END, 0); /* clear the explosion */ 245.  246.  	/* Do your injury last */ 247. 	if (uhurt) { 248. 		if (type >= 0 && flags.verbose && olet != SCROLL_CLASS) 249. 			You("are caught in the %s!", str); 250. 		/* do property damage first, in case we end up leaving bones */ 251. 		if (adtyp == AD_FIRE) (void) burnarmor; 252. 		destroy_item(SCROLL_CLASS, (int) adtyp); 253. 		destroy_item(SPBOOK_CLASS, (int) adtyp); 254. 		destroy_item(POTION_CLASS, (int) adtyp); 255. 		destroy_item(RING_CLASS, (int) adtyp); 256. 		destroy_item(WAND_CLASS, (int) adtyp); 257.  258.  		ugolemeffects((int) adtyp, damu); 259. 		if (uhurt == 2) u.uhp -= damu, flags.botl = 1; 260.  261.  		if (u.uhp <= 0) { 262. 			char buf[BUFSZ]; 263.  264.  			if (type >= 0 && olet != SCROLL_CLASS) { 265. 			    killer_format = NO_KILLER_PREFIX; 266. 			    Sprintf(buf, "caught %sself in %s own %s.",  267.  				    him[flags.female], his[flags.female], str); 268. 			} else { 269. 			    killer_format = KILLED_BY; 270. 			    Strcpy(buf, str); 271. 			}  272.  			killer = buf; 273. 			/* Known BUG: BURNING suppresses corpse in bones data, 274. 			   but done does not handle killer reason correctly */ 275. 			/* done(adtyp == AD_FIRE ? BURNING : DIED); */ 276. 			done(BURNING); 277. 		}  278.  		exercise(A_STR, FALSE); 279. 	}  280.   281.  	if (shopdamage) { 282. 		pay_for_damage(adtyp == AD_FIRE ? "burn away" :  283.  			       adtyp == AD_COLD ? "shatter" :  284.  			       adtyp == AD_DISN ? "disintegrate" : "destroy"); 285. 	}  286.  }  287.  #endif /* OVL0 */ 288. #ifdef OVL1 289.  290.  struct scatter_chain { 291. 	struct scatter_chain *next;	/* pointer to next scatter item	*/ 292. 	struct obj *obj;		/* pointer to the object	*/ 293. 	xchar ox;			/* location of			*/ 294. 	xchar oy;			/*	item			*/ 295. 	schar dx;			/* direction of			*/ 296. 	schar dy;			/*	travel			*/ 297. 	int range;			/* range of object		*/ 298. 	boolean stopped;		/* flag for in-motion/stopped	*/ 299. };  300.   301.  /*  302.   * scflags: 303.  *	VIS_EFFECTS	Add visual effects to display 304.  *	MAY_HITMON	Objects may hit monsters 305.  *	MAY_HITYOU	Objects may hit hero 306.  *	MAY_HIT		Objects may hit you or monsters 307.  *	MAY_DESTROY	Objects may be destroyed at random 308.  *	MAY_FRACTURE	Stone objects can be fractured (statues, boulders) 309.  */  310.   311.  void 312. scatter(sx,sy,blastforce,scflags) 313. int sx,sy;				/* location of objects to scatter */ 314. int blastforce;				/* force behind the scattering	*/ 315. unsigned int scflags; 316. {  317.  	register struct obj *otmp; 318. 	register int tmp; 319. 	int farthest = 0; 320. 	uchar typ; 321. 	long qtmp; 322. 	boolean used_up; 323. 	struct monst *mtmp; 324. 	struct scatter_chain *stmp, *stmp2 = 0; 325. 	struct scatter_chain *schain = (struct scatter_chain *)0; 326.  327.  	while ((otmp = level.objects[sx][sy]) != 0) { 328. 	    if (otmp->quan > 1L) { 329. 		qtmp = (long)rnd((int)otmp->quan - 1); 330. 		(void) splitobj(otmp, qtmp); 331. 	    }  332.  	    obj_extract_self(otmp); 333. 	    used_up = FALSE; 334.  335.  	    /* 9 in 10 chance of fracturing boulders or statues */ 336. 	    if ((scflags & MAY_FRACTURE)  337.  			&& ((otmp->otyp == BOULDER) || (otmp->otyp == STATUE))  338.  			&& rn2(10)) { 339. 		if (otmp->otyp == BOULDER) { 340. 		    pline("%s breaks apart.",The(xname(otmp))); 341. 		    fracture_rock(otmp); 342. 		    place_object(otmp, sx, sy);	/* put fragments on floor */ 343. 		} else { 344. 		    struct trap *trap; 345.  346.  		    if ((trap = t_at(sx,sy)) && trap->ttyp == STATUE_TRAP) 347. 			    deltrap(trap); 348. 		    pline("%s crumbles.",The(xname(otmp))); 349. 		    (void) break_statue(otmp); 350. 		    place_object(otmp, sx, sy);	/* put fragments on floor */ 351. 		}  352.  		used_up = TRUE; 353.  354.  	    /* 1 in 10 chance of destruction of obj; glass, egg destruction */ 355. 	    } else if ((scflags & MAY_DESTROY) && (!rn2(10) 356. 			|| (objects[otmp->otyp].oc_material == GLASS  357.  			|| otmp->otyp == EGG))) { 358. 		if (breaks(otmp, sx, sy, FALSE)) used_up = TRUE; 359. 	    }  360.   361.  	    if (!used_up) { 362. 		stmp = (struct scatter_chain *) 363. 					alloc(sizeof(struct scatter_chain)); 364. 		stmp->next = (struct scatter_chain *)0; 365. 		stmp->obj = otmp; 366. 		stmp->ox = sx; 367. 		stmp->oy = sy; 368. 		tmp = rn2(8);		/* get the direction */ 369. 		stmp->dx = xdir[tmp]; 370. 		stmp->dy = ydir[tmp]; 371. 		tmp = blastforce - (otmp->owt/40); 372. 		if (tmp < 1) tmp = 1; 373. 		stmp->range = rnd(tmp); /* anywhere up to that determ. by wt */ 374. 		if (farthest < stmp->range) farthest = stmp->range; 375. 		stmp->stopped = FALSE; 376. 		if (!schain) 377. 		    schain = stmp; 378. 		else 379. 		    stmp2->next = stmp; 380. 		stmp2 = stmp; 381. 	    }  382.  	}  383.   384.  	while (farthest-- > 0) { 385. 		for (stmp = schain; stmp; stmp = stmp->next) { 386. 		   if ((stmp->range-- > 0) && (!stmp->stopped)) { 387. 			bhitpos.x = stmp->ox + stmp->dx; 388. 			bhitpos.y = stmp->oy + stmp->dy; 389. 			typ = levl[bhitpos.x][bhitpos.y].typ; 390. 			if(!isok(bhitpos.x, bhitpos.y)) { 391. 				bhitpos.x -= stmp->dx; 392. 				bhitpos.y -= stmp->dy; 393. 				stmp->stopped = TRUE; 394. 			} else if(!ZAP_POS(typ) ||  395.  					closed_door(bhitpos.x, bhitpos.y)) { 396. 				bhitpos.x -= stmp->dx; 397. 				bhitpos.y -= stmp->dy; 398. 				stmp->stopped = TRUE; 399. 			} else if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) { 400. 				if (scflags & MAY_HITMON) { 401. 				    stmp->range--; 402. 				    if (ohitmon(mtmp, stmp->obj, 1, FALSE)) { 403. 					stmp->obj = (struct obj *)0; 404. 					stmp->stopped = TRUE; 405. 				    }  406.  				}  407.  			} else if (bhitpos.x==u.ux && bhitpos.y==u.uy) { 408. 				if (scflags & MAY_HITYOU) { 409. 				    int hitvalu, hitu; 410.  411.  				    if (multi) nomul(0); 412. 				    hitvalu = 8 + stmp->obj->spe; 413. 				    if (bigmonst(uasmon)) hitvalu++; 414. 				    hitu = thitu(hitvalu,  415.  						dmgval(stmp->obj, &youmonst),  416.  						stmp->obj,  417.  						xname(stmp->obj)); 418. 				    if (hitu) { 419. 					stmp->range -= 3; 420. 					stop_occupation; 421. 				    }  422.  				}  423.  			} else { 424. 				if (scflags & VIS_EFFECTS) { 425. 				    /* tmp_at(bhitpos.x, bhitpos.y); */ 426. 				    /* delay_output; */ 427. 				}  428.  			}  429.  			stmp->ox = bhitpos.x;  430. stmp->oy = bhitpos.y; 431. } 432.  		}  433.  	}  434.  	for (stmp = schain; stmp; stmp = stmp2) { 435. 		int x,y; 436.  437.  		stmp2 = stmp->next; 438. 		x = stmp->ox; y = stmp->oy; 439. 		if (stmp->obj) { 440. 			place_object(stmp->obj, x, y); 441. 			stackobj(stmp->obj); 442. 		}  443.  		free((genericptr_t)stmp); 444. 		newsym(x,y); 445. 	}  446.  }  447.   448.   449.  /*  450.   * Splatter burning oil from x,y to the surrounding area. 451.  *  452.   * This routine should really take a how and direction parameters. 453.  * The how is how it was caused, e.g. kicked verses thrown. The 454.  * direction is which way to spread the flaming oil. Different 455.  * "how"s would give different dispersal patterns. For example, 456.  * kicking a burning flask will splatter differently from a thrown 457.  * flask hitting the ground. 458.  *  459.   * For now, just perform a "regular" explosion. 460.  */  461.  void 462. splatter_burning_oil(x, y)  463. int x, y; 464. { 465.  /* ZT_SPELL(ZT_FIRE) = ZT_SPELL(AD_FIRE-1) = 10+(2-1) = 11 */ 466. #define ZT_SPELL_O_FIRE 11 /* value kludge, see zap.c */ 467.     explode(x, y, ZT_SPELL_O_FIRE, d(4,4), BURNING_OIL); 468. }  469.   470.  #endif /* OVL1 */ 471.  472.  /*explode.c*/