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
|
print regular death message when leashed, mounted steed dies of starvation
|
||||||
fix more funny messages, new and old
|
fix more funny messages, new and old
|
||||||
restore the behavior of bumping into closed doors when moving while impaired
|
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
|
Platform- and/or Interface-Specific Fixes
|
||||||
|
|||||||
+75
-10
@@ -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,
|
* 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.
|
* 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? */
|
/* only need to move the chain? */
|
||||||
if (carried(uball) || distmin(x, y, uball->ox, uball->oy) <= 2) {
|
if (carried(uball) || distmin(x, y, uball->ox, uball->oy) <= 2) {
|
||||||
|
xchar oldchainx = uchain->ox, oldchainy = uchain->oy;
|
||||||
*bc_control = BC_CHAIN;
|
*bc_control = BC_CHAIN;
|
||||||
move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
|
move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
|
||||||
if (carried(uball)) {
|
if (carried(uball)) {
|
||||||
@@ -383,11 +384,22 @@ boolean *cause_delay;
|
|||||||
}
|
}
|
||||||
#define CHAIN_IN_MIDDLE(chx, chy) \
|
#define CHAIN_IN_MIDDLE(chx, chy) \
|
||||||
(distmin(x, y, chx, chy) <= 1 && distmin(chx, chy, uball->ox, uball->oy) <= 1)
|
(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)) {
|
switch(dist2(x, y, uball->ox, uball->oy)) {
|
||||||
/* two spaces diagonal from ball, move chain inbetween */
|
/* two spaces diagonal from ball, move chain inbetween */
|
||||||
case 8:
|
case 8:
|
||||||
*chainx = (uball->ox + x)/2;
|
*chainx = (uball->ox + x)/2;
|
||||||
*chainy = (uball->oy + y)/2;
|
*chainy = (uball->oy + y)/2;
|
||||||
|
if (IS_CHAIN_ROCK(*chainx, *chainy))
|
||||||
|
SKIP_TO_DRAG;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* player is distance 2/1 from ball; move chain to one of the
|
/* player is distance 2/1 from ball; move chain to one of the
|
||||||
@@ -410,7 +422,40 @@ boolean *cause_delay;
|
|||||||
tempy = y;
|
tempy = y;
|
||||||
tempy2 = uball->oy;
|
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(tempx2, tempy2, uchain->ox, uchain->oy) ||
|
||||||
((dist2(tempx, tempy, uchain->ox, uchain->oy) ==
|
((dist2(tempx, tempy, uchain->ox, uchain->oy) ==
|
||||||
dist2(tempx2, tempy2, uchain->ox, uchain->oy)) && rn2(2))) {
|
dist2(tempx2, tempy2, uchain->ox, uchain->oy)) && rn2(2))) {
|
||||||
@@ -428,8 +473,10 @@ boolean *cause_delay;
|
|||||||
case 4:
|
case 4:
|
||||||
if (CHAIN_IN_MIDDLE(uchain->ox, uchain->oy))
|
if (CHAIN_IN_MIDDLE(uchain->ox, uchain->oy))
|
||||||
break;
|
break;
|
||||||
*chainx = (x + uchain->ox)/2;
|
*chainx = (x + uball->ox)/2;
|
||||||
*chainy = (y + uchain->oy)/2;
|
*chainy = (y + uball->oy)/2;
|
||||||
|
if (IS_CHAIN_ROCK(*chainx, *chainy))
|
||||||
|
SKIP_TO_DRAG;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ball is one space diagonal from player. Check for the
|
/* ball is one space diagonal from player. Check for the
|
||||||
@@ -447,6 +494,8 @@ boolean *cause_delay;
|
|||||||
*chainx = uball->ox;
|
*chainx = uball->ox;
|
||||||
else
|
else
|
||||||
*chainy = uball->oy;
|
*chainy = uball->oy;
|
||||||
|
if (IS_CHAIN_ROCK(*chainx, *chainy))
|
||||||
|
SKIP_TO_DRAG;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* fall through */
|
/* fall through */
|
||||||
@@ -470,11 +519,15 @@ boolean *cause_delay;
|
|||||||
default: impossible("bad chain movement");
|
default: impossible("bad chain movement");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#undef SKIP_TO_DRAG
|
||||||
|
#undef IS_CHAIN_ROCK
|
||||||
#undef CHAIN_IN_MIDDLE
|
#undef CHAIN_IN_MIDDLE
|
||||||
return TRUE;
|
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.",
|
You("cannot %sdrag the heavy iron ball.",
|
||||||
invent ? "carry all that and also " : "");
|
invent ? "carry all that and also " : "");
|
||||||
nomul(0);
|
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);
|
move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
|
||||||
*ballx = uchain->ox;
|
if (dist2(x, y, u.ux, u.uy) > 2) {
|
||||||
*bally = uchain->oy;
|
/* Awful case: we're still in range of the ball, so we thought we
|
||||||
*chainx = u.ux;
|
* could only move the chain, but it turned out that the target
|
||||||
*chainy = u.uy;
|
* 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;
|
*cause_delay = TRUE;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-5
@@ -246,11 +246,18 @@ register int nux,nuy;
|
|||||||
xchar ballx, bally, chainx, chainy;
|
xchar ballx, bally, chainx, chainy;
|
||||||
boolean cause_delay;
|
boolean cause_delay;
|
||||||
|
|
||||||
/* this should only drag the chain (and never give a near-
|
/* We really should only be dragging the chain here, since we
|
||||||
capacity message) since we already checked ball distance */
|
* checked the ball distance. However, some pathological
|
||||||
(void) drag_ball(u.ux, u.uy, &bc_control, &ballx, &bally,
|
* cases will drag the ball anyway. drag_ball() tries to
|
||||||
&chainx, &chainy, &cause_delay);
|
* handle those by ignoring near_capacity() and teleporting the
|
||||||
move_bc(0, bc_control, ballx, bally, chainx, chainy);
|
* 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
|
} else
|
||||||
placebc();
|
placebc();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user