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