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. */
5 /* Ball & Chain =============================================================*/
9 STATIC_DCL
int bc_order(void);
10 STATIC_DCL
void litter(void);
13 #define memory_object(x, y) (levl[x][y].mem_obj)
15 #define memory_object(x, y) (levl[x][y].glyph)
23 gets_hit
= (((uball
->ox
!= u
.ux
) || (uball
->oy
!= u
.uy
)) &&
24 ((uwep
== uball
)? FALSE
: (boolean
)rn2(5)));
26 pline("Startled, you drop the iron ball.");
28 setuwep((struct obj
*)0, FALSE
, TRUE
);
29 if (uswapwep
== uball
)
30 setuswapwep((struct obj
*)0, FALSE
);
32 setuqwep((struct obj
*)0);;
38 pline_The("iron ball falls on your %s.",
41 if(is_hardmaterial(uarmh
)) {
42 pline("Fortunately, you are wearing a hard helmet.");
44 } else if (flags
.verbose
)
45 Your("%s does not protect you.", xname(uarmh
));
47 losehp(dmg
, "crunched in the head by an iron ball",
53 * To make this work, we have to mess with the hero's mind. The rules for
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.
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.
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.
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
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
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 */
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.
102 * Should not be called while swallowed.
107 if (!uchain
|| !uball
) {
108 impossible("Where are your ball and chain?");
110 if (uchain
) obj_extract_self(uchain
);
112 setworn((struct obj
*)0, W_CHAIN
);
113 setworn((struct obj
*)0, W_BALL
);
117 (void) flooreffects(uchain
, u
.ux
, u
.uy
, ""); /* chain might rust */
119 if (!uchain
|| !uball
) { /* can apparently happen due to erosion destroying them --Amy */
120 You("no longer have a ball and chain.");
122 if (uchain
) obj_extract_self(uchain
);
124 setworn((struct obj
*)0, W_CHAIN
);
125 setworn((struct obj
*)0, W_BALL
);
130 if (carried(uball
)) /* the ball is carried */
131 u
.bc_order
= BCPOS_DIFFER
;
133 /* ball might rust -- already checked when carried */
134 (void) flooreffects(uball
, u
.ux
, u
.uy
, "");
136 if (!uchain
|| !uball
) { /* can apparently happen due to erosion destroying them --Amy */
137 You("no longer have a ball and chain.");
139 if (uchain
) obj_extract_self(uchain
);
141 setworn((struct obj
*)0, W_CHAIN
);
142 setworn((struct obj
*)0, W_BALL
);
147 place_object(uball
, u
.ux
, u
.uy
);
148 u
.bc_order
= BCPOS_CHAIN
;
151 /*if (!Is_waterlevel(&u.uz))*/ place_object(uchain
, u
.ux
, u
.uy
);
153 u
.bglyph
= u
.cglyph
= memory_object(u
.ux
, u
.uy
); /* pick up glyph */
161 if (u
.uswallow
) return; /* ball&chain not placed while swallowed */
163 if (!carried(uball
)) {
164 obj_extract_self(uball
);
165 if (Blind
&& (u
.bc_felt
& BC_BALL
)) /* drop glyph */
166 memory_object(uball
->ox
, uball
->oy
) = u
.bglyph
;
168 newsym(uball
->ox
,uball
->oy
);
170 obj_extract_self(uchain
);
171 if (Blind
&& (u
.bc_felt
& BC_CHAIN
)) /* drop glyph */
172 memory_object(uchain
->ox
, uchain
->oy
) = u
.cglyph
;
174 newsym(uchain
->ox
,uchain
->oy
);
175 u
.bc_felt
= 0; /* feel nothing */
180 * Return the stacking of the hero's ball & chain. This assumes that the
181 * hero is being punished.
188 if (uchain
->ox
!= uball
->ox
|| uchain
->oy
!= uball
->oy
|| carried(uball
)
192 for (obj
= level
.objects
[uball
->ox
][uball
->oy
]; obj
; obj
= obj
->nexthere
) {
193 if (obj
== uchain
) return BCPOS_CHAIN
;
194 if (obj
== uball
) return BCPOS_BALL
;
196 impossible("bc_order: ball&chain not in same location!");
203 * The hero is either about to go blind or already blind and just punished.
204 * Set up the ball and chain variables so that the ball and chain are "felt".
207 set_bc(already_blind
)
210 int ball_on_floor
= !carried(uball
);
212 u
.bc_order
= bc_order(); /* get the order */
213 u
.bc_felt
= ball_on_floor
? BC_BALL
|BC_CHAIN
: BC_CHAIN
; /* felt */
215 if (already_blind
|| u
.uswallow
) {
216 u
.cglyph
= u
.bglyph
= memory_object(u
.ux
, u
.uy
);
221 * Since we can still see, remove the ball&chain and get the glyph that
222 * would be beneath them. Then put the ball&chain back. This is pretty
223 * disgusting, but it will work.
225 remove_object(uchain
);
226 if (ball_on_floor
) remove_object(uball
);
228 newsym(uchain
->ox
, uchain
->oy
);
229 u
.cglyph
= memory_object(uchain
->ox
, uchain
->oy
);
231 if (u
.bc_order
== BCPOS_DIFFER
) { /* different locations */
232 place_object(uchain
, uchain
->ox
, uchain
->oy
);
233 newsym(uchain
->ox
, uchain
->oy
);
235 newsym(uball
->ox
, uball
->oy
); /* see under ball */
236 u
.bglyph
= memory_object(uball
->ox
, uball
->oy
);
237 place_object(uball
, uball
->ox
, uball
->oy
);
238 newsym(uball
->ox
, uball
->oy
); /* restore ball */
242 if (u
.bc_order
== BCPOS_CHAIN
) {
243 place_object(uball
, uball
->ox
, uball
->oy
);
244 place_object(uchain
, uchain
->ox
, uchain
->oy
);
246 place_object(uchain
, uchain
->ox
, uchain
->oy
);
247 place_object(uball
, uball
->ox
, uball
->oy
);
249 newsym(uball
->ox
, uball
->oy
);
257 * Move the ball and chain. This is called twice for every move. The first
258 * time to pick up the ball and chain before the move, the second time to
259 * place the ball and chain after the move. If the ball is carried, this
260 * function should never have BC_BALL as part of its control.
262 * Should not be called while swallowed.
265 move_bc(before
, control
, ballx
, bally
, chainx
, chainy
)
267 xchar ballx
, bally
, chainx
, chainy
; /* only matter !before */
271 * The hero is blind. Time to work hard. The ball and chain that
272 * are attached to the hero are very special. The hero knows that
273 * they are attached, so when they move, the hero knows that they
274 * aren't at the last position remembered. This is complicated
275 * by the fact that the hero can "feel" the surrounding locations
276 * at any time, hence, making one or both of them show up again.
277 * So, we have to keep track of which is felt at any one time and
281 if ((control
& BC_CHAIN
) && (control
& BC_BALL
)) {
283 * Both ball and chain moved. If felt, drop glyph.
285 if (u
.bc_felt
& BC_BALL
)
286 memory_object(uball
->ox
, uball
->oy
) = u
.bglyph
;
287 if (u
.bc_felt
& BC_CHAIN
)
288 memory_object(uchain
->ox
, uchain
->oy
) = u
.cglyph
;
291 /* Pick up glyph at new location. */
292 u
.bglyph
= memory_object(ballx
, bally
);
293 u
.cglyph
= memory_object(chainx
, chainy
);
295 movobj(uball
,ballx
,bally
);
296 movobj(uchain
,chainx
,chainy
);
297 } else if (control
& BC_BALL
) {
298 if (u
.bc_felt
& BC_BALL
) {
299 if (u
.bc_order
== BCPOS_DIFFER
) { /* ball by itself */
300 memory_object(uball
->ox
, uball
->oy
) = u
.bglyph
;
301 } else if (u
.bc_order
== BCPOS_BALL
) {
302 if (u
.bc_felt
& BC_CHAIN
) { /* know chain is there */
303 map_object(uchain
, 0);
305 memory_object(uball
->ox
, uball
->oy
) = u
.bglyph
;
308 u
.bc_felt
&= ~BC_BALL
; /* no longer feel the ball */
311 /* Pick up glyph at new position. */
312 u
.bglyph
= (ballx
!= chainx
|| bally
!= chainy
) ?
313 memory_object(ballx
, bally
) : u
.cglyph
;
315 movobj(uball
,ballx
,bally
);
316 } else if (control
& BC_CHAIN
) {
317 if (u
.bc_felt
& BC_CHAIN
) {
318 if (u
.bc_order
== BCPOS_DIFFER
) {
319 memory_object(uchain
->ox
, uchain
->oy
) = u
.cglyph
;
320 } else if (u
.bc_order
== BCPOS_CHAIN
) {
321 if (u
.bc_felt
& BC_BALL
) {
322 map_object(uball
, 0);
324 memory_object(uchain
->ox
, uchain
->oy
) = u
.cglyph
;
327 u
.bc_felt
&= ~BC_CHAIN
;
329 /* Pick up glyph at new position. */
330 u
.cglyph
= (ballx
!= chainx
|| bally
!= chainy
) ?
331 memory_object(chainx
, chainy
) : u
.bglyph
;
333 movobj(uchain
,chainx
,chainy
);
336 u
.bc_order
= bc_order(); /* reset the order */
341 * The hero is not blind. To make this work correctly, we need to
342 * pick up the ball and chain before the hero moves, then put them
343 * in their new positions after the hero moves.
348 * Neither ball nor chain is moving, so remember which was
349 * on top until !before. Use the variable u.bc_order
350 * since it is only valid when blind.
352 u
.bc_order
= bc_order();
355 remove_object(uchain
);
356 newsym(uchain
->ox
, uchain
->oy
);
357 if (!carried(uball
)) {
358 remove_object(uball
);
359 newsym(uball
->ox
, uball
->oy
);
362 int on_floor
= !carried(uball
);
364 if ((control
& BC_CHAIN
) ||
365 (!control
&& u
.bc_order
== BCPOS_CHAIN
)) {
366 /* If the chain moved or nothing moved & chain on top. */
367 if (on_floor
) place_object(uball
, ballx
, bally
);
368 place_object(uchain
, chainx
, chainy
); /* chain on top */
370 place_object(uchain
, chainx
, chainy
);
371 if (on_floor
) place_object(uball
, ballx
, bally
);
374 newsym(chainx
, chainy
);
375 if (on_floor
) newsym(ballx
, bally
);
380 /* return TRUE if the caller needs to place the ball and chain down again
382 * Should not be called while swallowed. Should be called before movement,
383 * because we might want to move the ball or chain to the hero's old position.
385 * It is called if we are moving. It is also called if we are teleporting
386 * *if* the ball doesn't move and we thus must drag the chain. It is not
387 * called for ordinary teleportation.
389 * allow_drag is only used in the ugly special case where teleporting must
390 * drag the chain, while an identical-looking movement must drag both the ball
394 drag_ball(x
, y
, bc_control
, ballx
, bally
, chainx
, chainy
, cause_delay
,
398 xchar
*ballx
, *bally
, *chainx
, *chainy
;
399 boolean
*cause_delay
;
402 struct trap
*t
= (struct trap
*)0;
403 boolean already_in_rock
;
407 *chainx
= uchain
->ox
;
408 *chainy
= uchain
->oy
;
410 *cause_delay
= FALSE
;
412 if (dist2(x
, y
, uchain
->ox
, uchain
->oy
) <= 2) { /* nothing moved */
413 move_bc(1, *bc_control
, *ballx
, *bally
, *chainx
, *chainy
);
417 /* only need to move the chain? */
418 if (carried(uball
) || distmin(x
, y
, uball
->ox
, uball
->oy
) <= 2) {
419 xchar oldchainx
= uchain
->ox
, oldchainy
= uchain
->oy
;
420 *bc_control
= BC_CHAIN
;
421 move_bc(1, *bc_control
, *ballx
, *bally
, *chainx
, *chainy
);
422 if (carried(uball
)) {
423 /* move chain only if necessary */
424 if (distmin(x
, y
, uchain
->ox
, uchain
->oy
) > 1) {
430 #define CHAIN_IN_MIDDLE(chx, chy) \
431 (distmin(x, y, chx, chy) <= 1 && distmin(chx, chy, uball->ox, uball->oy) <= 1)
432 #define IS_CHAIN_ROCK(x,y) \
433 (IS_ROCKWFL(levl[x][y].typ) || (IS_DOOR(levl[x][y].typ) && \
434 (levl[x][y].doormask & (D_CLOSED|D_LOCKED))))
435 /* Don't ever move the chain into solid rock. If we have to, then instead
436 * undo the move_bc() and jump to the drag ball code. Note that this also
437 * means the "cannot carry and drag" message will not appear, since unless we
438 * moved at least two squares there is no possibility of the chain position
439 * being in solid rock.
441 #define SKIP_TO_DRAG { *chainx = oldchainx; *chainy = oldchainy; \
442 move_bc(0, *bc_control, *ballx, *bally, *chainx, *chainy); \
444 if (IS_CHAIN_ROCK(u
.ux
, u
.uy
) || IS_CHAIN_ROCK(*chainx
, *chainy
)
445 || IS_CHAIN_ROCK(uball
->ox
, uball
->oy
))
446 already_in_rock
= TRUE
;
448 already_in_rock
= FALSE
;
450 switch(dist2(x
, y
, uball
->ox
, uball
->oy
)) {
451 /* two spaces diagonal from ball, move chain inbetween */
453 *chainx
= (uball
->ox
+ x
)/2;
454 *chainy
= (uball
->oy
+ y
)/2;
455 if (IS_CHAIN_ROCK(*chainx
, *chainy
) && !already_in_rock
)
459 /* player is distance 2/1 from ball; move chain to one of the
466 xchar tempx
, tempy
, tempx2
, tempy2
;
468 /* find position closest to current position of chain */
469 /* no effect if current position is already OK */
470 if (abs(x
- uball
->ox
) == 1) {
473 tempy
= tempy2
= (uball
->oy
+ y
)/2;
475 tempx
= tempx2
= (uball
->ox
+ x
)/2;
479 if (IS_CHAIN_ROCK(tempx
, tempy
) &&
480 !IS_CHAIN_ROCK(tempx2
, tempy2
) &&
483 /* Avoid pathological case *if* not teleporting:
485 * _X move northeast -----> X@
488 if (dist2(u
.ux
, u
.uy
, uball
->ox
, uball
->oy
) == 5 &&
489 dist2(x
, y
, tempx
, tempy
) == 1)
491 /* Avoid pathological case *if* not teleporting:
493 * _X move east -----> X_
496 if (dist2(u
.ux
, u
.uy
, uball
->ox
, uball
->oy
) == 4 &&
497 dist2(x
, y
, tempx
, tempy
) == 2)
502 } else if (!IS_CHAIN_ROCK(tempx
, tempy
) &&
503 IS_CHAIN_ROCK(tempx2
, tempy2
) &&
506 if (dist2(u
.ux
, u
.uy
, uball
->ox
, uball
->oy
) == 5 &&
507 dist2(x
, y
, tempx2
, tempy2
) == 1)
509 if (dist2(u
.ux
, u
.uy
, uball
->ox
, uball
->oy
) == 4 &&
510 dist2(x
, y
, tempx2
, tempy2
) == 2)
515 } else if (IS_CHAIN_ROCK(tempx
, tempy
) &&
516 IS_CHAIN_ROCK(tempx2
, tempy2
) &&
519 } else if (dist2(tempx
, tempy
, uchain
->ox
, uchain
->oy
) <
520 dist2(tempx2
, tempy2
, uchain
->ox
, uchain
->oy
) ||
521 ((dist2(tempx
, tempy
, uchain
->ox
, uchain
->oy
) ==
522 dist2(tempx2
, tempy2
, uchain
->ox
, uchain
->oy
)) && rn2(2))) {
532 /* ball is two spaces horizontal or vertical from player; move*/
533 /* chain inbetween *unless* current chain position is OK */
535 if (CHAIN_IN_MIDDLE(uchain
->ox
, uchain
->oy
))
537 *chainx
= (x
+ uball
->ox
)/2;
538 *chainy
= (y
+ uball
->oy
)/2;
539 if (IS_CHAIN_ROCK(*chainx
, *chainy
) && !already_in_rock
)
543 /* ball is one space diagonal from player. Check for the
544 * following special case:
546 * _ moving southwest becomes @_
548 * (This will also catch teleporting that happens to resemble
549 * this case, but oh well.) Otherwise fall through.
552 if (dist2(x
, y
, uball
->ox
, uball
->oy
) == 2 &&
553 dist2(x
, y
, uchain
->ox
, uchain
->oy
) == 4) {
558 if (IS_CHAIN_ROCK(*chainx
, *chainy
) && !already_in_rock
)
565 /* do nothing if possible */
566 if (CHAIN_IN_MIDDLE(uchain
->ox
, uchain
->oy
))
568 /* otherwise try to drag chain to player's old position */
569 if (CHAIN_IN_MIDDLE(u
.ux
, u
.uy
)) {
574 /* otherwise use player's new position (they must have
575 teleported, for this to happen) */
580 default: impossible("bad chain movement");
585 #undef CHAIN_IN_MIDDLE
591 if (near_capacity() > SLT_ENCUMBER
&& dist2(x
, y
, u
.ux
, u
.uy
) <= 2) {
592 You("cannot %sdrag the heavy iron ball.",
593 invent
? "carry all that and also " : "");
598 if ((is_pool(uchain
->ox
, uchain
->oy
) &&
599 /* water not mere continuation of previous water */
600 (levl
[uchain
->ox
][uchain
->oy
].typ
== POOL
||
601 !is_pool(uball
->ox
, uball
->oy
) ||
602 levl
[uball
->ox
][uball
->oy
].typ
== POOL
))
603 || ((t
= t_at(uchain
->ox
, uchain
->oy
)) &&
605 t
->ttyp
== SPIKED_PIT
||
606 t
->ttyp
== GIANT_CHASM
||
607 t
->ttyp
== SHIT_PIT
||
608 t
->ttyp
== MANA_PIT
||
609 t
->ttyp
== ANOXIC_PIT
||
610 t
->ttyp
== HYPOXIC_PIT
||
611 t
->ttyp
== ACID_PIT
||
613 t
->ttyp
== SHAFT_TRAP
||
614 t
->ttyp
== CURRENT_SHAFT
||
615 t
->ttyp
== TRAPDOOR
)) ) {
618 You_feel("a tug from the iron ball.");
619 if (t
&& !t
->hiddentrap
) t
->tseen
= 1;
621 struct monst
*victim
;
623 You("are jerked back by the iron ball!");
624 if ((victim
= m_at(uchain
->ox
, uchain
->oy
)) != 0) {
626 int dieroll
= rnd(20);
628 tmp
= -2 + Luck
+ find_mac(victim
);
629 tmp
+= omon_adj(victim
, uball
, TRUE
);
630 if (tmp
>= rnd(dieroll
))
631 (void) hmon(victim
,uball
,3,dieroll
);
633 miss(xname(uball
), victim
);
635 } /* now check again in case mon died */
636 if (!m_at(uchain
->ox
, uchain
->oy
)) {
639 newsym(u
.ux0
, u
.uy0
);
643 *bc_control
= BC_BALL
;
644 move_bc(1, *bc_control
, *ballx
, *bally
, *chainx
, *chainy
);
647 move_bc(0, *bc_control
, *ballx
, *bally
, *chainx
, *chainy
);
653 *bc_control
= BC_BALL
|BC_CHAIN
;
655 move_bc(1, *bc_control
, *ballx
, *bally
, *chainx
, *chainy
);
656 if (dist2(x
, y
, u
.ux
, u
.uy
) > 2) {
657 /* Awful case: we're still in range of the ball, so we thought we
658 * could only move the chain, but it turned out that the target
659 * square for the chain was rock, so we had to drag it instead.
660 * But we can't drag it either, because we teleported and are more
661 * than one square from our old position. Revert to the teleport
664 *ballx
= *chainx
= x
;
665 *bally
= *chainy
= y
;
679 * The punished hero drops or throws her iron ball. If the hero is
680 * blind, we must reset the order and glyph. Check for side effects.
681 * This routine expects the ball to be already placed.
683 * Should not be called while swallowed.
690 u
.bc_order
= bc_order(); /* get the order */
692 u
.bglyph
= (u
.bc_order
) ? u
.cglyph
: memory_object(x
, y
);
695 if (x
!= u
.ux
|| y
!= u
.uy
) {
697 const char *pullmsg
= "The ball pulls you out of the %s!";
699 if (u
.utrap
&& u
.utraptype
!= TT_INFLOOR
) {
700 switch(u
.utraptype
) {
702 pline(pullmsg
, "pit");
705 pline(pullmsg
, "glue");
708 pline(pullmsg
, "web");
709 pline_The("web is destroyed!");
710 deltrap(t_at(u
.ux
,u
.uy
));
713 pline(pullmsg
, "lava");
716 register long side
= rn2(3) ? LEFT_SIDE
: RIGHT_SIDE
;
717 pline(pullmsg
, "bear trap");
718 set_wounded_legs(side
, HWounded_legs
+ rn1(1000, 500));
721 Your("%s %s is severely damaged.",
722 (side
== LEFT_SIDE
) ? "left" : "right",
724 losehp(2, "leg damage from being pulled out of a bear trap",
731 fill_pit(u
.ux
, u
.uy
);
736 if (!Levitation
&& !MON_AT(x
, y
) && !u
.utrap
&&
739 (t
->ttyp
== PIT
|| t
->ttyp
== ANOXIC_PIT
|| t
->ttyp
== HYPOXIC_PIT
|| t
->ttyp
== ACID_PIT
|| t
->ttyp
== SPIKED_PIT
|| t
->ttyp
== GIANT_CHASM
|| t
->ttyp
== SHIT_PIT
|| t
->ttyp
== MANA_PIT
|| t
->ttyp
== SHAFT_TRAP
|| t
->ttyp
== CURRENT_SHAFT
||
740 t
->ttyp
== TRAPDOOR
|| t
->ttyp
== HOLE
)))) {
747 vision_full_recalc
= 1; /* hero has moved, recalculate vision later */
750 /* drop glyph under the chain */
751 if (u
.bc_felt
& BC_CHAIN
)
752 memory_object(uchain
->ox
, uchain
->oy
) = u
.cglyph
;
753 u
.bc_felt
= 0; /* feel nothing */
754 /* pick up new glyph */
755 u
.cglyph
= (u
.bc_order
) ? u
.bglyph
: memory_object(u
.ux
, u
.uy
);
757 movobj(uchain
,u
.ux
,u
.uy
); /* has a newsym */
759 u
.bc_order
= bc_order();
761 newsym(u
.ux0
,u
.uy0
); /* clean up old position */
762 if (u
.ux0
!= u
.ux
|| u
.uy0
!= u
.uy
) {
764 /* This used to give sokoban penalties but you can't actually bypass anything so the penalty is removed --Amy */
765 /* Soviet Russia comment is in apply.c */
767 if (issoviet
&& In_sokoban(&u
.uz
)) {
769 pline("Teper' vy teryayete ochko udachi KHAR KHAR. Eto deystviye ne pomoglo vam reshit' golovolomki, no my takiye elitnyye.");
770 if (evilfriday
) u
.ugangr
++;
781 struct obj
*otmp
= invent
, *nextobj
;
782 int capacity
= weight_cap();
785 nextobj
= otmp
->nobj
;
786 if ((otmp
!= uball
) && (rnd(capacity
) <= (int)otmp
->owt
)) {
787 if (canletgo(otmp
, "")) {
788 Your("%s you down the stairs.",
789 aobjnam(otmp
, "follow"));
801 uchar dragchance
= 3;
804 * Assume that the ball falls forward if:
806 * a) the character is wielding it, or
807 * b) the character has both hands available to hold it (i.e. is
808 * not wielding any weapon), or
809 * c) (perhaps) it falls forward out of his non-weapon hand
812 forward
= carried(uball
) && (uwep
== uball
|| !uwep
|| !rn2(3));
815 You("lose your grip on the iron ball.");
819 pline_The("iron ball drags you downstairs!");
820 if (PlayerHearsSoundEffects
) pline(issoviet
? "Vy s udovol'stviyem yeshche peretashchiv etu duratskuyu myach vmeste?" : "Rlalalalalaaaaar!");
821 losehp(rnd(6), "dragged downstairs by an iron ball",
827 pline_The("iron ball smacks into you!");
828 if (PlayerHearsSoundEffects
) pline(issoviet
? "Kha-kha-kha, tip bloka l'da smeyetsya yego zadnitsu smotret' vy imeyete delo s etoy duratskoy myach." : "Tschackschwack!");
829 losehp(rnd(20), "iron ball collision", KILLED_BY_AN
);
830 exercise(A_STR
, FALSE
);
833 if( (int) dragchance
>= rnd(6)) {
834 pline_The("iron ball drags you downstairs!");
835 if (PlayerHearsSoundEffects
) pline(issoviet
? "Vy s udovol'stviyem yeshche peretashchiv etu duratskuyu myach vmeste?" : "Rlalalalalaaaaar!");
836 losehp(rnd(3), "dragged downstairs by an iron ball",
838 exercise(A_STR
, FALSE
);