Source:NetHack 3.6.1/src/trap.c
(Redirected from Source:Ref/thitm)
Jump to navigation
Jump to search
Below is the full text to trap.c from the source code of NetHack 3.6.1. To link to a particular line, write [[Source:NetHack 3.6.1/src/trap.c#line123]], for example.
Contents
- 1 Top of file
- 2 burnarmor
- 3 erode_obj
- 4 grease_protect
- 5 maketrap
- 6 fall_through
- 7 animate_statue
- 8 activate_statue_trap
- 9 keep_saddle_with_steedcorpse
- 10 mu_maybe_destroy_web
- 11 dotrap
- 12 trapnote
- 13 steedintrap
- 14 blow_up_landmine
- 15 launch_drop_spot
- 16 launch_in_progress
- 17 force_launch_placement
- 18 launch_obj
- 19 seetrap
- 20 feeltrap
- 21 mkroll_launch
- 22 isclearpath
- 23 mintrap
- 24 instapetrify
- 25 minstapetrify
- 26 selftouch
- 27 mselftouch
- 28 float_up
- 29 fill_pit
- 30 float_down
- 31 climb_pit
- 32 dofiretrap
- 33 domagictrap
- 34 fire_damage
- 35 fire_damage_chain
- 36 lava_damage
- 37 acid_damage
- 38 water_damage
- 39 water_damage_chain
- 40 emergency_disrobe
- 41 drown
- 42 drain_en
- 43 dountrap
- 44 untrap_prob
- 45 cnv_trap_obj
- 46 move_into_trap
- 47 try_disarm
- 48 reward_untrap
- 49 disarm_holdingtrap
- 50 disarm_landmine
- 51 disarm_squeaky_board
- 52 disarm_shooting_trap
- 53 try_lift
- 54 help_monster_out
- 55 untrap
- 56 openholdingtrap
- 57 closeholdingtrap
- 58 openfallingtrap
- 59 chest_trap
- 60 t_at
- 61 deltrap
- 62 conjoined_pits
- 63 clear_conjoined_pits
- 64 adj_nonconjoined_pit
- 65 uteetering_at_seen_pit
- 66 delfloortrap
- 67 b_trapped
- 68 thitm
- 69 unconscious
- 70 lava_effects
- 71 sink_into_lava
- 72 sokoban_guilt
- 73 maybe_finish_sokoban
Top of file
1. /* NetHack 3.6 trap.c $NHDT-Date: 1524312044 2018/04/21 12:00:44 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.290 $ */ 2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3. /*-Copyright (c) Robert Patrick Rankin, 2013. */ 4. /* NetHack may be freely redistributed. See license for details. */
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.
5. 6. #include "hack.h" 7. 8. extern const char *const destroy_strings[][3]; /* from zap.c */ 9. 10. STATIC_DCL void FDECL(dofiretrap, (struct obj *)); 11. STATIC_DCL void NDECL(domagictrap); 12. STATIC_DCL boolean FDECL(emergency_disrobe, (boolean *)); 13. STATIC_DCL int FDECL(untrap_prob, (struct trap *)); 14. STATIC_DCL void FDECL(move_into_trap, (struct trap *)); 15. STATIC_DCL int FDECL(try_disarm, (struct trap *, BOOLEAN_P)); 16. STATIC_DCL void FDECL(reward_untrap, (struct trap *, struct monst *)); 17. STATIC_DCL int FDECL(disarm_holdingtrap, (struct trap *)); 18. STATIC_DCL int FDECL(disarm_landmine, (struct trap *)); 19. STATIC_DCL int FDECL(disarm_squeaky_board, (struct trap *)); 20. STATIC_DCL int FDECL(disarm_shooting_trap, (struct trap *, int)); 21. STATIC_DCL int FDECL(try_lift, (struct monst *, struct trap *, int, 22. BOOLEAN_P)); 23. STATIC_DCL int FDECL(help_monster_out, (struct monst *, struct trap *)); 24. STATIC_DCL boolean FDECL(thitm, (int, struct monst *, struct obj *, int, 25. BOOLEAN_P)); 26. STATIC_DCL void FDECL(launch_drop_spot, (struct obj *, XCHAR_P, XCHAR_P)); 27. STATIC_DCL int FDECL(mkroll_launch, (struct trap *, XCHAR_P, XCHAR_P, 28. SHORT_P, long)); 29. STATIC_DCL boolean FDECL(isclearpath, (coord *, int, SCHAR_P, SCHAR_P)); 30. STATIC_DCL char *FDECL(trapnote, (struct trap *, BOOLEAN_P)); 31. #if 0 32. STATIC_DCL void FDECL(join_adjacent_pits, (struct trap *)); 33. #endif 34. STATIC_DCL void FDECL(clear_conjoined_pits, (struct trap *)); 35. STATIC_DCL boolean FDECL(adj_nonconjoined_pit, (struct trap *)); 36. 37. STATIC_DCL int FDECL(steedintrap, (struct trap *, struct obj *)); 38. STATIC_DCL boolean FDECL(keep_saddle_with_steedcorpse, (unsigned, 39. struct obj *, 40. struct obj *)); 41. STATIC_DCL void NDECL(maybe_finish_sokoban); 42. 43. /* mintrap() should take a flags argument, but for time being we use this */ 44. STATIC_VAR int force_mintrap = 0; 45. 46. STATIC_VAR const char *const a_your[2] = { "a", "your" }; 47. STATIC_VAR const char *const A_Your[2] = { "A", "Your" }; 48. STATIC_VAR const char tower_of_flame[] = "tower of flame"; 49. STATIC_VAR const char *const A_gush_of_water_hits = "A gush of water hits"; 50. STATIC_VAR const char *const blindgas[6] = { "humid", "odorless", 51. "pungent", "chilling", 52. "acrid", "biting" }; 53.
burnarmor
54. /* called when you're hit by fire (dofiretrap,buzz,zapyourself,explode); 55. returns TRUE if hit on torso */ 56. boolean 57. burnarmor(victim) 58. struct monst *victim; 59. { 60. struct obj *item; 61. char buf[BUFSZ]; 62. int mat_idx, oldspe; 63. boolean hitting_u; 64. 65. if (!victim) 66. return 0; 67. hitting_u = (victim == &youmonst); 68. 69. /* burning damage may dry wet towel */ 70. item = hitting_u ? carrying(TOWEL) : m_carrying(victim, TOWEL); 71. while (item) { 72. if (is_wet_towel(item)) { 73. oldspe = item->spe; 74. dry_a_towel(item, rn2(oldspe + 1), TRUE); 75. if (item->spe != oldspe) 76. break; /* stop once one towel has been affected */ 77. } 78. item = item->nobj; 79. } 80. 81. #define burn_dmg(obj, descr) erode_obj(obj, descr, ERODE_BURN, EF_GREASE) 82. while (1) { 83. switch (rn2(5)) { 84. case 0: 85. item = hitting_u ? uarmh : which_armor(victim, W_ARMH); 86. if (item) { 87. mat_idx = objects[item->otyp].oc_material; 88. Sprintf(buf, "%s %s", materialnm[mat_idx], 89. helm_simple_name(item)); 90. } 91. if (!burn_dmg(item, item ? buf : "helmet")) 92. continue; 93. break; 94. case 1: 95. item = hitting_u ? uarmc : which_armor(victim, W_ARMC); 96. if (item) { 97. (void) burn_dmg(item, cloak_simple_name(item)); 98. return TRUE; 99. } 100. item = hitting_u ? uarm : which_armor(victim, W_ARM); 101. if (item) { 102. (void) burn_dmg(item, xname(item)); 103. return TRUE; 104. } 105. item = hitting_u ? uarmu : which_armor(victim, W_ARMU); 106. if (item) 107. (void) burn_dmg(item, "shirt"); 108. return TRUE; 109. case 2: 110. item = hitting_u ? uarms : which_armor(victim, W_ARMS); 111. if (!burn_dmg(item, "wooden shield")) 112. continue; 113. break; 114. case 3: 115. item = hitting_u ? uarmg : which_armor(victim, W_ARMG); 116. if (!burn_dmg(item, "gloves")) 117. continue; 118. break; 119. case 4: 120. item = hitting_u ? uarmf : which_armor(victim, W_ARMF); 121. if (!burn_dmg(item, "boots")) 122. continue; 123. break; 124. } 125. break; /* Out of while loop */ 126. } 127. #undef burn_dmg 128. 129. return FALSE; 130. } 131.
erode_obj
132. /* Generic erode-item function. 133. * "ostr", if non-null, is an alternate string to print instead of the 134. * object's name. 135. * "type" is an ERODE_* value for the erosion type 136. * "flags" is an or-ed list of EF_* flags 137. * 138. * Returns an erosion return value (ER_*) 139. */ 140. int 141. erode_obj(otmp, ostr, type, ef_flags) 142. register struct obj *otmp; 143. const char *ostr; 144. int type; 145. int ef_flags; 146. { 147. static NEARDATA const char 148. *const action[] = { "smoulder", "rust", "rot", "corrode" }, 149. *const msg[] = { "burnt", "rusted", "rotten", "corroded" }, 150. *const bythe[] = { "heat", "oxidation", "decay", "corrosion" }; 151. boolean vulnerable = FALSE, is_primary = TRUE, 152. check_grease = (ef_flags & EF_GREASE) ? TRUE : FALSE, 153. print = (ef_flags & EF_VERBOSE) ? TRUE : FALSE, 154. uvictim, vismon, visobj; 155. int erosion, cost_type; 156. struct monst *victim; 157. 158. if (!otmp) 159. return ER_NOTHING; 160. 161. victim = carried(otmp) ? &youmonst : mcarried(otmp) ? otmp->ocarry : NULL; 162. uvictim = (victim == &youmonst); 163. vismon = victim && (victim != &youmonst) && canseemon(victim); 164. /* Is bhitpos correct here? Ugh. */ 165. visobj = !victim && cansee(bhitpos.x, bhitpos.y); 166. 167. switch (type) { 168. case ERODE_BURN: 169. vulnerable = is_flammable(otmp); 170. check_grease = FALSE; 171. cost_type = COST_BURN; 172. break; 173. case ERODE_RUST: 174. vulnerable = is_rustprone(otmp); 175. cost_type = COST_RUST; 176. break; 177. case ERODE_ROT: 178. vulnerable = is_rottable(otmp); 179. check_grease = FALSE; 180. is_primary = FALSE; 181. cost_type = COST_ROT; 182. break; 183. case ERODE_CORRODE: 184. vulnerable = is_corrodeable(otmp); 185. is_primary = FALSE; 186. cost_type = COST_CORRODE; 187. break; 188. default: 189. impossible("Invalid erosion type in erode_obj"); 190. return ER_NOTHING; 191. } 192. erosion = is_primary ? otmp->oeroded : otmp->oeroded2; 193. 194. if (!ostr) 195. ostr = cxname(otmp); 196. /* 'visobj' messages insert "the"; probably ought to switch to the() */ 197. if (visobj && !(uvictim || vismon) && !strncmpi(ostr, "the ", 4)) 198. ostr += 4; 199. 200. if (check_grease && otmp->greased) { 201. grease_protect(otmp, ostr, victim); 202. return ER_GREASED; 203. } else if (!erosion_matters(otmp)) { 204. return ER_NOTHING; 205. } else if (!vulnerable || (otmp->oerodeproof && otmp->rknown)) { 206. if (flags.verbose && print && (uvictim || vismon)) 207. pline("%s %s %s not affected by %s.", 208. uvictim ? "Your" : s_suffix(Monnam(victim)), 209. ostr, vtense(ostr, "are"), bythe[type]); 210. return ER_NOTHING; 211. } else if (otmp->oerodeproof || (otmp->blessed && !rnl(4))) { 212. if (flags.verbose && (print || otmp->oerodeproof) 213. && (uvictim || vismon || visobj)) 214. pline("Somehow, %s %s %s not affected by the %s.", 215. uvictim ? "your" 216. : !vismon ? "the" /* visobj */ 217. : s_suffix(mon_nam(victim)), 218. ostr, vtense(ostr, "are"), bythe[type]); 219. /* We assume here that if the object is protected because it 220. * is blessed, it still shows some minor signs of wear, and 221. * the hero can distinguish this from an object that is 222. * actually proof against damage. 223. */ 224. if (otmp->oerodeproof) { 225. otmp->rknown = TRUE; 226. if (victim == &youmonst) 227. update_inventory(); 228. } 229. 230. return ER_NOTHING; 231. } else if (erosion < MAX_ERODE) { 232. const char *adverb = (erosion + 1 == MAX_ERODE) 233. ? " completely" 234. : erosion ? " further" : ""; 235. 236. if (uvictim || vismon || visobj) 237. pline("%s %s %s%s!", 238. uvictim ? "Your" 239. : !vismon ? "The" /* visobj */ 240. : s_suffix(Monnam(victim)), 241. ostr, vtense(ostr, action[type]), adverb); 242. 243. if (ef_flags & EF_PAY) 244. costly_alteration(otmp, cost_type); 245. 246. if (is_primary) 247. otmp->oeroded++; 248. else 249. otmp->oeroded2++; 250. 251. if (victim == &youmonst) 252. update_inventory(); 253. 254. return ER_DAMAGED; 255. } else if (ef_flags & EF_DESTROY) { 256. if (uvictim || vismon || visobj) 257. pline("%s %s %s away!", 258. uvictim ? "Your" 259. : !vismon ? "The" /* visobj */ 260. : s_suffix(Monnam(victim)), 261. ostr, vtense(ostr, action[type])); 262. 263. if (ef_flags & EF_PAY) 264. costly_alteration(otmp, cost_type); 265. 266. setnotworn(otmp); 267. delobj(otmp); 268. return ER_DESTROYED; 269. } else { 270. if (flags.verbose && print) { 271. if (uvictim) 272. Your("%s %s completely %s.", 273. ostr, vtense(ostr, Blind ? "feel" : "look"), msg[type]); 274. else if (vismon || visobj) 275. pline("%s %s %s completely %s.", 276. !vismon ? "The" : s_suffix(Monnam(victim)), 277. ostr, vtense(ostr, "look"), msg[type]); 278. } 279. return ER_NOTHING; 280. } 281. } 282.
grease_protect
283. /* Protect an item from erosion with grease. Returns TRUE if the grease 284. * wears off. 285. */ 286. boolean 287. grease_protect(otmp, ostr, victim) 288. register struct obj *otmp; 289. const char *ostr; 290. struct monst *victim; 291. { 292. static const char txt[] = "protected by the layer of grease!"; 293. boolean vismon = victim && (victim != &youmonst) && canseemon(victim); 294. 295. if (ostr) { 296. if (victim == &youmonst) 297. Your("%s %s %s", ostr, vtense(ostr, "are"), txt); 298. else if (vismon) 299. pline("%s's %s %s %s", Monnam(victim), 300. ostr, vtense(ostr, "are"), txt); 301. } else if (victim == &youmonst || vismon) { 302. pline("%s %s", Yobjnam2(otmp, "are"), txt); 303. } 304. if (!rn2(2)) { 305. otmp->greased = 0; 306. if (carried(otmp)) { 307. pline_The("grease dissolves."); 308. update_inventory(); 309. } 310. return TRUE; 311. } 312. return FALSE; 313. } 314.
maketrap
315. struct trap * 316. maketrap(x, y, typ) 317. int x, y, typ; 318. { 319. static union vlaunchinfo zero_vl; 320. boolean oldplace; 321. struct trap *ttmp; 322. struct rm *lev = &levl[x][y]; 323. 324. if ((ttmp = t_at(x, y)) != 0) { 325. if (ttmp->ttyp == MAGIC_PORTAL || ttmp->ttyp == VIBRATING_SQUARE) 326. return (struct trap *) 0; 327. oldplace = TRUE; 328. if (u.utrap && x == u.ux && y == u.uy 329. && ((u.utraptype == TT_BEARTRAP && typ != BEAR_TRAP) 330. || (u.utraptype == TT_WEB && typ != WEB) 331. || (u.utraptype == TT_PIT && typ != PIT 332. && typ != SPIKED_PIT))) 333. u.utrap = 0; 334. /* old <tx,ty> remain valid */ 335. } else if (IS_FURNITURE(lev->typ) 336. && (!IS_GRAVE(lev->typ) || (typ != PIT && typ != HOLE))) { 337. /* no trap on top of furniture (caller usually screens the 338. location to inhibit this, but wizard mode wishing doesn't) */ 339. return (struct trap *) 0; 340. } else { 341. oldplace = FALSE; 342. ttmp = newtrap(); 343. (void) memset((genericptr_t)ttmp, 0, sizeof(struct trap)); 344. ttmp->ntrap = 0; 345. ttmp->tx = x; 346. ttmp->ty = y; 347. } 348. /* [re-]initialize all fields except ntrap (handled below) and <tx,ty> */ 349. ttmp->vl = zero_vl; 350. ttmp->launch.x = ttmp->launch.y = -1; /* force error if used before set */ 351. ttmp->dst.dnum = ttmp->dst.dlevel = -1; 352. ttmp->madeby_u = 0; 353. ttmp->once = 0; 354. ttmp->tseen = (typ == HOLE); /* hide non-holes */ 355. ttmp->ttyp = typ; 356. 357. switch (typ) { 358. case SQKY_BOARD: { 359. int tavail[12], tpick[12], tcnt = 0, k; 360. struct trap *t; 361. 362. for (k = 0; k < 12; ++k) 363. tavail[k] = tpick[k] = 0; 364. for (t = ftrap; t; t = t->ntrap) 365. if (t->ttyp == SQKY_BOARD && t != ttmp) 366. tavail[t->tnote] = 1; 367. /* now populate tpick[] with the available indices */ 368. for (k = 0; k < 12; ++k) 369. if (tavail[k] == 0) 370. tpick[tcnt++] = k; 371. /* choose an unused note; if all are in use, pick a random one */ 372. ttmp->tnote = (short) ((tcnt > 0) ? tpick[rn2(tcnt)] : rn2(12)); 373. break; 374. } 375. case STATUE_TRAP: { /* create a "living" statue */ 376. struct monst *mtmp; 377. struct obj *otmp, *statue; 378. struct permonst *mptr; 379. int trycount = 10; 380. 381. do { /* avoid ultimately hostile co-aligned unicorn */ 382. mptr = &mons[rndmonnum()]; 383. } while (--trycount > 0 && is_unicorn(mptr) 384. && sgn(u.ualign.type) == sgn(mptr->maligntyp)); 385. statue = mkcorpstat(STATUE, (struct monst *) 0, mptr, x, y, 386. CORPSTAT_NONE); 387. mtmp = makemon(&mons[statue->corpsenm], 0, 0, MM_NOCOUNTBIRTH); 388. if (!mtmp) 389. break; /* should never happen */ 390. while (mtmp->minvent) { 391. otmp = mtmp->minvent; 392. otmp->owornmask = 0; 393. obj_extract_self(otmp); 394. (void) add_to_container(statue, otmp); 395. } 396. statue->owt = weight(statue); 397. mongone(mtmp); 398. break; 399. } 400. case ROLLING_BOULDER_TRAP: /* boulder will roll towards trigger */ 401. (void) mkroll_launch(ttmp, x, y, BOULDER, 1L); 402. break; 403. case PIT: 404. case SPIKED_PIT: 405. ttmp->conjoined = 0; 406. /*FALLTHRU*/ 407. case HOLE: 408. case TRAPDOOR: 409. if (*in_rooms(x, y, SHOPBASE) 410. && (typ == HOLE || typ == TRAPDOOR 411. || IS_DOOR(lev->typ) || IS_WALL(lev->typ))) 412. add_damage(x, y, /* schedule repair */ 413. ((IS_DOOR(lev->typ) || IS_WALL(lev->typ)) 414. && !context.mon_moving) 415. ? SHOP_HOLE_COST 416. : 0L); 417. lev->doormask = 0; /* subsumes altarmask, icedpool... */ 418. if (IS_ROOM(lev->typ)) /* && !IS_AIR(lev->typ) */ 419. lev->typ = ROOM; 420. /* 421. * some cases which can happen when digging 422. * down while phazing thru solid areas 423. */ 424. else if (lev->typ == STONE || lev->typ == SCORR) 425. lev->typ = CORR; 426. else if (IS_WALL(lev->typ) || lev->typ == SDOOR) 427. lev->typ = level.flags.is_maze_lev 428. ? ROOM 429. : level.flags.is_cavernous_lev ? CORR : DOOR; 430. 431. unearth_objs(x, y); 432. break; 433. } 434. 435. if (!oldplace) { 436. ttmp->ntrap = ftrap; 437. ftrap = ttmp; 438. } else { 439. /* oldplace; 440. it shouldn't be possible to override a sokoban pit or hole 441. with some other trap, but we'll check just to be safe */ 442. if (Sokoban) 443. maybe_finish_sokoban(); 444. } 445. return ttmp; 446. } 447.
fall_through
448. void 449. fall_through(td) 450. boolean td; /* td == TRUE : trap door or hole */ 451. { 452. d_level dtmp; 453. char msgbuf[BUFSZ]; 454. const char *dont_fall = 0; 455. int newlevel, bottom; 456. 457. /* we'll fall even while levitating in Sokoban; otherwise, if we 458. won't fall and won't be told that we aren't falling, give up now */ 459. if (Blind && Levitation && !Sokoban) 460. return; 461. 462. bottom = dunlevs_in_dungeon(&u.uz); 463. /* when in the upper half of the quest, don't fall past the 464. middle "quest locate" level if hero hasn't been there yet */ 465. if (In_quest(&u.uz)) { 466. int qlocate_depth = qlocate_level.dlevel; 467. 468. /* deepest reached < qlocate implies current < qlocate */ 469. if (dunlev_reached(&u.uz) < qlocate_depth) 470. bottom = qlocate_depth; /* early cut-off */ 471. } 472. newlevel = dunlev(&u.uz); /* current level */ 473. do { 474. newlevel++; 475. } while (!rn2(4) && newlevel < bottom); 476. 477. if (td) { 478. struct trap *t = t_at(u.ux, u.uy); 479. 480. feeltrap(t); 481. if (!Sokoban) { 482. if (t->ttyp == TRAPDOOR) 483. pline("A trap door opens up under you!"); 484. else 485. pline("There's a gaping hole under you!"); 486. } 487. } else 488. pline_The("%s opens up under you!", surface(u.ux, u.uy)); 489. 490. if (Sokoban && Can_fall_thru(&u.uz)) 491. ; /* KMH -- You can't escape the Sokoban level traps */ 492. else if (Levitation || u.ustuck 493. || (!Can_fall_thru(&u.uz) && !levl[u.ux][u.uy].candig) || Flying 494. || is_clinger(youmonst.data) 495. || (Inhell && !u.uevent.invoked && newlevel == bottom)) { 496. dont_fall = "don't fall in."; 497. } else if (youmonst.data->msize >= MZ_HUGE) { 498. dont_fall = "don't fit through."; 499. } else if (!next_to_u()) { 500. dont_fall = "are jerked back by your pet!"; 501. } 502. if (dont_fall) { 503. You1(dont_fall); 504. /* hero didn't fall through, but any objects here might */ 505. impact_drop((struct obj *) 0, u.ux, u.uy, 0); 506. if (!td) { 507. display_nhwindow(WIN_MESSAGE, FALSE); 508. pline_The("opening under you closes up."); 509. } 510. return; 511. } 512. 513. if (*u.ushops) 514. shopdig(1); 515. if (Is_stronghold(&u.uz)) { 516. find_hell(&dtmp); 517. } else { 518. int dist = newlevel - dunlev(&u.uz); 519. dtmp.dnum = u.uz.dnum; 520. dtmp.dlevel = newlevel; 521. if (dist > 1) 522. You("fall down a %s%sshaft!", dist > 3 ? "very " : "", 523. dist > 2 ? "deep " : ""); 524. } 525. if (!td) 526. Sprintf(msgbuf, "The hole in the %s above you closes up.", 527. ceiling(u.ux, u.uy)); 528. 529. schedule_goto(&dtmp, FALSE, TRUE, 0, (char *) 0, 530. !td ? msgbuf : (char *) 0); 531. } 532.
animate_statue
533. /* 534. * Animate the given statue. May have been via shatter attempt, trap, 535. * or stone to flesh spell. Return a monster if successfully animated. 536. * If the monster is animated, the object is deleted. If fail_reason 537. * is non-null, then fill in the reason for failure (or success). 538. * 539. * The cause of animation is: 540. * 541. * ANIMATE_NORMAL - hero "finds" the monster 542. * ANIMATE_SHATTER - hero tries to destroy the statue 543. * ANIMATE_SPELL - stone to flesh spell hits the statue 544. * 545. * Perhaps x, y is not needed if we can use get_obj_location() to find 546. * the statue's location... ??? 547. * 548. * Sequencing matters: 549. * create monster; if it fails, give up with statue intact; 550. * give "statue comes to life" message; 551. * if statue belongs to shop, have shk give "you owe" message; 552. * transfer statue contents to monster (after stolen_value()); 553. * delete statue. 554. * [This ordering means that if the statue ends up wearing a cloak of 555. * invisibility or a mummy wrapping, the visibility checks might be 556. * wrong, but to avoid that we'd have to clone the statue contents 557. * first in order to give them to the monster before checking their 558. * shop status--it's not worth the hassle.] 559. */ 560. struct monst * 561. animate_statue(statue, x, y, cause, fail_reason) 562. struct obj *statue; 563. xchar x, y; 564. int cause; 565. int *fail_reason; 566. { 567. int mnum = statue->corpsenm; 568. struct permonst *mptr = &mons[mnum]; 569. struct monst *mon = 0, *shkp; 570. struct obj *item; 571. coord cc; 572. boolean historic = (Role_if(PM_ARCHEOLOGIST) 573. && (statue->spe & STATUE_HISTORIC) != 0), 574. golem_xform = FALSE, use_saved_traits; 575. const char *comes_to_life; 576. char statuename[BUFSZ], tmpbuf[BUFSZ]; 577. static const char historic_statue_is_gone[] = 578. "that the historic statue is now gone"; 579. 580. if (cant_revive(&mnum, TRUE, statue)) { 581. /* mnum has changed; we won't be animating this statue as itself */ 582. if (mnum != PM_DOPPELGANGER) 583. mptr = &mons[mnum]; 584. use_saved_traits = FALSE; 585. } else if (is_golem(mptr) && cause == ANIMATE_SPELL) { 586. /* statue of any golem hit by stone-to-flesh becomes flesh golem */ 587. golem_xform = (mptr != &mons[PM_FLESH_GOLEM]); 588. mnum = PM_FLESH_GOLEM; 589. mptr = &mons[PM_FLESH_GOLEM]; 590. use_saved_traits = (has_omonst(statue) && !golem_xform); 591. } else { 592. use_saved_traits = has_omonst(statue); 593. } 594. 595. if (use_saved_traits) { 596. /* restore a petrified monster */ 597. cc.x = x, cc.y = y; 598. mon = montraits(statue, &cc); 599. if (mon && mon->mtame && !mon->isminion) 600. wary_dog(mon, TRUE); 601. } else { 602. /* statues of unique monsters from bones or wishing end 603. up here (cant_revive() sets mnum to be doppelganger; 604. mptr reflects the original form for use by newcham()) */ 605. if ((mnum == PM_DOPPELGANGER && mptr != &mons[PM_DOPPELGANGER]) 606. /* block quest guards from other roles */ 607. || (mptr->msound == MS_GUARDIAN 608. && quest_info(MS_GUARDIAN) != mnum)) { 609. mon = makemon(&mons[PM_DOPPELGANGER], x, y, 610. NO_MINVENT | MM_NOCOUNTBIRTH | MM_ADJACENTOK); 611. /* if hero has protection from shape changers, cham field will 612. be NON_PM; otherwise, set form to match the statue */ 613. if (mon && mon->cham >= LOW_PM) 614. (void) newcham(mon, mptr, FALSE, FALSE); 615. } else 616. mon = makemon(mptr, x, y, (cause == ANIMATE_SPELL) 617. ? (NO_MINVENT | MM_ADJACENTOK) 618. : NO_MINVENT); 619. } 620. 621. if (!mon) { 622. if (fail_reason) 623. *fail_reason = unique_corpstat(&mons[statue->corpsenm]) 624. ? AS_MON_IS_UNIQUE 625. : AS_NO_MON; 626. return (struct monst *) 0; 627. } 628. 629. /* a non-montraits() statue might specify gender */ 630. if (statue->spe & STATUE_MALE) 631. mon->female = FALSE; 632. else if (statue->spe & STATUE_FEMALE) 633. mon->female = TRUE; 634. /* if statue has been named, give same name to the monster */ 635. if (has_oname(statue) && !unique_corpstat(mon->data)) 636. mon = christen_monst(mon, ONAME(statue)); 637. /* mimic statue becomes seen mimic; other hiders won't be hidden */ 638. if (mon->m_ap_type) 639. seemimic(mon); 640. else 641. mon->mundetected = FALSE; 642. mon->msleeping = 0; 643. if (cause == ANIMATE_NORMAL || cause == ANIMATE_SHATTER) { 644. /* trap always releases hostile monster */ 645. mon->mtame = 0; /* (might be petrified pet tossed onto trap) */ 646. mon->mpeaceful = 0; 647. set_malign(mon); 648. } 649. 650. comes_to_life = !canspotmon(mon) 651. ? "disappears" 652. : golem_xform 653. ? "turns into flesh" 654. : (nonliving(mon->data) || is_vampshifter(mon)) 655. ? "moves" 656. : "comes to life"; 657. if ((x == u.ux && y == u.uy) || cause == ANIMATE_SPELL) { 658. /* "the|your|Manlobbi's statue [of a wombat]" */ 659. shkp = shop_keeper(*in_rooms(mon->mx, mon->my, SHOPBASE)); 660. Sprintf(statuename, "%s%s", shk_your(tmpbuf, statue), 661. (cause == ANIMATE_SPELL 662. /* avoid "of a shopkeeper" if it's Manlobbi himself 663. (if carried, it can't be unpaid--hence won't be 664. described as "Manlobbi's statue"--because there 665. wasn't any living shk when statue was picked up) */ 666. && (mon != shkp || carried(statue))) 667. ? xname(statue) 668. : "statue"); 669. pline("%s %s!", upstart(statuename), comes_to_life); 670. } else if (Hallucination) { /* They don't know it's a statue */ 671. pline_The("%s suddenly seems more animated.", rndmonnam((char *) 0)); 672. } else if (cause == ANIMATE_SHATTER) { 673. if (cansee(x, y)) 674. Sprintf(statuename, "%s%s", shk_your(tmpbuf, statue), 675. xname(statue)); 676. else 677. Strcpy(statuename, "a statue"); 678. pline("Instead of shattering, %s suddenly %s!", statuename, 679. comes_to_life); 680. } else { /* cause == ANIMATE_NORMAL */ 681. You("find %s posing as a statue.", 682. canspotmon(mon) ? a_monnam(mon) : something); 683. if (!canspotmon(mon) && Blind) 684. map_invisible(x, y); 685. stop_occupation(); 686. } 687. 688. /* if this isn't caused by a monster using a wand of striking, 689. there might be consequences for the hero */ 690. if (!context.mon_moving) { 691. /* if statue is owned by a shop, hero will have to pay for it; 692. stolen_value gives a message (about debt or use of credit) 693. which refers to "it" so needs to follow a message describing 694. the object ("the statue comes to life" one above) */ 695. if (cause != ANIMATE_NORMAL && costly_spot(x, y) 696. && (carried(statue) ? statue->unpaid : !statue->no_charge) 697. && (shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) != 0 698. /* avoid charging for Manlobbi's statue of Manlobbi 699. if stone-to-flesh is used on petrified shopkeep */ 700. && mon != shkp) 701. (void) stolen_value(statue, x, y, (boolean) shkp->mpeaceful, 702. FALSE); 703. 704. if (historic) { 705. You_feel("guilty %s.", historic_statue_is_gone); 706. adjalign(-1); 707. } 708. } else { 709. if (historic && cansee(x, y)) 710. You_feel("regret %s.", historic_statue_is_gone); 711. /* no alignment penalty */ 712. } 713. 714. /* transfer any statue contents to monster's inventory */ 715. while ((item = statue->cobj) != 0) { 716. obj_extract_self(item); 717. (void) mpickobj(mon, item); 718. } 719. m_dowear(mon, TRUE); 720. /* in case statue is wielded and hero zaps stone-to-flesh at self */ 721. if (statue->owornmask) 722. remove_worn_item(statue, TRUE); 723. /* statue no longer exists */ 724. delobj(statue); 725. 726. /* avoid hiding under nothing */ 727. if (x == u.ux && y == u.uy && Upolyd && hides_under(youmonst.data) 728. && !OBJ_AT(x, y)) 729. u.uundetected = 0; 730. 731. if (fail_reason) 732. *fail_reason = AS_OK; 733. return mon; 734. } 735.
activate_statue_trap
736. /* 737. * You've either stepped onto a statue trap's location or you've triggered a 738. * statue trap by searching next to it or by trying to break it with a wand 739. * or pick-axe. 740. */ 741. struct monst * 742. activate_statue_trap(trap, x, y, shatter) 743. struct trap *trap; 744. xchar x, y; 745. boolean shatter; 746. { 747. struct monst *mtmp = (struct monst *) 0; 748. struct obj *otmp = sobj_at(STATUE, x, y); 749. int fail_reason; 750. 751. /* 752. * Try to animate the first valid statue. Stop the loop when we 753. * actually create something or the failure cause is not because 754. * the mon was unique. 755. */ 756. deltrap(trap); 757. while (otmp) { 758. mtmp = animate_statue(otmp, x, y, 759. shatter ? ANIMATE_SHATTER : ANIMATE_NORMAL, 760. &fail_reason); 761. if (mtmp || fail_reason != AS_MON_IS_UNIQUE) 762. break; 763. 764. otmp = nxtobj(otmp, STATUE, TRUE); 765. } 766. 767. feel_newsym(x, y); 768. return mtmp; 769. } 770.
keep_saddle_with_steedcorpse
771. STATIC_OVL boolean 772. keep_saddle_with_steedcorpse(steed_mid, objchn, saddle) 773. unsigned steed_mid; 774. struct obj *objchn, *saddle; 775. { 776. if (!saddle) 777. return FALSE; 778. while (objchn) { 779. if (objchn->otyp == CORPSE && has_omonst(objchn)) { 780. struct monst *mtmp = OMONST(objchn); 781. 782. if (mtmp->m_id == steed_mid) { 783. /* move saddle */ 784. xchar x, y; 785. if (get_obj_location(objchn, &x, &y, 0)) { 786. obj_extract_self(saddle); 787. place_object(saddle, x, y); 788. stackobj(saddle); 789. } 790. return TRUE; 791. } 792. } 793. if (Has_contents(objchn) 794. && keep_saddle_with_steedcorpse(steed_mid, objchn->cobj, saddle)) 795. return TRUE; 796. objchn = objchn->nobj; 797. } 798. return FALSE; 799. } 800.
mu_maybe_destroy_web
801. /* monster or you go through and possibly destroy a web. 802. return TRUE if could go through. */ 803. boolean 804. mu_maybe_destroy_web(mtmp, domsg, trap) 805. struct monst *mtmp; 806. boolean domsg; 807. struct trap *trap; 808. { 809. boolean isyou = (mtmp == &youmonst); 810. struct permonst *mptr = mtmp->data; 811. if (amorphous(mptr) || is_whirly(mptr) || flaming(mptr) 812. || unsolid(mptr) || mptr == &mons[PM_GELATINOUS_CUBE]) { 813. xchar x = trap->tx; 814. xchar y = trap->ty; 815. if (flaming(mptr) || acidic(mptr)) { 816. if (domsg) { 817. if (isyou) 818. You("%s %s spider web!", 819. (flaming(mptr)) ? "burn" : "dissolve", 820. a_your[trap->madeby_u]); 821. else 822. pline("%s %s %s spider web!", Monnam(mtmp), 823. (flaming(mptr)) ? "burns" : "dissolves", 824. a_your[trap->madeby_u]); 825. } 826. deltrap(trap); 827. newsym(x, y); 828. return TRUE; 829. } 830. if (domsg) { 831. if (isyou) 832. You("flow through %s spider web.", a_your[trap->madeby_u]); 833. else { 834. pline("%s flows through %s spider web.", Monnam(mtmp), 835. a_your[trap->madeby_u]); 836. seetrap(trap); 837. } 838. } 839. return TRUE; 840. } 841. return FALSE; 842. } 843.
dotrap
844. void 845. dotrap(trap, trflags) 846. register struct trap *trap; 847. unsigned trflags; 848. { 849. register int ttype = trap->ttyp; 850. struct obj *otmp; 851. boolean already_seen = trap->tseen, 852. forcetrap = (trflags & FORCETRAP) != 0, 853. webmsgok = (trflags & NOWEBMSG) == 0, 854. forcebungle = (trflags & FORCEBUNGLE) != 0, 855. plunged = (trflags & TOOKPLUNGE) != 0, 856. viasitting = (trflags & VIASITTING) != 0, 857. conj_pit = conjoined_pits(trap, t_at(u.ux0, u.uy0), TRUE), 858. adj_pit = adj_nonconjoined_pit(trap); 859. int oldumort; 860. int steed_article = ARTICLE_THE; 861. 862. nomul(0); 863. 864. /* KMH -- You can't escape the Sokoban level traps */ 865. if (Sokoban && (ttype == PIT || ttype == SPIKED_PIT 866. || ttype == HOLE || ttype == TRAPDOOR)) { 867. /* The "air currents" message is still appropriate -- even when 868. * the hero isn't flying or levitating -- because it conveys the 869. * reason why the player cannot escape the trap with a dexterity 870. * check, clinging to the ceiling, etc. 871. */ 872. pline("Air currents pull you down into %s %s!", 873. a_your[trap->madeby_u], 874. defsyms[trap_to_defsym(ttype)].explanation); 875. /* then proceed to normal trap effect */ 876. } else if (already_seen && !forcetrap) { 877. if ((Levitation || (Flying && !plunged)) 878. && (ttype == PIT || ttype == SPIKED_PIT || ttype == HOLE 879. || ttype == BEAR_TRAP)) { 880. You("%s over %s %s.", Levitation ? "float" : "fly", 881. a_your[trap->madeby_u], 882. defsyms[trap_to_defsym(ttype)].explanation); 883. return; 884. } 885. if (!Fumbling && ttype != MAGIC_PORTAL && ttype != VIBRATING_SQUARE 886. && ttype != ANTI_MAGIC && !forcebungle && !plunged 887. && !conj_pit && !adj_pit 888. && (!rn2(5) || ((ttype == PIT || ttype == SPIKED_PIT) 889. && is_clinger(youmonst.data)))) { 890. You("escape %s %s.", (ttype == ARROW_TRAP && !trap->madeby_u) 891. ? "an" 892. : a_your[trap->madeby_u], 893. defsyms[trap_to_defsym(ttype)].explanation); 894. return; 895. } 896. } 897. 898. if (u.usteed) { 899. u.usteed->mtrapseen |= (1 << (ttype - 1)); 900. /* suppress article in various steed messages when using its 901. name (which won't occur when hallucinating) */ 902. if (has_mname(u.usteed) && !Hallucination) 903. steed_article = ARTICLE_NONE; 904. } 905. 906. switch (ttype) { 907. case ARROW_TRAP: 908. if (trap->once && trap->tseen && !rn2(15)) { 909. You_hear("a loud click!"); 910. deltrap(trap); 911. newsym(u.ux, u.uy); 912. break; 913. } 914. trap->once = 1; 915. seetrap(trap); 916. pline("An arrow shoots out at you!"); 917. otmp = mksobj(ARROW, TRUE, FALSE); 918. otmp->quan = 1L; 919. otmp->owt = weight(otmp); 920. otmp->opoisoned = 0; 921. if (u.usteed && !rn2(2) && steedintrap(trap, otmp)) { /* nothing */ 922. ; 923. } else if (thitu(8, dmgval(otmp, &youmonst), &otmp, "arrow")) { 924. if (otmp) 925. obfree(otmp, (struct obj *) 0); 926. } else { 927. place_object(otmp, u.ux, u.uy); 928. if (!Blind) 929. otmp->dknown = 1; 930. stackobj(otmp); 931. newsym(u.ux, u.uy); 932. } 933. break; 934. 935. case DART_TRAP: 936. if (trap->once && trap->tseen && !rn2(15)) { 937. You_hear("a soft click."); 938. deltrap(trap); 939. newsym(u.ux, u.uy); 940. break; 941. } 942. trap->once = 1; 943. seetrap(trap); 944. pline("A little dart shoots out at you!"); 945. otmp = mksobj(DART, TRUE, FALSE); 946. otmp->quan = 1L; 947. otmp->owt = weight(otmp); 948. if (!rn2(6)) 949. otmp->opoisoned = 1; 950. oldumort = u.umortality; 951. if (u.usteed && !rn2(2) && steedintrap(trap, otmp)) { /* nothing */ 952. ; 953. } else if (thitu(7, dmgval(otmp, &youmonst), &otmp, "little dart")) { 954. if (otmp) { 955. if (otmp->opoisoned) 956. poisoned("dart", A_CON, "little dart", 957. /* if damage triggered life-saving, 958. poison is limited to attrib loss */ 959. (u.umortality > oldumort) ? 0 : 10, TRUE); 960. obfree(otmp, (struct obj *) 0); 961. } 962. } else { 963. place_object(otmp, u.ux, u.uy); 964. if (!Blind) 965. otmp->dknown = 1; 966. stackobj(otmp); 967. newsym(u.ux, u.uy); 968. } 969. break; 970. 971. case ROCKTRAP: 972. if (trap->once && trap->tseen && !rn2(15)) { 973. pline("A trap door in %s opens, but nothing falls out!", 974. the(ceiling(u.ux, u.uy))); 975. deltrap(trap); 976. newsym(u.ux, u.uy); 977. } else { 978. int dmg = d(2, 6); /* should be std ROCK dmg? */ 979. 980. trap->once = 1; 981. feeltrap(trap); 982. otmp = mksobj_at(ROCK, u.ux, u.uy, TRUE, FALSE); 983. otmp->quan = 1L; 984. otmp->owt = weight(otmp); 985. 986. pline("A trap door in %s opens and %s falls on your %s!", 987. the(ceiling(u.ux, u.uy)), an(xname(otmp)), body_part(HEAD)); 988. 989. if (uarmh) { 990. if (is_metallic(uarmh)) { 991. pline("Fortunately, you are wearing a hard helmet."); 992. dmg = 2; 993. } else if (flags.verbose) { 994. pline("%s does not protect you.", Yname2(uarmh)); 995. } 996. } 997. 998. if (!Blind) 999. otmp->dknown = 1; 1000. stackobj(otmp); 1001. newsym(u.ux, u.uy); /* map the rock */ 1002. 1003. losehp(Maybe_Half_Phys(dmg), "falling rock", KILLED_BY_AN); 1004. exercise(A_STR, FALSE); 1005. } 1006. break; 1007. 1008. case SQKY_BOARD: /* stepped on a squeaky board */ 1009. if ((Levitation || Flying) && !forcetrap) { 1010. if (!Blind) { 1011. seetrap(trap); 1012. if (Hallucination) 1013. You("notice a crease in the linoleum."); 1014. else 1015. You("notice a loose board below you."); 1016. } 1017. } else { 1018. seetrap(trap); 1019. pline("A board beneath you %s%s%s.", 1020. Deaf ? "vibrates" : "squeaks ", 1021. Deaf ? "" : trapnote(trap, 0), Deaf ? "" : " loudly"); 1022. wake_nearby(); 1023. } 1024. break; 1025. 1026. case BEAR_TRAP: { 1027. int dmg = d(2, 4); 1028. 1029. if ((Levitation || Flying) && !forcetrap) 1030. break; 1031. feeltrap(trap); 1032. if (amorphous(youmonst.data) || is_whirly(youmonst.data) 1033. || unsolid(youmonst.data)) { 1034. pline("%s bear trap closes harmlessly through you.", 1035. A_Your[trap->madeby_u]); 1036. break; 1037. } 1038. if (!u.usteed && youmonst.data->msize <= MZ_SMALL) { 1039. pline("%s bear trap closes harmlessly over you.", 1040. A_Your[trap->madeby_u]); 1041. break; 1042. } 1043. u.utrap = rn1(4, 4); 1044. u.utraptype = TT_BEARTRAP; 1045. if (u.usteed) { 1046. pline("%s bear trap closes on %s %s!", A_Your[trap->madeby_u], 1047. s_suffix(mon_nam(u.usteed)), mbodypart(u.usteed, FOOT)); 1048. if (thitm(0, u.usteed, (struct obj *) 0, dmg, FALSE)) 1049. u.utrap = 0; /* steed died, hero not trapped */ 1050. } else { 1051. pline("%s bear trap closes on your %s!", A_Your[trap->madeby_u], 1052. body_part(FOOT)); 1053. set_wounded_legs(rn2(2) ? RIGHT_SIDE : LEFT_SIDE, rn1(10, 10)); 1054. if (u.umonnum == PM_OWLBEAR || u.umonnum == PM_BUGBEAR) 1055. You("howl in anger!"); 1056. losehp(Maybe_Half_Phys(dmg), "bear trap", KILLED_BY_AN); 1057. } 1058. exercise(A_DEX, FALSE); 1059. break; 1060. } 1061. 1062. case SLP_GAS_TRAP: 1063. seetrap(trap); 1064. if (Sleep_resistance || breathless(youmonst.data)) { 1065. You("are enveloped in a cloud of gas!"); 1066. } else { 1067. pline("A cloud of gas puts you to sleep!"); 1068. fall_asleep(-rnd(25), TRUE); 1069. } 1070. (void) steedintrap(trap, (struct obj *) 0); 1071. break; 1072. 1073. case RUST_TRAP: 1074. seetrap(trap); 1075. 1076. /* Unlike monsters, traps cannot aim their rust attacks at 1077. * you, so instead of looping through and taking either the 1078. * first rustable one or the body, we take whatever we get, 1079. * even if it is not rustable. 1080. */ 1081. switch (rn2(5)) { 1082. case 0: 1083. pline("%s you on the %s!", A_gush_of_water_hits, body_part(HEAD)); 1084. (void) water_damage(uarmh, helm_simple_name(uarmh), TRUE); 1085. break; 1086. case 1: 1087. pline("%s your left %s!", A_gush_of_water_hits, body_part(ARM)); 1088. if (water_damage(uarms, "shield", TRUE) != ER_NOTHING) 1089. break; 1090. if (u.twoweap || (uwep && bimanual(uwep))) 1091. (void) water_damage(u.twoweap ? uswapwep : uwep, 0, TRUE); 1092. glovecheck: 1093. (void) water_damage(uarmg, "gauntlets", TRUE); 1094. /* Not "metal gauntlets" since it gets called 1095. * even if it's leather for the message 1096. */ 1097. break; 1098. case 2: 1099. pline("%s your right %s!", A_gush_of_water_hits, body_part(ARM)); 1100. (void) water_damage(uwep, 0, TRUE); 1101. goto glovecheck; 1102. default: 1103. pline("%s you!", A_gush_of_water_hits); 1104. for (otmp = invent; otmp; otmp = otmp->nobj) 1105. if (otmp->lamplit && otmp != uwep 1106. && (otmp != uswapwep || !u.twoweap)) 1107. (void) snuff_lit(otmp); 1108. if (uarmc) 1109. (void) water_damage(uarmc, cloak_simple_name(uarmc), TRUE); 1110. else if (uarm) 1111. (void) water_damage(uarm, suit_simple_name(uarm), TRUE); 1112. else if (uarmu) 1113. (void) water_damage(uarmu, "shirt", TRUE); 1114. } 1115. update_inventory(); 1116. 1117. if (u.umonnum == PM_IRON_GOLEM) { 1118. int dam = u.mhmax; 1119. 1120. You("are covered with rust!"); 1121. losehp(Maybe_Half_Phys(dam), "rusting away", KILLED_BY); 1122. } else if (u.umonnum == PM_GREMLIN && rn2(3)) { 1123. (void) split_mon(&youmonst, (struct monst *) 0); 1124. } 1125. 1126. break; 1127. 1128. case FIRE_TRAP: 1129. seetrap(trap); 1130. dofiretrap((struct obj *) 0); 1131. break; 1132. 1133. case PIT: 1134. case SPIKED_PIT: 1135. /* KMH -- You can't escape the Sokoban level traps */ 1136. if (!Sokoban && (Levitation || (Flying && !plunged))) 1137. break; 1138. feeltrap(trap); 1139. if (!Sokoban && is_clinger(youmonst.data) && !plunged) { 1140. if (trap->tseen) { 1141. You_see("%s %spit below you.", a_your[trap->madeby_u], 1142. ttype == SPIKED_PIT ? "spiked " : ""); 1143. } else { 1144. pline("%s pit %sopens up under you!", A_Your[trap->madeby_u], 1145. ttype == SPIKED_PIT ? "full of spikes " : ""); 1146. You("don't fall in!"); 1147. } 1148. break; 1149. } 1150. if (!Sokoban) { 1151. char verbbuf[BUFSZ]; 1152. 1153. if (u.usteed) { 1154. if ((trflags & RECURSIVETRAP) != 0) 1155. Sprintf(verbbuf, "and %s fall", 1156. x_monnam(u.usteed, steed_article, (char *) 0, 1157. SUPPRESS_SADDLE, FALSE)); 1158. else 1159. Sprintf(verbbuf, "lead %s", 1160. x_monnam(u.usteed, steed_article, "poor", 1161. SUPPRESS_SADDLE, FALSE)); 1162. } else if (conj_pit) { 1163. You("move into an adjacent pit."); 1164. } else if (adj_pit) { 1165. You("stumble over debris%s.", 1166. !rn2(5) ? " between the pits" : ""); 1167. } else { 1168. Strcpy(verbbuf, 1169. !plunged ? "fall" : (Flying ? "dive" : "plunge")); 1170. You("%s into %s pit!", verbbuf, a_your[trap->madeby_u]); 1171. } 1172. } 1173. /* wumpus reference */ 1174. if (Role_if(PM_RANGER) && !trap->madeby_u && !trap->once 1175. && In_quest(&u.uz) && Is_qlocate(&u.uz)) { 1176. pline("Fortunately it has a bottom after all..."); 1177. trap->once = 1; 1178. } else if (u.umonnum == PM_PIT_VIPER || u.umonnum == PM_PIT_FIEND) { 1179. pline("How pitiful. Isn't that the pits?"); 1180. } 1181. if (ttype == SPIKED_PIT) { 1182. const char *predicament = "on a set of sharp iron spikes"; 1183. 1184. if (u.usteed) { 1185. pline("%s %s %s!", 1186. upstart(x_monnam(u.usteed, steed_article, "poor", 1187. SUPPRESS_SADDLE, FALSE)), 1188. conj_pit ? "steps" : "lands", predicament); 1189. } else 1190. You("%s %s!", conj_pit ? "step" : "land", predicament); 1191. } 1192. u.utrap = rn1(6, 2); 1193. u.utraptype = TT_PIT; 1194. if (!steedintrap(trap, (struct obj *) 0)) { 1195. if (ttype == SPIKED_PIT) { 1196. oldumort = u.umortality; 1197. losehp(Maybe_Half_Phys(rnd(conj_pit ? 4 : adj_pit ? 6 : 10)), 1198. plunged 1199. ? "deliberately plunged into a pit of iron spikes" 1200. : conj_pit ? "stepped into a pit of iron spikes" 1201. : adj_pit ? "stumbled into a pit of iron spikes" 1202. : "fell into a pit of iron spikes", 1203. NO_KILLER_PREFIX); 1204. if (!rn2(6)) 1205. poisoned("spikes", A_STR, 1206. (conj_pit || adj_pit) ? "stepping on poison spikes" 1207. : "fall onto poison spikes", 1208. /* if damage triggered life-saving, 1209. poison is limited to attrib loss */ 1210. (u.umortality > oldumort) ? 0 : 8, FALSE); 1211. } else { 1212. /* plunging flyers take spike damage but not pit damage */ 1213. if (!conj_pit 1214. && !(plunged && (Flying || is_clinger(youmonst.data)))) 1215. losehp(Maybe_Half_Phys(rnd(adj_pit ? 3 : 6)), 1216. plunged ? "deliberately plunged into a pit" 1217. : "fell into a pit", 1218. NO_KILLER_PREFIX); 1219. } 1220. if (Punished && !carried(uball)) { 1221. unplacebc(); 1222. ballfall(); 1223. placebc(); 1224. } 1225. if (!conj_pit) 1226. selftouch("Falling, you"); 1227. vision_full_recalc = 1; /* vision limits change */ 1228. exercise(A_STR, FALSE); 1229. exercise(A_DEX, FALSE); 1230. } 1231. break; 1232. 1233. case HOLE: 1234. case TRAPDOOR: 1235. if (!Can_fall_thru(&u.uz)) { 1236. seetrap(trap); /* normally done in fall_through */ 1237. impossible("dotrap: %ss cannot exist on this level.", 1238. defsyms[trap_to_defsym(ttype)].explanation); 1239. break; /* don't activate it after all */ 1240. } 1241. fall_through(TRUE); 1242. break; 1243. 1244. case TELEP_TRAP: 1245. seetrap(trap); 1246. tele_trap(trap); 1247. break; 1248. 1249. case LEVEL_TELEP: 1250. seetrap(trap); 1251. level_tele_trap(trap, trflags); 1252. break; 1253. 1254. case WEB: /* Our luckless player has stumbled into a web. */ 1255. feeltrap(trap); 1256. if (mu_maybe_destroy_web(&youmonst, webmsgok, trap)) 1257. break; 1258. if (webmaker(youmonst.data)) { 1259. if (webmsgok) 1260. pline(trap->madeby_u ? "You take a walk on your web." 1261. : "There is a spider web here."); 1262. break; 1263. } 1264. if (webmsgok) { 1265. char verbbuf[BUFSZ]; 1266. 1267. if (forcetrap || viasitting) { 1268. Strcpy(verbbuf, "are caught by"); 1269. } else if (u.usteed) { 1270. Sprintf(verbbuf, "lead %s into", 1271. x_monnam(u.usteed, steed_article, "poor", 1272. SUPPRESS_SADDLE, FALSE)); 1273. } else { 1274. Sprintf(verbbuf, "%s into", 1275. Levitation ? (const char *) "float" 1276. : locomotion(youmonst.data, "stumble")); 1277. } 1278. You("%s %s spider web!", verbbuf, a_your[trap->madeby_u]); 1279. } 1280. u.utraptype = TT_WEB; 1281. 1282. /* Time stuck in the web depends on your/steed strength. */ 1283. { 1284. register int str = ACURR(A_STR); 1285. 1286. /* If mounted, the steed gets trapped. Use mintrap 1287. * to do all the work. If mtrapped is set as a result, 1288. * unset it and set utrap instead. In the case of a 1289. * strongmonst and mintrap said it's trapped, use a 1290. * short but non-zero trap time. Otherwise, monsters 1291. * have no specific strength, so use player strength. 1292. * This gets skipped for webmsgok, which implies that 1293. * the steed isn't a factor. 1294. */ 1295. if (u.usteed && webmsgok) { 1296. /* mtmp location might not be up to date */ 1297. u.usteed->mx = u.ux; 1298. u.usteed->my = u.uy; 1299. 1300. /* mintrap currently does not return 2(died) for webs */ 1301. if (mintrap(u.usteed)) { 1302. u.usteed->mtrapped = 0; 1303. if (strongmonst(u.usteed->data)) 1304. str = 17; 1305. } else { 1306. break; 1307. } 1308. 1309. webmsgok = FALSE; /* mintrap printed the messages */ 1310. } 1311. if (str <= 3) 1312. u.utrap = rn1(6, 6); 1313. else if (str < 6) 1314. u.utrap = rn1(6, 4); 1315. else if (str < 9) 1316. u.utrap = rn1(4, 4); 1317. else if (str < 12) 1318. u.utrap = rn1(4, 2); 1319. else if (str < 15) 1320. u.utrap = rn1(2, 2); 1321. else if (str < 18) 1322. u.utrap = rnd(2); 1323. else if (str < 69) 1324. u.utrap = 1; 1325. else { 1326. u.utrap = 0; 1327. if (webmsgok) 1328. You("tear through %s web!", a_your[trap->madeby_u]); 1329. deltrap(trap); 1330. newsym(u.ux, u.uy); /* get rid of trap symbol */ 1331. } 1332. } 1333. break; 1334. 1335. case STATUE_TRAP: 1336. (void) activate_statue_trap(trap, u.ux, u.uy, FALSE); 1337. break; 1338. 1339. case MAGIC_TRAP: /* A magic trap. */ 1340. seetrap(trap); 1341. if (!rn2(30)) { 1342. deltrap(trap); 1343. newsym(u.ux, u.uy); /* update position */ 1344. You("are caught in a magical explosion!"); 1345. losehp(rnd(10), "magical explosion", KILLED_BY_AN); 1346. Your("body absorbs some of the magical energy!"); 1347. u.uen = (u.uenmax += 2); 1348. break; 1349. } else { 1350. domagictrap(); 1351. } 1352. (void) steedintrap(trap, (struct obj *) 0); 1353. break; 1354. 1355. case ANTI_MAGIC: 1356. seetrap(trap); 1357. /* hero without magic resistance loses spell energy, 1358. hero with magic resistance takes damage instead; 1359. possibly non-intuitive but useful for play balance */ 1360. if (!Antimagic) { 1361. drain_en(rnd(u.ulevel) + 1); 1362. } else { 1363. int dmgval2 = rnd(4), hp = Upolyd ? u.mh : u.uhp; 1364. 1365. /* Half_XXX_damage has opposite its usual effect (approx) 1366. but isn't cumulative if hero has more than one */ 1367. if (Half_physical_damage || Half_spell_damage) 1368. dmgval2 += rnd(4); 1369. /* give Magicbane wielder dose of own medicine */ 1370. if (uwep && uwep->oartifact == ART_MAGICBANE) 1371. dmgval2 += rnd(4); 1372. /* having an artifact--other than own quest one--which 1373. confers magic resistance simply by being carried 1374. also increases the effect */ 1375. for (otmp = invent; otmp; otmp = otmp->nobj) 1376. if (otmp->oartifact && !is_quest_artifact(otmp) 1377. && defends_when_carried(AD_MAGM, otmp)) 1378. break; 1379. if (otmp) 1380. dmgval2 += rnd(4); 1381. if (Passes_walls) 1382. dmgval2 = (dmgval2 + 3) / 4; 1383. 1384. You_feel((dmgval2 >= hp) ? "unbearably torpid!" 1385. : (dmgval2 >= hp / 4) ? "very lethargic." 1386. : "sluggish."); 1387. /* opposite of magical explosion */ 1388. losehp(dmgval2, "anti-magic implosion", KILLED_BY_AN); 1389. } 1390. break; 1391. 1392. case POLY_TRAP: { 1393. char verbbuf[BUFSZ]; 1394. 1395. seetrap(trap); 1396. if (viasitting) 1397. Strcpy(verbbuf, "trigger"); /* follows "You sit down." */ 1398. else if (u.usteed) 1399. Sprintf(verbbuf, "lead %s onto", 1400. x_monnam(u.usteed, steed_article, (char *) 0, 1401. SUPPRESS_SADDLE, FALSE)); 1402. else 1403. Sprintf(verbbuf, "%s onto", 1404. Levitation ? (const char *) "float" 1405. : locomotion(youmonst.data, "step")); 1406. You("%s a polymorph trap!", verbbuf); 1407. if (Antimagic || Unchanging) { 1408. shieldeff(u.ux, u.uy); 1409. You_feel("momentarily different."); 1410. /* Trap did nothing; don't remove it --KAA */ 1411. } else { 1412. (void) steedintrap(trap, (struct obj *) 0); 1413. deltrap(trap); /* delete trap before polymorph */ 1414. newsym(u.ux, u.uy); /* get rid of trap symbol */ 1415. You_feel("a change coming over you."); 1416. polyself(0); 1417. } 1418. break; 1419. } 1420. case LANDMINE: { 1421. unsigned steed_mid = 0; 1422. struct obj *saddle = 0; 1423. 1424. if ((Levitation || Flying) && !forcetrap) { 1425. if (!already_seen && rn2(3)) 1426. break; 1427. feeltrap(trap); 1428. pline("%s %s in a pile of soil below you.", 1429. already_seen ? "There is" : "You discover", 1430. trap->madeby_u ? "the trigger of your mine" : "a trigger"); 1431. if (already_seen && rn2(3)) 1432. break; 1433. pline("KAABLAMM!!! %s %s%s off!", 1434. forcebungle ? "Your inept attempt sets" 1435. : "The air currents set", 1436. already_seen ? a_your[trap->madeby_u] : "", 1437. already_seen ? " land mine" : "it"); 1438. } else { 1439. /* prevent landmine from killing steed, throwing you to 1440. * the ground, and you being affected again by the same 1441. * mine because it hasn't been deleted yet 1442. */ 1443. static boolean recursive_mine = FALSE; 1444. 1445. if (recursive_mine) 1446. break; 1447. feeltrap(trap); 1448. pline("KAABLAMM!!! You triggered %s land mine!", 1449. a_your[trap->madeby_u]); 1450. if (u.usteed) 1451. steed_mid = u.usteed->m_id; 1452. recursive_mine = TRUE; 1453. (void) steedintrap(trap, (struct obj *) 0); 1454. recursive_mine = FALSE; 1455. saddle = sobj_at(SADDLE, u.ux, u.uy); 1456. set_wounded_legs(LEFT_SIDE, rn1(35, 41)); 1457. set_wounded_legs(RIGHT_SIDE, rn1(35, 41)); 1458. exercise(A_DEX, FALSE); 1459. } 1460. blow_up_landmine(trap); 1461. if (steed_mid && saddle && !u.usteed) 1462. (void) keep_saddle_with_steedcorpse(steed_mid, fobj, saddle); 1463. newsym(u.ux, u.uy); /* update trap symbol */ 1464. losehp(Maybe_Half_Phys(rnd(16)), "land mine", KILLED_BY_AN); 1465. /* fall recursively into the pit... */ 1466. if ((trap = t_at(u.ux, u.uy)) != 0) 1467. dotrap(trap, RECURSIVETRAP); 1468. fill_pit(u.ux, u.uy); 1469. break; 1470. } 1471. 1472. case ROLLING_BOULDER_TRAP: { 1473. int style = ROLL | (trap->tseen ? LAUNCH_KNOWN : 0); 1474. 1475. feeltrap(trap); 1476. pline("Click! You trigger a rolling boulder trap!"); 1477. if (!launch_obj(BOULDER, trap->launch.x, trap->launch.y, 1478. trap->launch2.x, trap->launch2.y, style)) { 1479. deltrap(trap); 1480. newsym(u.ux, u.uy); /* get rid of trap symbol */ 1481. pline("Fortunately for you, no boulder was released."); 1482. } 1483. break; 1484. } 1485. 1486. case MAGIC_PORTAL: 1487. feeltrap(trap); 1488. domagicportal(trap); 1489. break; 1490. 1491. case VIBRATING_SQUARE: 1492. feeltrap(trap); 1493. /* messages handled elsewhere; the trap symbol is merely to mark the 1494. * square for future reference */ 1495. break; 1496. 1497. default: 1498. feeltrap(trap); 1499. impossible("You hit a trap of type %u", trap->ttyp); 1500. } 1501. } 1502.
trapnote
1503. STATIC_OVL char * 1504. trapnote(trap, noprefix) 1505. struct trap *trap; 1506. boolean noprefix; 1507. { 1508. static char tnbuf[12]; 1509. const char *tn, 1510. *tnnames[12] = { "C note", "D flat", "D note", "E flat", 1511. "E note", "F note", "F sharp", "G note", 1512. "G sharp", "A note", "B flat", "B note" }; 1513. 1514. tnbuf[0] = '\0'; 1515. tn = tnnames[trap->tnote]; 1516. if (!noprefix) 1517. Sprintf(tnbuf, "%s ", 1518. (*tn == 'A' || *tn == 'E' || *tn == 'F') ? "an" : "a"); 1519. Sprintf(eos(tnbuf), "%s", tn); 1520. return tnbuf; 1521. } 1522.
steedintrap
1523. STATIC_OVL int 1524. steedintrap(trap, otmp) 1525. struct trap *trap; 1526. struct obj *otmp; 1527. { 1528. struct monst *steed = u.usteed; 1529. int tt; 1530. boolean trapkilled, steedhit; 1531. 1532. if (!steed || !trap) 1533. return 0; 1534. tt = trap->ttyp; 1535. steed->mx = u.ux; 1536. steed->my = u.uy; 1537. trapkilled = steedhit = FALSE; 1538. 1539. switch (tt) { 1540. case ARROW_TRAP: 1541. if (!otmp) { 1542. impossible("steed hit by non-existant arrow?"); 1543. return 0; 1544. } 1545. trapkilled = thitm(8, steed, otmp, 0, FALSE); 1546. steedhit = TRUE; 1547. break; 1548. case DART_TRAP: 1549. if (!otmp) { 1550. impossible("steed hit by non-existant dart?"); 1551. return 0; 1552. } 1553. trapkilled = thitm(7, steed, otmp, 0, FALSE); 1554. steedhit = TRUE; 1555. break; 1556. case SLP_GAS_TRAP: 1557. if (!resists_sleep(steed) && !breathless(steed->data) 1558. && !steed->msleeping && steed->mcanmove) { 1559. if (sleep_monst(steed, rnd(25), -1)) 1560. /* no in_sight check here; you can feel it even if blind */ 1561. pline("%s suddenly falls asleep!", Monnam(steed)); 1562. } 1563. steedhit = TRUE; 1564. break; 1565. case LANDMINE: 1566. trapkilled = thitm(0, steed, (struct obj *) 0, rnd(16), FALSE); 1567. steedhit = TRUE; 1568. break; 1569. case PIT: 1570. case SPIKED_PIT: 1571. trapkilled = (steed->mhp <= 0 1572. || thitm(0, steed, (struct obj *) 0, 1573. rnd((tt == PIT) ? 6 : 10), FALSE)); 1574. steedhit = TRUE; 1575. break; 1576. case POLY_TRAP: 1577. if (!resists_magm(steed) && !resist(steed, WAND_CLASS, 0, NOTELL)) { 1578. (void) newcham(steed, (struct permonst *) 0, FALSE, FALSE); 1579. if (!can_saddle(steed) || !can_ride(steed)) 1580. dismount_steed(DISMOUNT_POLY); 1581. else 1582. You("have to adjust yourself in the saddle on %s.", 1583. x_monnam(steed, ARTICLE_A, (char *) 0, SUPPRESS_SADDLE, 1584. FALSE)); 1585. } 1586. steedhit = TRUE; 1587. break; 1588. default: 1589. break; 1590. } 1591. 1592. if (trapkilled) { 1593. dismount_steed(DISMOUNT_POLY); 1594. return 2; 1595. } 1596. return steedhit ? 1 : 0; 1597. } 1598.
blow_up_landmine
1599. /* some actions common to both player and monsters for triggered landmine */ 1600. void 1601. blow_up_landmine(trap) 1602. struct trap *trap; 1603. { 1604. int x = trap->tx, y = trap->ty, dbx, dby; 1605. struct rm *lev = &levl[x][y]; 1606. 1607. (void) scatter(x, y, 4, 1608. MAY_DESTROY | MAY_HIT | MAY_FRACTURE | VIS_EFFECTS, 1609. (struct obj *) 0); 1610. del_engr_at(x, y); 1611. wake_nearto(x, y, 400); 1612. if (IS_DOOR(lev->typ)) 1613. lev->doormask = D_BROKEN; 1614. /* destroy drawbridge if present */ 1615. if (lev->typ == DRAWBRIDGE_DOWN || is_drawbridge_wall(x, y) >= 0) { 1616. dbx = x, dby = y; 1617. /* if under the portcullis, the bridge is adjacent */ 1618. if (find_drawbridge(&dbx, &dby)) 1619. destroy_drawbridge(dbx, dby); 1620. trap = t_at(x, y); /* expected to be null after destruction */ 1621. } 1622. /* convert landmine into pit */ 1623. if (trap) { 1624. if (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz)) { 1625. /* no pits here */ 1626. deltrap(trap); 1627. } else { 1628. trap->ttyp = PIT; /* explosion creates a pit */ 1629. trap->madeby_u = FALSE; /* resulting pit isn't yours */ 1630. seetrap(trap); /* and it isn't concealed */ 1631. } 1632. } 1633. } 1634. 1635. /* 1636. * The following are used to track launched objects to 1637. * prevent them from vanishing if you are killed. They 1638. * will reappear at the launchplace in bones files. 1639. */ 1640. static struct { 1641. struct obj *obj; 1642. xchar x, y; 1643. } launchplace; 1644.
launch_drop_spot
1645. static void 1646. launch_drop_spot(obj, x, y) 1647. struct obj *obj; 1648. xchar x, y; 1649. { 1650. if (!obj) { 1651. launchplace.obj = (struct obj *) 0; 1652. launchplace.x = 0; 1653. launchplace.y = 0; 1654. } else { 1655. launchplace.obj = obj; 1656. launchplace.x = x; 1657. launchplace.y = y; 1658. } 1659. } 1660.
launch_in_progress
1661. boolean 1662. launch_in_progress() 1663. { 1664. if (launchplace.obj) 1665. return TRUE; 1666. return FALSE; 1667. } 1668.
force_launch_placement
1669. void 1670. force_launch_placement() 1671. { 1672. if (launchplace.obj) { 1673. launchplace.obj->otrapped = 0; 1674. place_object(launchplace.obj, launchplace.x, launchplace.y); 1675. } 1676. } 1677.
launch_obj
1678. /* 1679. * Move obj from (x1,y1) to (x2,y2) 1680. * 1681. * Return 0 if no object was launched. 1682. * 1 if an object was launched and placed somewhere. 1683. * 2 if an object was launched, but used up. 1684. */ 1685. int 1686. launch_obj(otyp, x1, y1, x2, y2, style) 1687. short otyp; 1688. register int x1, y1, x2, y2; 1689. int style; 1690. { 1691. register struct monst *mtmp; 1692. register struct obj *otmp, *otmp2; 1693. register int dx, dy; 1694. struct obj *singleobj; 1695. boolean used_up = FALSE; 1696. boolean otherside = FALSE; 1697. int dist; 1698. int tmp; 1699. int delaycnt = 0; 1700. 1701. otmp = sobj_at(otyp, x1, y1); 1702. /* Try the other side too, for rolling boulder traps */ 1703. if (!otmp && otyp == BOULDER) { 1704. otherside = TRUE; 1705. otmp = sobj_at(otyp, x2, y2); 1706. } 1707. if (!otmp) 1708. return 0; 1709. if (otherside) { /* swap 'em */ 1710. int tx, ty; 1711. 1712. tx = x1; 1713. ty = y1; 1714. x1 = x2; 1715. y1 = y2; 1716. x2 = tx; 1717. y2 = ty; 1718. } 1719. 1720. if (otmp->quan == 1L) { 1721. obj_extract_self(otmp); 1722. singleobj = otmp; 1723. otmp = (struct obj *) 0; 1724. } else { 1725. singleobj = splitobj(otmp, 1L); 1726. obj_extract_self(singleobj); 1727. } 1728. newsym(x1, y1); 1729. /* in case you're using a pick-axe to chop the boulder that's being 1730. launched (perhaps a monster triggered it), destroy context so that 1731. next dig attempt never thinks you're resuming previous effort */ 1732. if ((otyp == BOULDER || otyp == STATUE) 1733. && singleobj->ox == context.digging.pos.x 1734. && singleobj->oy == context.digging.pos.y) 1735. (void) memset((genericptr_t) &context.digging, 0, 1736. sizeof(struct dig_info)); 1737. 1738. dist = distmin(x1, y1, x2, y2); 1739. bhitpos.x = x1; 1740. bhitpos.y = y1; 1741. dx = sgn(x2 - x1); 1742. dy = sgn(y2 - y1); 1743. switch (style) { 1744. case ROLL | LAUNCH_UNSEEN: 1745. if (otyp == BOULDER) { 1746. You_hear(Hallucination ? "someone bowling." 1747. : "rumbling in the distance."); 1748. } 1749. style &= ~LAUNCH_UNSEEN; 1750. goto roll; 1751. case ROLL | LAUNCH_KNOWN: 1752. /* use otrapped as a flag to ohitmon */ 1753. singleobj->otrapped = 1; 1754. style &= ~LAUNCH_KNOWN; 1755. /* fall through */ 1756. roll: 1757. case ROLL: 1758. delaycnt = 2; 1759. /* fall through */ 1760. default: 1761. if (!delaycnt) 1762. delaycnt = 1; 1763. if (!cansee(bhitpos.x, bhitpos.y)) 1764. curs_on_u(); 1765. tmp_at(DISP_FLASH, obj_to_glyph(singleobj)); 1766. tmp_at(bhitpos.x, bhitpos.y); 1767. } 1768. /* Mark a spot to place object in bones files to prevent 1769. * loss of object. Use the starting spot to ensure that 1770. * a rolling boulder will still launch, which it wouldn't 1771. * do if left midstream. Unfortunately we can't use the 1772. * target resting spot, because there are some things/situations 1773. * that would prevent it from ever getting there (bars), and we 1774. * can't tell that yet. 1775. */ 1776. launch_drop_spot(singleobj, bhitpos.x, bhitpos.y); 1777. 1778. /* Set the object in motion */ 1779. while (dist-- > 0 && !used_up) { 1780. struct trap *t; 1781. tmp_at(bhitpos.x, bhitpos.y); 1782. tmp = delaycnt; 1783. 1784. /* dstage@u.washington.edu -- Delay only if hero sees it */ 1785. if (cansee(bhitpos.x, bhitpos.y)) 1786. while (tmp-- > 0) 1787. delay_output(); 1788. 1789. bhitpos.x += dx; 1790. bhitpos.y += dy; 1791. t = t_at(bhitpos.x, bhitpos.y); 1792. 1793. if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) { 1794. if (otyp == BOULDER && throws_rocks(mtmp->data)) { 1795. if (rn2(3)) { 1796. if (cansee(bhitpos.x, bhitpos.y)) 1797. pline("%s snatches the boulder.", Monnam(mtmp)); 1798. singleobj->otrapped = 0; 1799. (void) mpickobj(mtmp, singleobj); 1800. used_up = TRUE; 1801. launch_drop_spot((struct obj *) 0, 0, 0); 1802. break; 1803. } 1804. } 1805. if (ohitmon(mtmp, singleobj, (style == ROLL) ? -1 : dist, 1806. FALSE)) { 1807. used_up = TRUE; 1808. launch_drop_spot((struct obj *) 0, 0, 0); 1809. break; 1810. } 1811. } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) { 1812. if (multi) 1813. nomul(0); 1814. if (thitu(9 + singleobj->spe, dmgval(singleobj, &youmonst), 1815. &singleobj, (char *) 0)) 1816. stop_occupation(); 1817. } 1818. if (style == ROLL) { 1819. if (down_gate(bhitpos.x, bhitpos.y) != -1) { 1820. if (ship_object(singleobj, bhitpos.x, bhitpos.y, FALSE)) { 1821. used_up = TRUE; 1822. launch_drop_spot((struct obj *) 0, 0, 0); 1823. break; 1824. } 1825. } 1826. if (t && otyp == BOULDER) { 1827. switch (t->ttyp) { 1828. case LANDMINE: 1829. if (rn2(10) > 2) { 1830. pline( 1831. "KAABLAMM!!!%s", 1832. cansee(bhitpos.x, bhitpos.y) 1833. ? " The rolling boulder triggers a land mine." 1834. : ""); 1835. deltrap(t); 1836. del_engr_at(bhitpos.x, bhitpos.y); 1837. place_object(singleobj, bhitpos.x, bhitpos.y); 1838. singleobj->otrapped = 0; 1839. fracture_rock(singleobj); 1840. (void) scatter(bhitpos.x, bhitpos.y, 4, 1841. MAY_DESTROY | MAY_HIT | MAY_FRACTURE 1842. | VIS_EFFECTS, 1843. (struct obj *) 0); 1844. if (cansee(bhitpos.x, bhitpos.y)) 1845. newsym(bhitpos.x, bhitpos.y); 1846. used_up = TRUE; 1847. launch_drop_spot((struct obj *) 0, 0, 0); 1848. } 1849. break; 1850. case LEVEL_TELEP: 1851. case TELEP_TRAP: 1852. if (cansee(bhitpos.x, bhitpos.y)) 1853. pline("Suddenly the rolling boulder disappears!"); 1854. else 1855. You_hear("a rumbling stop abruptly."); 1856. singleobj->otrapped = 0; 1857. if (t->ttyp == TELEP_TRAP) 1858. (void) rloco(singleobj); 1859. else { 1860. int newlev = random_teleport_level(); 1861. d_level dest; 1862. 1863. if (newlev == depth(&u.uz) || In_endgame(&u.uz)) 1864. continue; 1865. add_to_migration(singleobj); 1866. get_level(&dest, newlev); 1867. singleobj->ox = dest.dnum; 1868. singleobj->oy = dest.dlevel; 1869. singleobj->owornmask = (long) MIGR_RANDOM; 1870. } 1871. seetrap(t); 1872. used_up = TRUE; 1873. launch_drop_spot((struct obj *) 0, 0, 0); 1874. break; 1875. case PIT: 1876. case SPIKED_PIT: 1877. case HOLE: 1878. case TRAPDOOR: 1879. /* the boulder won't be used up if there is a 1880. monster in the trap; stop rolling anyway */ 1881. x2 = bhitpos.x, y2 = bhitpos.y; /* stops here */ 1882. if (flooreffects(singleobj, x2, y2, "fall")) { 1883. used_up = TRUE; 1884. launch_drop_spot((struct obj *) 0, 0, 0); 1885. } 1886. dist = -1; /* stop rolling immediately */ 1887. break; 1888. } 1889. if (used_up || dist == -1) 1890. break; 1891. } 1892. if (flooreffects(singleobj, bhitpos.x, bhitpos.y, "fall")) { 1893. used_up = TRUE; 1894. launch_drop_spot((struct obj *) 0, 0, 0); 1895. break; 1896. } 1897. if (otyp == BOULDER 1898. && (otmp2 = sobj_at(BOULDER, bhitpos.x, bhitpos.y)) != 0) { 1899. const char *bmsg = " as one boulder sets another in motion"; 1900. 1901. if (!isok(bhitpos.x + dx, bhitpos.y + dy) || !dist 1902. || IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ)) 1903. bmsg = " as one boulder hits another"; 1904. 1905. You_hear("a loud crash%s!", 1906. cansee(bhitpos.x, bhitpos.y) ? bmsg : ""); 1907. obj_extract_self(otmp2); 1908. /* pass off the otrapped flag to the next boulder */ 1909. otmp2->otrapped = singleobj->otrapped; 1910. singleobj->otrapped = 0; 1911. place_object(singleobj, bhitpos.x, bhitpos.y); 1912. singleobj = otmp2; 1913. otmp2 = (struct obj *) 0; 1914. wake_nearto(bhitpos.x, bhitpos.y, 10 * 10); 1915. } 1916. } 1917. if (otyp == BOULDER && closed_door(bhitpos.x, bhitpos.y)) { 1918. if (cansee(bhitpos.x, bhitpos.y)) 1919. pline_The("boulder crashes through a door."); 1920. levl[bhitpos.x][bhitpos.y].doormask = D_BROKEN; 1921. if (dist) 1922. unblock_point(bhitpos.x, bhitpos.y); 1923. } 1924. 1925. /* if about to hit iron bars, do so now */ 1926. if (dist > 0 && isok(bhitpos.x + dx, bhitpos.y + dy) 1927. && levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS) { 1928. x2 = bhitpos.x, y2 = bhitpos.y; /* object stops here */ 1929. if (hits_bars(&singleobj, 1930. x2, y2, x2+dx, y2+dy, 1931. !rn2(20), 0)) { 1932. if (!singleobj) { 1933. used_up = TRUE; 1934. launch_drop_spot((struct obj *) 0, 0, 0); 1935. } 1936. break; 1937. } 1938. } 1939. } 1940. tmp_at(DISP_END, 0); 1941. launch_drop_spot((struct obj *) 0, 0, 0); 1942. if (!used_up) { 1943. singleobj->otrapped = 0; 1944. place_object(singleobj, x2, y2); 1945. newsym(x2, y2); 1946. return 1; 1947. } else 1948. return 2; 1949. } 1950.
seetrap
1951. void 1952. seetrap(trap) 1953. struct trap *trap; 1954. { 1955. if (!trap->tseen) { 1956. trap->tseen = 1; 1957. newsym(trap->tx, trap->ty); 1958. } 1959. } 1960.
feeltrap
1961. /* like seetrap() but overrides vision */ 1962. void 1963. feeltrap(trap) 1964. struct trap *trap; 1965. { 1966. trap->tseen = 1; 1967. map_trap(trap, 1); 1968. /* in case it's beneath something, redisplay the something */ 1969. newsym(trap->tx, trap->ty); 1970. } 1971.
mkroll_launch
1972. STATIC_OVL int 1973. mkroll_launch(ttmp, x, y, otyp, ocount) 1974. struct trap *ttmp; 1975. xchar x, y; 1976. short otyp; 1977. long ocount; 1978. { 1979. struct obj *otmp; 1980. register int tmp; 1981. schar dx, dy; 1982. int distance; 1983. coord cc; 1984. coord bcc; 1985. int trycount = 0; 1986. boolean success = FALSE; 1987. int mindist = 4; 1988. 1989. if (ttmp->ttyp == ROLLING_BOULDER_TRAP) 1990. mindist = 2; 1991. distance = rn1(5, 4); /* 4..8 away */ 1992. tmp = rn2(8); /* randomly pick a direction to try first */ 1993. while (distance >= mindist) { 1994. dx = xdir[tmp]; 1995. dy = ydir[tmp]; 1996. cc.x = x; 1997. cc.y = y; 1998. /* Prevent boulder from being placed on water */ 1999. if (ttmp->ttyp == ROLLING_BOULDER_TRAP 2000. && is_pool_or_lava(x + distance * dx, y + distance * dy)) 2001. success = FALSE; 2002. else 2003. success = isclearpath(&cc, distance, dx, dy); 2004. if (ttmp->ttyp == ROLLING_BOULDER_TRAP) { 2005. boolean success_otherway; 2006. 2007. bcc.x = x; 2008. bcc.y = y; 2009. success_otherway = isclearpath(&bcc, distance, -(dx), -(dy)); 2010. if (!success_otherway) 2011. success = FALSE; 2012. } 2013. if (success) 2014. break; 2015. if (++tmp > 7) 2016. tmp = 0; 2017. if ((++trycount % 8) == 0) 2018. --distance; 2019. } 2020. if (!success) { 2021. /* create the trap without any ammo, launch pt at trap location */ 2022. cc.x = bcc.x = x; 2023. cc.y = bcc.y = y; 2024. } else { 2025. otmp = mksobj(otyp, TRUE, FALSE); 2026. otmp->quan = ocount; 2027. otmp->owt = weight(otmp); 2028. place_object(otmp, cc.x, cc.y); 2029. stackobj(otmp); 2030. } 2031. ttmp->launch.x = cc.x; 2032. ttmp->launch.y = cc.y; 2033. if (ttmp->ttyp == ROLLING_BOULDER_TRAP) { 2034. ttmp->launch2.x = bcc.x; 2035. ttmp->launch2.y = bcc.y; 2036. } else 2037. ttmp->launch_otyp = otyp; 2038. newsym(ttmp->launch.x, ttmp->launch.y); 2039. return 1; 2040. } 2041.
isclearpath
2042. STATIC_OVL boolean 2043. isclearpath(cc, distance, dx, dy) 2044. coord *cc; 2045. int distance; 2046. schar dx, dy; 2047. { 2048. uchar typ; 2049. xchar x, y; 2050. 2051. x = cc->x; 2052. y = cc->y; 2053. while (distance-- > 0) { 2054. x += dx; 2055. y += dy; 2056. typ = levl[x][y].typ; 2057. if (!isok(x, y) || !ZAP_POS(typ) || closed_door(x, y)) 2058. return FALSE; 2059. } 2060. cc->x = x; 2061. cc->y = y; 2062. return TRUE; 2063. } 2064.
mintrap
2065. int 2066. mintrap(mtmp) 2067. register struct monst *mtmp; 2068. { 2069. register struct trap *trap = t_at(mtmp->mx, mtmp->my); 2070. boolean trapkilled = FALSE; 2071. struct permonst *mptr = mtmp->data; 2072. struct obj *otmp; 2073. 2074. if (!trap) { 2075. mtmp->mtrapped = 0; /* perhaps teleported? */ 2076. } else if (mtmp->mtrapped) { /* is currently in the trap */ 2077. if (!trap->tseen && cansee(mtmp->mx, mtmp->my) && canseemon(mtmp) 2078. && (trap->ttyp == SPIKED_PIT || trap->ttyp == BEAR_TRAP 2079. || trap->ttyp == HOLE || trap->ttyp == PIT 2080. || trap->ttyp == WEB)) { 2081. /* If you come upon an obviously trapped monster, then 2082. * you must be able to see the trap it's in too. 2083. */ 2084. seetrap(trap); 2085. } 2086. 2087. if (!rn2(40)) { 2088. if (sobj_at(BOULDER, mtmp->mx, mtmp->my) 2089. && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)) { 2090. if (!rn2(2)) { 2091. mtmp->mtrapped = 0; 2092. if (canseemon(mtmp)) 2093. pline("%s pulls free...", Monnam(mtmp)); 2094. fill_pit(mtmp->mx, mtmp->my); 2095. } 2096. } else { 2097. mtmp->mtrapped = 0; 2098. } 2099. } else if (metallivorous(mptr)) { 2100. if (trap->ttyp == BEAR_TRAP) { 2101. if (canseemon(mtmp)) 2102. pline("%s eats a bear trap!", Monnam(mtmp)); 2103. deltrap(trap); 2104. mtmp->meating = 5; 2105. mtmp->mtrapped = 0; 2106. } else if (trap->ttyp == SPIKED_PIT) { 2107. if (canseemon(mtmp)) 2108. pline("%s munches on some spikes!", Monnam(mtmp)); 2109. trap->ttyp = PIT; 2110. mtmp->meating = 5; 2111. } 2112. } 2113. } else { 2114. register int tt = trap->ttyp; 2115. boolean in_sight, tear_web, see_it, 2116. inescapable = force_mintrap || ((tt == HOLE || tt == PIT) 2117. && Sokoban && !trap->madeby_u); 2118. const char *fallverb; 2119. 2120. /* true when called from dotrap, inescapable is not an option */ 2121. if (mtmp == u.usteed) 2122. inescapable = TRUE; 2123. if (!inescapable && ((mtmp->mtrapseen & (1 << (tt - 1))) != 0 2124. || (tt == HOLE && !mindless(mptr)))) { 2125. /* it has been in such a trap - perhaps it escapes */ 2126. if (rn2(4)) 2127. return 0; 2128. } else { 2129. mtmp->mtrapseen |= (1 << (tt - 1)); 2130. } 2131. /* Monster is aggravated by being trapped by you. 2132. Recognizing who made the trap isn't completely 2133. unreasonable; everybody has their own style. */ 2134. if (trap->madeby_u && rnl(5)) 2135. setmangry(mtmp, TRUE); 2136. 2137. in_sight = canseemon(mtmp); 2138. see_it = cansee(mtmp->mx, mtmp->my); 2139. /* assume hero can tell what's going on for the steed */ 2140. if (mtmp == u.usteed) 2141. in_sight = TRUE; 2142. switch (tt) { 2143. case ARROW_TRAP: 2144. if (trap->once && trap->tseen && !rn2(15)) { 2145. if (in_sight && see_it) 2146. pline("%s triggers a trap but nothing happens.", 2147. Monnam(mtmp)); 2148. deltrap(trap); 2149. newsym(mtmp->mx, mtmp->my); 2150. break; 2151. } 2152. trap->once = 1; 2153. otmp = mksobj(ARROW, TRUE, FALSE); 2154. otmp->quan = 1L; 2155. otmp->owt = weight(otmp); 2156. otmp->opoisoned = 0; 2157. if (in_sight) 2158. seetrap(trap); 2159. if (thitm(8, mtmp, otmp, 0, FALSE)) 2160. trapkilled = TRUE; 2161. break; 2162. case DART_TRAP: 2163. if (trap->once && trap->tseen && !rn2(15)) { 2164. if (in_sight && see_it) 2165. pline("%s triggers a trap but nothing happens.", 2166. Monnam(mtmp)); 2167. deltrap(trap); 2168. newsym(mtmp->mx, mtmp->my); 2169. break; 2170. } 2171. trap->once = 1; 2172. otmp = mksobj(DART, TRUE, FALSE); 2173. otmp->quan = 1L; 2174. otmp->owt = weight(otmp); 2175. if (!rn2(6)) 2176. otmp->opoisoned = 1; 2177. if (in_sight) 2178. seetrap(trap); 2179. if (thitm(7, mtmp, otmp, 0, FALSE)) 2180. trapkilled = TRUE; 2181. break; 2182. case ROCKTRAP: 2183. if (trap->once && trap->tseen && !rn2(15)) { 2184. if (in_sight && see_it) 2185. pline( 2186. "A trap door above %s opens, but nothing falls out!", 2187. mon_nam(mtmp)); 2188. deltrap(trap); 2189. newsym(mtmp->mx, mtmp->my); 2190. break; 2191. } 2192. trap->once = 1; 2193. otmp = mksobj(ROCK, TRUE, FALSE); 2194. otmp->quan = 1L; 2195. otmp->owt = weight(otmp); 2196. if (in_sight) 2197. seetrap(trap); 2198. if (thitm(0, mtmp, otmp, d(2, 6), FALSE)) 2199. trapkilled = TRUE; 2200. break; 2201. case SQKY_BOARD: 2202. if (is_flyer(mptr)) 2203. break; 2204. /* stepped on a squeaky board */ 2205. if (in_sight) { 2206. if (!Deaf) { 2207. pline("A board beneath %s squeaks %s loudly.", 2208. mon_nam(mtmp), trapnote(trap, 0)); 2209. seetrap(trap); 2210. } else { 2211. pline("%s stops momentarily and appears to cringe.", 2212. Monnam(mtmp)); 2213. } 2214. } else { 2215. /* same near/far threshold as mzapmsg() */ 2216. int range = couldsee(mtmp->mx, mtmp->my) /* 9 or 5 */ 2217. ? (BOLT_LIM + 1) : (BOLT_LIM - 3); 2218. 2219. You_hear("a %s squeak %s.", trapnote(trap, 1), 2220. (distu(mtmp->mx, mtmp->my) <= range * range) 2221. ? "nearby" : "in the distance"); 2222. } 2223. /* wake up nearby monsters */ 2224. wake_nearto(mtmp->mx, mtmp->my, 40); 2225. break; 2226. case BEAR_TRAP: 2227. if (mptr->msize > MZ_SMALL && !amorphous(mptr) && !is_flyer(mptr) 2228. && !is_whirly(mptr) && !unsolid(mptr)) { 2229. mtmp->mtrapped = 1; 2230. if (in_sight) { 2231. pline("%s is caught in %s bear trap!", Monnam(mtmp), 2232. a_your[trap->madeby_u]); 2233. seetrap(trap); 2234. } else { 2235. if (mptr == &mons[PM_OWLBEAR] 2236. || mptr == &mons[PM_BUGBEAR]) 2237. You_hear("the roaring of an angry bear!"); 2238. } 2239. } else if (force_mintrap) { 2240. if (in_sight) { 2241. pline("%s evades %s bear trap!", Monnam(mtmp), 2242. a_your[trap->madeby_u]); 2243. seetrap(trap); 2244. } 2245. } 2246. if (mtmp->mtrapped) 2247. trapkilled = thitm(0, mtmp, (struct obj *) 0, d(2, 4), FALSE); 2248. break; 2249. case SLP_GAS_TRAP: 2250. if (!resists_sleep(mtmp) && !breathless(mptr) && !mtmp->msleeping 2251. && mtmp->mcanmove) { 2252. if (sleep_monst(mtmp, rnd(25), -1) && in_sight) { 2253. pline("%s suddenly falls asleep!", Monnam(mtmp)); 2254. seetrap(trap); 2255. } 2256. } 2257. break; 2258. case RUST_TRAP: { 2259. struct obj *target; 2260. 2261. if (in_sight) 2262. seetrap(trap); 2263. switch (rn2(5)) { 2264. case 0: 2265. if (in_sight) 2266. pline("%s %s on the %s!", A_gush_of_water_hits, 2267. mon_nam(mtmp), mbodypart(mtmp, HEAD)); 2268. target = which_armor(mtmp, W_ARMH); 2269. (void) water_damage(target, helm_simple_name(target), TRUE); 2270. break; 2271. case 1: 2272. if (in_sight) 2273. pline("%s %s's left %s!", A_gush_of_water_hits, 2274. mon_nam(mtmp), mbodypart(mtmp, ARM)); 2275. target = which_armor(mtmp, W_ARMS); 2276. if (water_damage(target, "shield", TRUE) != ER_NOTHING) 2277. break; 2278. target = MON_WEP(mtmp); 2279. if (target && bimanual(target)) 2280. (void) water_damage(target, 0, TRUE); 2281. glovecheck: 2282. target = which_armor(mtmp, W_ARMG); 2283. (void) water_damage(target, "gauntlets", TRUE); 2284. break; 2285. case 2: 2286. if (in_sight) 2287. pline("%s %s's right %s!", A_gush_of_water_hits, 2288. mon_nam(mtmp), mbodypart(mtmp, ARM)); 2289. (void) water_damage(MON_WEP(mtmp), 0, TRUE); 2290. goto glovecheck; 2291. default: 2292. if (in_sight) 2293. pline("%s %s!", A_gush_of_water_hits, mon_nam(mtmp)); 2294. for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) 2295. if (otmp->lamplit 2296. && (otmp->owornmask & (W_WEP | W_SWAPWEP)) == 0) 2297. (void) snuff_lit(otmp); 2298. if ((target = which_armor(mtmp, W_ARMC)) != 0) 2299. (void) water_damage(target, cloak_simple_name(target), 2300. TRUE); 2301. else if ((target = which_armor(mtmp, W_ARM)) != 0) 2302. (void) water_damage(target, suit_simple_name(target), 2303. TRUE); 2304. else if ((target = which_armor(mtmp, W_ARMU)) != 0) 2305. (void) water_damage(target, "shirt", TRUE); 2306. } 2307. 2308. if (mptr == &mons[PM_IRON_GOLEM]) { 2309. if (in_sight) 2310. pline("%s falls to pieces!", Monnam(mtmp)); 2311. else if (mtmp->mtame) 2312. pline("May %s rust in peace.", mon_nam(mtmp)); 2313. mondied(mtmp); 2314. if (mtmp->mhp <= 0) 2315. trapkilled = TRUE; 2316. } else if (mptr == &mons[PM_GREMLIN] && rn2(3)) { 2317. (void) split_mon(mtmp, (struct monst *) 0); 2318. } 2319. break; 2320. } /* RUST_TRAP */ 2321. case FIRE_TRAP: 2322. mfiretrap: 2323. if (in_sight) 2324. pline("A %s erupts from the %s under %s!", tower_of_flame, 2325. surface(mtmp->mx, mtmp->my), mon_nam(mtmp)); 2326. else if (see_it) /* evidently `mtmp' is invisible */ 2327. You_see("a %s erupt from the %s!", tower_of_flame, 2328. surface(mtmp->mx, mtmp->my)); 2329. 2330. if (resists_fire(mtmp)) { 2331. if (in_sight) { 2332. shieldeff(mtmp->mx, mtmp->my); 2333. pline("%s is uninjured.", Monnam(mtmp)); 2334. } 2335. } else { 2336. int num = d(2, 4), alt; 2337. boolean immolate = FALSE; 2338. 2339. /* paper burns very fast, assume straw is tightly 2340. * packed and burns a bit slower */ 2341. switch (monsndx(mptr)) { 2342. case PM_PAPER_GOLEM: 2343. immolate = TRUE; 2344. alt = mtmp->mhpmax; 2345. break; 2346. case PM_STRAW_GOLEM: 2347. alt = mtmp->mhpmax / 2; 2348. break; 2349. case PM_WOOD_GOLEM: 2350. alt = mtmp->mhpmax / 4; 2351. break; 2352. case PM_LEATHER_GOLEM: 2353. alt = mtmp->mhpmax / 8; 2354. break; 2355. default: 2356. alt = 0; 2357. break; 2358. } 2359. if (alt > num) 2360. num = alt; 2361. 2362. if (thitm(0, mtmp, (struct obj *) 0, num, immolate)) 2363. trapkilled = TRUE; 2364. else 2365. /* we know mhp is at least `num' below mhpmax, 2366. so no (mhp > mhpmax) check is needed here */ 2367. mtmp->mhpmax -= rn2(num + 1); 2368. } 2369. if (burnarmor(mtmp) || rn2(3)) { 2370. (void) destroy_mitem(mtmp, SCROLL_CLASS, AD_FIRE); 2371. (void) destroy_mitem(mtmp, SPBOOK_CLASS, AD_FIRE); 2372. (void) destroy_mitem(mtmp, POTION_CLASS, AD_FIRE); 2373. } 2374. if (burn_floor_objects(mtmp->mx, mtmp->my, see_it, FALSE) 2375. && !see_it && distu(mtmp->mx, mtmp->my) <= 3 * 3) 2376. You("smell smoke."); 2377. if (is_ice(mtmp->mx, mtmp->my)) 2378. melt_ice(mtmp->mx, mtmp->my, (char *) 0); 2379. if (see_it) 2380. seetrap(trap); 2381. break; 2382. case PIT: 2383. case SPIKED_PIT: 2384. fallverb = "falls"; 2385. if (is_flyer(mptr) || is_floater(mptr) 2386. || (mtmp->wormno && count_wsegs(mtmp) > 5) 2387. || is_clinger(mptr)) { 2388. if (force_mintrap && !Sokoban) { 2389. /* openfallingtrap; not inescapable here */ 2390. if (in_sight) { 2391. seetrap(trap); 2392. pline("%s doesn't fall into the pit.", Monnam(mtmp)); 2393. } 2394. break; /* inescapable = FALSE; */ 2395. } 2396. if (!inescapable) 2397. break; /* avoids trap */ 2398. fallverb = "is dragged"; /* sokoban pit */ 2399. } 2400. if (!passes_walls(mptr)) 2401. mtmp->mtrapped = 1; 2402. if (in_sight) { 2403. pline("%s %s into %s pit!", Monnam(mtmp), fallverb, 2404. a_your[trap->madeby_u]); 2405. if (mptr == &mons[PM_PIT_VIPER] 2406. || mptr == &mons[PM_PIT_FIEND]) 2407. pline("How pitiful. Isn't that the pits?"); 2408. seetrap(trap); 2409. } 2410. mselftouch(mtmp, "Falling, ", FALSE); 2411. if (mtmp->mhp <= 0 || thitm(0, mtmp, (struct obj *) 0, 2412. rnd((tt == PIT) ? 6 : 10), FALSE)) 2413. trapkilled = TRUE; 2414. break; 2415. case HOLE: 2416. case TRAPDOOR: 2417. if (!Can_fall_thru(&u.uz)) { 2418. impossible("mintrap: %ss cannot exist on this level.", 2419. defsyms[trap_to_defsym(tt)].explanation); 2420. break; /* don't activate it after all */ 2421. } 2422. if (is_flyer(mptr) || is_floater(mptr) || mptr == &mons[PM_WUMPUS] 2423. || (mtmp->wormno && count_wsegs(mtmp) > 5) 2424. || mptr->msize >= MZ_HUGE) { 2425. if (force_mintrap && !Sokoban) { 2426. /* openfallingtrap; not inescapable here */ 2427. if (in_sight) { 2428. seetrap(trap); 2429. if (tt == TRAPDOOR) 2430. pline( 2431. "A trap door opens, but %s doesn't fall through.", 2432. mon_nam(mtmp)); 2433. else /* (tt == HOLE) */ 2434. pline("%s doesn't fall through the hole.", 2435. Monnam(mtmp)); 2436. } 2437. break; /* inescapable = FALSE; */ 2438. } 2439. if (inescapable) { /* sokoban hole */ 2440. if (in_sight) { 2441. pline("%s seems to be yanked down!", Monnam(mtmp)); 2442. /* suppress message in mlevel_tele_trap() */ 2443. in_sight = FALSE; 2444. seetrap(trap); 2445. } 2446. } else 2447. break; 2448. } 2449. /*FALLTHRU*/ 2450. case LEVEL_TELEP: 2451. case MAGIC_PORTAL: { 2452. int mlev_res; 2453. 2454. mlev_res = mlevel_tele_trap(mtmp, trap, inescapable, in_sight); 2455. if (mlev_res) 2456. return mlev_res; 2457. break; 2458. } 2459. case TELEP_TRAP: 2460. mtele_trap(mtmp, trap, in_sight); 2461. break; 2462. case WEB: 2463. /* Monster in a web. */ 2464. if (webmaker(mptr)) 2465. break; 2466. if (mu_maybe_destroy_web(mtmp, in_sight, trap)) 2467. break; 2468. tear_web = FALSE; 2469. switch (monsndx(mptr)) { 2470. case PM_OWLBEAR: /* Eric Backus */ 2471. case PM_BUGBEAR: 2472. if (!in_sight) { 2473. You_hear("the roaring of a confused bear!"); 2474. mtmp->mtrapped = 1; 2475. break; 2476. } 2477. /*FALLTHRU*/ 2478. default: 2479. if (mptr->mlet == S_GIANT 2480. /* exclude baby dragons and relatively short worms */ 2481. || (mptr->mlet == S_DRAGON && extra_nasty(mptr)) 2482. || (mtmp->wormno && count_wsegs(mtmp) > 5)) { 2483. tear_web = TRUE; 2484. } else if (in_sight) { 2485. pline("%s is caught in %s spider web.", Monnam(mtmp), 2486. a_your[trap->madeby_u]); 2487. seetrap(trap); 2488. } 2489. mtmp->mtrapped = tear_web ? 0 : 1; 2490. break; 2491. /* this list is fairly arbitrary; it deliberately 2492. excludes wumpus & giant/ettin zombies/mummies */ 2493. case PM_TITANOTHERE: 2494. case PM_BALUCHITHERIUM: 2495. case PM_PURPLE_WORM: 2496. case PM_JABBERWOCK: 2497. case PM_IRON_GOLEM: 2498. case PM_BALROG: 2499. case PM_KRAKEN: 2500. case PM_MASTODON: 2501. case PM_ORION: 2502. case PM_NORN: 2503. case PM_CYCLOPS: 2504. case PM_LORD_SURTUR: 2505. tear_web = TRUE; 2506. break; 2507. } 2508. if (tear_web) { 2509. if (in_sight) 2510. pline("%s tears through %s spider web!", Monnam(mtmp), 2511. a_your[trap->madeby_u]); 2512. deltrap(trap); 2513. newsym(mtmp->mx, mtmp->my); 2514. } else if (force_mintrap && !mtmp->mtrapped) { 2515. if (in_sight) { 2516. pline("%s avoids %s spider web!", Monnam(mtmp), 2517. a_your[trap->madeby_u]); 2518. seetrap(trap); 2519. } 2520. } 2521. break; 2522. case STATUE_TRAP: 2523. break; 2524. case MAGIC_TRAP: 2525. /* A magic trap. Monsters usually immune. */ 2526. if (!rn2(21)) 2527. goto mfiretrap; 2528. break; 2529. case ANTI_MAGIC: 2530. /* similar to hero's case, more or less */ 2531. if (!resists_magm(mtmp)) { /* lose spell energy */ 2532. if (!mtmp->mcan && (attacktype(mptr, AT_MAGC) 2533. || attacktype(mptr, AT_BREA))) { 2534. mtmp->mspec_used += d(2, 2); 2535. if (in_sight) { 2536. seetrap(trap); 2537. pline("%s seems lethargic.", Monnam(mtmp)); 2538. } 2539. } 2540. } else { /* take some damage */ 2541. int dmgval2 = rnd(4); 2542. 2543. if ((otmp = MON_WEP(mtmp)) != 0 2544. && otmp->oartifact == ART_MAGICBANE) 2545. dmgval2 += rnd(4); 2546. for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) 2547. if (otmp->oartifact 2548. && defends_when_carried(AD_MAGM, otmp)) 2549. break; 2550. if (otmp) 2551. dmgval2 += rnd(4); 2552. if (passes_walls(mptr)) 2553. dmgval2 = (dmgval2 + 3) / 4; 2554. 2555. if (in_sight) 2556. seetrap(trap); 2557. mtmp->mhp -= dmgval2; 2558. if (mtmp->mhp <= 0) 2559. monkilled(mtmp, 2560. in_sight 2561. ? "compression from an anti-magic field" 2562. : (const char *) 0, 2563. -AD_MAGM); 2564. if (mtmp->mhp <= 0) 2565. trapkilled = TRUE; 2566. if (see_it) 2567. newsym(trap->tx, trap->ty); 2568. } 2569. break; 2570. case LANDMINE: 2571. if (rn2(3)) 2572. break; /* monsters usually don't set it off */ 2573. if (is_flyer(mptr)) { 2574. boolean already_seen = trap->tseen; 2575. 2576. if (in_sight && !already_seen) { 2577. pline("A trigger appears in a pile of soil below %s.", 2578. mon_nam(mtmp)); 2579. seetrap(trap); 2580. } 2581. if (rn2(3)) 2582. break; 2583. if (in_sight) { 2584. newsym(mtmp->mx, mtmp->my); 2585. pline_The("air currents set %s off!", 2586. already_seen ? "a land mine" : "it"); 2587. } 2588. } else if (in_sight) { 2589. newsym(mtmp->mx, mtmp->my); 2590. pline("%s%s triggers %s land mine!", 2591. !Deaf ? "KAABLAMM!!! " : "", Monnam(mtmp), 2592. a_your[trap->madeby_u]); 2593. } 2594. if (!in_sight && !Deaf) 2595. pline("Kaablamm! You hear an explosion in the distance!"); 2596. blow_up_landmine(trap); 2597. /* explosion might have destroyed a drawbridge; don't 2598. dish out more damage if monster is already dead */ 2599. if (mtmp->mhp <= 0 2600. || thitm(0, mtmp, (struct obj *) 0, rnd(16), FALSE)) { 2601. trapkilled = TRUE; 2602. } else { 2603. /* monsters recursively fall into new pit */ 2604. if (mintrap(mtmp) == 2) 2605. trapkilled = TRUE; 2606. } 2607. /* a boulder may fill the new pit, crushing monster */ 2608. fill_pit(trap->tx, trap->ty); 2609. if (mtmp->mhp <= 0) 2610. trapkilled = TRUE; 2611. if (unconscious()) { 2612. multi = -1; 2613. nomovemsg = "The explosion awakens you!"; 2614. } 2615. break; 2616. case POLY_TRAP: 2617. if (resists_magm(mtmp)) { 2618. shieldeff(mtmp->mx, mtmp->my); 2619. } else if (!resist(mtmp, WAND_CLASS, 0, NOTELL)) { 2620. if (newcham(mtmp, (struct permonst *) 0, FALSE, FALSE)) 2621. /* we're done with mptr but keep it up to date */ 2622. mptr = mtmp->data; 2623. if (in_sight) 2624. seetrap(trap); 2625. } 2626. break; 2627. case ROLLING_BOULDER_TRAP: 2628. if (!is_flyer(mptr)) { 2629. int style = ROLL | (in_sight ? 0 : LAUNCH_UNSEEN); 2630. 2631. newsym(mtmp->mx, mtmp->my); 2632. if (in_sight) 2633. pline("Click! %s triggers %s.", Monnam(mtmp), 2634. trap->tseen ? "a rolling boulder trap" : something); 2635. if (launch_obj(BOULDER, trap->launch.x, trap->launch.y, 2636. trap->launch2.x, trap->launch2.y, style)) { 2637. if (in_sight) 2638. trap->tseen = TRUE; 2639. if (mtmp->mhp <= 0) 2640. trapkilled = TRUE; 2641. } else { 2642. deltrap(trap); 2643. newsym(mtmp->mx, mtmp->my); 2644. } 2645. } 2646. break; 2647. case VIBRATING_SQUARE: 2648. if (see_it && !Blind) { 2649. if (in_sight) 2650. pline("You see a strange vibration beneath %s %s.", 2651. s_suffix(mon_nam(mtmp)), 2652. makeplural(mbodypart(mtmp, FOOT))); 2653. else 2654. pline("You see the ground vibrate in the distance."); 2655. seetrap(trap); 2656. } 2657. break; 2658. default: 2659. impossible("Some monster encountered a strange trap of type %d.", 2660. tt); 2661. } 2662. } 2663. if (trapkilled) 2664. return 2; 2665. return mtmp->mtrapped; 2666. } 2667.
instapetrify
2668. /* Combine cockatrice checks into single functions to avoid repeating code. */ 2669. void 2670. instapetrify(str) 2671. const char *str; 2672. { 2673. if (Stone_resistance) 2674. return; 2675. if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) 2676. return; 2677. You("turn to stone..."); 2678. killer.format = KILLED_BY; 2679. if (str != killer.name) 2680. Strcpy(killer.name, str ? str : ""); 2681. done(STONING); 2682. } 2683.
minstapetrify
2684. void 2685. minstapetrify(mon, byplayer) 2686. struct monst *mon; 2687. boolean byplayer; 2688. { 2689. if (resists_ston(mon)) 2690. return; 2691. if (poly_when_stoned(mon->data)) { 2692. mon_to_stone(mon); 2693. return; 2694. } 2695. if (!vamp_stone(mon)) 2696. return; 2697. 2698. /* give a "<mon> is slowing down" message and also remove 2699. intrinsic speed (comparable to similar effect on the hero) */ 2700. mon_adjust_speed(mon, -3, (struct obj *) 0); 2701. 2702. if (cansee(mon->mx, mon->my)) 2703. pline("%s turns to stone.", Monnam(mon)); 2704. if (byplayer) { 2705. stoned = TRUE; 2706. xkilled(mon, XKILL_NOMSG); 2707. } else 2708. monstone(mon); 2709. } 2710.
selftouch
2711. void 2712. selftouch(arg) 2713. const char *arg; 2714. { 2715. char kbuf[BUFSZ]; 2716. 2717. if (uwep && uwep->otyp == CORPSE && touch_petrifies(&mons[uwep->corpsenm]) 2718. && !Stone_resistance) { 2719. pline("%s touch the %s corpse.", arg, mons[uwep->corpsenm].mname); 2720. Sprintf(kbuf, "%s corpse", an(mons[uwep->corpsenm].mname)); 2721. instapetrify(kbuf); 2722. /* life-saved; unwield the corpse if we can't handle it */ 2723. if (!uarmg && !Stone_resistance) 2724. uwepgone(); 2725. } 2726. /* Or your secondary weapon, if wielded [hypothetical; we don't 2727. allow two-weapon combat when either weapon is a corpse] */ 2728. if (u.twoweap && uswapwep && uswapwep->otyp == CORPSE 2729. && touch_petrifies(&mons[uswapwep->corpsenm]) && !Stone_resistance) { 2730. pline("%s touch the %s corpse.", arg, mons[uswapwep->corpsenm].mname); 2731. Sprintf(kbuf, "%s corpse", an(mons[uswapwep->corpsenm].mname)); 2732. instapetrify(kbuf); 2733. /* life-saved; unwield the corpse */ 2734. if (!uarmg && !Stone_resistance) 2735. uswapwepgone(); 2736. } 2737. } 2738.
mselftouch
2739. void 2740. mselftouch(mon, arg, byplayer) 2741. struct monst *mon; 2742. const char *arg; 2743. boolean byplayer; 2744. { 2745. struct obj *mwep = MON_WEP(mon); 2746. 2747. if (mwep && mwep->otyp == CORPSE && touch_petrifies(&mons[mwep->corpsenm]) 2748. && !resists_ston(mon)) { 2749. if (cansee(mon->mx, mon->my)) { 2750. pline("%s%s touches %s.", arg ? arg : "", 2751. arg ? mon_nam(mon) : Monnam(mon), 2752. corpse_xname(mwep, (const char *) 0, CXN_PFX_THE)); 2753. } 2754. minstapetrify(mon, byplayer); 2755. /* if life-saved, might not be able to continue wielding */ 2756. if (mon->mhp > 0 && !which_armor(mon, W_ARMG) && !resists_ston(mon)) 2757. mwepgone(mon); 2758. } 2759. } 2760.
float_up
2761. /* start levitating */ 2762. void 2763. float_up() 2764. { 2765. context.botl = TRUE; 2766. if (u.utrap) { 2767. if (u.utraptype == TT_PIT) { 2768. u.utrap = 0; 2769. You("float up, out of the pit!"); 2770. vision_full_recalc = 1; /* vision limits change */ 2771. fill_pit(u.ux, u.uy); 2772. } else if (u.utraptype == TT_INFLOOR) { 2773. Your("body pulls upward, but your %s are still stuck.", 2774. makeplural(body_part(LEG))); 2775. } else { 2776. You("float up, only your %s is still stuck.", body_part(LEG)); 2777. } 2778. #if 0 2779. } else if (Is_waterlevel(&u.uz)) { 2780. pline("It feels as though you've lost some weight."); 2781. #endif 2782. } else if (u.uinwater) { 2783. spoteffects(TRUE); 2784. } else if (u.uswallow) { 2785. You(is_animal(u.ustuck->data) ? "float away from the %s." 2786. : "spiral up into %s.", 2787. is_animal(u.ustuck->data) ? surface(u.ux, u.uy) 2788. : mon_nam(u.ustuck)); 2789. } else if (Hallucination) { 2790. pline("Up, up, and awaaaay! You're walking on air!"); 2791. } else if (Is_airlevel(&u.uz)) { 2792. You("gain control over your movements."); 2793. } else { 2794. You("start to float in the air!"); 2795. } 2796. if (u.usteed && !is_floater(u.usteed->data) 2797. && !is_flyer(u.usteed->data)) { 2798. if (Lev_at_will) { 2799. pline("%s magically floats up!", Monnam(u.usteed)); 2800. } else { 2801. You("cannot stay on %s.", mon_nam(u.usteed)); 2802. dismount_steed(DISMOUNT_GENERIC); 2803. } 2804. } 2805. if (Flying) 2806. You("are no longer able to control your flight."); 2807. BFlying |= I_SPECIAL; 2808. /* levitation gives maximum carrying capacity, so encumbrance 2809. state might be reduced */ 2810. (void) encumber_msg(); 2811. return; 2812. } 2813.
fill_pit
2814. void 2815. fill_pit(x, y) 2816. int x, y; 2817. { 2818. struct obj *otmp; 2819. struct trap *t; 2820. 2821. if ((t = t_at(x, y)) && ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT)) 2822. && (otmp = sobj_at(BOULDER, x, y))) { 2823. obj_extract_self(otmp); 2824. (void) flooreffects(otmp, x, y, "settle"); 2825. } 2826. } 2827.
float_down
2828. /* stop levitating */ 2829. int 2830. float_down(hmask, emask) 2831. long hmask, emask; /* might cancel timeout */ 2832. { 2833. register struct trap *trap = (struct trap *) 0; 2834. d_level current_dungeon_level; 2835. boolean no_msg = FALSE; 2836. 2837. HLevitation &= ~hmask; 2838. ELevitation &= ~emask; 2839. if (Levitation) 2840. return 0; /* maybe another ring/potion/boots */ 2841. if (BLevitation) { 2842. /* Levitation is blocked, so hero is not actually floating 2843. hence shouldn't have float_down effects and feedback */ 2844. float_vs_flight(); /* before nomul() rather than after */ 2845. return 0; 2846. } 2847. context.botl = TRUE; 2848. nomul(0); /* stop running or resting */ 2849. if (BFlying) { 2850. /* controlled flight no longer overridden by levitation */ 2851. BFlying &= ~I_SPECIAL; 2852. if (Flying) { 2853. You("have stopped levitating and are now flying."); 2854. (void) encumber_msg(); /* carrying capacity might have changed */ 2855. return 1; 2856. } 2857. } 2858. if (u.uswallow) { 2859. You("float down, but you are still %s.", 2860. is_animal(u.ustuck->data) ? "swallowed" : "engulfed"); 2861. (void) encumber_msg(); 2862. return 1; 2863. } 2864. 2865. if (Punished && !carried(uball) 2866. && (is_pool(uball->ox, uball->oy) 2867. || ((trap = t_at(uball->ox, uball->oy)) 2868. && ((trap->ttyp == PIT) || (trap->ttyp == SPIKED_PIT) 2869. || (trap->ttyp == TRAPDOOR) || (trap->ttyp == HOLE))))) { 2870. u.ux0 = u.ux; 2871. u.uy0 = u.uy; 2872. u.ux = uball->ox; 2873. u.uy = uball->oy; 2874. movobj(uchain, uball->ox, uball->oy); 2875. newsym(u.ux0, u.uy0); 2876. vision_full_recalc = 1; /* in case the hero moved. */ 2877. } 2878. /* check for falling into pool - added by GAN 10/20/86 */ 2879. if (!Flying) { 2880. if (!u.uswallow && u.ustuck) { 2881. if (sticks(youmonst.data)) 2882. You("aren't able to maintain your hold on %s.", 2883. mon_nam(u.ustuck)); 2884. else 2885. pline("Startled, %s can no longer hold you!", 2886. mon_nam(u.ustuck)); 2887. u.ustuck = 0; 2888. } 2889. /* kludge alert: 2890. * drown() and lava_effects() print various messages almost 2891. * every time they're called which conflict with the "fall 2892. * into" message below. Thus, we want to avoid printing 2893. * confusing, duplicate or out-of-order messages. 2894. * Use knowledge of the two routines as a hack -- this 2895. * should really be handled differently -dlc 2896. */ 2897. if (is_pool(u.ux, u.uy) && !Wwalking && !Swimming && !u.uinwater) 2898. no_msg = drown(); 2899. 2900. if (is_lava(u.ux, u.uy)) { 2901. (void) lava_effects(); 2902. no_msg = TRUE; 2903. } 2904. } 2905. if (!trap) { 2906. trap = t_at(u.ux, u.uy); 2907. if (Is_airlevel(&u.uz)) { 2908. You("begin to tumble in place."); 2909. } else if (Is_waterlevel(&u.uz) && !no_msg) { 2910. You_feel("heavier."); 2911. /* u.uinwater msgs already in spoteffects()/drown() */ 2912. } else if (!u.uinwater && !no_msg) { 2913. if (!(emask & W_SADDLE)) { 2914. if (Sokoban && trap) { 2915. /* Justification elsewhere for Sokoban traps is based 2916. * on air currents. This is consistent with that. 2917. * The unexpected additional force of the air currents 2918. * once levitation ceases knocks you off your feet. 2919. */ 2920. if (Hallucination) 2921. pline("Bummer! You've crashed."); 2922. else 2923. You("fall over."); 2924. losehp(rnd(2), "dangerous winds", KILLED_BY); 2925. if (u.usteed) 2926. dismount_steed(DISMOUNT_FELL); 2927. selftouch("As you fall, you"); 2928. } else if (u.usteed && (is_floater(u.usteed->data) 2929. || is_flyer(u.usteed->data))) { 2930. You("settle more firmly in the saddle."); 2931. } else if (Hallucination) { 2932. pline("Bummer! You've %s.", 2933. is_pool(u.ux, u.uy) 2934. ? "splashed down" 2935. : "hit the ground"); 2936. } else { 2937. You("float gently to the %s.", surface(u.ux, u.uy)); 2938. } 2939. } 2940. } 2941. } 2942. 2943. /* levitation gives maximum carrying capacity, so having it end 2944. potentially triggers greater encumbrance; do this after 2945. 'come down' messages, before trap activation or autopickup */ 2946. (void) encumber_msg(); 2947. 2948. /* can't rely on u.uz0 for detecting trap door-induced level change; 2949. it gets changed to reflect the new level before we can check it */ 2950. assign_level(¤t_dungeon_level, &u.uz); 2951. if (trap) { 2952. switch (trap->ttyp) { 2953. case STATUE_TRAP: 2954. break; 2955. case HOLE: 2956. case TRAPDOOR: 2957. if (!Can_fall_thru(&u.uz) || u.ustuck) 2958. break; 2959. /*FALLTHRU*/ 2960. default: 2961. if (!u.utrap) /* not already in the trap */ 2962. dotrap(trap, 0); 2963. } 2964. } 2965. if (!Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz) && !u.uswallow 2966. /* falling through trap door calls goto_level, 2967. and goto_level does its own pickup() call */ 2968. && on_level(&u.uz, ¤t_dungeon_level)) 2969. (void) pickup(1); 2970. return 1; 2971. } 2972.
climb_pit
2973. /* shared code for climbing out of a pit */ 2974. void 2975. climb_pit() 2976. { 2977. if (!u.utrap || u.utraptype != TT_PIT) 2978. return; 2979. 2980. if (Passes_walls) { 2981. /* marked as trapped so they can pick things up */ 2982. You("ascend from the pit."); 2983. u.utrap = 0; 2984. fill_pit(u.ux, u.uy); 2985. vision_full_recalc = 1; /* vision limits change */ 2986. } else if (!rn2(2) && sobj_at(BOULDER, u.ux, u.uy)) { 2987. Your("%s gets stuck in a crevice.", body_part(LEG)); 2988. display_nhwindow(WIN_MESSAGE, FALSE); 2989. clear_nhwindow(WIN_MESSAGE); 2990. You("free your %s.", body_part(LEG)); 2991. } else if ((Flying || is_clinger(youmonst.data)) && !Sokoban) { 2992. /* eg fell in pit, then poly'd to a flying monster; 2993. or used '>' to deliberately enter it */ 2994. You("%s from the pit.", Flying ? "fly" : "climb"); 2995. u.utrap = 0; 2996. fill_pit(u.ux, u.uy); 2997. vision_full_recalc = 1; /* vision limits change */ 2998. } else if (!(--u.utrap)) { 2999. You("%s to the edge of the pit.", 3000. (Sokoban && Levitation) 3001. ? "struggle against the air currents and float" 3002. : u.usteed ? "ride" : "crawl"); 3003. fill_pit(u.ux, u.uy); 3004. vision_full_recalc = 1; /* vision limits change */ 3005. } else if (u.dz || flags.verbose) { 3006. if (u.usteed) 3007. Norep("%s is still in a pit.", upstart(y_monnam(u.usteed))); 3008. else 3009. Norep((Hallucination && !rn2(5)) 3010. ? "You've fallen, and you can't get up." 3011. : "You are still in a pit."); 3012. } 3013. } 3014.
dofiretrap
3015. STATIC_OVL void 3016. dofiretrap(box) 3017. struct obj *box; /* null for floor trap */ 3018. { 3019. boolean see_it = !Blind; 3020. int num, alt; 3021. 3022. /* Bug: for box case, the equivalent of burn_floor_objects() ought 3023. * to be done upon its contents. 3024. */ 3025. 3026. if ((box && !carried(box)) ? is_pool(box->ox, box->oy) : Underwater) { 3027. pline("A cascade of steamy bubbles erupts from %s!", 3028. the(box ? xname(box) : surface(u.ux, u.uy))); 3029. if (Fire_resistance) 3030. You("are uninjured."); 3031. else 3032. losehp(rnd(3), "boiling water", KILLED_BY); 3033. return; 3034. } 3035. pline("A %s %s from %s!", tower_of_flame, box ? "bursts" : "erupts", 3036. the(box ? xname(box) : surface(u.ux, u.uy))); 3037. if (Fire_resistance) { 3038. shieldeff(u.ux, u.uy); 3039. num = rn2(2); 3040. } else if (Upolyd) { 3041. num = d(2, 4); 3042. switch (u.umonnum) { 3043. case PM_PAPER_GOLEM: 3044. alt = u.mhmax; 3045. break; 3046. case PM_STRAW_GOLEM: 3047. alt = u.mhmax / 2; 3048. break; 3049. case PM_WOOD_GOLEM: 3050. alt = u.mhmax / 4; 3051. break; 3052. case PM_LEATHER_GOLEM: 3053. alt = u.mhmax / 8; 3054. break; 3055. default: 3056. alt = 0; 3057. break; 3058. } 3059. if (alt > num) 3060. num = alt; 3061. if (u.mhmax > mons[u.umonnum].mlevel) 3062. u.mhmax -= rn2(min(u.mhmax, num + 1)), context.botl = 1; 3063. } else { 3064. num = d(2, 4); 3065. if (u.uhpmax > u.ulevel) 3066. u.uhpmax -= rn2(min(u.uhpmax, num + 1)), context.botl = 1; 3067. } 3068. if (!num) 3069. You("are uninjured."); 3070. else 3071. losehp(num, tower_of_flame, KILLED_BY_AN); /* fire damage */ 3072. burn_away_slime(); 3073. 3074. if (burnarmor(&youmonst) || rn2(3)) { 3075. destroy_item(SCROLL_CLASS, AD_FIRE); 3076. destroy_item(SPBOOK_CLASS, AD_FIRE); 3077. destroy_item(POTION_CLASS, AD_FIRE); 3078. } 3079. if (!box && burn_floor_objects(u.ux, u.uy, see_it, TRUE) && !see_it) 3080. You("smell paper burning."); 3081. if (is_ice(u.ux, u.uy)) 3082. melt_ice(u.ux, u.uy, (char *) 0); 3083. } 3084.
domagictrap
3085. STATIC_OVL void 3086. domagictrap() 3087. { 3088. register int fate = rnd(20); 3089. 3090. /* What happened to the poor sucker? */ 3091. 3092. if (fate < 10) { 3093. /* Most of the time, it creates some monsters. */ 3094. register int cnt = rnd(4); 3095. 3096. /* blindness effects */ 3097. if (!resists_blnd(&youmonst)) { 3098. You("are momentarily blinded by a flash of light!"); 3099. make_blinded((long) rn1(5, 10), FALSE); 3100. if (!Blind) 3101. Your1(vision_clears); 3102. } else if (!Blind) { 3103. You_see("a flash of light!"); 3104. } 3105. 3106. /* deafness effects */ 3107. if (!Deaf) { 3108. You_hear("a deafening roar!"); 3109. incr_itimeout(&HDeaf, rn1(20, 30)); 3110. context.botl = TRUE; 3111. } else { 3112. /* magic vibrations still hit you */ 3113. You_feel("rankled."); 3114. incr_itimeout(&HDeaf, rn1(5, 15)); 3115. context.botl = TRUE; 3116. } 3117. while (cnt--) 3118. (void) makemon((struct permonst *) 0, u.ux, u.uy, NO_MM_FLAGS); 3119. } else 3120. switch (fate) { 3121. case 10: 3122. case 11: 3123. /* sometimes nothing happens */ 3124. break; 3125. case 12: /* a flash of fire */ 3126. dofiretrap((struct obj *) 0); 3127. break; 3128. 3129. /* odd feelings */ 3130. case 13: 3131. pline("A shiver runs up and down your %s!", body_part(SPINE)); 3132. break; 3133. case 14: 3134. You_hear(Hallucination ? "the moon howling at you." 3135. : "distant howling."); 3136. break; 3137. case 15: 3138. if (on_level(&u.uz, &qstart_level)) 3139. You_feel( 3140. "%slike the prodigal son.", 3141. (flags.female || (Upolyd && is_neuter(youmonst.data))) 3142. ? "oddly " 3143. : ""); 3144. else 3145. You("suddenly yearn for %s.", 3146. Hallucination 3147. ? "Cleveland" 3148. : (In_quest(&u.uz) || at_dgn_entrance("The Quest")) 3149. ? "your nearby homeland" 3150. : "your distant homeland"); 3151. break; 3152. case 16: 3153. Your("pack shakes violently!"); 3154. break; 3155. case 17: 3156. You(Hallucination ? "smell hamburgers." : "smell charred flesh."); 3157. break; 3158. case 18: 3159. You_feel("tired."); 3160. break; 3161. 3162. /* very occasionally something nice happens. */ 3163. case 19: { /* tame nearby monsters */ 3164. int i, j; 3165. struct monst *mtmp; 3166. 3167. (void) adjattrib(A_CHA, 1, FALSE); 3168. for (i = -1; i <= 1; i++) 3169. for (j = -1; j <= 1; j++) { 3170. if (!isok(u.ux + i, u.uy + j)) 3171. continue; 3172. mtmp = m_at(u.ux + i, u.uy + j); 3173. if (mtmp) 3174. (void) tamedog(mtmp, (struct obj *) 0); 3175. } 3176. break; 3177. } 3178. case 20: { /* uncurse stuff */ 3179. struct obj pseudo; 3180. long save_conf = HConfusion; 3181. 3182. pseudo = zeroobj; /* neither cursed nor blessed, 3183. and zero out oextra */ 3184. pseudo.otyp = SCR_REMOVE_CURSE; 3185. HConfusion = 0L; 3186. (void) seffects(&pseudo); 3187. HConfusion = save_conf; 3188. break; 3189. } 3190. default: 3191. break; 3192. } 3193. } 3194.
fire_damage
3195. /* Set an item on fire. 3196. * "force" means not to roll a luck-based protection check for the 3197. * item. 3198. * "x" and "y" are the coordinates to dump the contents of a 3199. * container, if it burns up. 3200. * 3201. * Return whether the object was destroyed. 3202. */ 3203. boolean 3204. fire_damage(obj, force, x, y) 3205. struct obj *obj; 3206. boolean force; 3207. xchar x, y; 3208. { 3209. int chance; 3210. struct obj *otmp, *ncobj; 3211. int in_sight = !Blind && couldsee(x, y); /* Don't care if it's lit */ 3212. int dindx; 3213. 3214. /* object might light in a controlled manner */ 3215. if (catch_lit(obj)) 3216. return FALSE; 3217. 3218. if (Is_container(obj)) { 3219. switch (obj->otyp) { 3220. case ICE_BOX: 3221. return FALSE; /* Immune */ 3222. case CHEST: 3223. chance = 40; 3224. break; 3225. case LARGE_BOX: 3226. chance = 30; 3227. break; 3228. default: 3229. chance = 20; 3230. break; 3231. } 3232. if ((!force && (Luck + 5) > rn2(chance)) 3233. || (is_flammable(obj) && obj->oerodeproof)) 3234. return FALSE; 3235. /* Container is burnt up - dump contents out */ 3236. if (in_sight) 3237. pline("%s catches fire and burns.", Yname2(obj)); 3238. if (Has_contents(obj)) { 3239. if (in_sight) 3240. pline("Its contents fall out."); 3241. for (otmp = obj->cobj; otmp; otmp = ncobj) { 3242. ncobj = otmp->nobj; 3243. obj_extract_self(otmp); 3244. if (!flooreffects(otmp, x, y, "")) 3245. place_object(otmp, x, y); 3246. } 3247. } 3248. setnotworn(obj); 3249. delobj(obj); 3250. return TRUE; 3251. } else if (!force && (Luck + 5) > rn2(20)) { 3252. /* chance per item of sustaining damage: 3253. * max luck (Luck==13): 10% 3254. * avg luck (Luck==0): 75% 3255. * awful luck (Luck<-4): 100% 3256. */ 3257. return FALSE; 3258. } else if (obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS) { 3259. if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL) 3260. return FALSE; 3261. if (obj->otyp == SPE_BOOK_OF_THE_DEAD) { 3262. if (in_sight) 3263. pline("Smoke rises from %s.", the(xname(obj))); 3264. return FALSE; 3265. } 3266. dindx = (obj->oclass == SCROLL_CLASS) ? 3 : 4; 3267. if (in_sight) 3268. pline("%s %s.", Yname2(obj), 3269. destroy_strings[dindx][(obj->quan > 1L)]); 3270. setnotworn(obj); 3271. delobj(obj); 3272. return TRUE; 3273. } else if (obj->oclass == POTION_CLASS) { 3274. dindx = (obj->otyp != POT_OIL) ? 1 : 2; 3275. if (in_sight) 3276. pline("%s %s.", Yname2(obj), 3277. destroy_strings[dindx][(obj->quan > 1L)]); 3278. setnotworn(obj); 3279. delobj(obj); 3280. return TRUE; 3281. } else if (erode_obj(obj, (char *) 0, ERODE_BURN, EF_DESTROY) 3282. == ER_DESTROYED) { 3283. return TRUE; 3284. } 3285. return FALSE; 3286. } 3287.
fire_damage_chain
3288. /* 3289. * Apply fire_damage() to an entire chain. 3290. * 3291. * Return number of objects destroyed. --ALI 3292. */ 3293. int 3294. fire_damage_chain(chain, force, here, x, y) 3295. struct obj *chain; 3296. boolean force, here; 3297. xchar x, y; 3298. { 3299. struct obj *obj, *nobj; 3300. int num = 0; 3301. 3302. for (obj = chain; obj; obj = nobj) { 3303. nobj = here ? obj->nexthere : obj->nobj; 3304. if (fire_damage(obj, force, x, y)) 3305. ++num; 3306. } 3307. 3308. if (num && (Blind && !couldsee(x, y))) 3309. You("smell smoke."); 3310. return num; 3311. } 3312.
lava_damage
3313. /* obj has been thrown or dropped into lava; damage is worse than mere fire */ 3314. boolean 3315. lava_damage(obj, x, y) 3316. struct obj *obj; 3317. xchar x, y; 3318. { 3319. int otyp = obj->otyp, ocls = obj->oclass; 3320. 3321. /* the Amulet, invocation items, and Rider corpses are never destroyed 3322. (let Book of the Dead fall through to fire_damage() to get feedback) */ 3323. if (obj_resists(obj, 0, 0) && otyp != SPE_BOOK_OF_THE_DEAD) 3324. return FALSE; 3325. /* destroy liquid (venom), wax, veggy, flesh, paper (except for scrolls 3326. and books--let fire damage deal with them), cloth, leather, wood, bone 3327. unless it's inherently or explicitly fireproof or contains something; 3328. note: potions are glass so fall through to fire_damage() and boil */ 3329. if (objects[otyp].oc_material < DRAGON_HIDE 3330. && ocls != SCROLL_CLASS && ocls != SPBOOK_CLASS 3331. && objects[otyp].oc_oprop != FIRE_RES 3332. && otyp != WAN_FIRE && otyp != FIRE_HORN 3333. /* assumes oerodeproof isn't overloaded for some other purpose on 3334. non-eroding items */ 3335. && !obj->oerodeproof 3336. /* fire_damage() knows how to deal with containers and contents */ 3337. && !Has_contents(obj)) { 3338. if (cansee(x, y)) { 3339. /* this feedback is pretty clunky and can become very verbose 3340. when former contents of a burned container get here via 3341. flooreffects() */ 3342. if (obj == thrownobj || obj == kickedobj) 3343. pline("%s %s up!", is_plural(obj) ? "They" : "It", 3344. otense(obj, "burn")); 3345. else 3346. You_see("%s hit lava and burn up!", doname(obj)); 3347. } 3348. if (carried(obj)) { /* shouldn't happen */ 3349. remove_worn_item(obj, TRUE); 3350. useupall(obj); 3351. } else 3352. delobj(obj); 3353. return TRUE; 3354. } 3355. return fire_damage(obj, TRUE, x, y); 3356. } 3357.
acid_damage
3358. void 3359. acid_damage(obj) 3360. struct obj *obj; 3361. { 3362. /* Scrolls but not spellbooks can be erased by acid. */ 3363. struct monst *victim; 3364. boolean vismon; 3365. 3366. if (!obj) 3367. return; 3368. 3369. victim = carried(obj) ? &youmonst : mcarried(obj) ? obj->ocarry : NULL; 3370. vismon = victim && (victim != &youmonst) && canseemon(victim); 3371. 3372. if (obj->greased) { 3373. grease_protect(obj, (char *) 0, victim); 3374. } else if (obj->oclass == SCROLL_CLASS && obj->otyp != SCR_BLANK_PAPER) { 3375. if (obj->otyp != SCR_BLANK_PAPER 3376. #ifdef MAIL 3377. && obj->otyp != SCR_MAIL 3378. #endif 3379. ) { 3380. if (!Blind) { 3381. if (victim == &youmonst) 3382. pline("Your %s.", aobjnam(obj, "fade")); 3383. else if (vismon) 3384. pline("%s %s.", s_suffix(Monnam(victim)), 3385. aobjnam(obj, "fade")); 3386. } 3387. } 3388. obj->otyp = SCR_BLANK_PAPER; 3389. obj->spe = 0; 3390. obj->dknown = 0; 3391. } else 3392. erode_obj(obj, (char *) 0, ERODE_CORRODE, EF_GREASE | EF_VERBOSE); 3393. } 3394. 3395. /* context for water_damage(), managed by water_damage_chain(); 3396. when more than one stack of potions of acid explode while processing 3397. a chain of objects, use alternate phrasing after the first message */ 3398. static struct h2o_ctx { 3399. int dkn_boom, unk_boom; /* track dknown, !dknown separately */ 3400. boolean ctx_valid; 3401. } acid_ctx = { 0, 0, FALSE }; 3402.
water_damage
3403. /* Get an object wet and damage it appropriately. 3404. * "ostr", if present, is used instead of the object name in some 3405. * messages. 3406. * "force" means not to roll luck to protect some objects. 3407. * Returns an erosion return value (ER_*) 3408. */ 3409. int 3410. water_damage(obj, ostr, force) 3411. struct obj *obj; 3412. const char *ostr; 3413. boolean force; 3414. { 3415. if (!obj) 3416. return ER_NOTHING; 3417. 3418. if (snuff_lit(obj)) 3419. return ER_DAMAGED; 3420. 3421. if (!ostr) 3422. ostr = cxname(obj); 3423. 3424. if (obj->otyp == CAN_OF_GREASE && obj->spe > 0) { 3425. return ER_NOTHING; 3426. } else if (obj->otyp == TOWEL && obj->spe < 7) { 3427. wet_a_towel(obj, rnd(7), TRUE); 3428. return ER_NOTHING; 3429. } else if (obj->greased) { 3430. if (!rn2(2)) 3431. obj->greased = 0; 3432. if (carried(obj)) 3433. update_inventory(); 3434. return ER_GREASED; 3435. } else if (Is_container(obj) && !Is_box(obj) 3436. && (obj->otyp != OILSKIN_SACK || (obj->cursed && !rn2(3)))) { 3437. if (carried(obj)) 3438. pline("Water gets into your %s!", ostr); 3439. 3440. water_damage_chain(obj->cobj, FALSE); 3441. return ER_DAMAGED; /* contents were damaged */ 3442. } else if (obj->otyp == OILSKIN_SACK) { 3443. if (carried(obj)) 3444. pline("Some water slides right off your %s.", ostr); 3445. makeknown(OILSKIN_SACK); 3446. /* not actually damaged, but because we /didn't/ get the "water 3447. gets into!" message, the player now has more information and 3448. thus we need to waste any potion they may have used (also, 3449. flavourwise the water is now on the floor) */ 3450. return ER_DAMAGED; 3451. } else if (!force && (Luck + 5) > rn2(20)) { 3452. /* chance per item of sustaining damage: 3453. * max luck: 10% 3454. * avg luck (Luck==0): 75% 3455. * awful luck (Luck<-4): 100% 3456. */ 3457. return ER_NOTHING; 3458. } else if (obj->oclass == SCROLL_CLASS) { 3459. if (obj->otyp == SCR_BLANK_PAPER 3460. #ifdef MAIL 3461. || obj->otyp == SCR_MAIL 3462. #endif 3463. ) return 0; 3464. if (carried(obj)) 3465. pline("Your %s %s.", ostr, vtense(ostr, "fade")); 3466. 3467. obj->otyp = SCR_BLANK_PAPER; 3468. obj->dknown = 0; 3469. obj->spe = 0; 3470. if (carried(obj)) 3471. update_inventory(); 3472. return ER_DAMAGED; 3473. } else if (obj->oclass == SPBOOK_CLASS) { 3474. if (obj->otyp == SPE_BOOK_OF_THE_DEAD) { 3475. pline("Steam rises from %s.", the(xname(obj))); 3476. return 0; 3477. } else if (obj->otyp == SPE_BLANK_PAPER) { 3478. return 0; 3479. } 3480. if (carried(obj)) 3481. pline("Your %s %s.", ostr, vtense(ostr, "fade")); 3482. 3483. if (obj->otyp == SPE_NOVEL) { 3484. obj->novelidx = 0; 3485. free_oname(obj); 3486. } 3487. 3488. obj->otyp = SPE_BLANK_PAPER; 3489. obj->dknown = 0; 3490. if (carried(obj)) 3491. update_inventory(); 3492. return ER_DAMAGED; 3493. } else if (obj->oclass == POTION_CLASS) { 3494. if (obj->otyp == POT_ACID) { 3495. char *bufp; 3496. boolean one = (obj->quan == 1L), update = carried(obj), 3497. exploded = FALSE; 3498. 3499. if (Blind && !carried(obj)) 3500. obj->dknown = 0; 3501. if (acid_ctx.ctx_valid) 3502. exploded = ((obj->dknown ? acid_ctx.dkn_boom 3503. : acid_ctx.unk_boom) > 0); 3504. /* First message is 3505. * "a [potion|<color> potion|potion of acid] explodes" 3506. * depending on obj->dknown (potion has been seen) and 3507. * objects[POT_ACID].oc_name_known (fully discovered), 3508. * or "some {plural version} explode" when relevant. 3509. * Second and subsequent messages for same chain and 3510. * matching dknown status are 3511. * "another [potion|<color> &c] explodes" or plural 3512. * variant. 3513. */ 3514. bufp = simpleonames(obj); 3515. pline("%s %s %s!", /* "A potion explodes!" */ 3516. !exploded ? (one ? "A" : "Some") 3517. : (one ? "Another" : "More"), 3518. bufp, vtense(bufp, "explode")); 3519. if (acid_ctx.ctx_valid) { 3520. if (obj->dknown) 3521. acid_ctx.dkn_boom++; 3522. else 3523. acid_ctx.unk_boom++; 3524. } 3525. setnotworn(obj); 3526. delobj(obj); 3527. if (update) 3528. update_inventory(); 3529. return ER_DESTROYED; 3530. } else if (obj->odiluted) { 3531. if (carried(obj)) 3532. pline("Your %s %s further.", ostr, vtense(ostr, "dilute")); 3533. 3534. obj->otyp = POT_WATER; 3535. obj->dknown = 0; 3536. obj->blessed = obj->cursed = 0; 3537. obj->odiluted = 0; 3538. if (carried(obj)) 3539. update_inventory(); 3540. return ER_DAMAGED; 3541. } else if (obj->otyp != POT_WATER) { 3542. if (carried(obj)) 3543. pline("Your %s %s.", ostr, vtense(ostr, "dilute")); 3544. 3545. obj->odiluted++; 3546. if (carried(obj)) 3547. update_inventory(); 3548. return ER_DAMAGED; 3549. } 3550. } else { 3551. return erode_obj(obj, ostr, ERODE_RUST, EF_NONE); 3552. } 3553. return ER_NOTHING; 3554. } 3555.
water_damage_chain
3556. void 3557. water_damage_chain(obj, here) 3558. struct obj *obj; 3559. boolean here; 3560. { 3561. struct obj *otmp; 3562. 3563. /* initialize acid context: so far, neither seen (dknown) potions of 3564. acid nor unseen have exploded during this water damage sequence */ 3565. acid_ctx.dkn_boom = acid_ctx.unk_boom = 0; 3566. acid_ctx.ctx_valid = TRUE; 3567. 3568. for (; obj; obj = otmp) { 3569. otmp = here ? obj->nexthere : obj->nobj; 3570. water_damage(obj, (char *) 0, FALSE); 3571. } 3572. 3573. /* reset acid context */ 3574. acid_ctx.dkn_boom = acid_ctx.unk_boom = 0; 3575. acid_ctx.ctx_valid = FALSE; 3576. } 3577.
emergency_disrobe
3578. /* 3579. * This function is potentially expensive - rolling 3580. * inventory list multiple times. Luckily it's seldom needed. 3581. * Returns TRUE if disrobing made player unencumbered enough to 3582. * crawl out of the current predicament. 3583. */ 3584. STATIC_OVL boolean 3585. emergency_disrobe(lostsome) 3586. boolean *lostsome; 3587. { 3588. int invc = inv_cnt(TRUE); 3589. 3590. while (near_capacity() > (Punished ? UNENCUMBERED : SLT_ENCUMBER)) { 3591. register struct obj *obj, *otmp = (struct obj *) 0; 3592. register int i; 3593. 3594. /* Pick a random object */ 3595. if (invc > 0) { 3596. i = rn2(invc); 3597. for (obj = invent; obj; obj = obj->nobj) { 3598. /* 3599. * Undroppables are: body armor, boots, gloves, 3600. * amulets, and rings because of the time and effort 3601. * in removing them + loadstone and other cursed stuff 3602. * for obvious reasons. 3603. */ 3604. if (!((obj->otyp == LOADSTONE && obj->cursed) || obj == uamul 3605. || obj == uleft || obj == uright || obj == ublindf 3606. || obj == uarm || obj == uarmc || obj == uarmg 3607. || obj == uarmf || obj == uarmu 3608. || (obj->cursed && (obj == uarmh || obj == uarms)) 3609. || welded(obj))) 3610. otmp = obj; 3611. /* reached the mark and found some stuff to drop? */ 3612. if (--i < 0 && otmp) 3613. break; 3614. 3615. /* else continue */ 3616. } 3617. } 3618. if (!otmp) 3619. return FALSE; /* nothing to drop! */ 3620. if (otmp->owornmask) 3621. remove_worn_item(otmp, FALSE); 3622. *lostsome = TRUE; 3623. dropx(otmp); 3624. invc--; 3625. } 3626. return TRUE; 3627. } 3628. 3629.
drown
3630. /* return TRUE iff player relocated */ 3631. boolean 3632. drown() 3633. { 3634. const char *pool_of_water; 3635. boolean inpool_ok = FALSE, crawl_ok; 3636. int i, x, y; 3637. 3638. /* happily wading in the same contiguous pool */ 3639. if (u.uinwater && is_pool(u.ux - u.dx, u.uy - u.dy) 3640. && (Swimming || Amphibious)) { 3641. /* water effects on objects every now and then */ 3642. if (!rn2(5)) 3643. inpool_ok = TRUE; 3644. else 3645. return FALSE; 3646. } 3647. 3648. if (!u.uinwater) { 3649. You("%s into the %s%c", Is_waterlevel(&u.uz) ? "plunge" : "fall", 3650. hliquid("water"), 3651. Amphibious || Swimming ? '.' : '!'); 3652. if (!Swimming && !Is_waterlevel(&u.uz)) 3653. You("sink like %s.", Hallucination ? "the Titanic" : "a rock"); 3654. } 3655. 3656. water_damage_chain(invent, FALSE); 3657. 3658. if (u.umonnum == PM_GREMLIN && rn2(3)) 3659. (void) split_mon(&youmonst, (struct monst *) 0); 3660. else if (u.umonnum == PM_IRON_GOLEM) { 3661. You("rust!"); 3662. i = Maybe_Half_Phys(d(2, 6)); 3663. if (u.mhmax > i) 3664. u.mhmax -= i; 3665. losehp(i, "rusting away", KILLED_BY); 3666. } 3667. if (inpool_ok) 3668. return FALSE; 3669. 3670. if ((i = number_leashed()) > 0) { 3671. pline_The("leash%s slip%s loose.", (i > 1) ? "es" : "", 3672. (i > 1) ? "" : "s"); 3673. unleash_all(); 3674. } 3675. 3676. if (Amphibious || Swimming) { 3677. if (Amphibious) { 3678. if (flags.verbose) 3679. pline("But you aren't drowning."); 3680. if (!Is_waterlevel(&u.uz)) { 3681. if (Hallucination) 3682. Your("keel hits the bottom."); 3683. else 3684. You("touch bottom."); 3685. } 3686. } 3687. if (Punished) { 3688. unplacebc(); 3689. placebc(); 3690. } 3691. vision_recalc(2); /* unsee old position */ 3692. u.uinwater = 1; 3693. under_water(1); 3694. vision_full_recalc = 1; 3695. return FALSE; 3696. } 3697. if ((Teleportation || can_teleport(youmonst.data)) && !Unaware 3698. && (Teleport_control || rn2(3) < Luck + 2)) { 3699. You("attempt a teleport spell."); /* utcsri!carroll */ 3700. if (!level.flags.noteleport) { 3701. (void) dotele(); 3702. if (!is_pool(u.ux, u.uy)) 3703. return TRUE; 3704. } else 3705. pline_The("attempted teleport spell fails."); 3706. } 3707. if (u.usteed) { 3708. dismount_steed(DISMOUNT_GENERIC); 3709. if (!is_pool(u.ux, u.uy)) 3710. return TRUE; 3711. } 3712. crawl_ok = FALSE; 3713. x = y = 0; /* lint suppression */ 3714. /* if sleeping, wake up now so that we don't crawl out of water 3715. while still asleep; we can't do that the same way that waking 3716. due to combat is handled; note unmul() clears u.usleep */ 3717. if (u.usleep) 3718. unmul("Suddenly you wake up!"); 3719. /* being doused will revive from fainting */ 3720. if (is_fainted()) 3721. reset_faint(); 3722. /* can't crawl if unable to move (crawl_ok flag stays false) */ 3723. if (multi < 0 || (Upolyd && !youmonst.data->mmove)) 3724. goto crawl; 3725. /* look around for a place to crawl to */ 3726. for (i = 0; i < 100; i++) { 3727. x = rn1(3, u.ux - 1); 3728. y = rn1(3, u.uy - 1); 3729. if (crawl_destination(x, y)) { 3730. crawl_ok = TRUE; 3731. goto crawl; 3732. } 3733. } 3734. /* one more scan */ 3735. for (x = u.ux - 1; x <= u.ux + 1; x++) 3736. for (y = u.uy - 1; y <= u.uy + 1; y++) 3737. if (crawl_destination(x, y)) { 3738. crawl_ok = TRUE; 3739. goto crawl; 3740. } 3741. crawl: 3742. if (crawl_ok) { 3743. boolean lost = FALSE; 3744. /* time to do some strip-tease... */ 3745. boolean succ = Is_waterlevel(&u.uz) ? TRUE : emergency_disrobe(&lost); 3746. 3747. You("try to crawl out of the %s.", hliquid("water")); 3748. if (lost) 3749. You("dump some of your gear to lose weight..."); 3750. if (succ) { 3751. pline("Pheew! That was close."); 3752. teleds(x, y, TRUE); 3753. return TRUE; 3754. } 3755. /* still too much weight */ 3756. pline("But in vain."); 3757. } 3758. u.uinwater = 1; 3759. You("drown."); 3760. for (i = 0; i < 5; i++) { /* arbitrary number of loops */ 3761. /* killer format and name are reconstructed every iteration 3762. because lifesaving resets them */ 3763. pool_of_water = waterbody_name(u.ux, u.uy); 3764. killer.format = KILLED_BY_AN; 3765. /* avoid "drowned in [a] water" */ 3766. if (!strcmp(pool_of_water, "water")) 3767. pool_of_water = "deep water", killer.format = KILLED_BY; 3768. Strcpy(killer.name, pool_of_water); 3769. done(DROWNING); 3770. /* oops, we're still alive. better get out of the water. */ 3771. if (safe_teleds(TRUE)) 3772. break; /* successful life-save */ 3773. /* nowhere safe to land; repeat drowning loop... */ 3774. pline("You're still drowning."); 3775. } 3776. if (u.uinwater) { 3777. u.uinwater = 0; 3778. You("find yourself back %s.", 3779. Is_waterlevel(&u.uz) ? "in an air bubble" : "on land"); 3780. } 3781. return TRUE; 3782. } 3783.
drain_en
3784. void 3785. drain_en(n) 3786. int n; 3787. { 3788. if (!u.uenmax) { 3789. /* energy is completely gone */ 3790. You_feel("momentarily lethargic."); 3791. } else { 3792. /* throttle further loss a bit when there's not much left to lose */ 3793. if (n > u.uenmax || n > u.ulevel) 3794. n = rnd(n); 3795. 3796. You_feel("your magical energy drain away%c", (n > u.uen) ? '!' : '.'); 3797. u.uen -= n; 3798. if (u.uen < 0) { 3799. u.uenmax -= rnd(-u.uen); 3800. if (u.uenmax < 0) 3801. u.uenmax = 0; 3802. u.uen = 0; 3803. } 3804. context.botl = 1; 3805. } 3806. } 3807.
dountrap
3808. /* disarm a trap */ 3809. int 3810. dountrap() 3811. { 3812. if (near_capacity() >= HVY_ENCUMBER) { 3813. pline("You're too strained to do that."); 3814. return 0; 3815. } 3816. if ((nohands(youmonst.data) && !webmaker(youmonst.data)) 3817. || !youmonst.data->mmove) { 3818. pline("And just how do you expect to do that?"); 3819. return 0; 3820. } else if (u.ustuck && sticks(youmonst.data)) { 3821. pline("You'll have to let go of %s first.", mon_nam(u.ustuck)); 3822. return 0; 3823. } 3824. if (u.ustuck || (welded(uwep) && bimanual(uwep))) { 3825. Your("%s seem to be too busy for that.", makeplural(body_part(HAND))); 3826. return 0; 3827. } 3828. return untrap(FALSE); 3829. } 3830.
untrap_prob
3831. /* Probability of disabling a trap. Helge Hafting */ 3832. STATIC_OVL int 3833. untrap_prob(ttmp) 3834. struct trap *ttmp; 3835. { 3836. int chance = 3; 3837. 3838. /* Only spiders know how to deal with webs reliably */ 3839. if (ttmp->ttyp == WEB && !webmaker(youmonst.data)) 3840. chance = 30; 3841. if (Confusion || Hallucination) 3842. chance++; 3843. if (Blind) 3844. chance++; 3845. if (Stunned) 3846. chance += 2; 3847. if (Fumbling) 3848. chance *= 2; 3849. /* Your own traps are better known than others. */ 3850. if (ttmp && ttmp->madeby_u) 3851. chance--; 3852. if (Role_if(PM_ROGUE)) { 3853. if (rn2(2 * MAXULEV) < u.ulevel) 3854. chance--; 3855. if (u.uhave.questart && chance > 1) 3856. chance--; 3857. } else if (Role_if(PM_RANGER) && chance > 1) 3858. chance--; 3859. return rn2(chance); 3860. } 3861.
cnv_trap_obj
3862. /* Replace trap with object(s). Helge Hafting */ 3863. void 3864. cnv_trap_obj(otyp, cnt, ttmp, bury_it) 3865. int otyp; 3866. int cnt; 3867. struct trap *ttmp; 3868. boolean bury_it; 3869. { 3870. struct obj *otmp = mksobj(otyp, TRUE, FALSE); 3871. 3872. otmp->quan = cnt; 3873. otmp->owt = weight(otmp); 3874. /* Only dart traps are capable of being poisonous */ 3875. if (otyp != DART) 3876. otmp->opoisoned = 0; 3877. place_object(otmp, ttmp->tx, ttmp->ty); 3878. if (bury_it) { 3879. /* magical digging first disarms this trap, then will unearth it */ 3880. (void) bury_an_obj(otmp, (boolean *) 0); 3881. } else { 3882. /* Sell your own traps only... */ 3883. if (ttmp->madeby_u) 3884. sellobj(otmp, ttmp->tx, ttmp->ty); 3885. stackobj(otmp); 3886. } 3887. newsym(ttmp->tx, ttmp->ty); 3888. if (u.utrap && ttmp->tx == u.ux && ttmp->ty == u.uy) 3889. u.utrap = 0; 3890. deltrap(ttmp); 3891. } 3892.
move_into_trap
3893. /* while attempting to disarm an adjacent trap, we've fallen into it */ 3894. STATIC_OVL void 3895. move_into_trap(ttmp) 3896. struct trap *ttmp; 3897. { 3898. int bc = 0; 3899. xchar x = ttmp->tx, y = ttmp->ty, bx, by, cx, cy; 3900. boolean unused; 3901. 3902. bx = by = cx = cy = 0; /* lint suppression */ 3903. /* we know there's no monster in the way, and we're not trapped */ 3904. if (!Punished 3905. || drag_ball(x, y, &bc, &bx, &by, &cx, &cy, &unused, TRUE)) { 3906. u.ux0 = u.ux, u.uy0 = u.uy; 3907. u.ux = x, u.uy = y; 3908. u.umoved = TRUE; 3909. newsym(u.ux0, u.uy0); 3910. vision_recalc(1); 3911. check_leash(u.ux0, u.uy0); 3912. if (Punished) 3913. move_bc(0, bc, bx, by, cx, cy); 3914. /* marking the trap unseen forces dotrap() to treat it like a new 3915. discovery and prevents pickup() -> look_here() -> check_here() 3916. from giving a redundant "there is a <trap> here" message when 3917. there are objects covering this trap */ 3918. ttmp->tseen = 0; /* hack for check_here() */ 3919. /* trigger the trap */ 3920. spoteffects(TRUE); /* pickup() + dotrap() */ 3921. exercise(A_WIS, FALSE); 3922. } 3923. } 3924.
try_disarm
3925. /* 0: doesn't even try 3926. * 1: tries and fails 3927. * 2: succeeds 3928. */ 3929. STATIC_OVL int 3930. try_disarm(ttmp, force_failure) 3931. struct trap *ttmp; 3932. boolean force_failure; 3933. { 3934. struct monst *mtmp = m_at(ttmp->tx, ttmp->ty); 3935. int ttype = ttmp->ttyp; 3936. boolean under_u = (!u.dx && !u.dy); 3937. boolean holdingtrap = (ttype == BEAR_TRAP || ttype == WEB); 3938. 3939. /* Test for monster first, monsters are displayed instead of trap. */ 3940. if (mtmp && (!mtmp->mtrapped || !holdingtrap)) { 3941. pline("%s is in the way.", Monnam(mtmp)); 3942. return 0; 3943. } 3944. /* We might be forced to move onto the trap's location. */ 3945. if (sobj_at(BOULDER, ttmp->tx, ttmp->ty) && !Passes_walls && !under_u) { 3946. There("is a boulder in your way."); 3947. return 0; 3948. } 3949. /* duplicate tight-space checks from test_move */ 3950. if (u.dx && u.dy && bad_rock(youmonst.data, u.ux, ttmp->ty) 3951. && bad_rock(youmonst.data, ttmp->tx, u.uy)) { 3952. if ((invent && (inv_weight() + weight_cap() > 600)) 3953. || bigmonst(youmonst.data)) { 3954. /* don't allow untrap if they can't get thru to it */ 3955. You("are unable to reach the %s!", 3956. defsyms[trap_to_defsym(ttype)].explanation); 3957. return 0; 3958. } 3959. } 3960. /* untrappable traps are located on the ground. */ 3961. if (!can_reach_floor(TRUE)) { 3962. if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) 3963. rider_cant_reach(); 3964. else 3965. You("are unable to reach the %s!", 3966. defsyms[trap_to_defsym(ttype)].explanation); 3967. return 0; 3968. } 3969. 3970. /* Will our hero succeed? */ 3971. if (force_failure || untrap_prob(ttmp)) { 3972. if (rnl(5)) { 3973. pline("Whoops..."); 3974. if (mtmp) { /* must be a trap that holds monsters */ 3975. if (ttype == BEAR_TRAP) { 3976. if (mtmp->mtame) 3977. abuse_dog(mtmp); 3978. mtmp->mhp -= rnd(4); 3979. if (mtmp->mhp <= 0) 3980. killed(mtmp); 3981. } else if (ttype == WEB) { 3982. if (!webmaker(youmonst.data)) { 3983. struct trap *ttmp2 = maketrap(u.ux, u.uy, WEB); 3984. 3985. if (ttmp2) { 3986. pline_The( 3987. "webbing sticks to you. You're caught too!"); 3988. dotrap(ttmp2, NOWEBMSG); 3989. if (u.usteed && u.utrap) { 3990. /* you, not steed, are trapped */ 3991. dismount_steed(DISMOUNT_FELL); 3992. } 3993. } 3994. } else 3995. pline("%s remains entangled.", Monnam(mtmp)); 3996. } 3997. } else if (under_u) { 3998. dotrap(ttmp, 0); 3999. } else { 4000. move_into_trap(ttmp); 4001. } 4002. } else { 4003. pline("%s %s is difficult to %s.", 4004. ttmp->madeby_u ? "Your" : under_u ? "This" : "That", 4005. defsyms[trap_to_defsym(ttype)].explanation, 4006. (ttype == WEB) ? "remove" : "disarm"); 4007. } 4008. return 1; 4009. } 4010. return 2; 4011. } 4012.
reward_untrap
4013. STATIC_OVL void 4014. reward_untrap(ttmp, mtmp) 4015. struct trap *ttmp; 4016. struct monst *mtmp; 4017. { 4018. if (!ttmp->madeby_u) { 4019. if (rnl(10) < 8 && !mtmp->mpeaceful && !mtmp->msleeping 4020. && !mtmp->mfrozen && !mindless(mtmp->data) 4021. && mtmp->data->mlet != S_HUMAN) { 4022. mtmp->mpeaceful = 1; 4023. set_malign(mtmp); /* reset alignment */ 4024. pline("%s is grateful.", Monnam(mtmp)); 4025. } 4026. /* Helping someone out of a trap is a nice thing to do, 4027. * A lawful may be rewarded, but not too often. */ 4028. if (!rn2(3) && !rnl(8) && u.ualign.type == A_LAWFUL) { 4029. adjalign(1); 4030. You_feel("that you did the right thing."); 4031. } 4032. } 4033. } 4034.
disarm_holdingtrap
4035. STATIC_OVL int 4036. disarm_holdingtrap(ttmp) /* Helge Hafting */ 4037. struct trap *ttmp; 4038. { 4039. struct monst *mtmp; 4040. int fails = try_disarm(ttmp, FALSE); 4041. 4042. if (fails < 2) 4043. return fails; 4044. 4045. /* ok, disarm it. */ 4046. 4047. /* untrap the monster, if any. 4048. There's no need for a cockatrice test, only the trap is touched */ 4049. if ((mtmp = m_at(ttmp->tx, ttmp->ty)) != 0) { 4050. mtmp->mtrapped = 0; 4051. You("remove %s %s from %s.", the_your[ttmp->madeby_u], 4052. (ttmp->ttyp == BEAR_TRAP) ? "bear trap" : "webbing", 4053. mon_nam(mtmp)); 4054. reward_untrap(ttmp, mtmp); 4055. } else { 4056. if (ttmp->ttyp == BEAR_TRAP) { 4057. You("disarm %s bear trap.", the_your[ttmp->madeby_u]); 4058. cnv_trap_obj(BEARTRAP, 1, ttmp, FALSE); 4059. } else /* if (ttmp->ttyp == WEB) */ { 4060. You("succeed in removing %s web.", the_your[ttmp->madeby_u]); 4061. deltrap(ttmp); 4062. } 4063. } 4064. newsym(u.ux + u.dx, u.uy + u.dy); 4065. return 1; 4066. } 4067.
disarm_landmine
4068. STATIC_OVL int 4069. disarm_landmine(ttmp) /* Helge Hafting */ 4070. struct trap *ttmp; 4071. { 4072. int fails = try_disarm(ttmp, FALSE); 4073. 4074. if (fails < 2) 4075. return fails; 4076. You("disarm %s land mine.", the_your[ttmp->madeby_u]); 4077. cnv_trap_obj(LAND_MINE, 1, ttmp, FALSE); 4078. return 1; 4079. } 4080. 4081. /* getobj will filter down to cans of grease and known potions of oil */ 4082. static NEARDATA const char oil[] = { ALL_CLASSES, TOOL_CLASS, POTION_CLASS, 4083. 0 }; 4084.
disarm_squeaky_board
4085. /* it may not make much sense to use grease on floor boards, but so what? */ 4086. STATIC_OVL int 4087. disarm_squeaky_board(ttmp) 4088. struct trap *ttmp; 4089. { 4090. struct obj *obj; 4091. boolean bad_tool; 4092. int fails; 4093. 4094. obj = getobj(oil, "untrap with"); 4095. if (!obj) 4096. return 0; 4097. 4098. bad_tool = (obj->cursed 4099. || ((obj->otyp != POT_OIL || obj->lamplit) 4100. && (obj->otyp != CAN_OF_GREASE || !obj->spe))); 4101. fails = try_disarm(ttmp, bad_tool); 4102. if (fails < 2) 4103. return fails; 4104. 4105. /* successfully used oil or grease to fix squeaky board */ 4106. if (obj->otyp == CAN_OF_GREASE) { 4107. consume_obj_charge(obj, TRUE); 4108. } else { 4109. useup(obj); /* oil */ 4110. makeknown(POT_OIL); 4111. } 4112. You("repair the squeaky board."); /* no madeby_u */ 4113. deltrap(ttmp); 4114. newsym(u.ux + u.dx, u.uy + u.dy); 4115. more_experienced(1, 5); 4116. newexplevel(); 4117. return 1; 4118. } 4119.
disarm_shooting_trap
4120. /* removes traps that shoot arrows, darts, etc. */ 4121. STATIC_OVL int 4122. disarm_shooting_trap(ttmp, otyp) 4123. struct trap *ttmp; 4124. int otyp; 4125. { 4126. int fails = try_disarm(ttmp, FALSE); 4127. 4128. if (fails < 2) 4129. return fails; 4130. You("disarm %s trap.", the_your[ttmp->madeby_u]); 4131. cnv_trap_obj(otyp, 50 - rnl(50), ttmp, FALSE); 4132. return 1; 4133. } 4134.
try_lift
4135. /* Is the weight too heavy? 4136. * Formula as in near_capacity() & check_capacity() */ 4137. STATIC_OVL int 4138. try_lift(mtmp, ttmp, wt, stuff) 4139. struct monst *mtmp; 4140. struct trap *ttmp; 4141. int wt; 4142. boolean stuff; 4143. { 4144. int wc = weight_cap(); 4145. 4146. if (((wt * 2) / wc) >= HVY_ENCUMBER) { 4147. pline("%s is %s for you to lift.", Monnam(mtmp), 4148. stuff ? "carrying too much" : "too heavy"); 4149. if (!ttmp->madeby_u && !mtmp->mpeaceful && mtmp->mcanmove 4150. && !mindless(mtmp->data) && mtmp->data->mlet != S_HUMAN 4151. && rnl(10) < 3) { 4152. mtmp->mpeaceful = 1; 4153. set_malign(mtmp); /* reset alignment */ 4154. pline("%s thinks it was nice of you to try.", Monnam(mtmp)); 4155. } 4156. return 0; 4157. } 4158. return 1; 4159. } 4160.
help_monster_out
4161. /* Help trapped monster (out of a (spiked) pit) */ 4162. STATIC_OVL int 4163. help_monster_out(mtmp, ttmp) 4164. struct monst *mtmp; 4165. struct trap *ttmp; 4166. { 4167. int wt; 4168. struct obj *otmp; 4169. boolean uprob; 4170. 4171. /* 4172. * This works when levitating too -- consistent with the ability 4173. * to hit monsters while levitating. 4174. * 4175. * Should perhaps check that our hero has arms/hands at the 4176. * moment. Helping can also be done by engulfing... 4177. * 4178. * Test the monster first - monsters are displayed before traps. 4179. */ 4180. if (!mtmp->mtrapped) { 4181. pline("%s isn't trapped.", Monnam(mtmp)); 4182. return 0; 4183. } 4184. /* Do you have the necessary capacity to lift anything? */ 4185. if (check_capacity((char *) 0)) 4186. return 1; 4187. 4188. /* Will our hero succeed? */ 4189. if ((uprob = untrap_prob(ttmp)) && !mtmp->msleeping && mtmp->mcanmove) { 4190. You("try to reach out your %s, but %s backs away skeptically.", 4191. makeplural(body_part(ARM)), mon_nam(mtmp)); 4192. return 1; 4193. } 4194. 4195. /* is it a cockatrice?... */ 4196. if (touch_petrifies(mtmp->data) && !uarmg && !Stone_resistance) { 4197. You("grab the trapped %s using your bare %s.", mtmp->data->mname, 4198. makeplural(body_part(HAND))); 4199. 4200. if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) { 4201. display_nhwindow(WIN_MESSAGE, FALSE); 4202. } else { 4203. char kbuf[BUFSZ]; 4204. 4205. Sprintf(kbuf, "trying to help %s out of a pit", 4206. an(mtmp->data->mname)); 4207. instapetrify(kbuf); 4208. return 1; 4209. } 4210. } 4211. /* need to do cockatrice check first if sleeping or paralyzed */ 4212. if (uprob) { 4213. You("try to grab %s, but cannot get a firm grasp.", mon_nam(mtmp)); 4214. if (mtmp->msleeping) { 4215. mtmp->msleeping = 0; 4216. pline("%s awakens.", Monnam(mtmp)); 4217. } 4218. return 1; 4219. } 4220. 4221. You("reach out your %s and grab %s.", makeplural(body_part(ARM)), 4222. mon_nam(mtmp)); 4223. 4224. if (mtmp->msleeping) { 4225. mtmp->msleeping = 0; 4226. pline("%s awakens.", Monnam(mtmp)); 4227. } else if (mtmp->mfrozen && !rn2(mtmp->mfrozen)) { 4228. /* After such manhandling, perhaps the effect wears off */ 4229. mtmp->mcanmove = 1; 4230. mtmp->mfrozen = 0; 4231. pline("%s stirs.", Monnam(mtmp)); 4232. } 4233. 4234. /* is the monster too heavy? */ 4235. wt = inv_weight() + mtmp->data->cwt; 4236. if (!try_lift(mtmp, ttmp, wt, FALSE)) 4237. return 1; 4238. 4239. /* is the monster with inventory too heavy? */ 4240. for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) 4241. wt += otmp->owt; 4242. if (!try_lift(mtmp, ttmp, wt, TRUE)) 4243. return 1; 4244. 4245. You("pull %s out of the pit.", mon_nam(mtmp)); 4246. mtmp->mtrapped = 0; 4247. fill_pit(mtmp->mx, mtmp->my); 4248. reward_untrap(ttmp, mtmp); 4249. return 1; 4250. } 4251.
untrap
4252. int 4253. untrap(force) 4254. boolean force; 4255. { 4256. register struct obj *otmp; 4257. register int x, y; 4258. int ch; 4259. struct trap *ttmp; 4260. struct monst *mtmp; 4261. const char *trapdescr; 4262. boolean here, useplural, deal_with_floor_trap, 4263. confused = (Confusion || Hallucination), 4264. trap_skipped = FALSE; 4265. int boxcnt = 0; 4266. char the_trap[BUFSZ], qbuf[QBUFSZ]; 4267. 4268. if (!getdir((char *) 0)) 4269. return 0; 4270. x = u.ux + u.dx; 4271. y = u.uy + u.dy; 4272. if (!isok(x, y)) { 4273. pline_The("perils lurking there are beyond your grasp."); 4274. return 0; 4275. } 4276. /* 'force' is true for #invoke; make it be true for #untrap if 4277. carrying MKoT */ 4278. if (!force && has_magic_key(&youmonst)) 4279. force = TRUE; 4280. 4281. ttmp = t_at(x, y); 4282. if (ttmp && !ttmp->tseen) 4283. ttmp = 0; 4284. trapdescr = ttmp ? defsyms[trap_to_defsym(ttmp->ttyp)].explanation : 0; 4285. here = (x == u.ux && y == u.uy); /* !u.dx && !u.dy */ 4286. 4287. if (here) /* are there are one or more containers here? */ 4288. for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) 4289. if (Is_box(otmp)) { 4290. if (++boxcnt > 1) 4291. break; 4292. } 4293. 4294. deal_with_floor_trap = can_reach_floor(FALSE); 4295. if (!deal_with_floor_trap) { 4296. *the_trap = '\0'; 4297. if (ttmp) 4298. Strcat(the_trap, an(trapdescr)); 4299. if (ttmp && boxcnt) 4300. Strcat(the_trap, " and "); 4301. if (boxcnt) 4302. Strcat(the_trap, (boxcnt == 1) ? "a container" : "containers"); 4303. useplural = ((ttmp && boxcnt > 0) || boxcnt > 1); 4304. /* note: boxcnt and useplural will always be 0 for !here case */ 4305. if (ttmp || boxcnt) 4306. There("%s %s %s but you can't reach %s%s.", 4307. useplural ? "are" : "is", the_trap, here ? "here" : "there", 4308. useplural ? "them" : "it", 4309. u.usteed ? " while mounted" : ""); 4310. trap_skipped = (ttmp != 0); 4311. } else { /* deal_with_floor_trap */ 4312. 4313. if (ttmp) { 4314. Strcpy(the_trap, the(trapdescr)); 4315. if (boxcnt) { 4316. if (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT) { 4317. You_cant("do much about %s%s.", the_trap, 4318. u.utrap ? " that you're stuck in" 4319. : " while standing on the edge of it"); 4320. trap_skipped = TRUE; 4321. deal_with_floor_trap = FALSE; 4322. } else { 4323. Sprintf( 4324. qbuf, "There %s and %s here. %s %s?", 4325. (boxcnt == 1) ? "is a container" : "are containers", 4326. an(trapdescr), 4327. (ttmp->ttyp == WEB) ? "Remove" : "Disarm", the_trap); 4328. switch (ynq(qbuf)) { 4329. case 'q': 4330. return 0; 4331. case 'n': 4332. trap_skipped = TRUE; 4333. deal_with_floor_trap = FALSE; 4334. break; 4335. } 4336. } 4337. } 4338. if (deal_with_floor_trap) { 4339. if (u.utrap) { 4340. You("cannot deal with %s while trapped%s!", the_trap, 4341. (x == u.ux && y == u.uy) ? " in it" : ""); 4342. return 1; 4343. } 4344. if ((mtmp = m_at(x, y)) != 0 4345. && (mtmp->m_ap_type == M_AP_FURNITURE 4346. || mtmp->m_ap_type == M_AP_OBJECT)) { 4347. stumble_onto_mimic(mtmp); 4348. return 1; 4349. } 4350. switch (ttmp->ttyp) { 4351. case BEAR_TRAP: 4352. case WEB: 4353. return disarm_holdingtrap(ttmp); 4354. case LANDMINE: 4355. return disarm_landmine(ttmp); 4356. case SQKY_BOARD: 4357. return disarm_squeaky_board(ttmp); 4358. case DART_TRAP: 4359. return disarm_shooting_trap(ttmp, DART); 4360. case ARROW_TRAP: 4361. return disarm_shooting_trap(ttmp, ARROW); 4362. case PIT: 4363. case SPIKED_PIT: 4364. if (here) { 4365. You("are already on the edge of the pit."); 4366. return 0; 4367. } 4368. if (!mtmp) { 4369. pline("Try filling the pit instead."); 4370. return 0; 4371. } 4372. return help_monster_out(mtmp, ttmp); 4373. default: 4374. You("cannot disable %s trap.", !here ? "that" : "this"); 4375. return 0; 4376. } 4377. } 4378. } /* end if */ 4379. 4380. if (boxcnt) { 4381. for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) 4382. if (Is_box(otmp)) { 4383. (void) safe_qbuf(qbuf, "There is ", 4384. " here. Check it for traps?", otmp, 4385. doname, ansimpleoname, "a box"); 4386. switch (ynq(qbuf)) { 4387. case 'q': 4388. return 0; 4389. case 'n': 4390. continue; 4391. } 4392. 4393. if ((otmp->otrapped 4394. && (force || (!confused 4395. && rn2(MAXULEV + 1 - u.ulevel) < 10))) 4396. || (!force && confused && !rn2(3))) { 4397. You("find a trap on %s!", the(xname(otmp))); 4398. if (!confused) 4399. exercise(A_WIS, TRUE); 4400. 4401. switch (ynq("Disarm it?")) { 4402. case 'q': 4403. return 1; 4404. case 'n': 4405. trap_skipped = TRUE; 4406. continue; 4407. } 4408. 4409. if (otmp->otrapped) { 4410. exercise(A_DEX, TRUE); 4411. ch = ACURR(A_DEX) + u.ulevel; 4412. if (Role_if(PM_ROGUE)) 4413. ch *= 2; 4414. if (!force && (confused || Fumbling 4415. || rnd(75 + level_difficulty() / 2) 4416. > ch)) { 4417. (void) chest_trap(otmp, FINGER, TRUE); 4418. } else { 4419. You("disarm it!"); 4420. otmp->otrapped = 0; 4421. } 4422. } else 4423. pline("That %s was not trapped.", xname(otmp)); 4424. return 1; 4425. } else { 4426. You("find no traps on %s.", the(xname(otmp))); 4427. return 1; 4428. } 4429. } 4430. 4431. You(trap_skipped ? "find no other traps here." 4432. : "know of no traps here."); 4433. return 0; 4434. } 4435. 4436. if (stumble_on_door_mimic(x, y)) 4437. return 1; 4438. 4439. } /* deal_with_floor_trap */ 4440. /* doors can be manipulated even while levitating/unskilled riding */ 4441. 4442. if (!IS_DOOR(levl[x][y].typ)) { 4443. if (!trap_skipped) 4444. You("know of no traps there."); 4445. return 0; 4446. } 4447. 4448. switch (levl[x][y].doormask) { 4449. case D_NODOOR: 4450. You("%s no door there.", Blind ? "feel" : "see"); 4451. return 0; 4452. case D_ISOPEN: 4453. pline("This door is safely open."); 4454. return 0; 4455. case D_BROKEN: 4456. pline("This door is broken."); 4457. return 0; 4458. } 4459. 4460. if (((levl[x][y].doormask & D_TRAPPED) != 0 4461. && (force || (!confused && rn2(MAXULEV - u.ulevel + 11) < 10))) 4462. || (!force && confused && !rn2(3))) { 4463. You("find a trap on the door!"); 4464. exercise(A_WIS, TRUE); 4465. if (ynq("Disarm it?") != 'y') 4466. return 1; 4467. if (levl[x][y].doormask & D_TRAPPED) { 4468. ch = 15 + (Role_if(PM_ROGUE) ? u.ulevel * 3 : u.ulevel); 4469. exercise(A_DEX, TRUE); 4470. if (!force && (confused || Fumbling 4471. || rnd(75 + level_difficulty() / 2) > ch)) { 4472. You("set it off!"); 4473. b_trapped("door", FINGER); 4474. levl[x][y].doormask = D_NODOOR; 4475. unblock_point(x, y); 4476. newsym(x, y); 4477. /* (probably ought to charge for this damage...) */ 4478. if (*in_rooms(x, y, SHOPBASE)) 4479. add_damage(x, y, 0L); 4480. } else { 4481. You("disarm it!"); 4482. levl[x][y].doormask &= ~D_TRAPPED; 4483. } 4484. } else 4485. pline("This door was not trapped."); 4486. return 1; 4487. } else { 4488. You("find no traps on the door."); 4489. return 1; 4490. } 4491. } 4492.
openholdingtrap
4493. /* for magic unlocking; returns true if targetted monster (which might 4494. be hero) gets untrapped; the trap remains intact */ 4495. boolean 4496. openholdingtrap(mon, noticed) 4497. struct monst *mon; 4498. boolean *noticed; /* set to true iff hero notices the effect; */ 4499. { /* otherwise left with its previous value intact */ 4500. struct trap *t; 4501. char buf[BUFSZ]; 4502. const char *trapdescr, *which; 4503. boolean ishero = (mon == &youmonst); 4504. 4505. if (!mon) 4506. return FALSE; 4507. if (mon == u.usteed) 4508. ishero = TRUE; 4509. t = t_at(ishero ? u.ux : mon->mx, ishero ? u.uy : mon->my); 4510. /* if no trap here or it's not a holding trap, we're done */ 4511. if (!t || (t->ttyp != BEAR_TRAP && t->ttyp != WEB)) 4512. return FALSE; 4513. 4514. trapdescr = defsyms[trap_to_defsym(t->ttyp)].explanation; 4515. which = t->tseen ? the_your[t->madeby_u] 4516. : index(vowels, *trapdescr) ? "an" : "a"; 4517. 4518. if (ishero) { 4519. if (!u.utrap) 4520. return FALSE; 4521. u.utrap = 0; /* released regardless of type */ 4522. *noticed = TRUE; 4523. /* give message only if trap was the expected type */ 4524. if (u.utraptype == TT_BEARTRAP || u.utraptype == TT_WEB) { 4525. if (u.usteed) 4526. Sprintf(buf, "%s is", noit_Monnam(u.usteed)); 4527. else 4528. Strcpy(buf, "You are"); 4529. pline("%s released from %s %s.", buf, which, trapdescr); 4530. } 4531. } else { 4532. if (!mon->mtrapped) 4533. return FALSE; 4534. mon->mtrapped = 0; 4535. if (canspotmon(mon)) { 4536. *noticed = TRUE; 4537. pline("%s is released from %s %s.", Monnam(mon), which, 4538. trapdescr); 4539. } else if (cansee(t->tx, t->ty) && t->tseen) { 4540. *noticed = TRUE; 4541. if (t->ttyp == WEB) 4542. pline("%s is released from %s %s.", Something, which, 4543. trapdescr); 4544. else /* BEAR_TRAP */ 4545. pline("%s %s opens.", upstart(strcpy(buf, which)), trapdescr); 4546. } 4547. /* might pacify monster if adjacent */ 4548. if (rn2(2) && distu(mon->mx, mon->my) <= 2) 4549. reward_untrap(t, mon); 4550. } 4551. return TRUE; 4552. } 4553.
closeholdingtrap
4554. /* for magic locking; returns true if targetted monster (which might 4555. be hero) gets hit by a trap (might avoid actually becoming trapped) */ 4556. boolean 4557. closeholdingtrap(mon, noticed) 4558. struct monst *mon; 4559. boolean *noticed; /* set to true iff hero notices the effect; */ 4560. { /* otherwise left with its previous value intact */ 4561. struct trap *t; 4562. unsigned dotrapflags; 4563. boolean ishero = (mon == &youmonst), result; 4564. 4565. if (!mon) 4566. return FALSE; 4567. if (mon == u.usteed) 4568. ishero = TRUE; 4569. t = t_at(ishero ? u.ux : mon->mx, ishero ? u.uy : mon->my); 4570. /* if no trap here or it's not a holding trap, we're done */ 4571. if (!t || (t->ttyp != BEAR_TRAP && t->ttyp != WEB)) 4572. return FALSE; 4573. 4574. if (ishero) { 4575. if (u.utrap) 4576. return FALSE; /* already trapped */ 4577. *noticed = TRUE; 4578. dotrapflags = FORCETRAP; 4579. /* dotrap calls mintrap when mounted hero encounters a web */ 4580. if (u.usteed) 4581. dotrapflags |= NOWEBMSG; 4582. ++force_mintrap; 4583. dotrap(t, dotrapflags); 4584. --force_mintrap; 4585. result = (u.utrap != 0); 4586. } else { 4587. if (mon->mtrapped) 4588. return FALSE; /* already trapped */ 4589. /* you notice it if you see the trap close/tremble/whatever 4590. or if you sense the monster who becomes trapped */ 4591. *noticed = cansee(t->tx, t->ty) || canspotmon(mon); 4592. ++force_mintrap; 4593. result = (mintrap(mon) != 0); 4594. --force_mintrap; 4595. } 4596. return result; 4597. } 4598.
openfallingtrap
4599. /* for magic unlocking; returns true if targetted monster (which might 4600. be hero) gets hit by a trap (target might avoid its effect) */ 4601. boolean 4602. openfallingtrap(mon, trapdoor_only, noticed) 4603. struct monst *mon; 4604. boolean trapdoor_only; 4605. boolean *noticed; /* set to true iff hero notices the effect; */ 4606. { /* otherwise left with its previous value intact */ 4607. struct trap *t; 4608. boolean ishero = (mon == &youmonst), result; 4609. 4610. if (!mon) 4611. return FALSE; 4612. if (mon == u.usteed) 4613. ishero = TRUE; 4614. t = t_at(ishero ? u.ux : mon->mx, ishero ? u.uy : mon->my); 4615. /* if no trap here or it's not a falling trap, we're done 4616. (note: falling rock traps have a trapdoor in the ceiling) */ 4617. if (!t || ((t->ttyp != TRAPDOOR && t->ttyp != ROCKTRAP) 4618. && (trapdoor_only || (t->ttyp != HOLE && t->ttyp != PIT 4619. && t->ttyp != SPIKED_PIT)))) 4620. return FALSE; 4621. 4622. if (ishero) { 4623. if (u.utrap) 4624. return FALSE; /* already trapped */ 4625. *noticed = TRUE; 4626. dotrap(t, FORCETRAP); 4627. result = (u.utrap != 0); 4628. } else { 4629. if (mon->mtrapped) 4630. return FALSE; /* already trapped */ 4631. /* you notice it if you see the trap close/tremble/whatever 4632. or if you sense the monster who becomes trapped */ 4633. *noticed = cansee(t->tx, t->ty) || canspotmon(mon); 4634. /* monster will be angered; mintrap doesn't handle that */ 4635. wakeup(mon, TRUE); 4636. ++force_mintrap; 4637. result = (mintrap(mon) != 0); 4638. --force_mintrap; 4639. /* mon might now be on the migrating monsters list */ 4640. } 4641. return result; 4642. } 4643.
chest_trap
4644. /* only called when the player is doing something to the chest directly */ 4645. boolean 4646. chest_trap(obj, bodypart, disarm) 4647. register struct obj *obj; 4648. register int bodypart; 4649. boolean disarm; 4650. { 4651. register struct obj *otmp = obj, *otmp2; 4652. char buf[80]; 4653. const char *msg; 4654. coord cc; 4655. 4656. if (get_obj_location(obj, &cc.x, &cc.y, 0)) /* might be carried */ 4657. obj->ox = cc.x, obj->oy = cc.y; 4658. 4659. otmp->otrapped = 0; /* trap is one-shot; clear flag first in case 4660. chest kills you and ends up in bones file */ 4661. You(disarm ? "set it off!" : "trigger a trap!"); 4662. display_nhwindow(WIN_MESSAGE, FALSE); 4663. if (Luck > -13 && rn2(13 + Luck) > 7) { /* saved by luck */ 4664. /* trap went off, but good luck prevents damage */ 4665. switch (rn2(13)) { 4666. case 12: 4667. case 11: 4668. msg = "explosive charge is a dud"; 4669. break; 4670. case 10: 4671. case 9: 4672. msg = "electric charge is grounded"; 4673. break; 4674. case 8: 4675. case 7: 4676. msg = "flame fizzles out"; 4677. break; 4678. case 6: 4679. case 5: 4680. case 4: 4681. msg = "poisoned needle misses"; 4682. break; 4683. case 3: 4684. case 2: 4685. case 1: 4686. case 0: 4687. msg = "gas cloud blows away"; 4688. break; 4689. default: 4690. impossible("chest disarm bug"); 4691. msg = (char *) 0; 4692. break; 4693. } 4694. if (msg) 4695. pline("But luckily the %s!", msg); 4696. } else { 4697. switch (rn2(20) ? ((Luck >= 13) ? 0 : rn2(13 - Luck)) : rn2(26)) { 4698. case 25: 4699. case 24: 4700. case 23: 4701. case 22: 4702. case 21: { 4703. struct monst *shkp = 0; 4704. long loss = 0L; 4705. boolean costly, insider; 4706. register xchar ox = obj->ox, oy = obj->oy; 4707. 4708. /* the obj location need not be that of player */ 4709. costly = (costly_spot(ox, oy) 4710. && (shkp = shop_keeper(*in_rooms(ox, oy, SHOPBASE))) 4711. != (struct monst *) 0); 4712. insider = (*u.ushops && inside_shop(u.ux, u.uy) 4713. && *in_rooms(ox, oy, SHOPBASE) == *u.ushops); 4714. 4715. pline("%s!", Tobjnam(obj, "explode")); 4716. Sprintf(buf, "exploding %s", xname(obj)); 4717. 4718. if (costly) 4719. loss += stolen_value(obj, ox, oy, (boolean) shkp->mpeaceful, 4720. TRUE); 4721. delete_contents(obj); 4722. /* unpunish() in advance if either ball or chain (or both) 4723. is going to be destroyed */ 4724. if (Punished && ((uchain->ox == u.ux && uchain->oy == u.uy) 4725. || (uball->where == OBJ_FLOOR 4726. && uball->ox == u.ux && uball->oy == u.uy))) 4727. unpunish(); 4728. 4729. for (otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp2) { 4730. otmp2 = otmp->nexthere; 4731. if (costly) 4732. loss += stolen_value(otmp, otmp->ox, otmp->oy, 4733. (boolean) shkp->mpeaceful, TRUE); 4734. delobj(otmp); 4735. } 4736. wake_nearby(); 4737. losehp(Maybe_Half_Phys(d(6, 6)), buf, KILLED_BY_AN); 4738. exercise(A_STR, FALSE); 4739. if (costly && loss) { 4740. if (insider) 4741. You("owe %ld %s for objects destroyed.", loss, 4742. currency(loss)); 4743. else { 4744. You("caused %ld %s worth of damage!", loss, 4745. currency(loss)); 4746. make_angry_shk(shkp, ox, oy); 4747. } 4748. } 4749. return TRUE; 4750. } /* case 21 */ 4751. case 20: 4752. case 19: 4753. case 18: 4754. case 17: 4755. pline("A cloud of noxious gas billows from %s.", the(xname(obj))); 4756. poisoned("gas cloud", A_STR, "cloud of poison gas", 15, FALSE); 4757. exercise(A_CON, FALSE); 4758. break; 4759. case 16: 4760. case 15: 4761. case 14: 4762. case 13: 4763. You_feel("a needle prick your %s.", body_part(bodypart)); 4764. poisoned("needle", A_CON, "poisoned needle", 10, FALSE); 4765. exercise(A_CON, FALSE); 4766. break; 4767. case 12: 4768. case 11: 4769. case 10: 4770. case 9: 4771. dofiretrap(obj); 4772. break; 4773. case 8: 4774. case 7: 4775. case 6: { 4776. int dmg; 4777. 4778. You("are jolted by a surge of electricity!"); 4779. if (Shock_resistance) { 4780. shieldeff(u.ux, u.uy); 4781. You("don't seem to be affected."); 4782. dmg = 0; 4783. } else 4784. dmg = d(4, 4); 4785. destroy_item(RING_CLASS, AD_ELEC); 4786. destroy_item(WAND_CLASS, AD_ELEC); 4787. if (dmg) 4788. losehp(dmg, "electric shock", KILLED_BY_AN); 4789. break; 4790. } /* case 6 */ 4791. case 5: 4792. case 4: 4793. case 3: 4794. if (!Free_action) { 4795. pline("Suddenly you are frozen in place!"); 4796. nomul(-d(5, 6)); 4797. multi_reason = "frozen by a trap"; 4798. exercise(A_DEX, FALSE); 4799. nomovemsg = You_can_move_again; 4800. } else 4801. You("momentarily stiffen."); 4802. break; 4803. case 2: 4804. case 1: 4805. case 0: 4806. pline("A cloud of %s gas billows from %s.", 4807. Blind ? blindgas[rn2(SIZE(blindgas))] : rndcolor(), 4808. the(xname(obj))); 4809. if (!Stunned) { 4810. if (Hallucination) 4811. pline("What a groovy feeling!"); 4812. else 4813. You("%s%s...", stagger(youmonst.data, "stagger"), 4814. Halluc_resistance ? "" 4815. : Blind ? " and get dizzy" 4816. : " and your vision blurs"); 4817. } 4818. make_stunned((HStun & TIMEOUT) + (long) rn1(7, 16), FALSE); 4819. (void) make_hallucinated( 4820. (HHallucination & TIMEOUT) + (long) rn1(5, 16), FALSE, 0L); 4821. break; 4822. default: 4823. impossible("bad chest trap"); 4824. break; 4825. } 4826. bot(); /* to get immediate botl re-display */ 4827. } 4828. 4829. return FALSE; 4830. } 4831.
t_at
4832. struct trap * 4833. t_at(x, y) 4834. register int x, y; 4835. { 4836. register struct trap *trap = ftrap; 4837. 4838. while (trap) { 4839. if (trap->tx == x && trap->ty == y) 4840. return trap; 4841. trap = trap->ntrap; 4842. } 4843. return (struct trap *) 0; 4844. } 4845.
deltrap
4846. void 4847. deltrap(trap) 4848. register struct trap *trap; 4849. { 4850. register struct trap *ttmp; 4851. 4852. clear_conjoined_pits(trap); 4853. if (trap == ftrap) { 4854. ftrap = ftrap->ntrap; 4855. } else { 4856. for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) 4857. if (ttmp->ntrap == trap) 4858. break; 4859. if (!ttmp) 4860. panic("deltrap: no preceding trap!"); 4861. ttmp->ntrap = trap->ntrap; 4862. } 4863. if (Sokoban && (trap->ttyp == PIT || trap->ttyp == HOLE)) 4864. maybe_finish_sokoban(); 4865. dealloc_trap(trap); 4866. } 4867.
conjoined_pits
4868. boolean 4869. conjoined_pits(trap2, trap1, u_entering_trap2) 4870. struct trap *trap2, *trap1; 4871. boolean u_entering_trap2; 4872. { 4873. int dx, dy, diridx, adjidx; 4874. 4875. if (!trap1 || !trap2) 4876. return FALSE; 4877. if (!isok(trap2->tx, trap2->ty) || !isok(trap1->tx, trap1->ty) 4878. || !(trap2->ttyp == PIT || trap2->ttyp == SPIKED_PIT) 4879. || !(trap1->ttyp == PIT || trap1->ttyp == SPIKED_PIT) 4880. || (u_entering_trap2 && !(u.utrap && u.utraptype == TT_PIT))) 4881. return FALSE; 4882. dx = sgn(trap2->tx - trap1->tx); 4883. dy = sgn(trap2->ty - trap1->ty); 4884. for (diridx = 0; diridx < 8; diridx++) 4885. if (xdir[diridx] == dx && ydir[diridx] == dy) 4886. break; 4887. /* diridx is valid if < 8 */ 4888. if (diridx < 8) { 4889. adjidx = (diridx + 4) % 8; 4890. if ((trap1->conjoined & (1 << diridx)) 4891. && (trap2->conjoined & (1 << adjidx))) 4892. return TRUE; 4893. } 4894. return FALSE; 4895. } 4896.
clear_conjoined_pits
4897. void 4898. clear_conjoined_pits(trap) 4899. struct trap *trap; 4900. { 4901. int diridx, adjidx, x, y; 4902. struct trap *t; 4903. 4904. if (trap && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)) { 4905. for (diridx = 0; diridx < 8; ++diridx) { 4906. if (trap->conjoined & (1 << diridx)) { 4907. x = trap->tx + xdir[diridx]; 4908. y = trap->ty + ydir[diridx]; 4909. if (isok(x, y) 4910. && (t = t_at(x, y)) != 0 4911. && (t->ttyp == PIT || t->ttyp == SPIKED_PIT)) { 4912. adjidx = (diridx + 4) % 8; 4913. t->conjoined &= ~(1 << adjidx); 4914. } 4915. trap->conjoined &= ~(1 << diridx); 4916. } 4917. } 4918. } 4919. } 4920.
adj_nonconjoined_pit
4921. boolean 4922. adj_nonconjoined_pit(adjtrap) 4923. struct trap *adjtrap; 4924. { 4925. struct trap *trap_with_u = t_at(u.ux0, u.uy0); 4926. 4927. if (trap_with_u && adjtrap && u.utrap && u.utraptype == TT_PIT && 4928. (trap_with_u->ttyp == PIT || trap_with_u->ttyp == SPIKED_PIT) && 4929. (adjtrap->ttyp == PIT || adjtrap->ttyp == SPIKED_PIT)) { 4930. int idx; 4931. for (idx = 0; idx < 8; idx++) { 4932. if (xdir[idx] == u.dx && ydir[idx] == u.dy) 4933. return TRUE; 4934. } 4935. } 4936. return FALSE; 4937. } 4938. 4939. #if 0 4940. /* 4941. * Mark all neighboring pits as conjoined pits. 4942. * (currently not called from anywhere) 4943. */ 4944. STATIC_OVL void 4945. join_adjacent_pits(trap) 4946. struct trap *trap; 4947. { 4948. struct trap *t; 4949. int diridx, x, y; 4950. 4951. if (!trap) 4952. return; 4953. for (diridx = 0; diridx < 8; ++diridx) { 4954. x = trap->tx + xdir[diridx]; 4955. y = trap->ty + ydir[diridx]; 4956. if (isok(x, y)) { 4957. if ((t = t_at(x, y)) != 0 4958. && (t->ttyp == PIT || t->ttyp == SPIKED_PIT)) { 4959. trap->conjoined |= (1 << diridx); 4960. join_adjacent_pits(t); 4961. } else 4962. trap->conjoined &= ~(1 << diridx); 4963. } 4964. } 4965. } 4966. #endif /*0*/ 4967.
uteetering_at_seen_pit
4968. /* 4969. * Returns TRUE if you escaped a pit and are standing on the precipice. 4970. */ 4971. boolean 4972. uteetering_at_seen_pit(trap) 4973. struct trap *trap; 4974. { 4975. if (trap && trap->tseen && (!u.utrap || u.utraptype != TT_PIT) 4976. && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)) 4977. return TRUE; 4978. else 4979. return FALSE; 4980. } 4981.
delfloortrap
4982. /* Destroy a trap that emanates from the floor. */ 4983. boolean 4984. delfloortrap(ttmp) 4985. register struct trap *ttmp; 4986. { 4987. /* some of these are arbitrary -dlc */ 4988. if (ttmp && ((ttmp->ttyp == SQKY_BOARD) || (ttmp->ttyp == BEAR_TRAP) 4989. || (ttmp->ttyp == LANDMINE) || (ttmp->ttyp == FIRE_TRAP) 4990. || (ttmp->ttyp == PIT) || (ttmp->ttyp == SPIKED_PIT) 4991. || (ttmp->ttyp == HOLE) || (ttmp->ttyp == TRAPDOOR) 4992. || (ttmp->ttyp == TELEP_TRAP) || (ttmp->ttyp == LEVEL_TELEP) 4993. || (ttmp->ttyp == WEB) || (ttmp->ttyp == MAGIC_TRAP) 4994. || (ttmp->ttyp == ANTI_MAGIC))) { 4995. register struct monst *mtmp; 4996. 4997. if (ttmp->tx == u.ux && ttmp->ty == u.uy) { 4998. u.utrap = 0; 4999. u.utraptype = 0; 5000. } else if ((mtmp = m_at(ttmp->tx, ttmp->ty)) != 0) { 5001. mtmp->mtrapped = 0; 5002. } 5003. deltrap(ttmp); 5004. return TRUE; 5005. } 5006. return FALSE; 5007. } 5008.
b_trapped
5009. /* used for doors (also tins). can be used for anything else that opens. */ 5010. void 5011. b_trapped(item, bodypart) 5012. const char *item; 5013. int bodypart; 5014. { 5015. int lvl = level_difficulty(), 5016. dmg = rnd(5 + (lvl < 5 ? lvl : 2 + lvl / 2)); 5017. 5018. pline("KABOOM!! %s was booby-trapped!", The(item)); 5019. wake_nearby(); 5020. losehp(Maybe_Half_Phys(dmg), "explosion", KILLED_BY_AN); 5021. exercise(A_STR, FALSE); 5022. if (bodypart) 5023. exercise(A_CON, FALSE); 5024. make_stunned((HStun & TIMEOUT) + (long) dmg, TRUE); 5025. } 5026.
thitm
5027. /* Monster is hit by trap. */ 5028. /* Note: doesn't work if both obj and d_override are null */ 5029. STATIC_OVL boolean 5030. thitm(tlev, mon, obj, d_override, nocorpse) 5031. int tlev; 5032. struct monst *mon; 5033. struct obj *obj; 5034. int d_override; 5035. boolean nocorpse; 5036. { 5037. int strike; 5038. boolean trapkilled = FALSE; 5039. 5040. if (d_override) 5041. strike = 1; 5042. else if (obj) 5043. strike = (find_mac(mon) + tlev + obj->spe <= rnd(20)); 5044. else 5045. strike = (find_mac(mon) + tlev <= rnd(20)); 5046. 5047. /* Actually more accurate than thitu, which doesn't take 5048. * obj->spe into account. 5049. */ 5050. if (!strike) { 5051. if (obj && cansee(mon->mx, mon->my)) 5052. pline("%s is almost hit by %s!", Monnam(mon), doname(obj)); 5053. } else { 5054. int dam = 1; 5055. 5056. if (obj && cansee(mon->mx, mon->my)) 5057. pline("%s is hit by %s!", Monnam(mon), doname(obj)); 5058. if (d_override) 5059. dam = d_override; 5060. else if (obj) { 5061. dam = dmgval(obj, mon); 5062. if (dam < 1) 5063. dam = 1; 5064. } 5065. mon->mhp -= dam; 5066. if (mon->mhp <= 0) { 5067. int xx = mon->mx, yy = mon->my; 5068. 5069. monkilled(mon, "", nocorpse ? -AD_RBRE : AD_PHYS); 5070. if (mon->mhp <= 0) { 5071. newsym(xx, yy); 5072. trapkilled = TRUE; 5073. } 5074. } 5075. } 5076. if (obj && (!strike || d_override)) { 5077. place_object(obj, mon->mx, mon->my); 5078. stackobj(obj); 5079. } else if (obj) 5080. dealloc_obj(obj); 5081. 5082. return trapkilled; 5083. } 5084.
unconscious
5085. boolean 5086. unconscious() 5087. { 5088. if (multi >= 0) 5089. return FALSE; 5090. 5091. return (boolean) (u.usleep 5092. || (nomovemsg 5093. && (!strncmp(nomovemsg, "You awake", 9) 5094. || !strncmp(nomovemsg, "You regain con", 14) 5095. || !strncmp(nomovemsg, "You are consci", 14)))); 5096. } 5097. 5098. static const char lava_killer[] = "molten lava"; 5099.
lava_effects
5100. boolean 5101. lava_effects() 5102. { 5103. register struct obj *obj, *obj2; 5104. int dmg = d(6, 6); /* only applicable for water walking */ 5105. boolean usurvive, boil_away; 5106. 5107. burn_away_slime(); 5108. if (likes_lava(youmonst.data)) 5109. return FALSE; 5110. 5111. usurvive = Fire_resistance || (Wwalking && dmg < u.uhp); 5112. /* 5113. * A timely interrupt might manage to salvage your life 5114. * but not your gear. For scrolls and potions this 5115. * will destroy whole stacks, where fire resistant hero 5116. * survivor only loses partial stacks via destroy_item(). 5117. * 5118. * Flag items to be destroyed before any messages so 5119. * that player causing hangup at --More-- won't get an 5120. * emergency save file created before item destruction. 5121. */ 5122. if (!usurvive) 5123. for (obj = invent; obj; obj = obj->nobj) 5124. if ((is_organic(obj) || obj->oclass == POTION_CLASS) 5125. && !obj->oerodeproof 5126. && objects[obj->otyp].oc_oprop != FIRE_RES 5127. && obj->otyp != SCR_FIRE && obj->otyp != SPE_FIREBALL 5128. && !obj_resists(obj, 0, 0)) /* for invocation items */ 5129. obj->in_use = 1; 5130. 5131. /* Check whether we should burn away boots *first* so we know whether to 5132. * make the player sink into the lava. Assumption: water walking only 5133. * comes from boots. 5134. */ 5135. if (uarmf && is_organic(uarmf) && !uarmf->oerodeproof) { 5136. obj = uarmf; 5137. pline("%s into flame!", Yobjnam2(obj, "burst")); 5138. iflags.in_lava_effects++; /* (see above) */ 5139. (void) Boots_off(); 5140. useup(obj); 5141. iflags.in_lava_effects--; 5142. } 5143. 5144. if (!Fire_resistance) { 5145. if (Wwalking) { 5146. pline_The("%s here burns you!", hliquid("lava")); 5147. if (usurvive) { 5148. losehp(dmg, lava_killer, KILLED_BY); /* lava damage */ 5149. goto burn_stuff; 5150. } 5151. } else 5152. You("fall into the %s!", hliquid("lava")); 5153. 5154. usurvive = Lifesaved || discover; 5155. if (wizard) 5156. usurvive = TRUE; 5157. 5158. /* prevent remove_worn_item() -> Boots_off(WATER_WALKING_BOOTS) -> 5159. spoteffects() -> lava_effects() recursion which would 5160. successfully delete (via useupall) the no-longer-worn boots; 5161. once recursive call returned, we would try to delete them again 5162. here in the outer call (and access stale memory, probably panic) */ 5163. iflags.in_lava_effects++; 5164. 5165. for (obj = invent; obj; obj = obj2) { 5166. obj2 = obj->nobj; 5167. /* above, we set in_use for objects which are to be destroyed */ 5168. if (obj->otyp == SPE_BOOK_OF_THE_DEAD && !Blind) { 5169. if (usurvive) 5170. pline("%s glows a strange %s, but remains intact.", 5171. The(xname(obj)), hcolor("dark red")); 5172. } else if (obj->in_use) { 5173. if (obj->owornmask) { 5174. if (usurvive) 5175. pline("%s into flame!", Yobjnam2(obj, "burst")); 5176. remove_worn_item(obj, TRUE); 5177. } 5178. useupall(obj); 5179. } 5180. } 5181. 5182. iflags.in_lava_effects--; 5183. 5184. /* s/he died... */ 5185. boil_away = (u.umonnum == PM_WATER_ELEMENTAL 5186. || u.umonnum == PM_STEAM_VORTEX 5187. || u.umonnum == PM_FOG_CLOUD); 5188. for (;;) { 5189. u.uhp = -1; 5190. /* killer format and name are reconstructed every iteration 5191. because lifesaving resets them */ 5192. killer.format = KILLED_BY; 5193. Strcpy(killer.name, lava_killer); 5194. You("%s...", boil_away ? "boil away" : "burn to a crisp"); 5195. done(BURNING); 5196. if (safe_teleds(TRUE)) 5197. break; /* successful life-save */ 5198. /* nowhere safe to land; repeat burning loop */ 5199. pline("You're still burning."); 5200. } 5201. You("find yourself back on solid %s.", surface(u.ux, u.uy)); 5202. return TRUE; 5203. } else if (!Wwalking && (!u.utrap || u.utraptype != TT_LAVA)) { 5204. boil_away = !Fire_resistance; 5205. /* if not fire resistant, sink_into_lava() will quickly be fatal; 5206. hero needs to escape immediately */ 5207. u.utrap = rn1(4, 4) + ((boil_away ? 2 : rn1(4, 12)) << 8); 5208. u.utraptype = TT_LAVA; 5209. You("sink into the %s%s!", hliquid("lava"), 5210. !boil_away 5211. ? ", but it only burns slightly" 5212. : " and are about to be immolated"); 5213. if (u.uhp > 1) 5214. losehp(!boil_away ? 1 : (u.uhp / 2), lava_killer, 5215. KILLED_BY); /* lava damage */ 5216. } 5217. 5218. burn_stuff: 5219. destroy_item(SCROLL_CLASS, AD_FIRE); 5220. destroy_item(SPBOOK_CLASS, AD_FIRE); 5221. destroy_item(POTION_CLASS, AD_FIRE); 5222. return FALSE; 5223. } 5224.
sink_into_lava
5225. /* called each turn when trapped in lava */ 5226. void 5227. sink_into_lava() 5228. { 5229. static const char sink_deeper[] = "You sink deeper into the lava."; 5230. 5231. if (!u.utrap || u.utraptype != TT_LAVA) { 5232. ; /* do nothing; this shouldn't happen */ 5233. } else if (!is_lava(u.ux, u.uy)) { 5234. u.utrap = 0; /* this shouldn't happen either */ 5235. } else if (!u.uinvulnerable) { 5236. /* ordinarily we'd have to be fire resistant to survive long 5237. enough to become stuck in lava, but it can happen without 5238. resistance if water walking boots allow survival and then 5239. get burned up; u.utrap time will be quite short in that case */ 5240. if (!Fire_resistance) 5241. u.uhp = (u.uhp + 2) / 3; 5242. 5243. u.utrap -= (1 << 8); 5244. if (u.utrap < (1 << 8)) { 5245. killer.format = KILLED_BY; 5246. Strcpy(killer.name, "molten lava"); 5247. You("sink below the surface and die."); 5248. burn_away_slime(); /* add insult to injury? */ 5249. done(DISSOLVED); 5250. /* can only get here via life-saving; try to get away from lava */ 5251. u.utrap = 0; 5252. (void) safe_teleds(TRUE); 5253. } else if (!u.umoved) { 5254. /* can't fully turn into slime while in lava, but might not 5255. have it be burned away until you've come awfully close */ 5256. if (Slimed && rnd(10 - 1) >= (int) (Slimed & TIMEOUT)) { 5257. pline(sink_deeper); 5258. burn_away_slime(); 5259. } else { 5260. Norep(sink_deeper); 5261. } 5262. u.utrap += rnd(4); 5263. } 5264. } 5265. } 5266.
sokoban_guilt
5267. /* called when something has been done (breaking a boulder, for instance) 5268. which entails a luck penalty if performed on a sokoban level */ 5269. void 5270. sokoban_guilt() 5271. { 5272. if (Sokoban) { 5273. change_luck(-1); 5274. /* TODO: issue some feedback so that player can learn that whatever 5275. he/she just did is a naughty thing to do in sokoban and should 5276. probably be avoided in future.... 5277. Caveat: doing this might introduce message sequencing issues, 5278. depending upon feedback during the various actions which trigger 5279. Sokoban luck penalties. */ 5280. } 5281. } 5282.
maybe_finish_sokoban
5283. /* called when a trap has been deleted or had its ttyp replaced */ 5284. STATIC_OVL void 5285. maybe_finish_sokoban() 5286. { 5287. struct trap *t; 5288. 5289. if (Sokoban && !in_mklev) { 5290. /* scan all remaining traps, ignoring any created by the hero; 5291. if this level has no more pits or holes, the current sokoban 5292. puzzle has been solved */ 5293. for (t = ftrap; t; t = t->ntrap) { 5294. if (t->madeby_u) 5295. continue; 5296. if (t->ttyp == PIT || t->ttyp == HOLE) 5297. break; 5298. } 5299. if (!t) { 5300. /* we've passed the last trap without finding a pit or hole; 5301. clear the sokoban_rules flag so that luck penalties for 5302. things like breaking boulders or jumping will no longer 5303. be given, and restrictions on diagonal moves are lifted */ 5304. Sokoban = 0; /* clear level.flags.sokoban_rules */ 5305. /* TODO: give some feedback about solving the sokoban puzzle 5306. (perhaps say "congratulations" in Japanese?) */ 5307. } 5308. } 5309. } 5310. 5311. /*trap.c*/