Source:NetHack 3.1.0/ball.c

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