Source:NetHack 3.2.0/ball.c

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