Source:SLASH'EM 0.0.7E7F2/explode.c
Revision as of 19:05, 7 March 2008 by Kernigh bot (talk | contribs) (SLASH'EM 0.0.7E7F2/explode.c moved to Source:SLASH'EM 0.0.7E7F2/explode.c: Robot: moved page)
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.
This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.
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*/