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