Source:NetHack 3.3.0/ball.c

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