1 /* NetHack 3.6 ball.c $NHDT-Date: 1450402033 2015/12/18 01:27:13 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.29 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
6 * =============================================================*/
10 STATIC_DCL
int NDECL(bc_order
);
11 STATIC_DCL
void NDECL(litter
);
19 pline("Startled, you drop the iron ball.");
21 setuwep((struct obj
*) 0);
22 if (uswapwep
== uball
)
23 setuswapwep((struct obj
*) 0);
25 setuqwep((struct obj
*) 0);
37 gets_hit
= (((uball
->ox
!= u
.ux
) || (uball
->oy
!= u
.uy
))
38 && ((uwep
== uball
) ? FALSE
: (boolean
) rn2(5)));
42 pline_The("iron ball falls on your %s.", body_part(HEAD
));
44 if (is_metallic(uarmh
)) {
45 pline("Fortunately, you are wearing a hard helmet.");
47 } else if (flags
.verbose
)
48 pline("%s does not protect you.", Yname2(uarmh
));
50 losehp(Maybe_Half_Phys(dmg
), "crunched in the head by an iron ball",
56 * To make this work, we have to mess with the hero's mind. The rules for
59 * 1. If the hero can see them, fine.
60 * 2. If the hero can't see either, it isn't seen.
61 * 3. If either is felt it is seen.
62 * 4. If either is felt and moved, it disappears.
64 * If the hero can see, then when a move is done, the ball and chain are
65 * first picked up, the positions under them are corrected, then they
66 * are moved after the hero moves. Not too bad.
68 * If the hero is blind, then she can "feel" the ball and/or chain at any
69 * time. However, when the hero moves, the felt ball and/or chain become
70 * unfelt and whatever was felt "under" the ball&chain appears. Pretty
71 * nifty, but it requires that the ball&chain "remember" what was under
72 * them --- i.e. they pick-up glyphs when they are felt and drop them when
73 * moved (and felt). When swallowed, the ball&chain are pulled completely
74 * off of the dungeon, but are still on the object chain. They are placed
75 * under the hero when she is expelled.
80 * int u.bglyph glyph under the ball
81 * int u.cglyph glyph under the chain
82 * int u.bc_felt mask for ball/chain being felt
83 * #define BC_BALL 0x01 bit mask in u.bc_felt for ball
84 * #define BC_CHAIN 0x02 bit mask in u.bc_felt for chain
85 * int u.bc_order ball & chain order
87 * u.bc_felt is also manipulated in display.c and read.c, the others only
88 * in this file. None of these variables are valid unless the player is
92 /* values for u.bc_order */
93 #define BCPOS_DIFFER 0 /* ball & chain at different positions */
94 #define BCPOS_CHAIN 1 /* chain on top of ball */
95 #define BCPOS_BALL 2 /* ball on top of chain */
98 * Place the ball & chain under the hero. Make sure that the ball & chain
99 * variables are set (actually only needed when blind, but what the heck).
100 * It is assumed that when this is called, the ball and chain are NOT
101 * attached to the object list.
103 * Should not be called while swallowed except on waterlevel.
108 if (!uchain
|| !uball
) {
109 impossible("Where are your ball and chain?");
113 (void) flooreffects(uchain
, u
.ux
, u
.uy
, ""); /* chain might rust */
115 if (carried(uball
)) /* the ball is carried */
116 u
.bc_order
= BCPOS_DIFFER
;
118 /* ball might rust -- already checked when carried */
119 (void) flooreffects(uball
, u
.ux
, u
.uy
, "");
120 place_object(uball
, u
.ux
, u
.uy
);
121 u
.bc_order
= BCPOS_CHAIN
;
124 place_object(uchain
, u
.ux
, u
.uy
);
126 u
.bglyph
= u
.cglyph
= levl
[u
.ux
][u
.uy
].glyph
; /* pick up glyph */
135 if (Is_waterlevel(&u
.uz
)) {
136 /* we need to proceed with the removal from the floor
137 * so that movebubbles() processing will disregard it as
138 * intended. Ignore all the vision stuff.
141 obj_extract_self(uball
);
142 obj_extract_self(uchain
);
144 /* ball&chain not unplaced while swallowed */
148 if (!carried(uball
)) {
149 obj_extract_self(uball
);
150 if (Blind
&& (u
.bc_felt
& BC_BALL
)) /* drop glyph */
151 levl
[uball
->ox
][uball
->oy
].glyph
= u
.bglyph
;
153 newsym(uball
->ox
, uball
->oy
);
155 obj_extract_self(uchain
);
156 if (Blind
&& (u
.bc_felt
& BC_CHAIN
)) /* drop glyph */
157 levl
[uchain
->ox
][uchain
->oy
].glyph
= u
.cglyph
;
159 newsym(uchain
->ox
, uchain
->oy
);
160 u
.bc_felt
= 0; /* feel nothing */
164 * Return the stacking of the hero's ball & chain. This assumes that the
165 * hero is being punished.
172 if (uchain
->ox
!= uball
->ox
|| uchain
->oy
!= uball
->oy
|| carried(uball
)
176 for (obj
= level
.objects
[uball
->ox
][uball
->oy
]; obj
;
177 obj
= obj
->nexthere
) {
183 impossible("bc_order: ball&chain not in same location!");
190 * The hero is either about to go blind or already blind and just punished.
191 * Set up the ball and chain variables so that the ball and chain are "felt".
194 set_bc(already_blind
)
197 int ball_on_floor
= !carried(uball
);
199 u
.bc_order
= bc_order(); /* get the order */
200 u
.bc_felt
= ball_on_floor
? BC_BALL
| BC_CHAIN
: BC_CHAIN
; /* felt */
202 if (already_blind
|| u
.uswallow
) {
203 u
.cglyph
= u
.bglyph
= levl
[u
.ux
][u
.uy
].glyph
;
208 * Since we can still see, remove the ball&chain and get the glyph that
209 * would be beneath them. Then put the ball&chain back. This is pretty
210 * disgusting, but it will work.
212 remove_object(uchain
);
214 remove_object(uball
);
216 newsym(uchain
->ox
, uchain
->oy
);
217 u
.cglyph
= levl
[uchain
->ox
][uchain
->oy
].glyph
;
219 if (u
.bc_order
== BCPOS_DIFFER
) { /* different locations */
220 place_object(uchain
, uchain
->ox
, uchain
->oy
);
221 newsym(uchain
->ox
, uchain
->oy
);
223 newsym(uball
->ox
, uball
->oy
); /* see under ball */
224 u
.bglyph
= levl
[uball
->ox
][uball
->oy
].glyph
;
225 place_object(uball
, uball
->ox
, uball
->oy
);
226 newsym(uball
->ox
, uball
->oy
); /* restore ball */
230 if (u
.bc_order
== BCPOS_CHAIN
) {
231 place_object(uball
, uball
->ox
, uball
->oy
);
232 place_object(uchain
, uchain
->ox
, uchain
->oy
);
234 place_object(uchain
, uchain
->ox
, uchain
->oy
);
235 place_object(uball
, uball
->ox
, uball
->oy
);
237 newsym(uball
->ox
, uball
->oy
);
244 * Move the ball and chain. This is called twice for every move. The first
245 * time to pick up the ball and chain before the move, the second time to
246 * place the ball and chain after the move. If the ball is carried, this
247 * function should never have BC_BALL as part of its control.
249 * Should not be called while swallowed.
252 move_bc(before
, control
, ballx
, bally
, chainx
, chainy
)
254 xchar ballx
, bally
, chainx
, chainy
; /* only matter !before */
258 * The hero is blind. Time to work hard. The ball and chain that
259 * are attached to the hero are very special. The hero knows that
260 * they are attached, so when they move, the hero knows that they
261 * aren't at the last position remembered. This is complicated
262 * by the fact that the hero can "feel" the surrounding locations
263 * at any time, hence, making one or both of them show up again.
264 * So, we have to keep track of which is felt at any one time and
268 if ((control
& BC_CHAIN
) && (control
& BC_BALL
)) {
270 * Both ball and chain moved. If felt, drop glyph.
272 if (u
.bc_felt
& BC_BALL
)
273 levl
[uball
->ox
][uball
->oy
].glyph
= u
.bglyph
;
274 if (u
.bc_felt
& BC_CHAIN
)
275 levl
[uchain
->ox
][uchain
->oy
].glyph
= u
.cglyph
;
278 /* Pick up glyph at new location. */
279 u
.bglyph
= levl
[ballx
][bally
].glyph
;
280 u
.cglyph
= levl
[chainx
][chainy
].glyph
;
282 movobj(uball
, ballx
, bally
);
283 movobj(uchain
, chainx
, chainy
);
284 } else if (control
& BC_BALL
) {
285 if (u
.bc_felt
& BC_BALL
) {
286 if (u
.bc_order
== BCPOS_DIFFER
) { /* ball by itself */
287 levl
[uball
->ox
][uball
->oy
].glyph
= u
.bglyph
;
288 } else if (u
.bc_order
== BCPOS_BALL
) {
289 if (u
.bc_felt
& BC_CHAIN
) { /* know chain is there */
290 map_object(uchain
, 0);
292 levl
[uball
->ox
][uball
->oy
].glyph
= u
.bglyph
;
295 u
.bc_felt
&= ~BC_BALL
; /* no longer feel the ball */
298 /* Pick up glyph at new position. */
299 u
.bglyph
= (ballx
!= chainx
|| bally
!= chainy
)
300 ? levl
[ballx
][bally
].glyph
303 movobj(uball
, ballx
, bally
);
304 } else if (control
& BC_CHAIN
) {
305 if (u
.bc_felt
& BC_CHAIN
) {
306 if (u
.bc_order
== BCPOS_DIFFER
) {
307 levl
[uchain
->ox
][uchain
->oy
].glyph
= u
.cglyph
;
308 } else if (u
.bc_order
== BCPOS_CHAIN
) {
309 if (u
.bc_felt
& BC_BALL
) {
310 map_object(uball
, 0);
312 levl
[uchain
->ox
][uchain
->oy
].glyph
= u
.cglyph
;
315 u
.bc_felt
&= ~BC_CHAIN
;
317 /* Pick up glyph at new position. */
318 u
.cglyph
= (ballx
!= chainx
|| bally
!= chainy
)
319 ? levl
[chainx
][chainy
].glyph
322 movobj(uchain
, chainx
, chainy
);
325 u
.bc_order
= bc_order(); /* reset the order */
330 * The hero is not blind. To make this work correctly, we need to
331 * pick up the ball and chain before the hero moves, then put them
332 * in their new positions after the hero moves.
337 * Neither ball nor chain is moving, so remember which was
338 * on top until !before. Use the variable u.bc_order
339 * since it is only valid when blind.
341 u
.bc_order
= bc_order();
344 remove_object(uchain
);
345 newsym(uchain
->ox
, uchain
->oy
);
346 if (!carried(uball
)) {
347 remove_object(uball
);
348 newsym(uball
->ox
, uball
->oy
);
351 int on_floor
= !carried(uball
);
353 if ((control
& BC_CHAIN
)
354 || (!control
&& u
.bc_order
== BCPOS_CHAIN
)) {
355 /* If the chain moved or nothing moved & chain on top. */
357 place_object(uball
, ballx
, bally
);
358 place_object(uchain
, chainx
, chainy
); /* chain on top */
360 place_object(uchain
, chainx
, chainy
);
362 place_object(uball
, ballx
, bally
);
365 newsym(chainx
, chainy
);
367 newsym(ballx
, bally
);
372 /* return TRUE if the caller needs to place the ball and chain down again
374 * Should not be called while swallowed. Should be called before movement,
375 * because we might want to move the ball or chain to the hero's old
378 * It is called if we are moving. It is also called if we are teleporting
379 * *if* the ball doesn't move and we thus must drag the chain. It is not
380 * called for ordinary teleportation.
382 * allow_drag is only used in the ugly special case where teleporting must
383 * drag the chain, while an identical-looking movement must drag both the ball
387 drag_ball(x
, y
, bc_control
, ballx
, bally
, chainx
, chainy
, cause_delay
,
391 xchar
*ballx
, *bally
, *chainx
, *chainy
;
392 boolean
*cause_delay
;
395 struct trap
*t
= (struct trap
*) 0;
396 boolean already_in_rock
;
400 *chainx
= uchain
->ox
;
401 *chainy
= uchain
->oy
;
403 *cause_delay
= FALSE
;
405 if (dist2(x
, y
, uchain
->ox
, uchain
->oy
) <= 2) { /* nothing moved */
406 move_bc(1, *bc_control
, *ballx
, *bally
, *chainx
, *chainy
);
410 /* only need to move the chain? */
411 if (carried(uball
) || distmin(x
, y
, uball
->ox
, uball
->oy
) <= 2) {
412 xchar oldchainx
= uchain
->ox
, oldchainy
= uchain
->oy
;
413 *bc_control
= BC_CHAIN
;
414 move_bc(1, *bc_control
, *ballx
, *bally
, *chainx
, *chainy
);
415 if (carried(uball
)) {
416 /* move chain only if necessary */
417 if (distmin(x
, y
, uchain
->ox
, uchain
->oy
) > 1) {
423 #define CHAIN_IN_MIDDLE(chx, chy) \
424 (distmin(x, y, chx, chy) <= 1 \
425 && distmin(chx, chy, uball->ox, uball->oy) <= 1)
426 #define IS_CHAIN_ROCK(x, y) \
427 (IS_ROCK(levl[x][y].typ) \
428 || (IS_DOOR(levl[x][y].typ) \
429 && (levl[x][y].doormask & (D_CLOSED | D_LOCKED))))
430 /* Don't ever move the chain into solid rock. If we have to, then instead
431 * undo the move_bc() and jump to the drag ball code. Note that this also
432 * means the "cannot carry and drag" message will not appear, since unless we
433 * moved at least two squares there is no possibility of the chain position
434 * being in solid rock.
436 #define SKIP_TO_DRAG \
438 *chainx = oldchainx; \
439 *chainy = oldchainy; \
440 move_bc(0, *bc_control, *ballx, *bally, *chainx, *chainy); \
443 if (IS_CHAIN_ROCK(u
.ux
, u
.uy
) || IS_CHAIN_ROCK(*chainx
, *chainy
)
444 || IS_CHAIN_ROCK(uball
->ox
, uball
->oy
))
445 already_in_rock
= TRUE
;
447 already_in_rock
= FALSE
;
449 switch (dist2(x
, y
, uball
->ox
, uball
->oy
)) {
450 /* two spaces diagonal from ball, move chain inbetween */
452 *chainx
= (uball
->ox
+ x
) / 2;
453 *chainy
= (uball
->oy
+ y
) / 2;
454 if (IS_CHAIN_ROCK(*chainx
, *chainy
) && !already_in_rock
)
458 /* player is distance 2/1 from ball; move chain to one of the
465 xchar tempx
, tempy
, tempx2
, tempy2
;
467 /* find position closest to current position of chain */
468 /* no effect if current position is already OK */
469 if (abs(x
- uball
->ox
) == 1) {
472 tempy
= tempy2
= (uball
->oy
+ y
) / 2;
474 tempx
= tempx2
= (uball
->ox
+ x
) / 2;
478 if (IS_CHAIN_ROCK(tempx
, tempy
) && !IS_CHAIN_ROCK(tempx2
, tempy2
)
479 && !already_in_rock
) {
481 /* Avoid pathological case *if* not teleporting:
483 * _X move northeast -----> X@
486 if (dist2(u
.ux
, u
.uy
, uball
->ox
, uball
->oy
) == 5
487 && dist2(x
, y
, tempx
, tempy
) == 1)
489 /* Avoid pathological case *if* not teleporting:
491 * _X move east -----> X_
494 if (dist2(u
.ux
, u
.uy
, uball
->ox
, uball
->oy
) == 4
495 && dist2(x
, y
, tempx
, tempy
) == 2)
500 } else if (!IS_CHAIN_ROCK(tempx
, tempy
)
501 && IS_CHAIN_ROCK(tempx2
, tempy2
) && !already_in_rock
) {
503 if (dist2(u
.ux
, u
.uy
, uball
->ox
, uball
->oy
) == 5
504 && dist2(x
, y
, tempx2
, tempy2
) == 1)
506 if (dist2(u
.ux
, u
.uy
, uball
->ox
, uball
->oy
) == 4
507 && dist2(x
, y
, tempx2
, tempy2
) == 2)
512 } else if (IS_CHAIN_ROCK(tempx
, tempy
)
513 && IS_CHAIN_ROCK(tempx2
, tempy2
) && !already_in_rock
) {
515 } else if (dist2(tempx
, tempy
, uchain
->ox
, uchain
->oy
)
516 < dist2(tempx2
, tempy2
, uchain
->ox
, uchain
->oy
)
517 || ((dist2(tempx
, tempy
, uchain
->ox
, uchain
->oy
)
518 == dist2(tempx2
, tempy2
, uchain
->ox
, uchain
->oy
))
529 /* ball is two spaces horizontal or vertical from player; move*/
530 /* chain inbetween *unless* current chain position is OK */
532 if (CHAIN_IN_MIDDLE(uchain
->ox
, uchain
->oy
))
534 *chainx
= (x
+ uball
->ox
) / 2;
535 *chainy
= (y
+ uball
->oy
) / 2;
536 if (IS_CHAIN_ROCK(*chainx
, *chainy
) && !already_in_rock
)
540 /* ball is one space diagonal from player. Check for the
541 * following special case:
543 * _ moving southwest becomes @_
545 * (This will also catch teleporting that happens to resemble
546 * this case, but oh well.) Otherwise fall through.
549 if (dist2(x
, y
, uball
->ox
, uball
->oy
) == 2
550 && dist2(x
, y
, uchain
->ox
, uchain
->oy
) == 4) {
555 if (IS_CHAIN_ROCK(*chainx
, *chainy
) && !already_in_rock
)
562 /* do nothing if possible */
563 if (CHAIN_IN_MIDDLE(uchain
->ox
, uchain
->oy
))
565 /* otherwise try to drag chain to player's old position */
566 if (CHAIN_IN_MIDDLE(u
.ux
, u
.uy
)) {
571 /* otherwise use player's new position (they must have
572 teleported, for this to happen) */
578 impossible("bad chain movement");
582 #undef CHAIN_IN_MIDDLE
588 if (near_capacity() > SLT_ENCUMBER
&& dist2(x
, y
, u
.ux
, u
.uy
) <= 2) {
589 You("cannot %sdrag the heavy iron ball.",
590 invent
? "carry all that and also " : "");
595 if ((is_pool(uchain
->ox
, uchain
->oy
)
596 /* water not mere continuation of previous water */
597 && (levl
[uchain
->ox
][uchain
->oy
].typ
== POOL
598 || !is_pool(uball
->ox
, uball
->oy
)
599 || levl
[uball
->ox
][uball
->oy
].typ
== POOL
))
600 || ((t
= t_at(uchain
->ox
, uchain
->oy
))
601 && (t
->ttyp
== PIT
|| t
->ttyp
== SPIKED_PIT
|| t
->ttyp
== HOLE
602 || t
->ttyp
== TRAPDOOR
))) {
604 You_feel("a tug from the iron ball.");
608 struct monst
*victim
;
610 You("are jerked back by the iron ball!");
611 if ((victim
= m_at(uchain
->ox
, uchain
->oy
)) != 0) {
614 tmp
= -2 + Luck
+ find_mac(victim
);
615 tmp
+= omon_adj(victim
, uball
, TRUE
);
617 (void) hmon(victim
, uball
, HMON_DRAGGED
);
619 miss(xname(uball
), victim
);
621 } /* now check again in case mon died */
622 if (!m_at(uchain
->ox
, uchain
->oy
)) {
625 newsym(u
.ux0
, u
.uy0
);
629 *bc_control
= BC_BALL
;
630 move_bc(1, *bc_control
, *ballx
, *bally
, *chainx
, *chainy
);
633 move_bc(0, *bc_control
, *ballx
, *bally
, *chainx
, *chainy
);
639 *bc_control
= BC_BALL
| BC_CHAIN
;
641 move_bc(1, *bc_control
, *ballx
, *bally
, *chainx
, *chainy
);
642 if (dist2(x
, y
, u
.ux
, u
.uy
) > 2) {
643 /* Awful case: we're still in range of the ball, so we thought we
644 * could only move the chain, but it turned out that the target
645 * square for the chain was rock, so we had to drag it instead.
646 * But we can't drag it either, because we teleported and are more
647 * than one square from our old position. Revert to the teleport
650 *ballx
= *chainx
= x
;
651 *bally
= *chainy
= y
;
653 xchar newchainx
= u
.ux
, newchainy
= u
.uy
;
656 * Generally, chain moves to hero's previous location and ball
657 * moves to chain's previous location, except that we try to
658 * keep the chain directly between the hero and the ball. But,
659 * take the simple approach if the hero's previous location or
660 * the potential between location is inaccessible.
662 if (dist2(x
, y
, uchain
->ox
, uchain
->oy
) == 4
663 && !IS_CHAIN_ROCK(newchainx
, newchainy
)) {
664 newchainx
= (x
+ uchain
->ox
) / 2;
665 newchainy
= (y
+ uchain
->oy
) / 2;
666 if (IS_CHAIN_ROCK(newchainx
, newchainy
)) {
667 /* don't let chain move to inaccessible location */
686 * The punished hero drops or throws her iron ball. If the hero is
687 * blind, we must reset the order and glyph. Check for side effects.
688 * This routine expects the ball to be already placed.
690 * Should not be called while swallowed.
698 u
.bc_order
= bc_order();
700 u
.bglyph
= (u
.bc_order
) ? u
.cglyph
: levl
[x
][y
].glyph
;
703 if (x
!= u
.ux
|| y
!= u
.uy
) {
705 const char *pullmsg
= "The ball pulls you out of the %s!";
707 if (u
.utrap
&& u
.utraptype
!= TT_INFLOOR
708 && u
.utraptype
!= TT_BURIEDBALL
) {
709 switch (u
.utraptype
) {
711 pline(pullmsg
, "pit");
714 pline(pullmsg
, "web");
715 pline_The("web is destroyed!");
716 deltrap(t_at(u
.ux
, u
.uy
));
719 pline(pullmsg
, hliquid("lava"));
722 register long side
= rn2(3) ? LEFT_SIDE
: RIGHT_SIDE
;
723 pline(pullmsg
, "bear trap");
724 set_wounded_legs(side
, rn1(1000, 500));
726 Your("%s %s is severely damaged.",
727 (side
== LEFT_SIDE
) ? "left" : "right",
729 losehp(Maybe_Half_Phys(2),
730 "leg damage from being pulled out of a bear trap",
737 fill_pit(u
.ux
, u
.uy
);
742 if (!Levitation
&& !MON_AT(x
, y
) && !u
.utrap
745 && (t
->ttyp
== PIT
|| t
->ttyp
== SPIKED_PIT
746 || t
->ttyp
== TRAPDOOR
|| t
->ttyp
== HOLE
)))) {
753 vision_full_recalc
= 1; /* hero has moved, recalculate vision later */
756 /* drop glyph under the chain */
757 if (u
.bc_felt
& BC_CHAIN
)
758 levl
[uchain
->ox
][uchain
->oy
].glyph
= u
.cglyph
;
759 u
.bc_felt
= 0; /* feel nothing */
760 /* pick up new glyph */
761 u
.cglyph
= (u
.bc_order
) ? u
.bglyph
: levl
[u
.ux
][u
.uy
].glyph
;
763 movobj(uchain
, u
.ux
, u
.uy
); /* has a newsym */
765 u
.bc_order
= bc_order();
767 newsym(u
.ux0
, u
.uy0
); /* clean up old position */
768 if (u
.ux0
!= u
.ux
|| u
.uy0
!= u
.uy
) {
778 struct obj
*otmp
= invent
, *nextobj
;
779 int capacity
= weight_cap();
782 nextobj
= otmp
->nobj
;
783 if ((otmp
!= uball
) && (rnd(capacity
) <= (int) otmp
->owt
)) {
784 if (canletgo(otmp
, "")) {
785 pline("%s you down the stairs.", Yobjnam2(otmp
, "follow"));
797 uchar dragchance
= 3;
800 * Assume that the ball falls forward if:
802 * a) the character is wielding it, or
803 * b) the character has both hands available to hold it (i.e. is
804 * not wielding any weapon), or
805 * c) (perhaps) it falls forward out of his non-weapon hand
807 forward
= carried(uball
) && (uwep
== uball
|| !uwep
|| !rn2(3));
810 You("lose your grip on the iron ball.");
812 cls(); /* previous level is still displayed although you
813 went down the stairs. Avoids bug C343-20 */
817 pline_The("iron ball drags you downstairs!");
818 losehp(Maybe_Half_Phys(rnd(6)),
819 "dragged downstairs by an iron ball", NO_KILLER_PREFIX
);
824 pline_The("iron ball smacks into you!");
825 losehp(Maybe_Half_Phys(rnd(20)), "iron ball collision",
827 exercise(A_STR
, FALSE
);
830 if ((int) dragchance
>= rnd(6)) {
831 pline_The("iron ball drags you downstairs!");
832 losehp(Maybe_Half_Phys(rnd(3)),
833 "dragged downstairs by an iron ball", NO_KILLER_PREFIX
);
834 exercise(A_STR
, FALSE
);