Source:NetHack 3.4.0/ball.c

Below is the full text to ball.c from the source code of NetHack 3.4.0. To link to a particular line, write [[NetHack 3.4.0/ball.c#line123 ]], for example.

Warning! This is the source code from an old release. For the latest release, see Source code

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