Wikia

Wikihack

Source:SLASH'EM 0.0.7E7F2/ball.c

2,032pages on
this wiki
Talk0

Below is the full text to ball.c from the source code of SLASH'EM 0.0.7E7F2. To link to a particular line, write [[SLASH'EM 0.0.7E7F2/ball.c#line123]], for example.

The latest source code for vanilla NetHack is at Source code.


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

Around Wikia's network

Random Wiki