iron balls/teleds
Fixing some iron ball/teleds stuff: -- If the player can pass through walls, ignore all checks for walls, or else things will behave weirdly. -- Instead of using the kludge "if the distance is >2 it must be a teleport", pass a parameter indicating whether they crawled or teleported onto the new space. This fixes a special case, where the player moved one space and the ball didn't move, but the chain moved through solid rock. This is acceptable if teleporting and unacceptable if dragging. This also required some rearrangement of teleds() so that u.ux,u.uy are set after placing the ball, not before. I'm still not sure the pit filling line is in the right place; anyone know? -- add some comments so I can look at the code in a month and still know what I did. Most of this patch is just adding the new parameter.
This commit is contained in:
@@ -109,7 +109,7 @@ E void NDECL(unplacebc);
|
||||
E void FDECL(set_bc, (int));
|
||||
E void FDECL(move_bc, (int,int,XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P));
|
||||
E boolean FDECL(drag_ball, (XCHAR_P,XCHAR_P,
|
||||
int *,xchar *,xchar *,xchar *,xchar *, boolean *));
|
||||
int *,xchar *,xchar *,xchar *,xchar *, boolean *,BOOLEAN_P));
|
||||
E void FDECL(drop_ball, (XCHAR_P,XCHAR_P));
|
||||
E void NDECL(drag_down);
|
||||
|
||||
@@ -1870,8 +1870,8 @@ E void FDECL(place_monster, (struct monst *,int,int));
|
||||
|
||||
E boolean FDECL(goodpos, (int,int,struct monst *));
|
||||
E boolean FDECL(enexto, (coord *,XCHAR_P,XCHAR_P,struct permonst *));
|
||||
E void FDECL(teleds, (int,int));
|
||||
E boolean NDECL(safe_teleds);
|
||||
E void FDECL(teleds, (int,int,BOOLEAN_P));
|
||||
E boolean FDECL(safe_teleds, (BOOLEAN_P));
|
||||
E boolean FDECL(teleport_pet, (struct monst *,BOOLEAN_P));
|
||||
E void NDECL(tele);
|
||||
E int NDECL(dotele);
|
||||
|
||||
@@ -1361,7 +1361,7 @@ int magic; /* 0=Physical, otherwise skill level */
|
||||
if (In_sokoban(&u.uz))
|
||||
change_luck(-1);
|
||||
|
||||
teleds(cc.x, cc.y);
|
||||
teleds(cc.x, cc.y, TRUE);
|
||||
nomul(-1);
|
||||
nomovemsg = "";
|
||||
morehungry(rnd(25));
|
||||
@@ -2180,7 +2180,7 @@ struct obj *obj;
|
||||
if (proficient && rn2(proficient + 2)) {
|
||||
if (!mtmp || enexto(&cc, rx, ry, youmonst.data)) {
|
||||
You("yank yourself out of the pit!");
|
||||
teleds(cc.x, cc.y);
|
||||
teleds(cc.x, cc.y, TRUE);
|
||||
u.utrap = 0;
|
||||
vision_full_recalc = 1;
|
||||
}
|
||||
|
||||
89
src/ball.c
89
src/ball.c
@@ -347,15 +347,26 @@ xchar ballx, bally, chainx, chainy; /* only matter !before */
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* It is called if we are moving. It is also called if we are teleporting
|
||||
* *if* the ball doesn't move and we thus must drag the chain. It is not
|
||||
* called for ordinary teleportation.
|
||||
*
|
||||
* allow_drag is only used in the ugly special case where teleporting must
|
||||
* drag the chain, while an identical-looking movement must drag both the ball
|
||||
* and chain.
|
||||
*/
|
||||
boolean
|
||||
drag_ball(x, y, bc_control, ballx, bally, chainx, chainy, cause_delay)
|
||||
drag_ball(x, y, bc_control, ballx, bally, chainx, chainy, cause_delay,
|
||||
allow_drag)
|
||||
xchar x, y;
|
||||
int *bc_control;
|
||||
xchar *ballx, *bally, *chainx, *chainy;
|
||||
boolean *cause_delay;
|
||||
boolean allow_drag;
|
||||
{
|
||||
struct trap *t = (struct trap *)0;
|
||||
boolean already_in_rock;
|
||||
|
||||
*ballx = uball->ox;
|
||||
*bally = uball->oy;
|
||||
@@ -375,7 +386,7 @@ boolean *cause_delay;
|
||||
*bc_control = BC_CHAIN;
|
||||
move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy);
|
||||
if (carried(uball)) {
|
||||
/* move chain only if necessary; assume they didn't teleport */
|
||||
/* move chain only if necessary */
|
||||
if (distmin(x, y, uchain->ox, uchain->oy) > 1) {
|
||||
*chainx = u.ux;
|
||||
*chainy = u.uy;
|
||||
@@ -388,17 +399,26 @@ boolean *cause_delay;
|
||||
(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.
|
||||
* undo the move_bc() and jump to the drag ball code. Note that this also
|
||||
* means the "cannot carry and drag" message will not appear, since unless we
|
||||
* moved at least two squares there is no possibility of the chain position
|
||||
* being in solid rock.
|
||||
*/
|
||||
#define SKIP_TO_DRAG { *chainx = oldchainx; *chainy = oldchainy; \
|
||||
move_bc(0, *bc_control, *ballx, *bally, *chainx, *chainy); \
|
||||
goto drag; }
|
||||
if (IS_CHAIN_ROCK(u.ux, u.uy) || IS_CHAIN_ROCK(*chainx, *chainy)
|
||||
|| IS_CHAIN_ROCK(uball->ox, uball->oy))
|
||||
already_in_rock = TRUE;
|
||||
else
|
||||
already_in_rock = FALSE;
|
||||
|
||||
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))
|
||||
if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock)
|
||||
SKIP_TO_DRAG;
|
||||
break;
|
||||
|
||||
@@ -423,37 +443,44 @@ boolean *cause_delay;
|
||||
tempy2 = uball->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;
|
||||
!IS_CHAIN_ROCK(tempx2, tempy2) &&
|
||||
!already_in_rock) {
|
||||
if (allow_drag) {
|
||||
/* Avoid pathological case *if* not teleporting:
|
||||
* 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 *if* not teleporting:
|
||||
* 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;
|
||||
IS_CHAIN_ROCK(tempx2, tempy2) &&
|
||||
!already_in_rock) {
|
||||
if (allow_drag) {
|
||||
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)) {
|
||||
IS_CHAIN_ROCK(tempx2, tempy2) &&
|
||||
!already_in_rock) {
|
||||
SKIP_TO_DRAG;
|
||||
} else if (dist2(tempx, tempy, uchain->ox, uchain->oy) <
|
||||
dist2(tempx2, tempy2, uchain->ox, uchain->oy) ||
|
||||
@@ -475,7 +502,7 @@ boolean *cause_delay;
|
||||
break;
|
||||
*chainx = (x + uball->ox)/2;
|
||||
*chainy = (y + uball->oy)/2;
|
||||
if (IS_CHAIN_ROCK(*chainx, *chainy))
|
||||
if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock)
|
||||
SKIP_TO_DRAG;
|
||||
break;
|
||||
|
||||
@@ -494,7 +521,7 @@ boolean *cause_delay;
|
||||
*chainx = uball->ox;
|
||||
else
|
||||
*chainy = uball->oy;
|
||||
if (IS_CHAIN_ROCK(*chainx, *chainy))
|
||||
if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock)
|
||||
SKIP_TO_DRAG;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -400,7 +400,7 @@ int dest, how;
|
||||
if (enexto(&xy, etmp->ex, etmp->ey, etmp->edata)) {
|
||||
pline("A %s force teleports you away...",
|
||||
Hallucination ? "normal" : "strange");
|
||||
teleds(xy.x, xy.y);
|
||||
teleds(xy.x, xy.y, FALSE);
|
||||
}
|
||||
/* otherwise on top of the drawbridge is the
|
||||
* only viable spot in the dungeon, so stay there
|
||||
|
||||
2
src/do.c
2
src/do.c
@@ -953,7 +953,7 @@ boolean at_stairs, falling, portal;
|
||||
|
||||
pline("A mysterious force momentarily surrounds you...");
|
||||
if (on_level(newlevel, &u.uz)) {
|
||||
(void) safe_teleds();
|
||||
(void) safe_teleds(FALSE);
|
||||
(void) next_to_u();
|
||||
return;
|
||||
} else
|
||||
|
||||
@@ -1126,7 +1126,7 @@ domove()
|
||||
/* Move ball and chain. */
|
||||
if (Punished)
|
||||
if (!drag_ball(x,y, &bc_control, &ballx, &bally, &chainx, &chainy,
|
||||
&cause_delay))
|
||||
&cause_delay, TRUE))
|
||||
return;
|
||||
|
||||
/* Check regions entering/leaving */
|
||||
|
||||
@@ -363,7 +363,7 @@ mattacku(mtmp)
|
||||
newsym(mtmp->mx,mtmp->my);
|
||||
place_monster(mtmp, u.ux, u.uy);
|
||||
if(mtmp->wormno) worm_move(mtmp);
|
||||
teleds(cc.x, cc.y);
|
||||
teleds(cc.x, cc.y, TRUE);
|
||||
set_apparxy(mtmp);
|
||||
newsym(u.ux,u.uy);
|
||||
} else {
|
||||
|
||||
@@ -219,7 +219,7 @@ register int trouble;
|
||||
/* teleport should always succeed, but if not,
|
||||
* just untrap them.
|
||||
*/
|
||||
if(!safe_teleds())
|
||||
if(!safe_teleds(FALSE))
|
||||
u.utrap = 0;
|
||||
break;
|
||||
case TROUBLE_STARVING:
|
||||
@@ -256,7 +256,7 @@ register int trouble;
|
||||
case TROUBLE_STUCK_IN_WALL:
|
||||
Your("surroundings change.");
|
||||
/* no control, but works on no-teleport levels */
|
||||
(void) safe_teleds();
|
||||
(void) safe_teleds(FALSE);
|
||||
break;
|
||||
case TROUBLE_CURSED_LEVITATION:
|
||||
if (uarmf && uarmf->otyp==LEVITATION_BOOTS
|
||||
|
||||
@@ -332,7 +332,7 @@ mount_steed(mtmp, force)
|
||||
}
|
||||
u.usteed = mtmp;
|
||||
remove_monster(mtmp->mx, mtmp->my);
|
||||
teleds(mtmp->mx, mtmp->my);
|
||||
teleds(mtmp->mx, mtmp->my, TRUE);
|
||||
return (TRUE);
|
||||
}
|
||||
|
||||
@@ -568,7 +568,7 @@ dismount_steed(reason)
|
||||
* teleds() clears u.utrap
|
||||
*/
|
||||
in_steed_dismounting = TRUE;
|
||||
teleds(cc.x, cc.y);
|
||||
teleds(cc.x, cc.y, TRUE);
|
||||
in_steed_dismounting = FALSE;
|
||||
|
||||
/* Put your steed in your trap */
|
||||
|
||||
@@ -201,34 +201,50 @@ boolean trapok;
|
||||
}
|
||||
|
||||
void
|
||||
teleds(nux, nuy)
|
||||
teleds(nux, nuy, allow_drag)
|
||||
register int nux,nuy;
|
||||
boolean allow_drag;
|
||||
{
|
||||
boolean dont_teleport_ball = FALSE;
|
||||
boolean ball_still_in_range = FALSE;
|
||||
|
||||
/* If they have to move the ball, then drag if allow_drag is true;
|
||||
* otherwise they are teleporting, so unplacebc().
|
||||
* If they don't have to move the ball, then always "drag" whether or
|
||||
* not allow_drag is true, because we are calling that function, not
|
||||
* to drag, but to move the chain. *However* there are some dumb
|
||||
* special cases:
|
||||
* 0 0
|
||||
* _X move east -----> X_
|
||||
* @ @
|
||||
* These are permissible if teleporting, but not if dragging. As a
|
||||
* result, drag_ball() needs to know about allow_drag and might end
|
||||
* up dragging the ball anyway. Also, drag_ball() might find that
|
||||
* dragging the ball is completely impossible (ball in range but there's
|
||||
* rock in the way), in which case it teleports the ball on its own.
|
||||
*/
|
||||
if (Punished) {
|
||||
/* If they're teleporting to a position where the ball doesn't need
|
||||
* to be moved, don't place the ball. Especially useful when this
|
||||
* function is being called for crawling out of water instead of
|
||||
* real teleportation.
|
||||
*/
|
||||
if (!carried(uball) && distmin(nux, nuy, uball->ox, uball->oy) <= 2)
|
||||
dont_teleport_ball = TRUE;
|
||||
else
|
||||
unplacebc();
|
||||
ball_still_in_range = TRUE; /* don't have to move the ball */
|
||||
else {
|
||||
/* have to move the ball */
|
||||
if (!allow_drag || distmin(u.ux, u.uy, nux, nuy) > 1) {
|
||||
/* we should not have dist > 1 and allow_drag at the same
|
||||
* time, but just in case, we must then revert to teleport.
|
||||
*/
|
||||
allow_drag = FALSE;
|
||||
unplacebc();
|
||||
}
|
||||
}
|
||||
}
|
||||
u.utrap = 0;
|
||||
u.ustuck = 0;
|
||||
u.ux0 = u.ux;
|
||||
u.uy0 = u.uy;
|
||||
u.ux = nux;
|
||||
u.uy = nuy;
|
||||
fill_pit(u.ux0, u.uy0); /* do this now so that cansee() is correct */
|
||||
|
||||
if (hides_under(youmonst.data))
|
||||
u.uundetected = OBJ_AT(nux, nuy);
|
||||
else if (youmonst.data->mlet == S_EEL)
|
||||
u.uundetected = is_pool(u.ux, u.uy);
|
||||
u.uundetected = is_pool(nux, nuy);
|
||||
else {
|
||||
u.uundetected = 0;
|
||||
/* mimics stop being unnoticed */
|
||||
@@ -241,25 +257,24 @@ register int nux,nuy;
|
||||
docrt();
|
||||
}
|
||||
if (Punished) {
|
||||
if (dont_teleport_ball) {
|
||||
if (ball_still_in_range || allow_drag) {
|
||||
int bc_control;
|
||||
xchar ballx, bally, chainx, chainy;
|
||||
boolean cause_delay;
|
||||
|
||||
/* 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))
|
||||
if (drag_ball(nux, nuy, &bc_control, &ballx, &bally,
|
||||
&chainx, &chainy, &cause_delay, allow_drag))
|
||||
move_bc(0, bc_control, ballx, bally, chainx, chainy);
|
||||
} else
|
||||
placebc();
|
||||
}
|
||||
}
|
||||
/* must set u.ux, u.uy after drag_ball(), which may need to know
|
||||
the old position if allow_drag is true... */
|
||||
u.ux = nux;
|
||||
u.uy = nuy;
|
||||
fill_pit(u.ux0, u.uy0);
|
||||
if (Punished) {
|
||||
if (!ball_still_in_range && !allow_drag)
|
||||
placebc();
|
||||
}
|
||||
initrack(); /* teleports mess up tracking monsters without this */
|
||||
update_player_regions();
|
||||
@@ -286,7 +301,8 @@ register int nux,nuy;
|
||||
}
|
||||
|
||||
boolean
|
||||
safe_teleds()
|
||||
safe_teleds(allow_drag)
|
||||
boolean allow_drag;
|
||||
{
|
||||
register int nux, nuy, tcnt = 0;
|
||||
|
||||
@@ -296,7 +312,7 @@ safe_teleds()
|
||||
} while (!teleok(nux, nuy, (boolean)(tcnt > 200)) && ++tcnt <= 400);
|
||||
|
||||
if (tcnt <= 400) {
|
||||
teleds(nux, nuy);
|
||||
teleds(nux, nuy, allow_drag);
|
||||
return TRUE;
|
||||
} else
|
||||
return FALSE;
|
||||
@@ -309,7 +325,7 @@ vault_tele()
|
||||
coord c;
|
||||
|
||||
if (croom && somexy(croom, &c) && teleok(c.x,c.y,FALSE)) {
|
||||
teleds(c.x,c.y);
|
||||
teleds(c.x,c.y,FALSE);
|
||||
return;
|
||||
}
|
||||
tele();
|
||||
@@ -394,14 +410,14 @@ tele()
|
||||
/* possible extensions: introduce a small error if
|
||||
magic power is low; allow transfer to solid rock */
|
||||
if (teleok(cc.x, cc.y, FALSE)) {
|
||||
teleds(cc.x, cc.y);
|
||||
teleds(cc.x, cc.y, FALSE);
|
||||
return;
|
||||
}
|
||||
pline("Sorry...");
|
||||
}
|
||||
}
|
||||
|
||||
(void) safe_teleds();
|
||||
(void) safe_teleds(FALSE);
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
@@ -2642,7 +2642,7 @@ crawl:;
|
||||
You("dump some of your gear to lose weight...");
|
||||
if (succ) {
|
||||
pline("Pheew! That was close.");
|
||||
teleds(x,y);
|
||||
teleds(x,y,TRUE);
|
||||
return(TRUE);
|
||||
}
|
||||
/* still too much weight */
|
||||
@@ -2655,7 +2655,7 @@ crawl:;
|
||||
"pool of water" : "moat";
|
||||
done(DROWNING);
|
||||
/* oops, we're still alive. better get out of the water. */
|
||||
while (!safe_teleds()) {
|
||||
while (!safe_teleds(TRUE)) {
|
||||
pline("You're still drowning.");
|
||||
done(DROWNING);
|
||||
}
|
||||
@@ -2758,7 +2758,8 @@ struct trap *ttmp;
|
||||
boolean unused;
|
||||
|
||||
/* we know there's no monster in the way, and we're not trapped */
|
||||
if (!Punished || drag_ball(x, y, &bc, &bx, &by, &cx, &cy, &unused)) {
|
||||
if (!Punished || drag_ball(x, y, &bc, &bx, &by, &cx, &cy, &unused,
|
||||
TRUE)) {
|
||||
u.ux0 = u.ux, u.uy0 = u.uy;
|
||||
u.ux = x, u.uy = y;
|
||||
u.umoved = TRUE;
|
||||
@@ -3618,7 +3619,7 @@ lava_effects()
|
||||
killer = lava_killer;
|
||||
You("burn to a crisp...");
|
||||
done(BURNING);
|
||||
while (!safe_teleds()) {
|
||||
while (!safe_teleds(TRUE)) {
|
||||
pline("You're still burning.");
|
||||
done(BURNING);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user