OSDN Git Service

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