| abstract
| - Below is the full text to ball.c from the source code of SLASH'EM 0.0.7E7F2. To link to a particular line, write [[SLASH'EM 0.0.7E7F2/ball.c#line123]], for example. The latest source code for vanilla NetHack is at Source code. 1. /* SCCS Id: @(#)ball.c 3.4 2003/02/03 */ 2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3. /* NetHack may be freely redistributed. See license for details. */ 4. 5. /* Ball & Chain =============================================================*/ 6. 7. #include "hack.h" 8. 9. STATIC_DCL int NDECL(bc_order); 10. STATIC_DCL void NDECL(litter); 11. 12. #ifdef DISPLAY_LAYERS 13. #define memory_object(x, y) (levl[x][y].mem_obj) 14. #else 15. #define memory_object(x, y) (levl[x][y].glyph) 16. #endif 17. 18. void 19. ballfall() 20. { 21. boolean gets_hit; 22. 23. gets_hit = (((uball->ox != u.ux) || (uball->oy != u.uy)) && 24. ((uwep == uball)? FALSE : (boolean)rn2(5))); 25. if (carried(uball)) { 26. pline("Startled, you drop the iron ball."); 27. if (uwep == uball) 28. setuwep((struct obj *)0, FALSE); 29. if (uswapwep == uball) 30. setuswapwep((struct obj *)0, FALSE); 31. if (uquiver == uball) 32. setuqwep((struct obj *)0);; 33. if (uwep != uball) 34. freeinv(uball); 35. } 36. if(gets_hit){ 37. int dmg = rn1(7,25); 38. pline_The("iron ball falls on your %s.", 39. body_part(HEAD)); 40. if (uarmh) { 41. if(is_metallic(uarmh)) { 42. pline("Fortunately, you are wearing a hard helmet."); 43. dmg = 3; 44. } else if (flags.verbose) 45. Your("%s does not protect you.", xname(uarmh)); 46. } 47. losehp(dmg, "crunched in the head by an iron ball", 48. NO_KILLER_PREFIX); 49. } 50. } 51. 52. /* 53. * To make this work, we have to mess with the hero's mind. The rules for 54. * ball&chain are: 55. * 56. * 1. If the hero can see them, fine. 57. * 2. If the hero can't see either, it isn't seen. 58. * 3. If either is felt it is seen. 59. * 4. If either is felt and moved, it disappears. 60. * 61. * If the hero can see, then when a move is done, the ball and chain are 62. * first picked up, the positions under them are corrected, then they 63. * are moved after the hero moves. Not too bad. 64. * 65. * If the hero is blind, then she can "feel" the ball and/or chain at any 66. * time. However, when the hero moves, the felt ball and/or chain become 67. * unfelt and whatever was felt "under" the ball&chain appears. Pretty 68. * nifty, but it requires that the ball&chain "remember" what was under 69. * them --- i.e. they pick-up glyphs when they are felt and drop them when 70. * moved (and felt). When swallowed, the ball&chain are pulled completely 71. * off of the dungeon, but are still on the object chain. They are placed 72. * under the hero when she is expelled. 73. */ 74. 75. /* 76. * from you.h 77. * int u.bglyph glyph under the ball 78. * int u.cglyph glyph under the chain 79. * int u.bc_felt mask for ball/chain being felt 80. * #define BC_BALL 0x01 bit mask in u.bc_felt for ball 81. * #define BC_CHAIN 0x02 bit mask in u.bc_felt for chain 82. * int u.bc_order ball & chain order 83. * 84. * u.bc_felt is also manipulated in display.c and read.c, the others only 85. * in this file. None of these variables are valid unless the player is 86. * Blind. 87. */ 88. 89. /* values for u.bc_order */ 90. #define BCPOS_DIFFER 0 /* ball & chain at different positions */ 91. #define BCPOS_CHAIN 1 /* chain on top of ball */ 92. #define BCPOS_BALL 2 /* ball on top of chain */ 93. 94. 95. 96. /* 97. * Place the ball & chain under the hero. Make sure that the ball & chain 98. * variables are set (actually only needed when blind, but what the heck). 99. * It is assumed that when this is called, the ball and chain are NOT 100. * attached to the object list. 101. * 102. * Should not be called while swallowed. 103. */ 104. void 105. placebc() 106. { 107. if (!uchain || !uball) { 108. impossible("Where are your ball and chain?"); 109. return; 110. } 111. 112. (void) flooreffects(uchain, u.ux, u.uy, ""); /* chain might rust */ 113. 114. if (carried(uball)) /* the ball is carried */ 115. u.bc_order = BCPOS_DIFFER; 116. else { 117. /* ball might rust -- already checked when carried */ 118. (void) flooreffects(uball, u.ux, u.uy, ""); 119. place_object(uball, u.ux, u.uy); 120. u.bc_order = BCPOS_CHAIN; 121. } 122. 123. place_object(uchain, u.ux, u.uy); 124. 125. u.bglyph = u.cglyph = memory_object(u.ux, u.uy); /* pick up glyph */ 126. 127. newsym(u.ux,u.uy); 128. } 129. 130. void 131. unplacebc() 132. { 133. if (u.uswallow) return; /* ball&chain not placed while swallowed */ 134. 135. if (!carried(uball)) { 136. obj_extract_self(uball); 137. if (Blind && (u.bc_felt & BC_BALL)) /* drop glyph */ 138. memory_object(uball->ox, uball->oy) = u.bglyph; 139. 140. newsym(uball->ox,uball->oy); 141. } 142. obj_extract_self(uchain); 143. if (Blind && (u.bc_felt & BC_CHAIN)) /* drop glyph */ 144. memory_object(uchain->ox, uchain->oy) = u.cglyph; 145. 146. newsym(uchain->ox,uchain->oy); 147. u.bc_felt = 0; /* feel nothing */ 148. } 149. 150. 151. /* 152. * Return the stacking of the hero's ball & chain. This assumes that the 153. * hero is being punished. 154. */ 155. STATIC_OVL int 156. bc_order() 157. { 158. struct obj *obj; 159. 160. if (uchain->ox != uball->ox || uchain->oy != uball->oy || carried(uball) 161. || u.uswallow) 162. return BCPOS_DIFFER; 163. 164. for (obj = level.objects[uball->ox][uball->oy]; obj; obj = obj->nexthere) { 165. if (obj == uchain) return BCPOS_CHAIN; 166. if (obj == uball) return BCPOS_BALL; 167. } 168. impossible("bc_order: ball&chain not in same location!"); 169. return BCPOS_DIFFER; 170. } 171. 172. /* 173. * set_bc() 174. * 175. * The hero is either about to go blind or already blind and just punished. 176. * Set up the ball and chain variables so that the ball and chain are "felt". 177. */ 178. void 179. set_bc(already_blind) 180. int already_blind; 181. { 182. int ball_on_floor = !carried(uball); 183. 184. u.bc_order = bc_order(); /* get the order */ 185. u.bc_felt = ball_on_floor ? BC_BALL|BC_CHAIN : BC_CHAIN; /* felt */ 186. 187. if (already_blind || u.uswallow) { 188. u.cglyph = u.bglyph = memory_object(u.ux, u.uy); 189. return; 190. } 191. 192. /* 193. * Since we can still see, remove the ball&chain and get the glyph that 194. * would be beneath them. Then put the ball&chain back. This is pretty 195. * disgusting, but it will work. 196. */ 197. remove_object(uchain); 198. if (ball_on_floor) remove_object(uball); 199. 200. newsym(uchain->ox, uchain->oy); 201. u.cglyph = memory_object(uchain->ox, uchain->oy); 202. 203. if (u.bc_order == BCPOS_DIFFER) { /* different locations */ 204. place_object(uchain, uchain->ox, uchain->oy); 205. newsym(uchain->ox, uchain->oy); 206. if (ball_on_floor) { 207. newsym(uball->ox, uball->oy); /* see under ball */ 208. u.bglyph = memory_object(uball->ox, uball->oy); 209. place_object(uball, uball->ox, uball->oy); 210. newsym(uball->ox, uball->oy); /* restore ball */ 211. } 212. } else { 213. u.bglyph = u.cglyph; 214. if (u.bc_order == BCPOS_CHAIN) { 215. place_object(uball, uball->ox, uball->oy); 216. place_object(uchain, uchain->ox, uchain->oy); 217. } else { 218. place_object(uchain, uchain->ox, uchain->oy); 219. place_object(uball, uball->ox, uball->oy); 220. } 221. newsym(uball->ox, uball->oy); 222. } 223. } 224. 225. 226. /* 227. * move_bc() 228. * 229. * Move the ball and chain. This is called twice for every move. The first 230. * time to pick up the ball and chain before the move, the second time to 231. * place the ball and chain after the move. If the ball is carried, this 232. * function should never have BC_BALL as part of its control. 233. * 234. * Should not be called while swallowed. 235. */ 236. void 237. move_bc(before, control, ballx, bally, chainx, chainy) 238. int before, control; 239. xchar ballx, bally, chainx, chainy; /* only matter !before */ 240. { 241. if (Blind) { 242. /* 243. * The hero is blind. Time to work hard. The ball and chain that 244. * are attached to the hero are very special. The hero knows that 245. * they are attached, so when they move, the hero knows that they 246. * aren't at the last position remembered. This is complicated 247. * by the fact that the hero can "feel" the surrounding locations 248. * at any time, hence, making one or both of them show up again. 249. * So, we have to keep track of which is felt at any one time and 250. * act accordingly. 251. */ 252. if (!before) { 253. if ((control & BC_CHAIN) && (control & BC_BALL)) { 254. /* 255. * Both ball and chain moved. If felt, drop glyph. 256. */ 257. if (u.bc_felt & BC_BALL) 258. memory_object(uball->ox, uball->oy) = u.bglyph; 259. if (u.bc_felt & BC_CHAIN) 260. memory_object(uchain->ox, uchain->oy) = u.cglyph; 261. u.bc_felt = 0; 262. 263. /* Pick up glyph at new location. */ 264. u.bglyph = memory_object(ballx, bally); 265. u.cglyph = memory_object(chainx, chainy); 266. 267. movobj(uball,ballx,bally); 268. movobj(uchain,chainx,chainy); 269. } else if (control & BC_BALL) { 270. if (u.bc_felt & BC_BALL) { 271. if (u.bc_order == BCPOS_DIFFER) { /* ball by itself */ 272. memory_object(uball->ox, uball->oy) = u.bglyph; 273. } else if (u.bc_order == BCPOS_BALL) { 274. if (u.bc_felt & BC_CHAIN) { /* know chain is there */ 275. map_object(uchain, 0); 276. } else { 277. memory_object(uball->ox, uball->oy) = u.bglyph; 278. } 279. } 280. u.bc_felt &= ~BC_BALL; /* no longer feel the ball */ 281. } 282. 283. /* Pick up glyph at new position. */ 284. u.bglyph = (ballx != chainx || bally != chainy) ? 285. memory_object(ballx, bally) : u.cglyph; 286. 287. movobj(uball,ballx,bally); 288. } else if (control & BC_CHAIN) { 289. if (u.bc_felt & BC_CHAIN) { 290. if (u.bc_order == BCPOS_DIFFER) { 291. memory_object(uchain->ox, uchain->oy) = u.cglyph; 292. } else if (u.bc_order == BCPOS_CHAIN) { 293. if (u.bc_felt & BC_BALL) { 294. map_object(uball, 0); 295. } else { 296. memory_object(uchain->ox, uchain->oy) = u.cglyph; 297. } 298. } 299. u.bc_felt &= ~BC_CHAIN; 300. } 301. /* Pick up glyph at new position. */ 302. u.cglyph = (ballx != chainx || bally != chainy) ? 303. memory_object(chainx, chainy) : u.bglyph; 304. 305. movobj(uchain,chainx,chainy); 306. } 307. 308. u.bc_order = bc_order(); /* reset the order */ 309. } 310. 311. } else { 312. /* 313. * The hero is not blind. To make this work correctly, we need to 314. * pick up the ball and chain before the hero moves, then put them 315. * in their new positions after the hero moves. 316. */ 317. if (before) { 318. if (!control) { 319. /* 320. * Neither ball nor chain is moving, so remember which was 321. * on top until !before. Use the variable u.bc_order 322. * since it is only valid when blind. 323. */ 324. u.bc_order = bc_order(); 325. } 326. 327. remove_object(uchain); 328. newsym(uchain->ox, uchain->oy); 329. if (!carried(uball)) { 330. remove_object(uball); 331. newsym(uball->ox, uball->oy); 332. } 333. } else { 334. int on_floor = !carried(uball); 335. 336. if ((control & BC_CHAIN) || 337. (!control && u.bc_order == BCPOS_CHAIN)) { 338. /* If the chain moved or nothing moved & chain on top. */ 339. if (on_floor) place_object(uball, ballx, bally); 340. place_object(uchain, chainx, chainy); /* chain on top */ 341. } else { 342. place_object(uchain, chainx, chainy); 343. if (on_floor) place_object(uball, ballx, bally); 344. /* ball on top */ 345. } 346. newsym(chainx, chainy); 347. if (on_floor) newsym(ballx, bally); 348. } 349. } 350. } 351. 352. /* return TRUE if the caller needs to place the ball and chain down again 353. * 354. * Should not be called while swallowed. Should be called before movement, 355. * because we might want to move the ball or chain to the hero's old position. 356. * 357. * It is called if we are moving. It is also called if we are teleporting 358. * *if* the ball doesn't move and we thus must drag the chain. It is not 359. * called for ordinary teleportation. 360. * 361. * allow_drag is only used in the ugly special case where teleporting must 362. * drag the chain, while an identical-looking movement must drag both the ball 363. * and chain. 364. */ 365. boolean 366. drag_ball(x, y, bc_control, ballx, bally, chainx, chainy, cause_delay, 367. allow_drag) 368. xchar x, y; 369. int *bc_control; 370. xchar *ballx, *bally, *chainx, *chainy; 371. boolean *cause_delay; 372. boolean allow_drag; 373. { 374. struct trap *t = (struct trap *)0; 375. boolean already_in_rock; 376. 377. *ballx = uball->ox; 378. *bally = uball->oy; 379. *chainx = uchain->ox; 380. *chainy = uchain->oy; 381. *bc_control = 0; 382. *cause_delay = FALSE; 383. 384. if (dist2(x, y, uchain->ox, uchain->oy) <= 2) { /* nothing moved */ 385. move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy); 386. return TRUE; 387. } 388. 389. /* only need to move the chain? */ 390. if (carried(uball) || distmin(x, y, uball->ox, uball->oy) <= 2) { 391. xchar oldchainx = uchain->ox, oldchainy = uchain->oy; 392. *bc_control = BC_CHAIN; 393. move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy); 394. if (carried(uball)) { 395. /* move chain only if necessary */ 396. if (distmin(x, y, uchain->ox, uchain->oy) > 1) { 397. *chainx = u.ux; 398. *chainy = u.uy; 399. } 400. return TRUE; 401. } 402. #define CHAIN_IN_MIDDLE(chx, chy) \ 403. (distmin(x, y, chx, chy) <= 1 && distmin(chx, chy, uball->ox, uball->oy) <= 1) 404. #define IS_CHAIN_ROCK(x,y) \ 405. (IS_ROCK(levl[x][y].typ) || (IS_DOOR(levl[x][y].typ) && \ 406. (levl[x][y].doormask & (D_CLOSED|D_LOCKED)))) 407. /* Don't ever move the chain into solid rock. If we have to, then instead 408. * undo the move_bc() and jump to the drag ball code. Note that this also 409. * means the "cannot carry and drag" message will not appear, since unless we 410. * moved at least two squares there is no possibility of the chain position 411. * being in solid rock. 412. */ 413. #define SKIP_TO_DRAG { *chainx = oldchainx; *chainy = oldchainy; \ 414. move_bc(0, *bc_control, *ballx, *bally, *chainx, *chainy); \ 415. goto drag; } 416. if (IS_CHAIN_ROCK(u.ux, u.uy) || IS_CHAIN_ROCK(*chainx, *chainy) 417. || IS_CHAIN_ROCK(uball->ox, uball->oy)) 418. already_in_rock = TRUE; 419. else 420. already_in_rock = FALSE; 421. 422. switch(dist2(x, y, uball->ox, uball->oy)) { 423. /* two spaces diagonal from ball, move chain inbetween */ 424. case 8: 425. *chainx = (uball->ox + x)/2; 426. *chainy = (uball->oy + y)/2; 427. if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock) 428. SKIP_TO_DRAG; 429. break; 430. 431. /* player is distance 2/1 from ball; move chain to one of the 432. * two spaces between 433. * @ 434. * __ 435. * 0 436. */ 437. case 5: { 438. xchar tempx, tempy, tempx2, tempy2; 439. 440. /* find position closest to current position of chain */ 441. /* no effect if current position is already OK */ 442. if (abs(x - uball->ox) == 1) { 443. tempx = x; 444. tempx2 = uball->ox; 445. tempy = tempy2 = (uball->oy + y)/2; 446. } else { 447. tempx = tempx2 = (uball->ox + x)/2; 448. tempy = y; 449. tempy2 = uball->oy; 450. } 451. if (IS_CHAIN_ROCK(tempx, tempy) && 452. !IS_CHAIN_ROCK(tempx2, tempy2) && 453. !already_in_rock) { 454. if (allow_drag) { 455. /* Avoid pathological case *if* not teleporting: 456. * 0 0_ 457. * _X move northeast -----> X@ 458. * @ 459. */ 460. if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 5 && 461. dist2(x, y, tempx, tempy) == 1) 462. SKIP_TO_DRAG; 463. /* Avoid pathological case *if* not teleporting: 464. * 0 0 465. * _X move east -----> X_ 466. * @ @ 467. */ 468. if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 4 && 469. dist2(x, y, tempx, tempy) == 2) 470. SKIP_TO_DRAG; 471. } 472. *chainx = tempx2; 473. *chainy = tempy2; 474. } else if (!IS_CHAIN_ROCK(tempx, tempy) && 475. IS_CHAIN_ROCK(tempx2, tempy2) && 476. !already_in_rock) { 477. if (allow_drag) { 478. if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 5 && 479. dist2(x, y, tempx2, tempy2) == 1) 480. SKIP_TO_DRAG; 481. if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 4 && 482. dist2(x, y, tempx2, tempy2) == 2) 483. SKIP_TO_DRAG; 484. } 485. *chainx = tempx; 486. *chainy = tempy; 487. } else if (IS_CHAIN_ROCK(tempx, tempy) && 488. IS_CHAIN_ROCK(tempx2, tempy2) && 489. !already_in_rock) { 490. SKIP_TO_DRAG; 491. } else if (dist2(tempx, tempy, uchain->ox, uchain->oy) < 492. dist2(tempx2, tempy2, uchain->ox, uchain->oy) || 493. ((dist2(tempx, tempy, uchain->ox, uchain->oy) == 494. dist2(tempx2, tempy2, uchain->ox, uchain->oy)) && rn2(2))) { 495. *chainx = tempx; 496. *chainy = tempy; 497. } else { 498. *chainx = tempx2; 499. *chainy = tempy2; 500. } 501. break; 502. } 503. 504. /* ball is two spaces horizontal or vertical from player; move*/ 505. /* chain inbetween *unless* current chain position is OK */ 506. case 4: 507. if (CHAIN_IN_MIDDLE(uchain->ox, uchain->oy)) 508. break; 509. *chainx = (x + uball->ox)/2; 510. *chainy = (y + uball->oy)/2; 511. if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock) 512. SKIP_TO_DRAG; 513. break; 514. 515. /* ball is one space diagonal from player. Check for the 516. * following special case: 517. * @ 518. * _ moving southwest becomes @_ 519. * 0 0 520. * (This will also catch teleporting that happens to resemble 521. * this case, but oh well.) Otherwise fall through. 522. */ 523. case 2: 524. if (dist2(x, y, uball->ox, uball->oy) == 2 && 525. dist2(x, y, uchain->ox, uchain->oy) == 4) { 526. if (uchain->oy == y) 527. *chainx = uball->ox; 528. else 529. *chainy = uball->oy; 530. if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock) 531. SKIP_TO_DRAG; 532. break; 533. } 534. /* fall through */ 535. case 1: 536. case 0: 537. /* do nothing if possible */ 538. if (CHAIN_IN_MIDDLE(uchain->ox, uchain->oy)) 539. break; 540. /* otherwise try to drag chain to player's old position */ 541. if (CHAIN_IN_MIDDLE(u.ux, u.uy)) { 542. *chainx = u.ux; 543. *chainy = u.uy; 544. break; 545. } 546. /* otherwise use player's new position (they must have 547. teleported, for this to happen) */ 548. *chainx = x; 549. *chainy = y; 550. break; 551. 552. default: impossible("bad chain movement"); 553. break; 554. } 555. #undef SKIP_TO_DRAG 556. #undef IS_CHAIN_ROCK 557. #undef CHAIN_IN_MIDDLE 558. return TRUE; 559. } 560. 561. drag: 562. 563. if (near_capacity() > SLT_ENCUMBER && dist2(x, y, u.ux, u.uy) <= 2) { 564. You("cannot %sdrag the heavy iron ball.", 565. invent ? "carry all that and also " : ""); 566. nomul(0); 567. return FALSE; 568. } 569. 570. if ((is_pool(uchain->ox, uchain->oy) && 571. /* water not mere continuation of previous water */ 572. (levl[uchain->ox][uchain->oy].typ == POOL || 573. !is_pool(uball->ox, uball->oy) || 574. levl[uball->ox][uball->oy].typ == POOL)) 575. || ((t = t_at(uchain->ox, uchain->oy)) && 576. (t->ttyp == PIT || 577. t->ttyp == SPIKED_PIT || 578. t->ttyp == HOLE || 579. t->ttyp == TRAPDOOR)) ) { 580. 581. if (Levitation) { 582. You_feel("a tug from the iron ball."); 583. if (t) t->tseen = 1; 584. } else { 585. struct monst *victim; 586. 587. You("are jerked back by the iron ball!"); 588. if ((victim = m_at(uchain->ox, uchain->oy)) != 0) { 589. int tmp; 590. 591. tmp = -2 + Luck + find_mac(victim); 592. tmp += omon_adj(victim, uball, TRUE); 593. if (tmp >= rnd(20)) 594. (void) hmon(victim,uball,3); 595. else 596. miss(xname(uball), victim); 597. 598. } /* now check again in case mon died */ 599. if (!m_at(uchain->ox, uchain->oy)) { 600. u.ux = uchain->ox; 601. u.uy = uchain->oy; 602. newsym(u.ux0, u.uy0); 603. } 604. nomul(0); 605. 606. *bc_control = BC_BALL; 607. move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy); 608. *ballx = uchain->ox; 609. *bally = uchain->oy; 610. move_bc(0, *bc_control, *ballx, *bally, *chainx, *chainy); 611. spoteffects(TRUE); 612. return FALSE; 613. } 614. } 615. 616. *bc_control = BC_BALL|BC_CHAIN; 617. 618. move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy); 619. if (dist2(x, y, u.ux, u.uy) > 2) { 620. /* Awful case: we're still in range of the ball, so we thought we 621. * could only move the chain, but it turned out that the target 622. * square for the chain was rock, so we had to drag it instead. 623. * But we can't drag it either, because we teleported and are more 624. * than one square from our old position. Revert to the teleport 625. * behavior. 626. */ 627. *ballx = *chainx = x; 628. *bally = *chainy = y; 629. } else { 630. *ballx = uchain->ox; 631. *bally = uchain->oy; 632. *chainx = u.ux; 633. *chainy = u.uy; 634. } 635. *cause_delay = TRUE; 636. return TRUE; 637. } 638. 639. /* 640. * drop_ball() 641. * 642. * The punished hero drops or throws her iron ball. If the hero is 643. * blind, we must reset the order and glyph. Check for side effects. 644. * This routine expects the ball to be already placed. 645. * 646. * Should not be called while swallowed. 647. */ 648. void 649. drop_ball(x, y) 650. xchar x, y; 651. { 652. if (Blind) { 653. u.bc_order = bc_order(); /* get the order */ 654. /* pick up glyph */ 655. u.bglyph = (u.bc_order) ? u.cglyph : memory_object(x, y); 656. } 657. 658. if (x != u.ux || y != u.uy) { 659. struct trap *t; 660. const char *pullmsg = "The ball pulls you out of the %s!"; 661. 662. if (u.utrap && u.utraptype != TT_INFLOOR) { 663. switch(u.utraptype) { 664. case TT_PIT: 665. pline(pullmsg, "pit"); 666. break; 667. case TT_WEB: 668. pline(pullmsg, "web"); 669. pline_The("web is destroyed!"); 670. deltrap(t_at(u.ux,u.uy)); 671. break; 672. case TT_LAVA: 673. pline(pullmsg, "lava"); 674. break; 675. case TT_BEARTRAP: { 676. register long side = rn2(3) ? LEFT_SIDE : RIGHT_SIDE; 677. pline(pullmsg, "bear trap"); 678. set_wounded_legs(side, rn1(1000, 500)); 679. #ifdef STEED 680. if (!u.usteed) 681. #endif 682. { 683. Your("%s %s is severely damaged.", 684. (side == LEFT_SIDE) ? "left" : "right", 685. body_part(LEG)); 686. losehp(2, "leg damage from being pulled out of a bear trap", 687. KILLED_BY); 688. } 689. break; 690. } 691. } 692. u.utrap = 0; 693. fill_pit(u.ux, u.uy); 694. } 695. 696. u.ux0 = u.ux; 697. u.uy0 = u.uy; 698. if (!Levitation && !MON_AT(x, y) && !u.utrap && 699. (is_pool(x, y) || 700. ((t = t_at(x, y)) && 701. (t->ttyp == PIT || t->ttyp == SPIKED_PIT || 702. t->ttyp == TRAPDOOR || t->ttyp == HOLE)))) { 703. u.ux = x; 704. u.uy = y; 705. } else { 706. u.ux = x - u.dx; 707. u.uy = y - u.dy; 708. } 709. vision_full_recalc = 1; /* hero has moved, recalculate vision later */ 710. 711. if (Blind) { 712. /* drop glyph under the chain */ 713. if (u.bc_felt & BC_CHAIN) 714. memory_object(uchain->ox, uchain->oy) = u.cglyph; 715. u.bc_felt = 0; /* feel nothing */ 716. /* pick up new glyph */ 717. u.cglyph = (u.bc_order) ? u.bglyph : memory_object(u.ux, u.uy); 718. } 719. movobj(uchain,u.ux,u.uy); /* has a newsym */ 720. if (Blind) { 721. u.bc_order = bc_order(); 722. } 723. newsym(u.ux0,u.uy0); /* clean up old position */ 724. if (u.ux0 != u.ux || u.uy0 != u.uy) { 725. spoteffects(TRUE); 726. if (In_sokoban(&u.uz)) 727. change_luck(-1); /* Sokoban guilt */ 728. } 729. } 730. } 731. 732. 733. STATIC_OVL void 734. litter() 735. { 736. struct obj *otmp = invent, *nextobj; 737. int capacity = weight_cap(); 738. 739. while (otmp) { 740. nextobj = otmp->nobj; 741. if ((otmp != uball) && (rnd(capacity) <= (int)otmp->owt)) { 742. if (canletgo(otmp, "")) { 743. Your("%s you down the stairs.", 744. aobjnam(otmp, "follow")); 745. dropx(otmp); 746. } 747. } 748. otmp = nextobj; 749. } 750. } 751. 752. void 753. drag_down() 754. { 755. boolean forward; 756. uchar dragchance = 3; 757. 758. /* 759. * Assume that the ball falls forward if: 760. * 761. * a) the character is wielding it, or 762. * b) the character has both hands available to hold it (i.e. is 763. * not wielding any weapon), or 764. * c) (perhaps) it falls forward out of his non-weapon hand 765. */ 766. 767. forward = carried(uball) && (uwep == uball || !uwep || !rn2(3)); 768. 769. if (carried(uball)) 770. You("lose your grip on the iron ball."); 771. 772. if (forward) { 773. if(rn2(6)) { 774. pline_The("iron ball drags you downstairs!"); 775. losehp(rnd(6), "dragged downstairs by an iron ball", 776. NO_KILLER_PREFIX); 777. litter(); 778. } 779. } else { 780. if(rn2(2)) { 781. pline_The("iron ball smacks into you!"); 782. losehp(rnd(20), "iron ball collision", KILLED_BY_AN); 783. exercise(A_STR, FALSE); 784. dragchance -= 2; 785. } 786. if( (int) dragchance >= rnd(6)) { 787. pline_The("iron ball drags you downstairs!"); 788. losehp(rnd(3), "dragged downstairs by an iron ball", 789. NO_KILLER_PREFIX); 790. exercise(A_STR, FALSE); 791. litter(); 792. } 793. } 794. } 795. 796. /*ball.c*/
|