Source:SLASH'EM 0.0.7E7F2/ball.c

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.

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*/