OSDN Git Service

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