#define GET_MAX_MOVE_DELAY(e) ( (element_info[e].move_delay_fixed) + \
(element_info[e].move_delay_random))
-#if 1
+#define ELEMENT_CAN_ENTER_FIELD_BASE(e, x, y, condition) \
+ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \
+ (CAN_MOVE_INTO_ACID(e) && \
+ Feld[x][y] == EL_ACID) || \
+ (condition)))
+
+#if 0
#define ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, condition) \
(IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \
(condition) || \
#define ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, condition) \
(IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \
(condition) || \
+ (CAN_MOVE_INTO_ACID(e) && \
+ Feld[x][y] == EL_ACID) || \
(DONT_COLLIDE_WITH(e) && \
- IS_FREE_OR_PLAYER(x, y))))
+ IS_PLAYER(x, y) && \
+ !PLAYER_ENEMY_PROTECTED(x, y))))
#endif
#define ELEMENT_CAN_ENTER_FIELD_GENERIC_2(x, y, condition) \
#define ELEMENT_CAN_ENTER_FIELD_OR_ACID_2(x, y) \
ELEMENT_CAN_ENTER_FIELD_GENERIC_2(x, y, (Feld[x][y] == EL_ACID))
-#define ENEMY_CAN_ENTER_FIELD(x, y) (IN_LEV_FIELD(x, y) && IS_FREE(x, y))
+#if 0
+#define ENEMY_CAN_ENTER_FIELD(e, x, y) (IN_LEV_FIELD(x, y) && IS_FREE(x, y))
+#else
+#define ENEMY_CAN_ENTER_FIELD(e, x, y) ELEMENT_CAN_ENTER_FIELD_BASE(e, x, y, 0)
+#endif
#define YAMYAM_CAN_ENTER_FIELD(x, y) \
(IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) || \
Feld[x][y] == EL_EXIT_OPEN || \
Feld[x][y] == EL_ACID))
-#if 0
-#if 1
-#define MAZE_RUNNER_CAN_ENTER_FIELD(x, y) \
- (IN_LEV_FIELD(x, y) && IS_FREE(x, y))
-#else
-#define MAZE_RUNNER_CAN_ENTER_FIELD(x, y) \
- (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \
- IS_FOOD_DARK_YAMYAM(Feld[x][y])))
-#endif
-#endif
-
#define GROUP_NR(e) ((e) - EL_GROUP_START)
#define MOVE_ENTER_EL(e) (element_info[e].move_enter_element)
#define IS_IN_GROUP(e, nr) (element_info[e].in_group[nr] == TRUE)
#define IS_EQUAL_OR_IN_GROUP(e, ge) \
(IS_GROUP_ELEMENT(ge) ? IS_IN_GROUP(e, GROUP_NR(ge)) : (e) == (ge))
-#if 1
+#if 0
#define CE_ENTER_FIELD_COND(e, x, y) \
(!IS_PLAYER(x, y) && \
(Feld[x][y] == EL_ACID || \
#else
#define CE_ENTER_FIELD_COND(e, x, y) \
(!IS_PLAYER(x, y) && \
- (Feld[x][y] == EL_ACID || \
- Feld[x][y] == MOVE_ENTER_EL(e) || \
- (IS_GROUP_ELEMENT(MOVE_ENTER_EL(e)) && \
- IS_IN_GROUP_EL(Feld[x][y], MOVE_ENTER_EL(e)))))
+ IS_EQUAL_OR_IN_GROUP(Feld[x][y], MOVE_ENTER_EL(e)))
#endif
#define CUSTOM_ELEMENT_CAN_ENTER_FIELD(e, x, y) \
}
}
+static inline void InitField_WithBug1(int x, int y, boolean init_game)
+{
+ InitField(x, y, init_game);
+
+ /* not needed to call InitMovDir() -- already done by InitField()! */
+ if (game.engine_version < VERSION_IDENT(3,0,9,0) &&
+ CAN_MOVE(Feld[x][y]))
+ InitMovDir(x, y);
+}
+
+static inline void InitField_WithBug2(int x, int y, boolean init_game)
+{
+ int old_element = Feld[x][y];
+
+ InitField(x, y, init_game);
+
+ /* not needed to call InitMovDir() -- already done by InitField()! */
+ if (game.engine_version < VERSION_IDENT(3,0,9,0) &&
+ CAN_MOVE(old_element) &&
+ (old_element < EL_MOLE_LEFT || old_element > EL_MOLE_DOWN))
+ InitMovDir(x, y);
+
+ /* this case is in fact a combination of not less than three bugs:
+ first, it calls InitMovDir() for elements that can move, although this is
+ already done by InitField(); then, it checks the element that was at this
+ field _before_ the call to InitField() (which can change it)
+
+ */
+}
+
void DrawGameDoorValues()
{
int i, j;
if (IS_MOVING(x, y))
{
Moving2Blocked(x, y, &newx, &newy);
+#if 0
if (Feld[newx][newy] != EL_BLOCKED)
return;
+#else
+ if (Feld[newx][newy] != EL_BLOCKED)
+ {
+ /* element is moving, but target field is not free (blocked), but
+ already occupied by something different (example: acid pool);
+ in this case, only remove the moving field, but not the target */
+
+ RemoveField(oldx, oldy);
+
+ Store[oldx][oldy] = Store2[oldx][oldy] = 0;
+
+ DrawLevelField(oldx, oldy);
+
+ return;
+ }
+#endif
}
else if (element == EL_BLOCKED)
{
ChangeDelay[x][y] = 0;
ChangePage[x][y] = -1;
+#if 1
+ InitField_WithBug2(x, y, FALSE);
+#else
InitField(x, y, FALSE);
#if 1
/* !!! not needed !!! */
+#if 1
+ if (game.engine_version < VERSION_IDENT(3,0,9,0) &&
+ CAN_MOVE(Feld[x][y]) && Feld[x][y] != EL_MOLE)
+ InitMovDir(x, y);
+#else
if (CAN_MOVE(element))
InitMovDir(x, y);
+#endif
+#endif
#endif
DrawLevelField(x, y);
void SplashAcid(int x, int y)
{
+#if 1
+ if (IN_LEV_FIELD(x - 1, y - 1) && IS_FREE(x - 1, y - 1) &&
+ (!IN_LEV_FIELD(x - 1, y - 2) ||
+ !CAN_FALL(MovingOrBlocked2Element(x - 1, y - 2))))
+ Feld[x - 1][y - 1] = EL_ACID_SPLASH_LEFT;
+
+ if (IN_LEV_FIELD(x + 1, y - 1) && IS_FREE(x + 1, y - 1) &&
+ (!IN_LEV_FIELD(x + 1, y - 2) ||
+ !CAN_FALL(MovingOrBlocked2Element(x + 1, y - 2))))
+ Feld[x + 1][y - 1] = EL_ACID_SPLASH_RIGHT;
+
+ PlayLevelSound(x, y, SND_ACID_SPLASHING);
+#else
+ /* input: position of element entering acid (obsolete) */
+
int element = Feld[x][y];
+ if (!IN_LEV_FIELD(x, y + 1) || Feld[x][y + 1] != EL_ACID)
+ return;
+
if (element != EL_ACID_SPLASH_LEFT &&
element != EL_ACID_SPLASH_RIGHT)
{
PlayLevelSound(x, y, SND_ACID_SPLASHING);
- if (IN_LEV_FIELD(x-1, y) && IS_FREE(x-1, y) &&
- (!IN_LEV_FIELD(x-1, y-1) ||
- !CAN_FALL(MovingOrBlocked2Element(x-1, y-1))))
- Feld[x-1][y] = EL_ACID_SPLASH_LEFT;
+ if (IN_LEV_FIELD(x - 1, y) && IS_FREE(x - 1, y) &&
+ (!IN_LEV_FIELD(x - 1, y - 1) ||
+ !CAN_FALL(MovingOrBlocked2Element(x - 1, y - 1))))
+ Feld[x - 1][y] = EL_ACID_SPLASH_LEFT;
- if (IN_LEV_FIELD(x+1, y) && IS_FREE(x+1, y) &&
- (!IN_LEV_FIELD(x+1, y-1) ||
- !CAN_FALL(MovingOrBlocked2Element(x+1, y-1))))
- Feld[x+1][y] = EL_ACID_SPLASH_RIGHT;
+ if (IN_LEV_FIELD(x + 1, y) && IS_FREE(x + 1, y) &&
+ (!IN_LEV_FIELD(x + 1, y - 1) ||
+ !CAN_FALL(MovingOrBlocked2Element(x + 1, y - 1))))
+ Feld[x + 1][y] = EL_ACID_SPLASH_RIGHT;
}
+#endif
}
static void InitBeltMovement()
if (!lastline && smashed == EL_ACID) /* element falls into acid */
{
- SplashAcid(x, y);
+ SplashAcid(x, y + 1);
return;
}
{
TestIfBadThingTouchesOtherBadThing(x, y);
- if (ENEMY_CAN_ENTER_FIELD(right_x, right_y))
+ if (ENEMY_CAN_ENTER_FIELD(element, right_x, right_y))
MovDir[x][y] = right_dir;
- else if (!ENEMY_CAN_ENTER_FIELD(move_x, move_y))
+ else if (!ENEMY_CAN_ENTER_FIELD(element, move_x, move_y))
MovDir[x][y] = left_dir;
if (element == EL_BUG && MovDir[x][y] != old_move_dir)
{
TestIfBadThingTouchesOtherBadThing(x, y);
- if (ENEMY_CAN_ENTER_FIELD(left_x, left_y))
+ if (ENEMY_CAN_ENTER_FIELD(element, left_x, left_y))
MovDir[x][y] = left_dir;
- else if (!ENEMY_CAN_ENTER_FIELD(move_x, move_y))
+ else if (!ENEMY_CAN_ENTER_FIELD(element, move_x, move_y))
MovDir[x][y] = right_dir;
if ((element == EL_SPACESHIP ||
void StartMoving(int x, int y)
{
+#if 0
boolean use_spring_bug = (game.engine_version < VERSION_IDENT(2,2,0,0));
+#endif
boolean started_moving = FALSE; /* some elements can fall _and_ move */
int element = Feld[x][y];
else if (CAN_FALL(element) && Feld[x][y + 1] == EL_ACID)
#endif
{
- SplashAcid(x, y);
+ SplashAcid(x, y + 1);
InitMovingField(x, y, MV_DOWN);
started_moving = TRUE;
Impact(x, y);
}
- else if (IS_FREE(x, y + 1) && element == EL_SPRING && use_spring_bug)
+ else if (IS_FREE(x, y + 1) && element == EL_SPRING && level.use_spring_bug)
{
if (MovDir[x][y] == MV_NO_MOVING)
{
#endif
}
+#if 1
+#if 1
+ else if (CAN_MOVE_INTO_ACID(element) &&
+ IN_LEV_FIELD(newx, newy) && Feld[newx][newy] == EL_ACID &&
+ (MovDir[x][y] == MV_DOWN ||
+ game.engine_version > VERSION_IDENT(3,0,8,0)))
+#else
+ else if (CAN_MOVE_INTO_ACID(element) && MovDir[x][y] == MV_DOWN &&
+ IN_LEV_FIELD(newx, newy) && Feld[newx][newy] == EL_ACID)
+#endif
+#else
+
else if ((element == EL_PENGUIN ||
element == EL_ROBOT ||
element == EL_SATELLITE ||
IS_CUSTOM_ELEMENT(element)) &&
IN_LEV_FIELD(newx, newy) &&
MovDir[x][y] == MV_DOWN && Feld[newx][newy] == EL_ACID)
+#endif
{
- SplashAcid(x, y);
+ SplashAcid(newx, newy);
Store[x][y] = EL_ACID;
}
else if (element == EL_PENGUIN && IN_LEV_FIELD(newx, newy))
AmoebaCnt[AmoebaNr[newx][newy]]--;
}
+#if 0
+ /* !!! test !!! */
+ if (IS_MOVING(newx, newy) || IS_BLOCKED(newx, newy))
+#else
if (IS_MOVING(newx, newy))
+#endif
+ {
RemoveMovingField(newx, newy);
+ }
else
{
Feld[newx][newy] = EL_EMPTY;
int nextx = newx + dx, nexty = newy + dy;
#endif
#if 1
- boolean pushed = (Pushed[x][y] && IS_PLAYER(x, y));
+ boolean pushed_by_player = (Pushed[x][y] && IS_PLAYER(x, y));
boolean pushed_by_conveyor = (Pushed[x][y] && !IS_PLAYER(x, y));
#else
- boolean pushed = Pushed[x][y];
+ boolean pushed_by_player = Pushed[x][y];
#endif
MovPos[x][y] += getElementMoveStepsize(x, y);
#if 0
- if (pushed && IS_PLAYER(x, y))
+ if (pushed_by_player && IS_PLAYER(x, y))
{
/* special case: moving object pushed by player */
MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x,y)->MovPos));
}
#else
- if (pushed) /* special case: moving object pushed by player */
+ if (pushed_by_player) /* special case: moving object pushed by player */
MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x,y)->MovPos));
#endif
Stop[newx][newy] = TRUE; /* ignore this element until the next frame */
/* prevent pushed element from moving on in pushed direction */
- if (pushed && CAN_MOVE(element) &&
+ if (pushed_by_player && CAN_MOVE(element) &&
element_info[element].move_pattern & MV_ANY_DIRECTION &&
!(element_info[element].move_pattern & direction))
TurnRound(newx, newy);
MovDir[newx][newy] = 0;
#endif
- if (!pushed) /* special case: moving object pushed by player */
+ if (!pushed_by_player)
{
WasJustMoving[newx][newy] = 3;
if (element_info[Feld[x][y]].move_direction_initial == MV_START_PREVIOUS)
MovDir[x][y] = previous_move_direction;
+#if 1
+ InitField_WithBug1(x, y, FALSE);
+#else
InitField(x, y, FALSE);
if (CAN_MOVE(Feld[x][y]))
InitMovDir(x, y);
+#endif
DrawLevelField(x, y);
#endif
#if 1
+ /* for downwards compatibility, the following code emulates a fixed bug that
+ occured when pushing elements (causing elements that just made their last
+ pushing step to already (if possible) make their first falling step in the
+ same game frame, which is bad); this code is also needed to use the famous
+ "spring push bug" which is used in older levels and might be wanted to be
+ used also in newer levels, but in this case the buggy pushing code is only
+ affecting the "spring" element and no other elements */
+
+#if 1
+ if (game.engine_version < VERSION_IDENT(2,2,0,7) || level.use_spring_bug)
+#else
if (game.engine_version < VERSION_IDENT(2,2,0,7))
+#endif
{
for (i = 0; i < MAX_PLAYERS; i++)
{
int x = player->jx;
int y = player->jy;
+#if 1
+ if (player->active && player->is_pushing && player->is_moving &&
+ IS_MOVING(x, y) &&
+ (game.engine_version < VERSION_IDENT(2,2,0,7) ||
+ Feld[x][y] == EL_SPRING))
+#else
if (player->active && player->is_pushing && player->is_moving &&
IS_MOVING(x, y))
+#endif
{
ContinueMoving(x, y);
{
if (element == EL_ACID && dx == 0 && dy == 1)
{
- SplashAcid(jx, jy);
+ SplashAcid(new_jx, new_jy);
Feld[jx][jy] = EL_PLAYER_1;
InitMovingField(jx, jy, MV_DOWN);
Store[jx][jy] = EL_ACID;
CH_SIDE_BOTTOM, /* moving up */
CH_SIDE_TOP, /* moving down */
};
+#if 0
boolean use_spring_bug = (game.engine_version < VERSION_IDENT(2,2,0,0));
+#endif
int jx = oldx, jy = oldy;
int dx = x - jx, dy = y - jy;
int nextx = x + dx, nexty = y + dy;
return MF_NO_ACTION;
if (CAN_FALL(element) && IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1) &&
- !(element == EL_SPRING && use_spring_bug))
+ !(element == EL_SPRING && level.use_spring_bug))
return MF_NO_ACTION;
#if 1
if (Feld[jx][jy] == new_element) /* uninitialized unless CE change */
{
+#if 1
+ InitField_WithBug1(jx, jy, FALSE);
+#else
InitField(jx, jy, FALSE);
if (CAN_MOVE(Feld[jx][jy]))
InitMovDir(jx, jy);
+#endif
}
new_element = Feld[jx][jy];