Source:Ball.c

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