Below is the full text to src/explode.c from NetHack 3.4.3. To link to a particular line, write [[explode.c#line123]], for example.
Top of file
Edit
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. /* 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, expltype)
26. int x, y;
27. int type; /* the same as in zap.c */
28. int dam;
29. char olet;
30. int expltype;
31. {
32. int i, j, k, damu = dam;
33. boolean starting = 1;
34. boolean visible, any_shield;
35. int uhurt = 0; /* 0=unhurt, 1=items damaged, 2=you and items damaged */
36. const char *str;
37. int idamres, idamnonres;
38. struct monst *mtmp;
39. uchar adtyp;
40. int explmask[3][3];
41. /* 0=normal explosion, 1=do shieldeff, 2=do nothing */
42. boolean shopdamage = FALSE;
43. boolean generic = FALSE;
44.
45. if (olet == WAND_CLASS) /* retributive strike */
46. switch (Role_switch) {
47. case PM_PRIEST:
48. case PM_MONK:
49. case PM_WIZARD: damu /= 5;
50. break;
51. case PM_HEALER:
52. case PM_KNIGHT: damu /= 2;
53. break;
54. default: break;
55. }
56.
57. if (olet == MON_EXPLODE) {
58. str = killer;
59. killer = 0; /* set again later as needed */
60. adtyp = AD_PHYS;
61. } else
62. switch (abs(type) % 10) {
63. case 0: str = "magical blast";
64. adtyp = AD_MAGM;
65. break;
66. case 1: str = olet == BURNING_OIL ? "burning oil" :
67. olet == SCROLL_CLASS ? "tower of flame" :
68. "fireball";
69. adtyp = AD_FIRE;
70. break;
71. case 2: str = "ball of cold";
72. adtyp = AD_COLD;
73. break;
74. case 4: str = (olet == WAND_CLASS) ? "death field" :
75. "disintegration field";
76. adtyp = AD_DISN;
77. break;
78. case 5: str = "ball of lightning";
79. adtyp = AD_ELEC;
80. break;
81. case 6: str = "poison gas cloud";
82. adtyp = AD_DRST;
83. break;
84. case 7: str = "splash of acid";
85. adtyp = AD_ACID;
86. break;
87. default: impossible("explosion base type %d?", type); return;
88. }
89.
90. any_shield = visible = FALSE;
91. for (i=0; i<3; i++) for (j=0; j<3; j++) {
92. if (!isok(i+x-1, j+y-1)) {
93. explmask[i][j] = 2;
94. continue;
95. } else
96. explmask[i][j] = 0;
97.
98. if (i+x-1 == u.ux && j+y-1 == u.uy) {
99. switch(adtyp) {
100. case AD_PHYS:
101. explmask[i][j] = 0;
102. break;
103. case AD_MAGM:
104. explmask[i][j] = !!Antimagic;
105. break;
106. case AD_FIRE:
107. explmask[i][j] = !!Fire_resistance;
108. break;
109. case AD_COLD:
110. explmask[i][j] = !!Cold_resistance;
111. break;
112. case AD_DISN:
113. explmask[i][j] = (olet == WAND_CLASS) ?
114. !!(nonliving(youmonst.data) || is_demon(youmonst.data)) :
115. !!Disint_resistance;
116. break;
117. case AD_ELEC:
118. explmask[i][j] = !!Shock_resistance;
119. break;
120. case AD_DRST:
121. explmask[i][j] = !!Poison_resistance;
122. break;
123. case AD_ACID:
124. explmask[i][j] = !!Acid_resistance;
125. break;
126. default:
127. impossible("explosion type %d?", adtyp);
128. break;
129. }
130. }
131. /* can be both you and mtmp if you're swallowed */
132. mtmp = m_at(i+x-1, j+y-1);
133. #ifdef STEED
134. if (!mtmp && i+x-1 == u.ux && j+y-1 == u.uy)
135. mtmp = u.usteed;
136. #endif
137. if (mtmp) {
138. if (mtmp->mhp < 1) explmask[i][j] = 2;
139. else switch(adtyp) {
140. case AD_PHYS:
141. break;
142. case AD_MAGM:
143. explmask[i][j] |= resists_magm(mtmp);
144. break;
145. case AD_FIRE:
146. explmask[i][j] |= resists_fire(mtmp);
147. break;
148. case AD_COLD:
149. explmask[i][j] |= resists_cold(mtmp);
150. break;
151. case AD_DISN:
152. explmask[i][j] |= (olet == WAND_CLASS) ?
153. (nonliving(mtmp->data) || is_demon(mtmp->data)) :
154. resists_disint(mtmp);
155. break;
156. case AD_ELEC:
157. explmask[i][j] |= resists_elec(mtmp);
158. break;
159. case AD_DRST:
160. explmask[i][j] |= resists_poison(mtmp);
161. break;
162. case AD_ACID:
163. explmask[i][j] |= resists_acid(mtmp);
164. break;
165. default:
166. impossible("explosion type %d?", adtyp);
167. break;
168. }
169. }
170. if (mtmp && cansee(i+x-1,j+y-1) && !canspotmon(mtmp))
171. map_invisible(i+x-1, j+y-1);
172. else if (!mtmp && glyph_is_invisible(levl[i+x-1][j+y-1].glyph)) {
173. unmap_object(i+x-1, j+y-1);
174. newsym(i+x-1, j+y-1);
175. }
176. if (cansee(i+x-1, j+y-1)) visible = TRUE;
177. if (explmask[i][j] == 1) any_shield = TRUE;
178. }
179.
180. if (visible) {
181. /* Start the explosion */
182. for (i=0; i<3; i++) for (j=0; j<3; j++) {
183. if (explmask[i][j] == 2) continue;
184. tmp_at(starting ? DISP_BEAM : DISP_CHANGE,
185. explosion_to_glyph(expltype,expl[i][j]));
186. tmp_at(i+x-1, j+y-1);
187. starting = 0;
188. }
189. curs_on_u(); /* will flush screen and output */
190.
191. if (any_shield && flags.sparkle) { /* simulate shield effect */
192. for (k = 0; k < SHIELD_COUNT; k++) {
193. for (i=0; i<3; i++) for (j=0; j<3; j++) {
194. if (explmask[i][j] == 1)
195. /*
196. * Bypass tmp_at() and send the shield glyphs
197. * directly to the buffered screen. tmp_at()
198. * will clean up the location for us later.
199. */
200. show_glyph(i+x-1, j+y-1,
201. cmap_to_glyph(shield_static[k]));
202. }
203. curs_on_u(); /* will flush screen and output */
204. delay_output();
205. }
206.
207. /* Cover last shield glyph with blast symbol. */
208. for (i=0; i<3; i++) for (j=0; j<3; j++) {
209. if (explmask[i][j] == 1)
210. show_glyph(i+x-1,j+y-1,
211. explosion_to_glyph(expltype, expl[i][j]));
212. }
213.
214. } else { /* delay a little bit. */
215. delay_output();
216. delay_output();
217. }
218.
219. tmp_at(DISP_END, 0); /* clear the explosion */
220. } else {
221. if (olet == MON_EXPLODE) {
222. str = "explosion";
223. generic = TRUE;
224. }
225. if (flags.soundok) You_hear("a blast.");
226. }
227.
228. if (dam)
229. for (i=0; i<3; i++) for (j=0; j<3; j++) {
230. if (explmask[i][j] == 2) continue;
231. if (i+x-1 == u.ux && j+y-1 == u.uy)
232. uhurt = (explmask[i][j] == 1) ? 1 : 2;
233. idamres = idamnonres = 0;
234. if (type >= 0)
235. (void)zap_over_floor((xchar)(i+x-1), (xchar)(j+y-1),
236. type, &shopdamage);
237.
238. mtmp = m_at(i+x-1, j+y-1);
239. #ifdef STEED
240. if (!mtmp && i+x-1 == u.ux && j+y-1 == u.uy)
241. mtmp = u.usteed;
242. #endif
243. if (!mtmp) continue;
244. if (u.uswallow && mtmp == u.ustuck) {
245. if (is_animal(u.ustuck->data))
246. pline("%s gets %s!",
247. Monnam(u.ustuck),
248. (adtyp == AD_FIRE) ? "heartburn" :
249. (adtyp == AD_COLD) ? "chilly" :
250. (adtyp == AD_DISN) ? ((olet == WAND_CLASS) ?
251. "irradiated by pure energy" : "perforated") :
252. (adtyp == AD_ELEC) ? "shocked" :
253. (adtyp == AD_DRST) ? "poisoned" :
254. (adtyp == AD_ACID) ? "an upset stomach" :
255. "fried");
256. else
257. pline("%s gets slightly %s!",
258. Monnam(u.ustuck),
259. (adtyp == AD_FIRE) ? "toasted" :
260. (adtyp == AD_COLD) ? "chilly" :
261. (adtyp == AD_DISN) ? ((olet == WAND_CLASS) ?
262. "overwhelmed by pure energy" : "perforated") :
263. (adtyp == AD_ELEC) ? "shocked" :
264. (adtyp == AD_DRST) ? "intoxicated" :
265. (adtyp == AD_ACID) ? "burned" :
266. "fried");
267. } else if (cansee(i+x-1, j+y-1)) {
268. if(mtmp->m_ap_type) seemimic(mtmp);
269. pline("%s is caught in the %s!", Monnam(mtmp), str);
270. }
271.
272. idamres += destroy_mitem(mtmp, SCROLL_CLASS, (int) adtyp);
273. idamres += destroy_mitem(mtmp, SPBOOK_CLASS, (int) adtyp);
274. idamnonres += destroy_mitem(mtmp, POTION_CLASS, (int) adtyp);
275. idamnonres += destroy_mitem(mtmp, WAND_CLASS, (int) adtyp);
276. idamnonres += destroy_mitem(mtmp, RING_CLASS, (int) adtyp);
277.
278. if (explmask[i][j] == 1) {
279. golemeffects(mtmp, (int) adtyp, dam + idamres);
280. mtmp->mhp -= idamnonres;
281. } else {
282. /* call resist with 0 and do damage manually so 1) we can
283. * get out the message before doing the damage, and 2) we can
284. * call mondied, not killed, if it's not your blast
285. */
286. int mdam = dam;
287.
288. if (resist(mtmp, olet, 0, FALSE)) {
289. if (cansee(i+x-1,j+y-1))
290. pline("%s resists the %s!", Monnam(mtmp), str);
291. mdam = dam/2;
292. }
293. if (mtmp == u.ustuck)
294. mdam *= 2;
295. if (resists_cold(mtmp) && adtyp == AD_FIRE)
296. mdam *= 2;
297. else if (resists_fire(mtmp) && adtyp == AD_COLD)
298. mdam *= 2;
299. mtmp->mhp -= mdam;
300. mtmp->mhp -= (idamres + idamnonres);
301. }
302. if (mtmp->mhp <= 0) {
303. /* KMH -- Don't blame the player for pets killing gas spores */
304. if (!flags.mon_moving) killed(mtmp);
305. else monkilled(mtmp, "", (int)adtyp);
306. } else if (!flags.mon_moving) setmangry(mtmp);
307. }
308.
309. /* Do your injury last */
310. if (uhurt) {
311. if ((type >= 0 || adtyp == AD_PHYS) && /* gas spores */
312. flags.verbose && olet != SCROLL_CLASS)
313. You("are caught in the %s!", str);
314. /* do property damage first, in case we end up leaving bones */
315. if (adtyp == AD_FIRE) burn_away_slime();
316. if (Invulnerable) {
317. damu = 0;
318. You("are unharmed!");
319. } else if (Half_physical_damage && adtyp == AD_PHYS)
320. damu = (damu+1) / 2;
321. if (adtyp == AD_FIRE) (void) burnarmor(&youmonst);
322. destroy_item(SCROLL_CLASS, (int) adtyp);
323. destroy_item(SPBOOK_CLASS, (int) adtyp);
324. destroy_item(POTION_CLASS, (int) adtyp);
325. destroy_item(RING_CLASS, (int) adtyp);
326. destroy_item(WAND_CLASS, (int) adtyp);
327.
328. ugolemeffects((int) adtyp, damu);
329. if (uhurt == 2) {
330. if (Upolyd)
331. u.mh -= damu;
332. else
333. u.uhp -= damu;
334. flags.botl = 1;
335. }
336.
337. if (u.uhp <= 0 || (Upolyd && u.mh <= 0)) {
338. if (Upolyd) {
339. rehumanize();
340. } else {
341. if (olet == MON_EXPLODE) {
342. /* killer handled by caller */
343. if (str != killer_buf && !generic)
344. Strcpy(killer_buf, str);
345. killer_format = KILLED_BY_AN;
346. } else if (type >= 0 && olet != SCROLL_CLASS) {
347. killer_format = NO_KILLER_PREFIX;
348. Sprintf(killer_buf, "caught %sself in %s own %s",
349. uhim(), uhis(), str);
350. } else if (!strncmpi(str,"tower of flame", 8) ||
351. !strncmpi(str,"fireball", 8)) {
352. killer_format = KILLED_BY_AN;
353. Strcpy(killer_buf, str);
354. } else {
355. killer_format = KILLED_BY;
356. Strcpy(killer_buf, str);
357. }
358. killer = killer_buf;
359. /* Known BUG: BURNING suppresses corpse in bones data,
360. but done does not handle killer reason correctly */
361. done((adtyp == AD_FIRE) ? BURNING : DIED);
362. }
363. }
364. exercise(A_STR, FALSE);
365. }
366.
367. if (shopdamage) {
368. pay_for_damage(adtyp == AD_FIRE ? "burn away" :
369. adtyp == AD_COLD ? "shatter" :
370. adtyp == AD_DISN ? "disintegrate" : "destroy",
371. FALSE);
372. }
373.
374. /* explosions are noisy */
375. i = dam * dam;
376. if (i < 50) i = 50; /* in case random damage is very small */
377. wake_nearto(x, y, i);
378. }
379. #endif /* OVL0 */
380. #ifdef OVL1
381.
382. struct scatter_chain {
383. struct scatter_chain *next; /* pointer to next scatter item */
384. struct obj *obj; /* pointer to the object */
385. xchar ox; /* location of */
386. xchar oy; /* item */
387. schar dx; /* direction of */
388. schar dy; /* travel */
389. int range; /* range of object */
390. boolean stopped; /* flag for in-motion/stopped */
391. };
392.
393. /*
394. * scflags:
395. * VIS_EFFECTS Add visual effects to display
396. * MAY_HITMON Objects may hit monsters
397. * MAY_HITYOU Objects may hit hero
398. * MAY_HIT Objects may hit you or monsters
399. * MAY_DESTROY Objects may be destroyed at random
400. * MAY_FRACTURE Stone objects can be fractured (statues, boulders)
401. */
402.
403. /* returns number of scattered objects */
404. long
405. scatter(sx,sy,blastforce,scflags, obj)
406. int sx,sy; /* location of objects to scatter */
407. int blastforce; /* force behind the scattering */
408. unsigned int scflags;
409. struct obj *obj; /* only scatter this obj */
410. {
411. register struct obj *otmp;
412. register int tmp;
413. int farthest = 0;
414. uchar typ;
415. long qtmp;
416. boolean used_up;
417. boolean individual_object = obj ? TRUE : FALSE;
418. struct monst *mtmp;
419. struct scatter_chain *stmp, *stmp2 = 0;
420. struct scatter_chain *schain = (struct scatter_chain *)0;
421. long total = 0L;
422.
423. while ((otmp = individual_object ? obj : level.objects[sx][sy]) != 0) {
424. if (otmp->quan > 1L) {
425. qtmp = otmp->quan - 1;
426. if (qtmp > LARGEST_INT) qtmp = LARGEST_INT;
427. qtmp = (long)rnd((int)qtmp);
428. otmp = splitobj(otmp, qtmp);
429. } else {
430. obj = (struct obj *)0; /* all used */
431. }
432. obj_extract_self(otmp);
433. used_up = FALSE;
434.
435. /* 9 in 10 chance of fracturing boulders or statues */
436. if ((scflags & MAY_FRACTURE)
437. && ((otmp->otyp == BOULDER) || (otmp->otyp == STATUE))
438. && rn2(10)) {
439. if (otmp->otyp == BOULDER) {
440. pline("%s apart.", Tobjnam(otmp, "break"));
441. fracture_rock(otmp);
442. place_object(otmp, sx, sy);
443. if ((otmp = sobj_at(BOULDER, sx, sy)) != 0) {
444. /* another boulder here, restack it to the top */
445. obj_extract_self(otmp);
446. place_object(otmp, sx, sy);
447. }
448. } else {
449. struct trap *trap;
450.
451. if ((trap = t_at(sx,sy)) && trap->ttyp == STATUE_TRAP)
452. deltrap(trap);
453. pline("%s.", Tobjnam(otmp, "crumble"));
454. (void) break_statue(otmp);
455. place_object(otmp, sx, sy); /* put fragments on floor */
456. }
457. used_up = TRUE;
458.
459. /* 1 in 10 chance of destruction of obj; glass, egg destruction */
460. } else if ((scflags & MAY_DESTROY) && (!rn2(10)
461. || (objects[otmp->otyp].oc_material == GLASS
462. || otmp->otyp == EGG))) {
463. if (breaks(otmp, (xchar)sx, (xchar)sy)) used_up = TRUE;
464. }
465.
466. if (!used_up) {
467. stmp = (struct scatter_chain *)
468. alloc(sizeof(struct scatter_chain));
469. stmp->next = (struct scatter_chain *)0;
470. stmp->obj = otmp;
471. stmp->ox = sx;
472. stmp->oy = sy;
473. tmp = rn2(8); /* get the direction */
474. stmp->dx = xdir[tmp];
475. stmp->dy = ydir[tmp];
476. tmp = blastforce - (otmp->owt/40);
477. if (tmp < 1) tmp = 1;
478. stmp->range = rnd(tmp); /* anywhere up to that determ. by wt */
479. if (farthest < stmp->range) farthest = stmp->range;
480. stmp->stopped = FALSE;
481. if (!schain)
482. schain = stmp;
483. else
484. stmp2->next = stmp;
485. stmp2 = stmp;
486. }
487. }
488.
489. while (farthest-- > 0) {
490. for (stmp = schain; stmp; stmp = stmp->next) {
491. if ((stmp->range-- > 0) && (!stmp->stopped)) {
492. bhitpos.x = stmp->ox + stmp->dx;
493. bhitpos.y = stmp->oy + stmp->dy;
494. typ = levl[bhitpos.x][bhitpos.y].typ;
495. if(!isok(bhitpos.x, bhitpos.y)) {
496. bhitpos.x -= stmp->dx;
497. bhitpos.y -= stmp->dy;
498. stmp->stopped = TRUE;
499. } else if(!ZAP_POS(typ) ||
500. closed_door(bhitpos.x, bhitpos.y)) {
501. bhitpos.x -= stmp->dx;
502. bhitpos.y -= stmp->dy;
503. stmp->stopped = TRUE;
504. } else if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
505. if (scflags & MAY_HITMON) {
506. stmp->range--;
507. if (ohitmon(mtmp, stmp->obj, 1, FALSE)) {
508. stmp->obj = (struct obj *)0;
509. stmp->stopped = TRUE;
510. }
511. }
512. } else if (bhitpos.x==u.ux && bhitpos.y==u.uy) {
513. if (scflags & MAY_HITYOU) {
514. int hitvalu, hitu;
515.
516. if (multi) nomul(0);
517. hitvalu = 8 + stmp->obj->spe;
518. if (bigmonst(youmonst.data)) hitvalu++;
519. hitu = thitu(hitvalu,
520. dmgval(stmp->obj, &youmonst),
521. stmp->obj, (char *)0);
522. if (hitu) {
523. stmp->range -= 3;
524. stop_occupation();
525. }
526. }
527. } else {
528. if (scflags & VIS_EFFECTS) {
529. /* tmp_at(bhitpos.x, bhitpos.y); */
530. /* delay_output(); */
531. }
532. }
533. stmp->ox = bhitpos.x;
534. stmp->oy = bhitpos.y;
535. }
536. }
537. }
538. for (stmp = schain; stmp; stmp = stmp2) {
539. int x,y;
540.
541. stmp2 = stmp->next;
542. x = stmp->ox; y = stmp->oy;
543. if (stmp->obj) {
544. if ( x!=sx || y!=sy )
545. total += stmp->obj->quan;
546. place_object(stmp->obj, x, y);
547. stackobj(stmp->obj);
548. }
549. free((genericptr_t)stmp);
550. newsym(x,y);
551. }
552.
553. return total;
554. }
555.
556.
splatter_burning_oil
Edit
557. /*
558. * Splatter burning oil from x,y to the surrounding area.
559. *
560. * This routine should really take a how and direction parameters.
561. * The how is how it was caused, e.g. kicked verses thrown. The
562. * direction is which way to spread the flaming oil. Different
563. * "how"s would give different dispersal patterns. For example,
564. * kicking a burning flask will splatter differently from a thrown
565. * flask hitting the ground.
566. *
567. * For now, just perform a "regular" explosion.
568. */
569. void
570. splatter_burning_oil(x, y)
571. int x, y;
572. {
573. /* ZT_SPELL(ZT_FIRE) = ZT_SPELL(AD_FIRE-1) = 10+(2-1) = 11 */
574. #define ZT_SPELL_O_FIRE 11 /* value kludge, see zap.c */
575. explode(x, y, ZT_SPELL_O_FIRE, d(4,4), BURNING_OIL, EXPL_FIERY);
576. }
577.
578. #endif /* OVL1 */
579.
580. /*explode.c*/