OSDN Git Service

e3e1196495d7568ef1275db487ea64e3776e1f62
[jnethack/source.git] / src / ball.c
1 /* NetHack 3.6  ball.c  $NHDT-Date: 1557088406 2019/05/05 20:33:26 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.36 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) David Cohrs, 2006. */
4 /* NetHack may be freely redistributed.  See license for details. */
5
6 /* JNetHack Copyright */
7 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000  */
8 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2019            */
9 /* JNetHack may be freely redistributed.  See license for details. */
10
11 /* Ball & Chain
12  * =============================================================*/
13
14 #include "hack.h"
15
16 STATIC_DCL int NDECL(bc_order);
17 STATIC_DCL void NDECL(litter);
18
19 void
20 ballrelease(showmsg)
21 boolean showmsg;
22 {
23     if (carried(uball)) {
24         if (showmsg)
25 /*JP
26             pline("Startled, you drop the iron ball.");
27 */
28             pline("\8bÁ\82¢\82Ä\82 \82È\82½\82Í\93S\8b\85\82ð\97\8e\82µ\82½\81D");
29         if (uwep == uball)
30             setuwep((struct obj *) 0);
31         if (uswapwep == uball)
32             setuswapwep((struct obj *) 0);
33         if (uquiver == uball)
34             setuqwep((struct obj *) 0);
35         /* [this used to test 'if (uwep != uball)' but that always passes
36            after the setuwep() above] */
37         freeinv(uball); /* remove from inventory but don't place on floor */
38         encumber_msg();
39     }
40 }
41
42 /* ball&chain might hit hero when falling through a trap door */
43 void
44 ballfall()
45 {
46     boolean gets_hit;
47
48     gets_hit = (((uball->ox != u.ux) || (uball->oy != u.uy))
49                 && ((uwep == uball) ? FALSE : (boolean) rn2(5)));
50     ballrelease(TRUE);
51     if (gets_hit) {
52         int dmg = rn1(7, 25);
53
54 /*JP
55         pline_The("iron ball falls on your %s.", body_part(HEAD));
56 */
57         pline("\93S\8b\85\82Í\82 \82È\82½\82Ì%s\82Ì\8fã\82É\97\8e\82¿\82½\81D", body_part(HEAD));
58         if (uarmh) {
59             if (is_metallic(uarmh)) {
60 /*JP
61                 pline("Fortunately, you are wearing a hard helmet.");
62 */
63                 pline("\8dK\89^\82É\82à\81C\82 \82È\82½\82Í\8cÅ\82¢\8a\95\82ð\90g\82É\82Â\82¯\82Ä\82¢\82½\81D");
64                 dmg = 3;
65             } else if (flags.verbose)
66 /*JP
67                 pline("%s does not protect you.", Yname2(uarmh));
68 */
69                 Your("%s\82Å\82Í\8eç\82ê\82È\82¢\81D", xname(uarmh));
70         }
71 #if 0 /*JP*/
72         losehp(Maybe_Half_Phys(dmg), "crunched in the head by an iron ball",
73                NO_KILLER_PREFIX);
74 #else
75         losehp(Maybe_Half_Phys(dmg), "\93S\8b\85\82Å\93ª\82ð\91Å\82Á\82Ä", KILLED_BY);
76 #endif
77     }
78 }
79
80 /*
81  *  To make this work, we have to mess with the hero's mind.  The rules for
82  *  ball&chain are:
83  *
84  *      1. If the hero can see them, fine.
85  *      2. If the hero can't see either, it isn't seen.
86  *      3. If either is felt it is seen.
87  *      4. If either is felt and moved, it disappears.
88  *
89  *  If the hero can see, then when a move is done, the ball and chain are
90  *  first picked up, the positions under them are corrected, then they
91  *  are moved after the hero moves.  Not too bad.
92  *
93  *  If the hero is blind, then she can "feel" the ball and/or chain at any
94  *  time.  However, when the hero moves, the felt ball and/or chain become
95  *  unfelt and whatever was felt "under" the ball&chain appears.  Pretty
96  *  nifty, but it requires that the ball&chain "remember" what was under
97  *  them --- i.e. they pick-up glyphs when they are felt and drop them when
98  *  moved (and felt).  When swallowed, the ball&chain are pulled completely
99  *  off of the dungeon, but are still on the object chain.  They are placed
100  *  under the hero when she is expelled.
101  */
102
103 /*
104  * from you.h
105  *      int u.bglyph            glyph under the ball
106  *      int u.cglyph            glyph under the chain
107  *      int u.bc_felt           mask for ball/chain being felt
108  *      #define BC_BALL  0x01   bit mask in u.bc_felt for ball
109  *      #define BC_CHAIN 0x02   bit mask in u.bc_felt for chain
110  *      int u.bc_order          ball & chain order
111  *
112  * u.bc_felt is also manipulated in display.c and read.c, the others only
113  * in this file.  None of these variables are valid unless the player is
114  * Blind.
115  */
116
117 /* values for u.bc_order */
118 #define BCPOS_DIFFER 0 /* ball & chain at different positions */
119 #define BCPOS_CHAIN 1  /* chain on top of ball */
120 #define BCPOS_BALL 2   /* ball on top of chain */
121
122 /*
123  *  Place the ball & chain under the hero.  Make sure that the ball & chain
124  *  variables are set (actually only needed when blind, but what the heck).
125  *  It is assumed that when this is called, the ball and chain are NOT
126  *  attached to the object list.
127  *
128  *  Should not be called while swallowed except on waterlevel.
129  */
130 void
131 placebc()
132 {
133     if (!uchain || !uball) {
134         impossible("Where are your ball and chain?");
135         return;
136     }
137
138     (void) flooreffects(uchain, u.ux, u.uy, ""); /* chain might rust */
139
140     if (carried(uball)) { /* the ball is carried */
141         u.bc_order = BCPOS_DIFFER;
142     } else {
143         /* ball might rust -- already checked when carried */
144         (void) flooreffects(uball, u.ux, u.uy, "");
145         place_object(uball, u.ux, u.uy);
146         u.bc_order = BCPOS_CHAIN;
147     }
148
149     place_object(uchain, u.ux, u.uy);
150
151     u.bglyph = u.cglyph = levl[u.ux][u.uy].glyph; /* pick up glyph */
152
153     newsym(u.ux, u.uy);
154 }
155
156 void
157 unplacebc()
158 {
159     if (u.uswallow) {
160         if (Is_waterlevel(&u.uz)) {
161             /* we need to proceed with the removal from the floor
162              * so that movebubbles() processing will disregard it as
163              * intended. Ignore all the vision stuff.
164              */
165             if (!carried(uball))
166                 obj_extract_self(uball);
167             obj_extract_self(uchain);
168         }
169         /* ball&chain not unplaced while swallowed */
170         return;
171     }
172
173     if (!carried(uball)) {
174         obj_extract_self(uball);
175         if (Blind && (u.bc_felt & BC_BALL)) /* drop glyph */
176             levl[uball->ox][uball->oy].glyph = u.bglyph;
177
178         newsym(uball->ox, uball->oy);
179     }
180     obj_extract_self(uchain);
181     if (Blind && (u.bc_felt & BC_CHAIN)) /* drop glyph */
182         levl[uchain->ox][uchain->oy].glyph = u.cglyph;
183
184     newsym(uchain->ox, uchain->oy);
185     u.bc_felt = 0; /* feel nothing */
186 }
187
188 /*
189  *  Return the stacking of the hero's ball & chain.  This assumes that the
190  *  hero is being punished.
191  */
192 STATIC_OVL int
193 bc_order()
194 {
195     struct obj *obj;
196
197     if (uchain->ox != uball->ox || uchain->oy != uball->oy || carried(uball)
198         || u.uswallow)
199         return BCPOS_DIFFER;
200
201     for (obj = level.objects[uball->ox][uball->oy]; obj;
202          obj = obj->nexthere) {
203         if (obj == uchain)
204             return BCPOS_CHAIN;
205         if (obj == uball)
206             return BCPOS_BALL;
207     }
208     impossible("bc_order:  ball&chain not in same location!");
209     return BCPOS_DIFFER;
210 }
211
212 /*
213  *  set_bc()
214  *
215  *  The hero is either about to go blind or already blind and just punished.
216  *  Set up the ball and chain variables so that the ball and chain are "felt".
217  */
218 void
219 set_bc(already_blind)
220 int already_blind;
221 {
222     int ball_on_floor = !carried(uball);
223
224     u.bc_order = bc_order(); /* get the order */
225     u.bc_felt = ball_on_floor ? BC_BALL | BC_CHAIN : BC_CHAIN; /* felt */
226
227     if (already_blind || u.uswallow) {
228         u.cglyph = u.bglyph = levl[u.ux][u.uy].glyph;
229         return;
230     }
231
232     /*
233      *  Since we can still see, remove the ball&chain and get the glyph that
234      *  would be beneath them.  Then put the ball&chain back.  This is pretty
235      *  disgusting, but it will work.
236      */
237     remove_object(uchain);
238     if (ball_on_floor)
239         remove_object(uball);
240
241     newsym(uchain->ox, uchain->oy);
242     u.cglyph = levl[uchain->ox][uchain->oy].glyph;
243
244     if (u.bc_order == BCPOS_DIFFER) { /* different locations */
245         place_object(uchain, uchain->ox, uchain->oy);
246         newsym(uchain->ox, uchain->oy);
247         if (ball_on_floor) {
248             newsym(uball->ox, uball->oy); /* see under ball */
249             u.bglyph = levl[uball->ox][uball->oy].glyph;
250             place_object(uball, uball->ox, uball->oy);
251             newsym(uball->ox, uball->oy); /* restore ball */
252         }
253     } else {
254         u.bglyph = u.cglyph;
255         if (u.bc_order == BCPOS_CHAIN) {
256             place_object(uball, uball->ox, uball->oy);
257             place_object(uchain, uchain->ox, uchain->oy);
258         } else {
259             place_object(uchain, uchain->ox, uchain->oy);
260             place_object(uball, uball->ox, uball->oy);
261         }
262         newsym(uball->ox, uball->oy);
263     }
264 }
265
266 /*
267  *  move_bc()
268  *
269  *  Move the ball and chain.  This is called twice for every move.  The first
270  *  time to pick up the ball and chain before the move, the second time to
271  *  place the ball and chain after the move.  If the ball is carried, this
272  *  function should never have BC_BALL as part of its control.
273  *
274  *  Should not be called while swallowed.
275  */
276 void
277 move_bc(before, control, ballx, bally, chainx, chainy)
278 int before, control;
279 xchar ballx, bally, chainx, chainy; /* only matter !before */
280 {
281     if (Blind) {
282         /*
283          *  The hero is blind.  Time to work hard.  The ball and chain that
284          *  are attached to the hero are very special.  The hero knows that
285          *  they are attached, so when they move, the hero knows that they
286          *  aren't at the last position remembered.  This is complicated
287          *  by the fact that the hero can "feel" the surrounding locations
288          *  at any time, hence, making one or both of them show up again.
289          *  So, we have to keep track of which is felt at any one time and
290          *  act accordingly.
291          */
292         if (!before) {
293             if ((control & BC_CHAIN) && (control & BC_BALL)) {
294                 /*
295                  *  Both ball and chain moved.  If felt, drop glyph.
296                  */
297                 if (u.bc_felt & BC_BALL)
298                     levl[uball->ox][uball->oy].glyph = u.bglyph;
299                 if (u.bc_felt & BC_CHAIN)
300                     levl[uchain->ox][uchain->oy].glyph = u.cglyph;
301                 u.bc_felt = 0;
302
303                 /* Pick up glyph at new location. */
304                 u.bglyph = levl[ballx][bally].glyph;
305                 u.cglyph = levl[chainx][chainy].glyph;
306
307                 movobj(uball, ballx, bally);
308                 movobj(uchain, chainx, chainy);
309             } else if (control & BC_BALL) {
310                 if (u.bc_felt & BC_BALL) {
311                     if (u.bc_order == BCPOS_DIFFER) { /* ball by itself */
312                         levl[uball->ox][uball->oy].glyph = u.bglyph;
313                     } else if (u.bc_order == BCPOS_BALL) {
314                         if (u.bc_felt & BC_CHAIN) { /* know chain is there */
315                             map_object(uchain, 0);
316                         } else {
317                             levl[uball->ox][uball->oy].glyph = u.bglyph;
318                         }
319                     }
320                     u.bc_felt &= ~BC_BALL; /* no longer feel the ball */
321                 }
322
323                 /* Pick up glyph at new position. */
324                 u.bglyph = (ballx != chainx || bally != chainy)
325                                ? levl[ballx][bally].glyph
326                                : u.cglyph;
327
328                 movobj(uball, ballx, bally);
329             } else if (control & BC_CHAIN) {
330                 if (u.bc_felt & BC_CHAIN) {
331                     if (u.bc_order == BCPOS_DIFFER) {
332                         levl[uchain->ox][uchain->oy].glyph = u.cglyph;
333                     } else if (u.bc_order == BCPOS_CHAIN) {
334                         if (u.bc_felt & BC_BALL) {
335                             map_object(uball, 0);
336                         } else {
337                             levl[uchain->ox][uchain->oy].glyph = u.cglyph;
338                         }
339                     }
340                     u.bc_felt &= ~BC_CHAIN;
341                 }
342                 /* Pick up glyph at new position. */
343                 u.cglyph = (ballx != chainx || bally != chainy)
344                                ? levl[chainx][chainy].glyph
345                                : u.bglyph;
346
347                 movobj(uchain, chainx, chainy);
348             }
349
350             u.bc_order = bc_order(); /* reset the order */
351         }
352
353     } else {
354         /*
355          *  The hero is not blind.  To make this work correctly, we need to
356          *  pick up the ball and chain before the hero moves, then put them
357          *  in their new positions after the hero moves.
358          */
359         if (before) {
360             if (!control) {
361                 /*
362                  * Neither ball nor chain is moving, so remember which was
363                  * on top until !before.  Use the variable u.bc_order
364                  * since it is only valid when blind.
365                  */
366                 u.bc_order = bc_order();
367             }
368
369             remove_object(uchain);
370             newsym(uchain->ox, uchain->oy);
371             if (!carried(uball)) {
372                 remove_object(uball);
373                 newsym(uball->ox, uball->oy);
374             }
375         } else {
376             int on_floor = !carried(uball);
377
378             if ((control & BC_CHAIN)
379                 || (!control && u.bc_order == BCPOS_CHAIN)) {
380                 /* If the chain moved or nothing moved & chain on top. */
381                 if (on_floor)
382                     place_object(uball, ballx, bally);
383                 place_object(uchain, chainx, chainy); /* chain on top */
384             } else {
385                 place_object(uchain, chainx, chainy);
386                 if (on_floor)
387                     place_object(uball, ballx, bally);
388                 /* ball on top */
389             }
390             newsym(chainx, chainy);
391             if (on_floor)
392                 newsym(ballx, bally);
393         }
394     }
395 }
396
397 /* return TRUE if the caller needs to place the ball and chain down again
398  *
399  *  Should not be called while swallowed.  Should be called before movement,
400  *  because we might want to move the ball or chain to the hero's old
401  * position.
402  *
403  * It is called if we are moving.  It is also called if we are teleporting
404  * *if* the ball doesn't move and we thus must drag the chain.  It is not
405  * called for ordinary teleportation.
406  *
407  * allow_drag is only used in the ugly special case where teleporting must
408  * drag the chain, while an identical-looking movement must drag both the ball
409  * and chain.
410  */
411 boolean
412 drag_ball(x, y, bc_control, ballx, bally, chainx, chainy, cause_delay,
413           allow_drag)
414 xchar x, y;
415 int *bc_control;
416 xchar *ballx, *bally, *chainx, *chainy;
417 boolean *cause_delay;
418 boolean allow_drag;
419 {
420     struct trap *t = (struct trap *) 0;
421     boolean already_in_rock;
422
423     *ballx = uball->ox;
424     *bally = uball->oy;
425     *chainx = uchain->ox;
426     *chainy = uchain->oy;
427     *bc_control = 0;
428     *cause_delay = FALSE;
429
430     if (dist2(x, y, uchain->ox, uchain->oy) <= 2) { /* nothing moved */
431         move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
432         return TRUE;
433     }
434
435     /* only need to move the chain? */
436     if (carried(uball) || distmin(x, y, uball->ox, uball->oy) <= 2) {
437         xchar oldchainx = uchain->ox, oldchainy = uchain->oy;
438
439         *bc_control = BC_CHAIN;
440         move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
441         if (carried(uball)) {
442             /* move chain only if necessary */
443             if (distmin(x, y, uchain->ox, uchain->oy) > 1) {
444                 *chainx = u.ux;
445                 *chainy = u.uy;
446             }
447             return TRUE;
448         }
449 #define CHAIN_IN_MIDDLE(chx, chy) \
450     (distmin(x, y, chx, chy) <= 1 \
451      && distmin(chx, chy, uball->ox, uball->oy) <= 1)
452 #define IS_CHAIN_ROCK(x, y)      \
453     (IS_ROCK(levl[x][y].typ)     \
454      || (IS_DOOR(levl[x][y].typ) \
455          && (levl[x][y].doormask & (D_CLOSED | D_LOCKED))))
456 /* Don't ever move the chain into solid rock.  If we have to, then instead
457  * undo the move_bc() and jump to the drag ball code.  Note that this also
458  * means the "cannot carry and drag" message will not appear, since unless we
459  * moved at least two squares there is no possibility of the chain position
460  * being in solid rock.
461  */
462 #define SKIP_TO_DRAG                                               \
463     {                                                              \
464         *chainx = oldchainx;                                       \
465         *chainy = oldchainy;                                       \
466         move_bc(0, *bc_control, *ballx, *bally, *chainx, *chainy); \
467         goto drag;                                                 \
468     }
469         if (IS_CHAIN_ROCK(u.ux, u.uy) || IS_CHAIN_ROCK(*chainx, *chainy)
470             || IS_CHAIN_ROCK(uball->ox, uball->oy))
471             already_in_rock = TRUE;
472         else
473             already_in_rock = FALSE;
474
475         switch (dist2(x, y, uball->ox, uball->oy)) {
476         /* two spaces diagonal from ball, move chain inbetween */
477         case 8:
478             *chainx = (uball->ox + x) / 2;
479             *chainy = (uball->oy + y) / 2;
480             if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock)
481                 SKIP_TO_DRAG;
482             break;
483
484         /* player is distance 2/1 from ball; move chain to one of the
485          * two spaces between
486          *   @
487          *   __
488          *    0
489          */
490         case 5: {
491             xchar tempx, tempy, tempx2, tempy2;
492
493             /* find position closest to current position of chain */
494             /* no effect if current position is already OK */
495             if (abs(x - uball->ox) == 1) {
496                 tempx = x;
497                 tempx2 = uball->ox;
498                 tempy = tempy2 = (uball->oy + y) / 2;
499             } else {
500                 tempx = tempx2 = (uball->ox + x) / 2;
501                 tempy = y;
502                 tempy2 = uball->oy;
503             }
504             if (IS_CHAIN_ROCK(tempx, tempy) && !IS_CHAIN_ROCK(tempx2, tempy2)
505                 && !already_in_rock) {
506                 if (allow_drag) {
507                     /* Avoid pathological case *if* not teleporting:
508                      *   0                          0_
509                      *   _X  move northeast  ----->  X@
510                      *    @
511                      */
512                     if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 5
513                         && dist2(x, y, tempx, tempy) == 1)
514                         SKIP_TO_DRAG;
515                     /* Avoid pathological case *if* not teleporting:
516                      *    0                          0
517                      *   _X  move east       ----->  X_
518                      *    @                           @
519                      */
520                     if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 4
521                         && dist2(x, y, tempx, tempy) == 2)
522                         SKIP_TO_DRAG;
523                 }
524                 *chainx = tempx2;
525                 *chainy = tempy2;
526             } else if (!IS_CHAIN_ROCK(tempx, tempy)
527                        && IS_CHAIN_ROCK(tempx2, tempy2) && !already_in_rock) {
528                 if (allow_drag) {
529                     if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 5
530                         && dist2(x, y, tempx2, tempy2) == 1)
531                         SKIP_TO_DRAG;
532                     if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 4
533                         && dist2(x, y, tempx2, tempy2) == 2)
534                         SKIP_TO_DRAG;
535                 }
536                 *chainx = tempx;
537                 *chainy = tempy;
538             } else if (IS_CHAIN_ROCK(tempx, tempy)
539                        && IS_CHAIN_ROCK(tempx2, tempy2) && !already_in_rock) {
540                 SKIP_TO_DRAG;
541             } else if (dist2(tempx, tempy, uchain->ox, uchain->oy)
542                            < dist2(tempx2, tempy2, uchain->ox, uchain->oy)
543                        || ((dist2(tempx, tempy, uchain->ox, uchain->oy)
544                             == dist2(tempx2, tempy2, uchain->ox, uchain->oy))
545                            && rn2(2))) {
546                 *chainx = tempx;
547                 *chainy = tempy;
548             } else {
549                 *chainx = tempx2;
550                 *chainy = tempy2;
551             }
552             break;
553         }
554
555         /* ball is two spaces horizontal or vertical from player; move*/
556         /* chain inbetween *unless* current chain position is OK */
557         case 4:
558             if (CHAIN_IN_MIDDLE(uchain->ox, uchain->oy))
559                 break;
560             *chainx = (x + uball->ox) / 2;
561             *chainy = (y + uball->oy) / 2;
562             if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock)
563                 SKIP_TO_DRAG;
564             break;
565
566         /* ball is one space diagonal from player.  Check for the
567          * following special case:
568          *   @
569          *    _    moving southwest becomes  @_
570          *   0                                0
571          * (This will also catch teleporting that happens to resemble
572          * this case, but oh well.)  Otherwise fall through.
573          */
574         case 2:
575             if (dist2(x, y, uball->ox, uball->oy) == 2
576                 && dist2(x, y, uchain->ox, uchain->oy) == 4) {
577                 if (uchain->oy == y)
578                     *chainx = uball->ox;
579                 else
580                     *chainy = uball->oy;
581                 if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock)
582                     SKIP_TO_DRAG;
583                 break;
584             }
585         /* fall through */
586         case 1:
587         case 0:
588             /* do nothing if possible */
589             if (CHAIN_IN_MIDDLE(uchain->ox, uchain->oy))
590                 break;
591             /* otherwise try to drag chain to player's old position */
592             if (CHAIN_IN_MIDDLE(u.ux, u.uy)) {
593                 *chainx = u.ux;
594                 *chainy = u.uy;
595                 break;
596             }
597             /* otherwise use player's new position (they must have
598                teleported, for this to happen) */
599             *chainx = x;
600             *chainy = y;
601             break;
602
603         default:
604             impossible("bad chain movement");
605             break;
606         }
607 #undef SKIP_TO_DRAG
608 #undef CHAIN_IN_MIDDLE
609         return TRUE;
610     }
611
612  drag:
613
614     if (near_capacity() > SLT_ENCUMBER && dist2(x, y, u.ux, u.uy) <= 2) {
615 #if 0 /*JP*/
616         You("cannot %sdrag the heavy iron ball.",
617             invent ? "carry all that and also " : "");
618 #else
619         You("%s\8fd\82¢\93S\8b\85\82ð\82Ð\82«\82¸\82é\82±\82Æ\82ª\82Å\82«\82È\82¢\81D",
620             invent ? "\82»\82ê\82¾\82¯\82Ì\89×\95¨\82ð\8e\9d\82Á\82½\82Ü\82Ü" : "");
621 #endif
622         nomul(0);
623         return FALSE;
624     }
625
626     if ((is_pool(uchain->ox, uchain->oy)
627          /* water not mere continuation of previous water */
628          && (levl[uchain->ox][uchain->oy].typ == POOL
629              || !is_pool(uball->ox, uball->oy)
630              || levl[uball->ox][uball->oy].typ == POOL))
631         || ((t = t_at(uchain->ox, uchain->oy))
632             && (is_pit(t->ttyp) || is_hole(t->ttyp)))) {
633         if (Levitation) {
634 /*JP
635             You_feel("a tug from the iron ball.");
636 */
637             You("\93S\8b\85\82É\88ø\82Á\82Ï\82ç\82ê\82½\81D");
638             if (t)
639                 t->tseen = 1;
640         } else {
641             struct monst *victim;
642
643 /*JP
644             You("are jerked back by the iron ball!");
645 */
646             You("\93S\8b\85\82É\82®\82¢\82Æ\88ø\82Á\82Ï\82ç\82ê\82½\81I");
647             if ((victim = m_at(uchain->ox, uchain->oy)) != 0) {
648                 int tmp;
649                 int dieroll = rnd(20);
650
651                 tmp = -2 + Luck + find_mac(victim);
652                 tmp += omon_adj(victim, uball, TRUE);
653
654                 if (tmp >= dieroll)
655                     (void) hmon(victim, uball, HMON_DRAGGED, dieroll);
656                 else
657                     miss(xname(uball), victim);
658
659             } /* now check again in case mon died */
660             if (!m_at(uchain->ox, uchain->oy)) {
661                 u.ux = uchain->ox;
662                 u.uy = uchain->oy;
663                 newsym(u.ux0, u.uy0);
664             }
665             nomul(0);
666
667             *bc_control = BC_BALL;
668             move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
669             *ballx = uchain->ox;
670             *bally = uchain->oy;
671             move_bc(0, *bc_control, *ballx, *bally, *chainx, *chainy);
672             spoteffects(TRUE);
673             return FALSE;
674         }
675     }
676
677     *bc_control = BC_BALL | BC_CHAIN;
678
679     move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
680     if (dist2(x, y, u.ux, u.uy) > 2) {
681         /* Awful case: we're still in range of the ball, so we thought we
682          * could only move the chain, but it turned out that the target
683          * square for the chain was rock, so we had to drag it instead.
684          * But we can't drag it either, because we teleported and are more
685          * than one square from our old position.  Revert to the teleport
686          * behavior.
687          */
688         *ballx = *chainx = x;
689         *bally = *chainy = y;
690     } else {
691         xchar newchainx = u.ux, newchainy = u.uy;
692
693         /*
694          * Generally, chain moves to hero's previous location and ball
695          * moves to chain's previous location, except that we try to
696          * keep the chain directly between the hero and the ball.  But,
697          * take the simple approach if the hero's previous location or
698          * the potential between location is inaccessible.
699          */
700         if (dist2(x, y, uchain->ox, uchain->oy) == 4
701             && !IS_CHAIN_ROCK(newchainx, newchainy)) {
702             newchainx = (x + uchain->ox) / 2;
703             newchainy = (y + uchain->oy) / 2;
704             if (IS_CHAIN_ROCK(newchainx, newchainy)) {
705                 /* don't let chain move to inaccessible location */
706                 newchainx = u.ux;
707                 newchainy = u.uy;
708             }
709         }
710
711         *ballx = uchain->ox;
712         *bally = uchain->oy;
713         *chainx = newchainx;
714         *chainy = newchainy;
715     }
716 #undef IS_CHAIN_ROCK
717     *cause_delay = TRUE;
718     return TRUE;
719 }
720
721 /*
722  *  drop_ball()
723  *
724  *  The punished hero drops or throws her iron ball.  If the hero is
725  *  blind, we must reset the order and glyph.  Check for side effects.
726  *  This routine expects the ball to be already placed.
727  *
728  *  Should not be called while swallowed.
729  */
730 void
731 drop_ball(x, y)
732 xchar x, y;
733 {
734     if (Blind) {
735         /* get the order */
736         u.bc_order = bc_order();
737         /* pick up glyph */
738         u.bglyph = (u.bc_order) ? u.cglyph : levl[x][y].glyph;
739     }
740
741     if (x != u.ux || y != u.uy) {
742 /*JP
743         static const char *pullmsg = "The ball pulls you out of the %s!";
744 */
745         static const char *pullmsg = "\93S\8b\85\82Í%s\82©\82ç\82 \82È\82½\82ð\88ø\82Á\82Ï\82è\8fo\82µ\82½\81I";
746         struct trap *t;
747         long side;
748
749         if (u.utrap
750             && u.utraptype != TT_INFLOOR && u.utraptype != TT_BURIEDBALL) {
751             switch (u.utraptype) {
752             case TT_PIT:
753 /*JP
754                 pline(pullmsg, "pit");
755 */
756                 pline(pullmsg, "\97\8e\82µ\8c\8a");
757                 break;
758             case TT_WEB:
759 /*JP
760                 pline(pullmsg, "web");
761 */
762                 pline(pullmsg, "\82­\82à\82Ì\91\83");
763 /*JP
764                 pline_The("web is destroyed!");
765 */
766                 pline("\82­\82à\82Ì\91\83\82Í\82±\82í\82ê\82½\81I");
767                 deltrap(t_at(u.ux, u.uy));
768                 break;
769             case TT_LAVA:
770 /*JP
771                 pline(pullmsg, hliquid("lava"));
772 */
773                 pline(pullmsg, hliquid("\97n\8aâ"));
774                 break;
775             case TT_BEARTRAP:
776                 side = rn2(3) ? LEFT_SIDE : RIGHT_SIDE;
777 /*JP
778                 pline(pullmsg, "bear trap");
779 */
780                 pline(pullmsg, "\8cF\82Ìã©");
781                 set_wounded_legs(side, rn1(1000, 500));
782                 if (!u.usteed) {
783 #if 0 /*JP*/
784                     Your("%s %s is severely damaged.",
785                          (side == LEFT_SIDE) ? "left" : "right",
786                          body_part(LEG));
787 #else
788                     Your("%s%s\82Í\82Ð\82Ç\82¢\8f\9d\82ð\95\89\82Á\82½\81D",
789                          (side == LEFT_SIDE) ? "\8d¶" : "\89E",
790                          body_part(LEG));
791 #endif
792 #if 0 /*JP*/
793                     losehp(Maybe_Half_Phys(2),
794                            "leg damage from being pulled out of a bear trap",
795                            KILLED_BY);
796 #else
797                     losehp(Maybe_Half_Phys(2),
798                            "\8cF\82Ìã©\82©\82ç\94²\82¯\82æ\82¤\82Æ\91«\82ð\88ø\82Á\82Ï\82Á\82Ä",
799                            KILLED_BY);
800 #endif
801                 }
802                 break;
803             }
804             reset_utrap(TRUE);
805             fill_pit(u.ux, u.uy);
806         }
807
808         u.ux0 = u.ux;
809         u.uy0 = u.uy;
810         if (!Levitation && !MON_AT(x, y) && !u.utrap
811             && (is_pool(x, y)
812                 || ((t = t_at(x, y))
813                     && (is_pit(t->ttyp)
814                         || is_hole(t->ttyp))))) {
815             u.ux = x;
816             u.uy = y;
817         } else {
818             u.ux = x - u.dx;
819             u.uy = y - u.dy;
820         }
821         vision_full_recalc = 1; /* hero has moved, recalculate vision later */
822
823         if (Blind) {
824             /* drop glyph under the chain */
825             if (u.bc_felt & BC_CHAIN)
826                 levl[uchain->ox][uchain->oy].glyph = u.cglyph;
827             u.bc_felt = 0; /* feel nothing */
828             /* pick up new glyph */
829             u.cglyph = (u.bc_order) ? u.bglyph : levl[u.ux][u.uy].glyph;
830         }
831         movobj(uchain, u.ux, u.uy); /* has a newsym */
832         if (Blind) {
833             u.bc_order = bc_order();
834         }
835         newsym(u.ux0, u.uy0); /* clean up old position */
836         if (u.ux0 != u.ux || u.uy0 != u.uy) {
837             spoteffects(TRUE);
838             sokoban_guilt();
839         }
840     }
841 }
842
843 /* ball&chain cause hero to randomly lose stuff from inventory */
844 STATIC_OVL void
845 litter()
846 {
847     struct obj *otmp, *nextobj = 0;
848     int capacity = weight_cap();
849
850     for (otmp = invent; otmp; otmp = nextobj) {
851         nextobj = otmp->nobj;
852         if ((otmp != uball) && (rnd(capacity) <= (int) otmp->owt)) {
853             if (canletgo(otmp, "")) {
854 #if 0 /*JP*/
855                 You("drop %s and %s %s down the stairs with you.",
856                     yname(otmp), (otmp->quan == 1L) ? "it" : "they",
857                     otense(otmp, "fall"));
858 #else
859                 You("%s\82ð\97\8e\82Æ\82µ\81C\82»\82ê\82Í\82 \82È\82½\82Æ\88ê\8f\8f\82É\8aK\92i\82ð\97\8e\82¿\82Ä\82¢\82Á\82½\81D",
860                     yname(otmp));
861 #endif
862                 dropx(otmp);
863                 encumber_msg(); /* drop[xyz]() probably ought to to this... */
864             }
865         }
866     }
867 }
868
869 void
870 drag_down()
871 {
872     boolean forward;
873     uchar dragchance = 3;
874
875     /*
876      *  Assume that the ball falls forward if:
877      *
878      *  a) the character is wielding it, or
879      *  b) the character has both hands available to hold it (i.e. is
880      *     not wielding any weapon), or
881      *  c) (perhaps) it falls forward out of his non-weapon hand
882      */
883     forward = carried(uball) && (uwep == uball || !uwep || !rn2(3));
884
885     if (carried(uball))
886 /*JP
887         You("lose your grip on the iron ball.");
888 */
889         You("\93S\8b\85\82ð\8eè\82©\82ç\97\8e\82µ\82Ä\82µ\82Ü\82Á\82½\81D");
890
891     cls();  /* previous level is still displayed although you
892                went down the stairs. Avoids bug C343-20 */
893
894     if (forward) {
895         if (rn2(6)) {
896 /*JP
897             pline_The("iron ball drags you downstairs!");
898 */
899             You("\93S\8b\85\82É\82æ\82Á\82Ä\8aK\92i\82ð\82±\82ë\82ª\82è\97\8e\82¿\82½\81I");
900             losehp(Maybe_Half_Phys(rnd(6)),
901 /*JP
902                    "dragged downstairs by an iron ball", NO_KILLER_PREFIX);
903 */
904                    "\93S\8b\85\82É\82æ\82è\8aK\92i\82ð\82±\82ë\82ª\82è\97\8e\82¿\82Ä", KILLED_BY);
905             litter();
906         }
907     } else {
908         if (rn2(2)) {
909 /*JP
910             pline_The("iron ball smacks into you!");
911 */
912             pline("\93S\8b\85\82Í\82 \82È\82½\82É\83S\83c\83\93\82Æ\82Ô\82Â\82©\82Á\82½\81I");
913 /*JP
914             losehp(Maybe_Half_Phys(rnd(20)), "iron ball collision",
915 */
916             losehp(Maybe_Half_Phys(rnd(20)), "\93S\8b\85\82Ì\8fÕ\93Ë\82Å",
917                    KILLED_BY_AN);
918             exercise(A_STR, FALSE);
919             dragchance -= 2;
920         }
921         if ((int) dragchance >= rnd(6)) {
922 /*JP
923             pline_The("iron ball drags you downstairs!");
924 */
925             You("\93S\8b\85\82É\82æ\82Á\82Ä\8aK\92i\82ð\82±\82ë\82ª\82è\97\8e\82¿\82½\81I");
926             losehp(Maybe_Half_Phys(rnd(3)),
927 /*JP
928                    "dragged downstairs by an iron ball", NO_KILLER_PREFIX);
929 */
930                    "\93S\8b\85\82É\82æ\82è\8aK\92i\82ð\82±\82ë\82ª\82è\97\8e\82¿\82Ä", KILLED_BY);
931             exercise(A_STR, FALSE);
932             litter();
933         }
934     }
935 }
936
937 void
938 bc_sanity_check()
939 {
940     int otyp;
941     unsigned save_nameknown;
942     const char *onam;
943
944     if (Punished && (!uball || !uchain)) {
945         impossible("Punished without %s%s%s?",
946                    !uball ? "iron ball" : "",
947                    (!uball && !uchain) ? " and " : "",
948                    !uchain ? "attached chain" : "");
949     } else if (!Punished && (uball || uchain)) {
950         impossible("Attached %s%s%s without being Punished?",
951                    uchain ? "chain" : "",
952                    (uchain && uball) ? " and " : "",
953                    uball ? "iron ball" : "");
954     }
955     /* ball is free when swallowed, changing levels, other times? */
956     if (uball && (uball->otyp != HEAVY_IRON_BALL
957                   || (uball->where != OBJ_FLOOR
958                       && uball->where != OBJ_INVENT
959                       && uball->where != OBJ_FREE)
960                   || (uball->owornmask & W_BALL) == 0L
961                   || (uball->owornmask & ~(W_BALL | W_WEAPON)) != 0L)) {
962         otyp = uball->otyp;
963         if (otyp < STRANGE_OBJECT || otyp >= NUM_OBJECTS
964             || !OBJ_NAME(objects[otyp])) {
965             onam = "glorkum";
966         } else {
967             save_nameknown = objects[otyp].oc_name_known;
968             objects[otyp].oc_name_known = 1;
969             onam = simple_typename(otyp);
970             objects[otyp].oc_name_known = save_nameknown;
971         }
972         impossible("uball: type %d (%s), where %d, wornmask=0x%08lx",
973                    otyp, onam, uball->where, uball->owornmask);
974     }
975     /* similar check to ball except can't be in inventory */
976     if (uchain && (uchain->otyp != IRON_CHAIN
977                    || (uchain->where != OBJ_FLOOR
978                        && uchain->where != OBJ_FREE)
979                    /* [could simplify this to owornmask != W_CHAIN] */
980                    || (uchain->owornmask & W_CHAIN) == 0L
981                    || (uchain->owornmask & ~W_CHAIN) != 0L)) {
982         otyp = uchain->otyp;
983         if (otyp < STRANGE_OBJECT || otyp >= NUM_OBJECTS
984             || !OBJ_NAME(objects[otyp])) {
985             onam = "glorkum";
986         } else {
987             save_nameknown = objects[otyp].oc_name_known;
988             objects[otyp].oc_name_known = 1;
989             onam = simple_typename(otyp);
990             objects[otyp].oc_name_known = save_nameknown;
991         }
992         impossible("uchain: type %d (%s), where %d, wornmask=0x%08lx",
993                    otyp, onam, uchain->where, uchain->owornmask);
994     }
995     /* [check bc_order too?] */
996 }
997
998 /*ball.c*/