Gaming
 

Source:Ball.c

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.

Contents

[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.    
The NetHack General Public License applies to screenshots, source code and other content from NetHack.
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*/