1    | /*	SCCS Id: @(#)ball.c	3.3	97/04/23	*/
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   | 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   | 
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   | 
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  | 
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  | 
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  | 
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  | 
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  | 
346  | /* return TRUE if ball could be dragged
347  |  *
348  |  *  Should not be called while swallowed.
349  |  */
350  | boolean
351  | drag_ball(x, y, bc_control, ballx, bally, chainx, chainy, cause_delay)
352  | xchar x, y;
353  | int *bc_control;
354  | xchar *ballx, *bally, *chainx, *chainy;
355  | boolean *cause_delay;
356  | {
357  | 	struct trap *t = (struct trap *)0;
358  | 
359  | 	*ballx  = uball->ox;
360  | 	*bally  = uball->oy;
361  | 	*chainx = uchain->ox;
362  | 	*chainy = uchain->oy;
363  | 	*bc_control = 0;
364  | 	*cause_delay = FALSE;
365  | 
366  | 	if (dist2(x, y, uchain->ox, uchain->oy) <= 2) {	/* nothing moved */
367  | 	    move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
368  | 	    return TRUE;
369  | 	}
370  | 
371  | 	if (carried(uball) || dist2(x, y, uball->ox, uball->oy) < 3 ||
372  | 		(uball->ox == uchain->ox && uball->oy == uchain->oy)) {
373  | 	    /*
374  | 	     * Case where the ball doesn't move but the chain can't just move
375  | 	     * to the player's position:
376  | 	     *   @                                             _
377  | 	     *    _    moving southwest becomes  @_  and not  @
378  | 	     *   0                                0            0
379  | 	     */
380  | 	    *bc_control = BC_CHAIN;
381  | 	    move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
382  | 	    if (dist2(x, y, uball->ox, uball->oy) == 2 &&
383  | 		    dist2(x, y, uchain->ox, uchain->oy) == 4) {
384  | 		if (uchain->oy == y)
385  | 		    *chainx = uball->ox;
386  | 		else
387  | 		    *chainy = uball->oy;
388  | 	    } else {
389  | 		*chainx = u.ux;
390  | 		*chainy = u.uy;
391  | 	    }
392  | 	    return TRUE;
393  | 	}
394  | 
395  | 	if (near_capacity() > SLT_ENCUMBER) {
396  | 	    You("cannot %sdrag the heavy iron ball.",
397  | 			    invent ? "carry all that and also " : "");
398  | 	    nomul(0);
399  | 	    return FALSE;
400  | 	}
401  | 
402  | 	if ((is_pool(uchain->ox, uchain->oy) &&
403  | 			/* water not mere continuation of previous water */
404  | 			(levl[uchain->ox][uchain->oy].typ == POOL ||
405  | 			 !is_pool(uball->ox, uball->oy) ||
406  | 			 levl[uball->ox][uball->oy].typ == POOL))
407  | 	    || ((t = t_at(uchain->ox, uchain->oy)) &&
408  | 			(t->ttyp == PIT ||
409  | 			 t->ttyp == SPIKED_PIT ||
410  | 			 t->ttyp == HOLE ||
411  | 			 t->ttyp == TRAPDOOR)) ) {
412  | 
413  | 	    if (Levitation) {
414  | 		You_feel("a tug from the iron ball.");
415  | 		if (t) t->tseen = 1;
416  | 	    } else {
417  | 		struct monst *victim;
418  | 
419  | 		You("are jerked back by the iron ball!");
420  | 		if ((victim = m_at(uchain->ox, uchain->oy)) != 0) {
421  | 		    int tmp;
422  | 
423  | 		    tmp = -2 + Luck + find_mac(victim);
424  | 		    tmp += omon_adj(victim, uball, TRUE);
425  | 		    if (tmp >= rnd(20))
426  | 			(void) hmon(victim,uball,1);
427  | 		    else
428  | 			miss(xname(uball), victim);
429  | 
430  | 		}		/* now check again in case mon died */
431  | 		if (!m_at(uchain->ox, uchain->oy)) {
432  | 		    u.ux = uchain->ox;
433  | 		    u.uy = uchain->oy;
434  | 		    newsym(u.ux0, u.uy0);
435  | 		}
436  | 		nomul(0);
437  | 
438  | 		*bc_control = BC_BALL;
439  | 		move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
440  | 		*ballx = uchain->ox;
441  | 		*bally = uchain->oy;
442  | 		move_bc(0, *bc_control, *ballx, *bally, *chainx, *chainy);
443  | 		spoteffects(TRUE);
444  | 		return FALSE;
445  | 	    }
446  | 	}
447  | 
448  | 	*bc_control = BC_BALL|BC_CHAIN;;
449  | 
450  | 	move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
451  | 	*ballx  = uchain->ox;
452  | 	*bally  = uchain->oy;
453  | 	*chainx = u.ux;
454  | 	*chainy = u.uy;
455  | 	*cause_delay = TRUE;
456  | 	return TRUE;
457  | }
458  | 
459  | /*
460  |  *  drop_ball()
461  |  *
462  |  *  The punished hero drops or throws her iron ball.  If the hero is
463  |  *  blind, we must reset the order and glyph.  Check for side effects.
464  |  *  This routine expects the ball to be already placed.
465  |  *
466  |  *  Should not be called while swallowed.
467  |  */
468  | void
469  | drop_ball(x, y)
470  | xchar x, y;
471  | {
472  |     if (Blind) {
473  | 	u.bc_order = bc_order();			/* get the order */
474  | 							/* pick up glyph */
475  | 	u.bglyph = (u.bc_order) ? u.cglyph : levl[x][y].glyph;
476  |     }
477  | 
478  |     if (x != u.ux || y != u.uy) {
479  | 	struct trap *t;
480  | 	const char *pullmsg = "The ball pulls you out of the %s!";
481  | 
482  | 	if (u.utrap && u.utraptype != TT_INFLOOR) {
483  | 	    switch(u.utraptype) {
484  | 	    case TT_PIT:
485  | 		pline(pullmsg, "pit");
486  | 		break;
487  | 	    case TT_WEB:
488  | 		pline(pullmsg, "web");
489  | 		pline_The("web is destroyed!");
490  | 		deltrap(t_at(u.ux,u.uy));
491  | 		break;
492  | 	    case TT_LAVA:
493  | 		pline(pullmsg, "lava");
494  | 		break;
495  | 	    case TT_BEARTRAP: {
496  | 		register long side = rn2(3) ? LEFT_SIDE : RIGHT_SIDE;
497  | 		pline(pullmsg, "bear trap");
498  | 		set_wounded_legs(side, rn1(1000, 500));
499  | #ifdef STEED
500  | 		if (!u.usteed)
501  | #endif
502  | 		{
503  | 		    Your("%s %s is severely damaged.",
504  | 					(side == LEFT_SIDE) ? "left" : "right",
505  | 					body_part(LEG));
506  | 		    losehp(2, "leg damage from being pulled out of a bear trap",
507  | 					KILLED_BY);
508  | 		}
509  | 		break;
510  | 	      }
511  | 	    }
512  | 	    u.utrap = 0;
513  | 	    fill_pit(u.ux, u.uy);
514  | 	}
515  | 
516  | 	u.ux0 = u.ux;
517  | 	u.uy0 = u.uy;
518  | 	if (!Levitation && !MON_AT(x, y) && !u.utrap &&
519  | 			    (is_pool(x, y) ||
520  | 			     ((t = t_at(x, y)) &&
521  | 			      (t->ttyp == PIT || t->ttyp == SPIKED_PIT ||
522  | 			       t->ttyp == TRAPDOOR || t->ttyp == HOLE)))) {
523  | 	    u.ux = x;
524  | 	    u.uy = y;
525  | 	} else {
526  | 	    u.ux = x - u.dx;
527  | 	    u.uy = y - u.dy;
528  | 	}
529  | 	vision_full_recalc = 1;	/* hero has moved, recalculate vision later */
530  | 
531  | 	if (Blind) {
532  | 	    /* drop glyph under the chain */
533  | 	    if (u.bc_felt & BC_CHAIN)
534  | 		levl[uchain->ox][uchain->oy].glyph = u.cglyph;
535  | 	    u.bc_felt  = 0;		/* feel nothing */
536  | 	    /* pick up new glyph */
537  | 	    u.cglyph = (u.bc_order) ? u.bglyph : levl[u.ux][u.uy].glyph;
538  | 	}
539  | 	movobj(uchain,u.ux,u.uy);	/* has a newsym */
540  | 	if (Blind) {
541  | 	    u.bc_order = bc_order();
542  | 	}
543  | 	newsym(u.ux0,u.uy0);		/* clean up old position */
544  | 	if (u.ux0 != u.ux || u.uy0 != u.uy) {
545  | 	    spoteffects(TRUE);
546  | 	    if (In_sokoban(&u.uz))
547  | 		change_luck(-1);	/* Sokoban guilt */
548  | 	}
549  |     }
550  | }
551  | 
552  | 
553  | STATIC_OVL void
554  | litter()
555  | {
556  | 	struct obj *otmp = invent, *nextobj;
557  | 	int capacity = weight_cap();
558  | 
559  | 	while (otmp) {
560  | 		nextobj = otmp->nobj;
561  | 		if ((otmp != uball) && (rnd(capacity) <= (int)otmp->owt)) {
562  | 			if (otmp == uwep)
563  | 				setuwep((struct obj *)0);
564  | 			if ((otmp != uwep) && (canletgo(otmp, ""))) {
565  | 				Your("%s you down the stairs.",
566  | 				     aobjnam(otmp, "follow"));
567  | 				dropx(otmp);
568  | 			}
569  | 		}
570  | 		otmp = nextobj;
571  | 	}
572  | }
573  | 
574  | void
575  | drag_down()
576  | {
577  | 	boolean forward;
578  | 	uchar dragchance = 3;
579  | 
580  | 	/*
581  | 	 *	Assume that the ball falls forward if:
582  | 	 *
583  | 	 *	a) the character is wielding it, or
584  | 	 *	b) the character has both hands available to hold it (i.e. is
585  | 	 *	   not wielding any weapon), or
586  | 	 *	c) (perhaps) it falls forward out of his non-weapon hand
587  | 	 */
588  | 
589  | 	forward = carried(uball) && (uwep == uball || !uwep || !rn2(3));
590  | 
591  | 	if (carried(uball))
592  | 		You("lose your grip on the iron ball.");
593  | 
594  | 	if (forward) {
595  | 		if(rn2(6)) {
596  | 			pline_The("iron ball drags you downstairs!");
597  | 			losehp(rnd(6), "dragged downstairs by an iron ball",
598  | 				NO_KILLER_PREFIX);
599  | 			litter();
600  | 		}
601  | 	} else {
602  | 		if(rn2(2)) {
603  | 			pline_The("iron ball smacks into you!");
604  | 			losehp(rnd(20), "iron ball collision", KILLED_BY_AN);
605  | 			exercise(A_STR, FALSE);
606  | 			dragchance -= 2;
607  | 		}
608  | 		if( (int) dragchance >= rnd(6)) {
609  | 			pline_The("iron ball drags you downstairs!");
610  | 			losehp(rnd(3), "dragged downstairs by an iron ball",
611  | 				NO_KILLER_PREFIX);
612  | 			exercise(A_STR, FALSE);
613  | 			litter();
614  | 		}
615  | 	}
616  | }
617  | 
618  | /*ball.c*/