iron balls (R676)
Well, this proved rather annoying. Problems included: -- the solid rock problem that was noticed -- teleporting to a spot two spaces away but on the other side of solid rock could also leave the chain in solid rock -- in one place I said chainx instead of ballx, which could cause problems with teleporting -- the teleport code moved the player before moving the ball, violating the assumption that the player hasn't been moved yet (which only caused problems after I added the solid rock fix). Ball movement still isn't quite right, though the cases are really rare. I may fix them later.
This commit is contained in:
@@ -17,6 +17,7 @@ wall symbol not replaced when digging while blind and levitating
|
||||
print regular death message when leashed, mounted steed dies of starvation
|
||||
fix more funny messages, new and old
|
||||
restore the behavior of bumping into closed doors when moving while impaired
|
||||
fix iron ball cases that could put the chain in solid rock
|
||||
|
||||
|
||||
Platform- and/or Interface-Specific Fixes
|
||||
|
||||
85
src/ball.c
85
src/ball.c
@@ -343,7 +343,7 @@ xchar ballx, bally, chainx, chainy; /* only matter !before */
|
||||
}
|
||||
}
|
||||
|
||||
/* return TRUE if ball could be dragged
|
||||
/* return TRUE if the caller needs to place the ball and chain down again
|
||||
*
|
||||
* Should not be called while swallowed. Should be called before movement,
|
||||
* because we might want to move the ball or chain to the hero's old position.
|
||||
@@ -371,6 +371,7 @@ boolean *cause_delay;
|
||||
|
||||
/* only need to move the chain? */
|
||||
if (carried(uball) || distmin(x, y, uball->ox, uball->oy) <= 2) {
|
||||
xchar oldchainx = uchain->ox, oldchainy = uchain->oy;
|
||||
*bc_control = BC_CHAIN;
|
||||
move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
|
||||
if (carried(uball)) {
|
||||
@@ -383,11 +384,22 @@ boolean *cause_delay;
|
||||
}
|
||||
#define CHAIN_IN_MIDDLE(chx, chy) \
|
||||
(distmin(x, y, chx, chy) <= 1 && distmin(chx, chy, uball->ox, uball->oy) <= 1)
|
||||
#define IS_CHAIN_ROCK(x,y) \
|
||||
(IS_ROCK(levl[x][y].typ) || (IS_DOOR(levl[x][y].typ) && \
|
||||
(levl[x][y].doormask & (D_CLOSED|D_LOCKED))))
|
||||
/* Don't ever move the chain into solid rock. If we have to, then instead
|
||||
* undo the move_bc() and jump to the drag ball code.
|
||||
*/
|
||||
#define SKIP_TO_DRAG do { *chainx = oldchainx; *chainy = oldchainy; \
|
||||
move_bc(0, *bc_control, *ballx, *bally, *chainx, *chainy); \
|
||||
goto drag; } while(0)
|
||||
switch(dist2(x, y, uball->ox, uball->oy)) {
|
||||
/* two spaces diagonal from ball, move chain inbetween */
|
||||
case 8:
|
||||
*chainx = (uball->ox + x)/2;
|
||||
*chainy = (uball->oy + y)/2;
|
||||
if (IS_CHAIN_ROCK(*chainx, *chainy))
|
||||
SKIP_TO_DRAG;
|
||||
break;
|
||||
|
||||
/* player is distance 2/1 from ball; move chain to one of the
|
||||
@@ -410,7 +422,40 @@ boolean *cause_delay;
|
||||
tempy = y;
|
||||
tempy2 = uball->oy;
|
||||
}
|
||||
if (dist2(tempx, tempy, uchain->ox, uchain->oy) <
|
||||
if (IS_CHAIN_ROCK(tempx, tempy) &&
|
||||
!IS_CHAIN_ROCK(tempx2, tempy2)) {
|
||||
/* Avoid pathological case:
|
||||
* 0 0_
|
||||
* _X move northeast -----> X@
|
||||
* @
|
||||
*/
|
||||
if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 5 &&
|
||||
dist2(x, y, tempx, tempy) == 1)
|
||||
SKIP_TO_DRAG;
|
||||
/* Avoid pathological case:
|
||||
* 0 0
|
||||
* _X move east -----> X_
|
||||
* @ @
|
||||
*/
|
||||
if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 4 &&
|
||||
dist2(x, y, tempx, tempy) == 2)
|
||||
SKIP_TO_DRAG;
|
||||
*chainx = tempx2;
|
||||
*chainy = tempy2;
|
||||
} else if (!IS_CHAIN_ROCK(tempx, tempy) &&
|
||||
IS_CHAIN_ROCK(tempx2, tempy2)) {
|
||||
if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 5 &&
|
||||
dist2(x, y, tempx2, tempy2) == 1)
|
||||
SKIP_TO_DRAG;
|
||||
if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 4 &&
|
||||
dist2(x, y, tempx2, tempy2) == 2)
|
||||
SKIP_TO_DRAG;
|
||||
*chainx = tempx;
|
||||
*chainy = tempy;
|
||||
} else if (IS_CHAIN_ROCK(tempx, tempy) &&
|
||||
IS_CHAIN_ROCK(tempx2, tempy2)) {
|
||||
SKIP_TO_DRAG;
|
||||
} else if (dist2(tempx, tempy, uchain->ox, uchain->oy) <
|
||||
dist2(tempx2, tempy2, uchain->ox, uchain->oy) ||
|
||||
((dist2(tempx, tempy, uchain->ox, uchain->oy) ==
|
||||
dist2(tempx2, tempy2, uchain->ox, uchain->oy)) && rn2(2))) {
|
||||
@@ -428,8 +473,10 @@ boolean *cause_delay;
|
||||
case 4:
|
||||
if (CHAIN_IN_MIDDLE(uchain->ox, uchain->oy))
|
||||
break;
|
||||
*chainx = (x + uchain->ox)/2;
|
||||
*chainy = (y + uchain->oy)/2;
|
||||
*chainx = (x + uball->ox)/2;
|
||||
*chainy = (y + uball->oy)/2;
|
||||
if (IS_CHAIN_ROCK(*chainx, *chainy))
|
||||
SKIP_TO_DRAG;
|
||||
break;
|
||||
|
||||
/* ball is one space diagonal from player. Check for the
|
||||
@@ -447,6 +494,8 @@ boolean *cause_delay;
|
||||
*chainx = uball->ox;
|
||||
else
|
||||
*chainy = uball->oy;
|
||||
if (IS_CHAIN_ROCK(*chainx, *chainy))
|
||||
SKIP_TO_DRAG;
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
@@ -470,11 +519,15 @@ boolean *cause_delay;
|
||||
default: impossible("bad chain movement");
|
||||
break;
|
||||
}
|
||||
#undef SKIP_TO_DRAG
|
||||
#undef IS_CHAIN_ROCK
|
||||
#undef CHAIN_IN_MIDDLE
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (near_capacity() > SLT_ENCUMBER) {
|
||||
drag:
|
||||
|
||||
if (near_capacity() > SLT_ENCUMBER && dist2(x, y, u.ux, u.uy) <= 2) {
|
||||
You("cannot %sdrag the heavy iron ball.",
|
||||
invent ? "carry all that and also " : "");
|
||||
nomul(0);
|
||||
@@ -527,13 +580,25 @@ boolean *cause_delay;
|
||||
}
|
||||
}
|
||||
|
||||
*bc_control = BC_BALL|BC_CHAIN;;
|
||||
*bc_control = BC_BALL|BC_CHAIN;
|
||||
|
||||
move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
|
||||
*ballx = uchain->ox;
|
||||
*bally = uchain->oy;
|
||||
*chainx = u.ux;
|
||||
*chainy = u.uy;
|
||||
if (dist2(x, y, u.ux, u.uy) > 2) {
|
||||
/* Awful case: we're still in range of the ball, so we thought we
|
||||
* could only move the chain, but it turned out that the target
|
||||
* square for the chain was rock, so we had to drag it instead.
|
||||
* But we can't drag it either, because we teleported and are more
|
||||
* than one square from our old position. Revert to the teleport
|
||||
* behavior.
|
||||
*/
|
||||
*ballx = *chainx = x;
|
||||
*bally = *chainy = y;
|
||||
} else {
|
||||
*ballx = uchain->ox;
|
||||
*bally = uchain->oy;
|
||||
*chainx = u.ux;
|
||||
*chainy = u.uy;
|
||||
}
|
||||
*cause_delay = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -246,11 +246,18 @@ register int nux,nuy;
|
||||
xchar ballx, bally, chainx, chainy;
|
||||
boolean cause_delay;
|
||||
|
||||
/* this should only drag the chain (and never give a near-
|
||||
capacity message) since we already checked ball distance */
|
||||
(void) drag_ball(u.ux, u.uy, &bc_control, &ballx, &bally,
|
||||
&chainx, &chainy, &cause_delay);
|
||||
move_bc(0, bc_control, ballx, bally, chainx, chainy);
|
||||
/* We really should only be dragging the chain here, since we
|
||||
* checked the ball distance. However, some pathological
|
||||
* cases will drag the ball anyway. drag_ball() tries to
|
||||
* handle those by ignoring near_capacity() and teleporting the
|
||||
* ball and chain along with you. Bug: if you only teleported
|
||||
* one square, drag_ball() has no way to distinguish between
|
||||
* teleporting and moving, and treats it like a move. (Note
|
||||
* that teleds() doesn't imply teleporting.)
|
||||
*/
|
||||
if (drag_ball(u.ux, u.uy, &bc_control, &ballx, &bally,
|
||||
&chainx, &chainy, &cause_delay))
|
||||
move_bc(0, bc_control, ballx, bally, chainx, chainy);
|
||||
} else
|
||||
placebc();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user