OSDN Git Service

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