Blindfold removal fix
[slashemextended.git] / src / ball.c
blob0f8606a35e79bd3b7b3f1d0e94931eb67b5ed4d7
1 /* SCCS Id: @(#)ball.c 3.4 2003/02/03 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 /* Ball & Chain =============================================================*/
7 #include "hack.h"
9 STATIC_DCL int bc_order(void);
10 STATIC_DCL void litter(void);
12 #ifdef DISPLAY_LAYERS
13 #define memory_object(x, y) (levl[x][y].mem_obj)
14 #else
15 #define memory_object(x, y) (levl[x][y].glyph)
16 #endif
18 void
19 ballfall()
21 boolean gets_hit;
23 gets_hit = (((uball->ox != u.ux) || (uball->oy != u.uy)) &&
24 ((uwep == uball)? FALSE : (boolean)rn2(5)));
25 if (carried(uball)) {
26 pline("Startled, you drop the iron ball.");
27 if (uwep == uball)
28 setuwep((struct obj *)0, FALSE, TRUE);
29 if (uswapwep == uball)
30 setuswapwep((struct obj *)0, FALSE);
31 if (uquiver == uball)
32 setuqwep((struct obj *)0);;
33 if (uwep != uball)
34 freeinv(uball);
36 if(gets_hit){
37 int dmg = rn1(7,25);
38 pline_The("iron ball falls on your %s.",
39 body_part(HEAD));
40 if (uarmh) {
41 if(is_hardmaterial(uarmh)) {
42 pline("Fortunately, you are wearing a hard helmet.");
43 dmg = 3;
44 } else if (flags.verbose)
45 Your("%s does not protect you.", xname(uarmh));
47 losehp(dmg, "crunched in the head by an iron ball",
48 NO_KILLER_PREFIX);
53 * To make this work, we have to mess with the hero's mind. The rules for
54 * ball&chain are:
56 * 1. If the hero can see them, fine.
57 * 2. If the hero can't see either, it isn't seen.
58 * 3. If either is felt it is seen.
59 * 4. If either is felt and moved, it disappears.
61 * If the hero can see, then when a move is done, the ball and chain are
62 * first picked up, the positions under them are corrected, then they
63 * are moved after the hero moves. Not too bad.
65 * If the hero is blind, then she can "feel" the ball and/or chain at any
66 * time. However, when the hero moves, the felt ball and/or chain become
67 * unfelt and whatever was felt "under" the ball&chain appears. Pretty
68 * nifty, but it requires that the ball&chain "remember" what was under
69 * them --- i.e. they pick-up glyphs when they are felt and drop them when
70 * moved (and felt). When swallowed, the ball&chain are pulled completely
71 * off of the dungeon, but are still on the object chain. They are placed
72 * under the hero when she is expelled.
76 * from you.h
77 * int u.bglyph glyph under the ball
78 * int u.cglyph glyph under the chain
79 * int u.bc_felt mask for ball/chain being felt
80 * #define BC_BALL 0x01 bit mask in u.bc_felt for ball
81 * #define BC_CHAIN 0x02 bit mask in u.bc_felt for chain
82 * int u.bc_order ball & chain order
84 * u.bc_felt is also manipulated in display.c and read.c, the others only
85 * in this file. None of these variables are valid unless the player is
86 * Blind.
89 /* values for u.bc_order */
90 #define BCPOS_DIFFER 0 /* ball & chain at different positions */
91 #define BCPOS_CHAIN 1 /* chain on top of ball */
92 #define BCPOS_BALL 2 /* ball on top of chain */
97 * Place the ball & chain under the hero. Make sure that the ball & chain
98 * variables are set (actually only needed when blind, but what the heck).
99 * It is assumed that when this is called, the ball and chain are NOT
100 * attached to the object list.
102 * Should not be called while swallowed.
104 void
105 placebc()
107 if (!uchain || !uball) {
108 impossible("Where are your ball and chain?");
110 if (uchain) obj_extract_self(uchain);
112 setworn((struct obj *)0, W_CHAIN);
113 setworn((struct obj *)0, W_BALL);
114 return;
117 (void) flooreffects(uchain, u.ux, u.uy, ""); /* chain might rust */
119 if (!uchain || !uball) { /* can apparently happen due to erosion destroying them --Amy */
120 You("no longer have a ball and chain.");
122 if (uchain) obj_extract_self(uchain);
124 setworn((struct obj *)0, W_CHAIN);
125 setworn((struct obj *)0, W_BALL);
126 return;
130 if (carried(uball)) /* the ball is carried */
131 u.bc_order = BCPOS_DIFFER;
132 else {
133 /* ball might rust -- already checked when carried */
134 (void) flooreffects(uball, u.ux, u.uy, "");
136 if (!uchain || !uball) { /* can apparently happen due to erosion destroying them --Amy */
137 You("no longer have a ball and chain.");
139 if (uchain) obj_extract_self(uchain);
141 setworn((struct obj *)0, W_CHAIN);
142 setworn((struct obj *)0, W_BALL);
143 return;
147 place_object(uball, u.ux, u.uy);
148 u.bc_order = BCPOS_CHAIN;
151 /*if (!Is_waterlevel(&u.uz))*/ place_object(uchain, u.ux, u.uy);
153 u.bglyph = u.cglyph = memory_object(u.ux, u.uy); /* pick up glyph */
155 newsym(u.ux,u.uy);
158 void
159 unplacebc()
161 if (u.uswallow) return; /* ball&chain not placed while swallowed */
163 if (!carried(uball)) {
164 obj_extract_self(uball);
165 if (Blind && (u.bc_felt & BC_BALL)) /* drop glyph */
166 memory_object(uball->ox, uball->oy) = u.bglyph;
168 newsym(uball->ox,uball->oy);
170 obj_extract_self(uchain);
171 if (Blind && (u.bc_felt & BC_CHAIN)) /* drop glyph */
172 memory_object(uchain->ox, uchain->oy) = u.cglyph;
174 newsym(uchain->ox,uchain->oy);
175 u.bc_felt = 0; /* feel nothing */
180 * Return the stacking of the hero's ball & chain. This assumes that the
181 * hero is being punished.
183 STATIC_OVL int
184 bc_order()
186 struct obj *obj;
188 if (uchain->ox != uball->ox || uchain->oy != uball->oy || carried(uball)
189 || u.uswallow)
190 return BCPOS_DIFFER;
192 for (obj = level.objects[uball->ox][uball->oy]; obj; obj = obj->nexthere) {
193 if (obj == uchain) return BCPOS_CHAIN;
194 if (obj == uball) return BCPOS_BALL;
196 impossible("bc_order: ball&chain not in same location!");
197 return BCPOS_DIFFER;
201 * set_bc()
203 * The hero is either about to go blind or already blind and just punished.
204 * Set up the ball and chain variables so that the ball and chain are "felt".
206 void
207 set_bc(already_blind)
208 int already_blind;
210 int ball_on_floor = !carried(uball);
212 u.bc_order = bc_order(); /* get the order */
213 u.bc_felt = ball_on_floor ? BC_BALL|BC_CHAIN : BC_CHAIN; /* felt */
215 if (already_blind || u.uswallow) {
216 u.cglyph = u.bglyph = memory_object(u.ux, u.uy);
217 return;
221 * Since we can still see, remove the ball&chain and get the glyph that
222 * would be beneath them. Then put the ball&chain back. This is pretty
223 * disgusting, but it will work.
225 remove_object(uchain);
226 if (ball_on_floor) remove_object(uball);
228 newsym(uchain->ox, uchain->oy);
229 u.cglyph = memory_object(uchain->ox, uchain->oy);
231 if (u.bc_order == BCPOS_DIFFER) { /* different locations */
232 place_object(uchain, uchain->ox, uchain->oy);
233 newsym(uchain->ox, uchain->oy);
234 if (ball_on_floor) {
235 newsym(uball->ox, uball->oy); /* see under ball */
236 u.bglyph = memory_object(uball->ox, uball->oy);
237 place_object(uball, uball->ox, uball->oy);
238 newsym(uball->ox, uball->oy); /* restore ball */
240 } else {
241 u.bglyph = u.cglyph;
242 if (u.bc_order == BCPOS_CHAIN) {
243 place_object(uball, uball->ox, uball->oy);
244 place_object(uchain, uchain->ox, uchain->oy);
245 } else {
246 place_object(uchain, uchain->ox, uchain->oy);
247 place_object(uball, uball->ox, uball->oy);
249 newsym(uball->ox, uball->oy);
255 * move_bc()
257 * Move the ball and chain. This is called twice for every move. The first
258 * time to pick up the ball and chain before the move, the second time to
259 * place the ball and chain after the move. If the ball is carried, this
260 * function should never have BC_BALL as part of its control.
262 * Should not be called while swallowed.
264 void
265 move_bc(before, control, ballx, bally, chainx, chainy)
266 int before, control;
267 xchar ballx, bally, chainx, chainy; /* only matter !before */
269 if (Blind) {
271 * The hero is blind. Time to work hard. The ball and chain that
272 * are attached to the hero are very special. The hero knows that
273 * they are attached, so when they move, the hero knows that they
274 * aren't at the last position remembered. This is complicated
275 * by the fact that the hero can "feel" the surrounding locations
276 * at any time, hence, making one or both of them show up again.
277 * So, we have to keep track of which is felt at any one time and
278 * act accordingly.
280 if (!before) {
281 if ((control & BC_CHAIN) && (control & BC_BALL)) {
283 * Both ball and chain moved. If felt, drop glyph.
285 if (u.bc_felt & BC_BALL)
286 memory_object(uball->ox, uball->oy) = u.bglyph;
287 if (u.bc_felt & BC_CHAIN)
288 memory_object(uchain->ox, uchain->oy) = u.cglyph;
289 u.bc_felt = 0;
291 /* Pick up glyph at new location. */
292 u.bglyph = memory_object(ballx, bally);
293 u.cglyph = memory_object(chainx, chainy);
295 movobj(uball,ballx,bally);
296 movobj(uchain,chainx,chainy);
297 } else if (control & BC_BALL) {
298 if (u.bc_felt & BC_BALL) {
299 if (u.bc_order == BCPOS_DIFFER) { /* ball by itself */
300 memory_object(uball->ox, uball->oy) = u.bglyph;
301 } else if (u.bc_order == BCPOS_BALL) {
302 if (u.bc_felt & BC_CHAIN) { /* know chain is there */
303 map_object(uchain, 0);
304 } else {
305 memory_object(uball->ox, uball->oy) = u.bglyph;
308 u.bc_felt &= ~BC_BALL; /* no longer feel the ball */
311 /* Pick up glyph at new position. */
312 u.bglyph = (ballx != chainx || bally != chainy) ?
313 memory_object(ballx, bally) : u.cglyph;
315 movobj(uball,ballx,bally);
316 } else if (control & BC_CHAIN) {
317 if (u.bc_felt & BC_CHAIN) {
318 if (u.bc_order == BCPOS_DIFFER) {
319 memory_object(uchain->ox, uchain->oy) = u.cglyph;
320 } else if (u.bc_order == BCPOS_CHAIN) {
321 if (u.bc_felt & BC_BALL) {
322 map_object(uball, 0);
323 } else {
324 memory_object(uchain->ox, uchain->oy) = u.cglyph;
327 u.bc_felt &= ~BC_CHAIN;
329 /* Pick up glyph at new position. */
330 u.cglyph = (ballx != chainx || bally != chainy) ?
331 memory_object(chainx, chainy) : u.bglyph;
333 movobj(uchain,chainx,chainy);
336 u.bc_order = bc_order(); /* reset the order */
339 } else {
341 * The hero is not blind. To make this work correctly, we need to
342 * pick up the ball and chain before the hero moves, then put them
343 * in their new positions after the hero moves.
345 if (before) {
346 if (!control) {
348 * Neither ball nor chain is moving, so remember which was
349 * on top until !before. Use the variable u.bc_order
350 * since it is only valid when blind.
352 u.bc_order = bc_order();
355 remove_object(uchain);
356 newsym(uchain->ox, uchain->oy);
357 if (!carried(uball)) {
358 remove_object(uball);
359 newsym(uball->ox, uball->oy);
361 } else {
362 int on_floor = !carried(uball);
364 if ((control & BC_CHAIN) ||
365 (!control && u.bc_order == BCPOS_CHAIN)) {
366 /* If the chain moved or nothing moved & chain on top. */
367 if (on_floor) place_object(uball, ballx, bally);
368 place_object(uchain, chainx, chainy); /* chain on top */
369 } else {
370 place_object(uchain, chainx, chainy);
371 if (on_floor) place_object(uball, ballx, bally);
372 /* ball on top */
374 newsym(chainx, chainy);
375 if (on_floor) newsym(ballx, bally);
380 /* return TRUE if the caller needs to place the ball and chain down again
382 * Should not be called while swallowed. Should be called before movement,
383 * because we might want to move the ball or chain to the hero's old position.
385 * It is called if we are moving. It is also called if we are teleporting
386 * *if* the ball doesn't move and we thus must drag the chain. It is not
387 * called for ordinary teleportation.
389 * allow_drag is only used in the ugly special case where teleporting must
390 * drag the chain, while an identical-looking movement must drag both the ball
391 * and chain.
393 boolean
394 drag_ball(x, y, bc_control, ballx, bally, chainx, chainy, cause_delay,
395 allow_drag)
396 xchar x, y;
397 int *bc_control;
398 xchar *ballx, *bally, *chainx, *chainy;
399 boolean *cause_delay;
400 boolean allow_drag;
402 struct trap *t = (struct trap *)0;
403 boolean already_in_rock;
405 *ballx = uball->ox;
406 *bally = uball->oy;
407 *chainx = uchain->ox;
408 *chainy = uchain->oy;
409 *bc_control = 0;
410 *cause_delay = FALSE;
412 if (dist2(x, y, uchain->ox, uchain->oy) <= 2) { /* nothing moved */
413 move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
414 return TRUE;
417 /* only need to move the chain? */
418 if (carried(uball) || distmin(x, y, uball->ox, uball->oy) <= 2) {
419 xchar oldchainx = uchain->ox, oldchainy = uchain->oy;
420 *bc_control = BC_CHAIN;
421 move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
422 if (carried(uball)) {
423 /* move chain only if necessary */
424 if (distmin(x, y, uchain->ox, uchain->oy) > 1) {
425 *chainx = u.ux;
426 *chainy = u.uy;
428 return TRUE;
430 #define CHAIN_IN_MIDDLE(chx, chy) \
431 (distmin(x, y, chx, chy) <= 1 && distmin(chx, chy, uball->ox, uball->oy) <= 1)
432 #define IS_CHAIN_ROCK(x,y) \
433 (IS_ROCKWFL(levl[x][y].typ) || (IS_DOOR(levl[x][y].typ) && \
434 (levl[x][y].doormask & (D_CLOSED|D_LOCKED))))
435 /* Don't ever move the chain into solid rock. If we have to, then instead
436 * undo the move_bc() and jump to the drag ball code. Note that this also
437 * means the "cannot carry and drag" message will not appear, since unless we
438 * moved at least two squares there is no possibility of the chain position
439 * being in solid rock.
441 #define SKIP_TO_DRAG { *chainx = oldchainx; *chainy = oldchainy; \
442 move_bc(0, *bc_control, *ballx, *bally, *chainx, *chainy); \
443 goto drag; }
444 if (IS_CHAIN_ROCK(u.ux, u.uy) || IS_CHAIN_ROCK(*chainx, *chainy)
445 || IS_CHAIN_ROCK(uball->ox, uball->oy))
446 already_in_rock = TRUE;
447 else
448 already_in_rock = FALSE;
450 switch(dist2(x, y, uball->ox, uball->oy)) {
451 /* two spaces diagonal from ball, move chain inbetween */
452 case 8:
453 *chainx = (uball->ox + x)/2;
454 *chainy = (uball->oy + y)/2;
455 if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock)
456 SKIP_TO_DRAG;
457 break;
459 /* player is distance 2/1 from ball; move chain to one of the
460 * two spaces between
462 * __
465 case 5: {
466 xchar tempx, tempy, tempx2, tempy2;
468 /* find position closest to current position of chain */
469 /* no effect if current position is already OK */
470 if (abs(x - uball->ox) == 1) {
471 tempx = x;
472 tempx2 = uball->ox;
473 tempy = tempy2 = (uball->oy + y)/2;
474 } else {
475 tempx = tempx2 = (uball->ox + x)/2;
476 tempy = y;
477 tempy2 = uball->oy;
479 if (IS_CHAIN_ROCK(tempx, tempy) &&
480 !IS_CHAIN_ROCK(tempx2, tempy2) &&
481 !already_in_rock) {
482 if (allow_drag) {
483 /* Avoid pathological case *if* not teleporting:
484 * 0 0_
485 * _X move northeast -----> X@
488 if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 5 &&
489 dist2(x, y, tempx, tempy) == 1)
490 SKIP_TO_DRAG;
491 /* Avoid pathological case *if* not teleporting:
492 * 0 0
493 * _X move east -----> X_
494 * @ @
496 if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 4 &&
497 dist2(x, y, tempx, tempy) == 2)
498 SKIP_TO_DRAG;
500 *chainx = tempx2;
501 *chainy = tempy2;
502 } else if (!IS_CHAIN_ROCK(tempx, tempy) &&
503 IS_CHAIN_ROCK(tempx2, tempy2) &&
504 !already_in_rock) {
505 if (allow_drag) {
506 if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 5 &&
507 dist2(x, y, tempx2, tempy2) == 1)
508 SKIP_TO_DRAG;
509 if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 4 &&
510 dist2(x, y, tempx2, tempy2) == 2)
511 SKIP_TO_DRAG;
513 *chainx = tempx;
514 *chainy = tempy;
515 } else if (IS_CHAIN_ROCK(tempx, tempy) &&
516 IS_CHAIN_ROCK(tempx2, tempy2) &&
517 !already_in_rock) {
518 SKIP_TO_DRAG;
519 } else if (dist2(tempx, tempy, uchain->ox, uchain->oy) <
520 dist2(tempx2, tempy2, uchain->ox, uchain->oy) ||
521 ((dist2(tempx, tempy, uchain->ox, uchain->oy) ==
522 dist2(tempx2, tempy2, uchain->ox, uchain->oy)) && rn2(2))) {
523 *chainx = tempx;
524 *chainy = tempy;
525 } else {
526 *chainx = tempx2;
527 *chainy = tempy2;
529 break;
532 /* ball is two spaces horizontal or vertical from player; move*/
533 /* chain inbetween *unless* current chain position is OK */
534 case 4:
535 if (CHAIN_IN_MIDDLE(uchain->ox, uchain->oy))
536 break;
537 *chainx = (x + uball->ox)/2;
538 *chainy = (y + uball->oy)/2;
539 if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock)
540 SKIP_TO_DRAG;
541 break;
543 /* ball is one space diagonal from player. Check for the
544 * following special case:
546 * _ moving southwest becomes @_
547 * 0 0
548 * (This will also catch teleporting that happens to resemble
549 * this case, but oh well.) Otherwise fall through.
551 case 2:
552 if (dist2(x, y, uball->ox, uball->oy) == 2 &&
553 dist2(x, y, uchain->ox, uchain->oy) == 4) {
554 if (uchain->oy == y)
555 *chainx = uball->ox;
556 else
557 *chainy = uball->oy;
558 if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock)
559 SKIP_TO_DRAG;
560 break;
562 /* fall through */
563 case 1:
564 case 0:
565 /* do nothing if possible */
566 if (CHAIN_IN_MIDDLE(uchain->ox, uchain->oy))
567 break;
568 /* otherwise try to drag chain to player's old position */
569 if (CHAIN_IN_MIDDLE(u.ux, u.uy)) {
570 *chainx = u.ux;
571 *chainy = u.uy;
572 break;
574 /* otherwise use player's new position (they must have
575 teleported, for this to happen) */
576 *chainx = x;
577 *chainy = y;
578 break;
580 default: impossible("bad chain movement");
581 break;
583 #undef SKIP_TO_DRAG
584 #undef IS_CHAIN_ROCK
585 #undef CHAIN_IN_MIDDLE
586 return TRUE;
589 drag:
591 if (near_capacity() > SLT_ENCUMBER && dist2(x, y, u.ux, u.uy) <= 2) {
592 You("cannot %sdrag the heavy iron ball.",
593 invent ? "carry all that and also " : "");
594 nomul(0, 0, FALSE);
595 return FALSE;
598 if ((is_pool(uchain->ox, uchain->oy) &&
599 /* water not mere continuation of previous water */
600 (levl[uchain->ox][uchain->oy].typ == POOL ||
601 !is_pool(uball->ox, uball->oy) ||
602 levl[uball->ox][uball->oy].typ == POOL))
603 || ((t = t_at(uchain->ox, uchain->oy)) &&
604 (t->ttyp == PIT ||
605 t->ttyp == SPIKED_PIT ||
606 t->ttyp == GIANT_CHASM ||
607 t->ttyp == SHIT_PIT ||
608 t->ttyp == MANA_PIT ||
609 t->ttyp == ANOXIC_PIT ||
610 t->ttyp == HYPOXIC_PIT ||
611 t->ttyp == ACID_PIT ||
612 t->ttyp == HOLE ||
613 t->ttyp == SHAFT_TRAP ||
614 t->ttyp == CURRENT_SHAFT ||
615 t->ttyp == TRAPDOOR)) ) {
617 if (Levitation) {
618 You_feel("a tug from the iron ball.");
619 if (t && !t->hiddentrap) t->tseen = 1;
620 } else {
621 struct monst *victim;
623 You("are jerked back by the iron ball!");
624 if ((victim = m_at(uchain->ox, uchain->oy)) != 0) {
625 int tmp;
626 int dieroll = rnd(20);
628 tmp = -2 + Luck + find_mac(victim);
629 tmp += omon_adj(victim, uball, TRUE);
630 if (tmp >= rnd(dieroll))
631 (void) hmon(victim,uball,3,dieroll);
632 else
633 miss(xname(uball), victim);
635 } /* now check again in case mon died */
636 if (!m_at(uchain->ox, uchain->oy)) {
637 u.ux = uchain->ox;
638 u.uy = uchain->oy;
639 newsym(u.ux0, u.uy0);
641 nomul(0, 0, FALSE);
643 *bc_control = BC_BALL;
644 move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
645 *ballx = uchain->ox;
646 *bally = uchain->oy;
647 move_bc(0, *bc_control, *ballx, *bally, *chainx, *chainy);
648 spoteffects(TRUE);
649 return FALSE;
653 *bc_control = BC_BALL|BC_CHAIN;
655 move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
656 if (dist2(x, y, u.ux, u.uy) > 2) {
657 /* Awful case: we're still in range of the ball, so we thought we
658 * could only move the chain, but it turned out that the target
659 * square for the chain was rock, so we had to drag it instead.
660 * But we can't drag it either, because we teleported and are more
661 * than one square from our old position. Revert to the teleport
662 * behavior.
664 *ballx = *chainx = x;
665 *bally = *chainy = y;
666 } else {
667 *ballx = uchain->ox;
668 *bally = uchain->oy;
669 *chainx = u.ux;
670 *chainy = u.uy;
672 *cause_delay = TRUE;
673 return TRUE;
677 * drop_ball()
679 * The punished hero drops or throws her iron ball. If the hero is
680 * blind, we must reset the order and glyph. Check for side effects.
681 * This routine expects the ball to be already placed.
683 * Should not be called while swallowed.
685 void
686 drop_ball(x, y)
687 xchar x, y;
689 if (Blind) {
690 u.bc_order = bc_order(); /* get the order */
691 /* pick up glyph */
692 u.bglyph = (u.bc_order) ? u.cglyph : memory_object(x, y);
695 if (x != u.ux || y != u.uy) {
696 struct trap *t;
697 const char *pullmsg = "The ball pulls you out of the %s!";
699 if (u.utrap && u.utraptype != TT_INFLOOR) {
700 switch(u.utraptype) {
701 case TT_PIT:
702 pline(pullmsg, "pit");
703 break;
704 case TT_GLUE:
705 pline(pullmsg, "glue");
706 break;
707 case TT_WEB:
708 pline(pullmsg, "web");
709 pline_The("web is destroyed!");
710 deltrap(t_at(u.ux,u.uy));
711 break;
712 case TT_LAVA:
713 pline(pullmsg, "lava");
714 break;
715 case TT_BEARTRAP: {
716 register long side = rn2(3) ? LEFT_SIDE : RIGHT_SIDE;
717 pline(pullmsg, "bear trap");
718 set_wounded_legs(side, HWounded_legs + rn1(1000, 500));
719 if (!u.usteed)
721 Your("%s %s is severely damaged.",
722 (side == LEFT_SIDE) ? "left" : "right",
723 body_part(LEG));
724 losehp(2, "leg damage from being pulled out of a bear trap",
725 KILLED_BY);
727 break;
730 u.utrap = 0;
731 fill_pit(u.ux, u.uy);
734 u.ux0 = u.ux;
735 u.uy0 = u.uy;
736 if (!Levitation && !MON_AT(x, y) && !u.utrap &&
737 (is_pool(x, y) ||
738 ((t = t_at(x, y)) &&
739 (t->ttyp == PIT || t->ttyp == ANOXIC_PIT || t->ttyp == HYPOXIC_PIT || t->ttyp == ACID_PIT || t->ttyp == SPIKED_PIT || t->ttyp == GIANT_CHASM || t->ttyp == SHIT_PIT || t->ttyp == MANA_PIT || t->ttyp == SHAFT_TRAP || t->ttyp == CURRENT_SHAFT ||
740 t->ttyp == TRAPDOOR || t->ttyp == HOLE)))) {
741 u.ux = x;
742 u.uy = y;
743 } else {
744 u.ux = x - u.dx;
745 u.uy = y - u.dy;
747 vision_full_recalc = 1; /* hero has moved, recalculate vision later */
749 if (Blind) {
750 /* drop glyph under the chain */
751 if (u.bc_felt & BC_CHAIN)
752 memory_object(uchain->ox, uchain->oy) = u.cglyph;
753 u.bc_felt = 0; /* feel nothing */
754 /* pick up new glyph */
755 u.cglyph = (u.bc_order) ? u.bglyph : memory_object(u.ux, u.uy);
757 movobj(uchain,u.ux,u.uy); /* has a newsym */
758 if (Blind) {
759 u.bc_order = bc_order();
761 newsym(u.ux0,u.uy0); /* clean up old position */
762 if (u.ux0 != u.ux || u.uy0 != u.uy) {
763 spoteffects(TRUE);
764 /* This used to give sokoban penalties but you can't actually bypass anything so the penalty is removed --Amy */
765 /* Soviet Russia comment is in apply.c */
767 if (issoviet && In_sokoban(&u.uz)) {
768 change_luck(-1);
769 pline("Teper' vy teryayete ochko udachi KHAR KHAR. Eto deystviye ne pomoglo vam reshit' golovolomki, no my takiye elitnyye.");
770 if (evilfriday) u.ugangr++;
778 STATIC_OVL void
779 litter()
781 struct obj *otmp = invent, *nextobj;
782 int capacity = weight_cap();
784 while (otmp) {
785 nextobj = otmp->nobj;
786 if ((otmp != uball) && (rnd(capacity) <= (int)otmp->owt)) {
787 if (canletgo(otmp, "")) {
788 Your("%s you down the stairs.",
789 aobjnam(otmp, "follow"));
790 dropx(otmp);
793 otmp = nextobj;
797 void
798 drag_down()
800 boolean forward;
801 uchar dragchance = 3;
804 * Assume that the ball falls forward if:
806 * a) the character is wielding it, or
807 * b) the character has both hands available to hold it (i.e. is
808 * not wielding any weapon), or
809 * c) (perhaps) it falls forward out of his non-weapon hand
812 forward = carried(uball) && (uwep == uball || !uwep || !rn2(3));
814 if (carried(uball))
815 You("lose your grip on the iron ball.");
817 if (forward) {
818 if(rn2(6)) {
819 pline_The("iron ball drags you downstairs!");
820 if (PlayerHearsSoundEffects) pline(issoviet ? "Vy s udovol'stviyem yeshche peretashchiv etu duratskuyu myach vmeste?" : "Rlalalalalaaaaar!");
821 losehp(rnd(6), "dragged downstairs by an iron ball",
822 NO_KILLER_PREFIX);
823 litter();
825 } else {
826 if(rn2(2)) {
827 pline_The("iron ball smacks into you!");
828 if (PlayerHearsSoundEffects) pline(issoviet ? "Kha-kha-kha, tip bloka l'da smeyetsya yego zadnitsu smotret' vy imeyete delo s etoy duratskoy myach." : "Tschackschwack!");
829 losehp(rnd(20), "iron ball collision", KILLED_BY_AN);
830 exercise(A_STR, FALSE);
831 dragchance -= 2;
833 if( (int) dragchance >= rnd(6)) {
834 pline_The("iron ball drags you downstairs!");
835 if (PlayerHearsSoundEffects) pline(issoviet ? "Vy s udovol'stviyem yeshche peretashchiv etu duratskuyu myach vmeste?" : "Rlalalalalaaaaar!");
836 losehp(rnd(3), "dragged downstairs by an iron ball",
837 NO_KILLER_PREFIX);
838 exercise(A_STR, FALSE);
839 litter();
844 /*ball.c*/