Source:NetHack 3.1.0/ball.c

From NetHackWiki
Jump to navigation Jump to search

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

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

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