+ int old_move_dir = MovDir[x][y];
+ int left_dir = turn[old_move_dir].left;
+ int right_dir = turn[old_move_dir].right;
+ int back_dir = turn[old_move_dir].back;
+
+ int left_dx = move_xy[left_dir].x, left_dy = move_xy[left_dir].y;
+ int right_dx = move_xy[right_dir].x, right_dy = move_xy[right_dir].y;
+ int move_dx = move_xy[old_move_dir].x, move_dy = move_xy[old_move_dir].y;
+ int back_dx = move_xy[back_dir].x, back_dy = move_xy[back_dir].y;
+
+ int left_x = x + left_dx, left_y = y + left_dy;
+ int right_x = x + right_dx, right_y = y + right_dy;
+ int move_x = x + move_dx, move_y = y + move_dy;
+
+ int xx, yy;
+
+ if (element == EL_BUG || element == EL_BD_BUTTERFLY)
+ {
+ TestIfBadThingTouchesOtherBadThing(x, y);
+
+ if (ENEMY_CAN_ENTER_FIELD(element, right_x, right_y))
+ MovDir[x][y] = right_dir;
+ 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)
+ MovDelay[x][y] = 9;
+ else if (element == EL_BD_BUTTERFLY) /* && MovDir[x][y] == left_dir) */
+ MovDelay[x][y] = 1;
+ }
+#if 0
+ else if (element == EL_SPACESHIP || element == EL_BD_FIREFLY ||
+ element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
+ {
+ TestIfBadThingTouchesOtherBadThing(x, y);
+
+ if (ENEMY_CAN_ENTER_FIELD(element, left_x, left_y))
+ MovDir[x][y] = left_dir;
+ else if (!ENEMY_CAN_ENTER_FIELD(element, move_x, move_y))
+ MovDir[x][y] = right_dir;
+
+ if ((element == EL_SPACESHIP ||
+ element == EL_SP_SNIKSNAK ||
+ element == EL_SP_ELECTRON)
+ && MovDir[x][y] != old_move_dir)
+ MovDelay[x][y] = 9;
+ else if (element == EL_BD_FIREFLY) /* && MovDir[x][y] == right_dir) */
+ MovDelay[x][y] = 1;
+ }
+#else
+ else if (element == EL_SPACESHIP || element == EL_BD_FIREFLY)
+ {
+ TestIfBadThingTouchesOtherBadThing(x, y);
+
+ if (ENEMY_CAN_ENTER_FIELD(element, left_x, left_y))
+ MovDir[x][y] = left_dir;
+ else if (!ENEMY_CAN_ENTER_FIELD(element, move_x, move_y))
+ MovDir[x][y] = right_dir;
+
+ if (element == EL_SPACESHIP && MovDir[x][y] != old_move_dir)
+ MovDelay[x][y] = 9;
+ else if (element == EL_BD_FIREFLY) /* && MovDir[x][y] == right_dir) */
+ MovDelay[x][y] = 1;
+ }
+ else if (element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
+ {
+ TestIfBadThingTouchesOtherBadThing(x, y);
+
+ if (ELEMENT_CAN_ENTER_FIELD_BASE_4(element, left_x, left_y, 0))
+ MovDir[x][y] = left_dir;
+ else if (!ELEMENT_CAN_ENTER_FIELD_BASE_4(element, move_x, move_y, 0))
+ MovDir[x][y] = right_dir;
+
+ if (MovDir[x][y] != old_move_dir)
+ MovDelay[x][y] = 9;
+ }
+#endif
+ else if (element == EL_YAMYAM)
+ {
+ boolean can_turn_left = YAMYAM_CAN_ENTER_FIELD(element, left_x, left_y);
+ boolean can_turn_right = YAMYAM_CAN_ENTER_FIELD(element, right_x, right_y);
+
+ if (can_turn_left && can_turn_right)
+ MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
+ else if (can_turn_left)
+ MovDir[x][y] = (RND(2) ? left_dir : back_dir);
+ else if (can_turn_right)
+ MovDir[x][y] = (RND(2) ? right_dir : back_dir);
+ else
+ MovDir[x][y] = back_dir;
+
+ MovDelay[x][y] = 16 + 16 * RND(3);
+ }
+ else if (element == EL_DARK_YAMYAM)
+ {
+ boolean can_turn_left = DARK_YAMYAM_CAN_ENTER_FIELD(element,
+ left_x, left_y);
+ boolean can_turn_right = DARK_YAMYAM_CAN_ENTER_FIELD(element,
+ right_x, right_y);
+
+ if (can_turn_left && can_turn_right)
+ MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
+ else if (can_turn_left)
+ MovDir[x][y] = (RND(2) ? left_dir : back_dir);
+ else if (can_turn_right)
+ MovDir[x][y] = (RND(2) ? right_dir : back_dir);
+ else
+ MovDir[x][y] = back_dir;
+
+ MovDelay[x][y] = 16 + 16 * RND(3);
+ }
+ else if (element == EL_PACMAN)
+ {
+ boolean can_turn_left = PACMAN_CAN_ENTER_FIELD(element, left_x, left_y);
+ boolean can_turn_right = PACMAN_CAN_ENTER_FIELD(element, right_x, right_y);
+
+ if (can_turn_left && can_turn_right)
+ MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
+ else if (can_turn_left)
+ MovDir[x][y] = (RND(2) ? left_dir : back_dir);
+ else if (can_turn_right)
+ MovDir[x][y] = (RND(2) ? right_dir : back_dir);
+ else
+ MovDir[x][y] = back_dir;
+
+ MovDelay[x][y] = 6 + RND(40);
+ }
+ else if (element == EL_PIG)
+ {
+ boolean can_turn_left = PIG_CAN_ENTER_FIELD(element, left_x, left_y);
+ boolean can_turn_right = PIG_CAN_ENTER_FIELD(element, right_x, right_y);
+ boolean can_move_on = PIG_CAN_ENTER_FIELD(element, move_x, move_y);
+ boolean should_turn_left, should_turn_right, should_move_on;
+ int rnd_value = 24;
+ int rnd = RND(rnd_value);
+
+ should_turn_left = (can_turn_left &&
+ (!can_move_on ||
+ IN_LEV_FIELD_AND_NOT_FREE(x + back_dx + left_dx,
+ y + back_dy + left_dy)));
+ should_turn_right = (can_turn_right &&
+ (!can_move_on ||
+ IN_LEV_FIELD_AND_NOT_FREE(x + back_dx + right_dx,
+ y + back_dy + right_dy)));
+ should_move_on = (can_move_on &&
+ (!can_turn_left ||
+ !can_turn_right ||
+ IN_LEV_FIELD_AND_NOT_FREE(x + move_dx + left_dx,
+ y + move_dy + left_dy) ||
+ IN_LEV_FIELD_AND_NOT_FREE(x + move_dx + right_dx,
+ y + move_dy + right_dy)));
+
+ if (should_turn_left || should_turn_right || should_move_on)
+ {
+ if (should_turn_left && should_turn_right && should_move_on)
+ MovDir[x][y] = (rnd < rnd_value / 3 ? left_dir :
+ rnd < 2 * rnd_value / 3 ? right_dir :
+ old_move_dir);
+ else if (should_turn_left && should_turn_right)
+ MovDir[x][y] = (rnd < rnd_value / 2 ? left_dir : right_dir);
+ else if (should_turn_left && should_move_on)
+ MovDir[x][y] = (rnd < rnd_value / 2 ? left_dir : old_move_dir);
+ else if (should_turn_right && should_move_on)
+ MovDir[x][y] = (rnd < rnd_value / 2 ? right_dir : old_move_dir);
+ else if (should_turn_left)
+ MovDir[x][y] = left_dir;
+ else if (should_turn_right)
+ MovDir[x][y] = right_dir;
+ else if (should_move_on)
+ MovDir[x][y] = old_move_dir;
+ }
+ else if (can_move_on && rnd > rnd_value / 8)
+ MovDir[x][y] = old_move_dir;
+ else if (can_turn_left && can_turn_right)
+ MovDir[x][y] = (rnd < rnd_value / 2 ? left_dir : right_dir);
+ else if (can_turn_left && rnd > rnd_value / 8)
+ MovDir[x][y] = left_dir;
+ else if (can_turn_right && rnd > rnd_value/8)
+ MovDir[x][y] = right_dir;
+ else
+ MovDir[x][y] = back_dir;
+
+ xx = x + move_xy[MovDir[x][y]].x;
+ yy = y + move_xy[MovDir[x][y]].y;
+
+#if 1
+ /* !!! this bugfix breaks at least BD2K3, level 010 !!! [re-recorded] */
+ if (!IN_LEV_FIELD(xx, yy) ||
+ (!IS_FREE(xx, yy) && !IS_FOOD_PIG(Feld[xx][yy])))
+ MovDir[x][y] = old_move_dir;
+#else
+ if (!IS_FREE(xx, yy) && !IS_FOOD_PIG(Feld[xx][yy]))
+ MovDir[x][y] = old_move_dir;
+#endif
+
+ MovDelay[x][y] = 0;
+ }
+ else if (element == EL_DRAGON)
+ {
+ boolean can_turn_left = DRAGON_CAN_ENTER_FIELD(element, left_x, left_y);
+ boolean can_turn_right = DRAGON_CAN_ENTER_FIELD(element, right_x, right_y);
+ boolean can_move_on = DRAGON_CAN_ENTER_FIELD(element, move_x, move_y);
+ int rnd_value = 24;
+ int rnd = RND(rnd_value);
+
+#if 0
+ if (FrameCounter < 1 && x == 0 && y == 29)
+ printf(":2: %d/%d: %d [%d]\n", x, y, MovDir[x][y], FrameCounter);
+#endif
+
+ if (can_move_on && rnd > rnd_value / 8)
+ MovDir[x][y] = old_move_dir;
+ else if (can_turn_left && can_turn_right)
+ MovDir[x][y] = (rnd < rnd_value / 2 ? left_dir : right_dir);
+ else if (can_turn_left && rnd > rnd_value / 8)
+ MovDir[x][y] = left_dir;
+ else if (can_turn_right && rnd > rnd_value / 8)
+ MovDir[x][y] = right_dir;
+ else
+ MovDir[x][y] = back_dir;
+
+ xx = x + move_xy[MovDir[x][y]].x;
+ yy = y + move_xy[MovDir[x][y]].y;
+
+#if 0
+ if (FrameCounter < 1 && x == 0 && y == 29)
+ printf(":3: %d/%d: %d (%d/%d: %d) [%d]\n", x, y, MovDir[x][y],
+ xx, yy, Feld[xx][yy],
+ FrameCounter);
+#endif
+
+#if 1
+ if (!IN_LEV_FIELD_AND_IS_FREE(xx, yy))
+ MovDir[x][y] = old_move_dir;
+#else
+ if (!IS_FREE(xx, yy))
+ MovDir[x][y] = old_move_dir;
+#endif
+
+#if 0
+ if (FrameCounter < 1 && x == 0 && y == 29)
+ printf(":4: %d/%d: %d [%d]\n", x, y, MovDir[x][y], FrameCounter);
+#endif
+
+ MovDelay[x][y] = 0;
+ }
+ else if (element == EL_MOLE)
+ {
+ boolean can_move_on =
+ (MOLE_CAN_ENTER_FIELD(element, move_x, move_y,
+ IS_AMOEBOID(Feld[move_x][move_y]) ||
+ Feld[move_x][move_y] == EL_AMOEBA_SHRINKING));
+ if (!can_move_on)
+ {
+ boolean can_turn_left =
+ (MOLE_CAN_ENTER_FIELD(element, left_x, left_y,
+ IS_AMOEBOID(Feld[left_x][left_y])));
+
+ boolean can_turn_right =
+ (MOLE_CAN_ENTER_FIELD(element, right_x, right_y,
+ IS_AMOEBOID(Feld[right_x][right_y])));
+
+ if (can_turn_left && can_turn_right)
+ MovDir[x][y] = (RND(2) ? left_dir : right_dir);
+ else if (can_turn_left)
+ MovDir[x][y] = left_dir;
+ else
+ MovDir[x][y] = right_dir;
+ }
+
+ if (MovDir[x][y] != old_move_dir)
+ MovDelay[x][y] = 9;
+ }
+ else if (element == EL_BALLOON)
+ {
+ MovDir[x][y] = game.balloon_dir;
+ MovDelay[x][y] = 0;
+ }
+ else if (element == EL_SPRING)
+ {
+#if 0
+ if (MovDir[x][y] & MV_HORIZONTAL &&
+ !SPRING_CAN_ENTER_FIELD(element, move_x, move_y))
+ MovDir[x][y] = MV_NO_MOVING;
+#else
+ if (MovDir[x][y] & MV_HORIZONTAL &&
+ (!SPRING_CAN_ENTER_FIELD(element, move_x, move_y) ||
+ SPRING_CAN_ENTER_FIELD(element, x, y + 1)))
+ MovDir[x][y] = MV_NO_MOVING;
+#endif
+
+ MovDelay[x][y] = 0;
+ }
+ else if (element == EL_ROBOT ||
+ element == EL_SATELLITE ||
+ element == EL_PENGUIN)
+ {
+ int attr_x = -1, attr_y = -1;
+
+ if (AllPlayersGone)
+ {
+ attr_x = ExitX;
+ attr_y = ExitY;
+ }
+ else
+ {
+ int i;
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ struct PlayerInfo *player = &stored_player[i];
+ int jx = player->jx, jy = player->jy;
+
+ if (!player->active)
+ continue;
+
+ if (attr_x == -1 ||
+ ABS(jx - x) + ABS(jy - y) < ABS(attr_x - x) + ABS(attr_y - y))
+ {
+ attr_x = jx;
+ attr_y = jy;
+ }
+ }
+ }
+
+#if 1
+ if (element == EL_ROBOT && ZX >= 0 && ZY >= 0 &&
+ (Feld[ZX][ZY] == EL_ROBOT_WHEEL_ACTIVE ||
+ game.engine_version < VERSION_IDENT(3,1,0,0)))
+#else
+ if (element == EL_ROBOT && ZX >= 0 && ZY >= 0)
+#endif
+ {
+ attr_x = ZX;
+ attr_y = ZY;
+ }
+
+ if (element == EL_PENGUIN)
+ {
+ int i;
+ static int xy[4][2] =
+ {
+ { 0, -1 },
+ { -1, 0 },
+ { +1, 0 },
+ { 0, +1 }
+ };
+
+ for (i = 0; i < NUM_DIRECTIONS; i++)
+ {
+ int ex = x + xy[i][0];
+ int ey = y + xy[i][1];
+
+ if (IN_LEV_FIELD(ex, ey) && Feld[ex][ey] == EL_EXIT_OPEN)
+ {
+ attr_x = ex;
+ attr_y = ey;
+ break;
+ }
+ }
+ }
+
+ MovDir[x][y] = MV_NO_MOVING;
+ if (attr_x < x)
+ MovDir[x][y] |= (AllPlayersGone ? MV_RIGHT : MV_LEFT);
+ else if (attr_x > x)
+ MovDir[x][y] |= (AllPlayersGone ? MV_LEFT : MV_RIGHT);
+ if (attr_y < y)
+ MovDir[x][y] |= (AllPlayersGone ? MV_DOWN : MV_UP);
+ else if (attr_y > y)
+ MovDir[x][y] |= (AllPlayersGone ? MV_UP : MV_DOWN);
+
+ if (element == EL_ROBOT)
+ {
+ int newx, newy;
+
+ if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL)
+ MovDir[x][y] &= (RND(2) ? MV_HORIZONTAL : MV_VERTICAL);
+ Moving2Blocked(x, y, &newx, &newy);
+
+ if (IN_LEV_FIELD(newx, newy) && IS_FREE_OR_PLAYER(newx, newy))
+ MovDelay[x][y] = 8 + 8 * !RND(3);
+ else
+ MovDelay[x][y] = 16;
+ }
+ else if (element == EL_PENGUIN)
+ {
+ int newx, newy;
+
+ MovDelay[x][y] = 1;
+
+ if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL)
+ {
+ boolean first_horiz = RND(2);
+ int new_move_dir = MovDir[x][y];
+
+ MovDir[x][y] =
+ new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
+ Moving2Blocked(x, y, &newx, &newy);
+
+ if (PENGUIN_CAN_ENTER_FIELD(EL_PENGUIN, newx, newy))
+ return;
+
+ MovDir[x][y] =
+ new_move_dir & (!first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
+ Moving2Blocked(x, y, &newx, &newy);
+
+ if (PENGUIN_CAN_ENTER_FIELD(EL_PENGUIN, newx, newy))
+ return;
+
+ MovDir[x][y] = old_move_dir;
+ return;
+ }
+ }
+ else /* (element == EL_SATELLITE) */
+ {
+ int newx, newy;
+
+ MovDelay[x][y] = 1;
+
+ if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL)
+ {
+ boolean first_horiz = RND(2);
+ int new_move_dir = MovDir[x][y];
+
+ MovDir[x][y] =
+ new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
+ Moving2Blocked(x, y, &newx, &newy);
+
+ if (SATELLITE_CAN_ENTER_FIELD(newx, newy))
+ return;
+
+ MovDir[x][y] =
+ new_move_dir & (!first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
+ Moving2Blocked(x, y, &newx, &newy);
+
+ if (SATELLITE_CAN_ENTER_FIELD(newx, newy))
+ return;
+
+ MovDir[x][y] = old_move_dir;
+ return;
+ }
+ }
+ }
+ else if (move_pattern == MV_TURNING_LEFT ||
+ move_pattern == MV_TURNING_RIGHT ||
+ move_pattern == MV_TURNING_LEFT_RIGHT ||
+ move_pattern == MV_TURNING_RIGHT_LEFT ||
+ move_pattern == MV_TURNING_RANDOM ||
+ move_pattern == MV_ALL_DIRECTIONS)
+ {
+ boolean can_turn_left =
+ CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y);
+ boolean can_turn_right =
+ CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, right_x,right_y);
+
+ if (move_pattern == MV_TURNING_LEFT)
+ MovDir[x][y] = left_dir;
+ else if (move_pattern == MV_TURNING_RIGHT)
+ MovDir[x][y] = right_dir;
+ else if (move_pattern == MV_TURNING_LEFT_RIGHT)
+ MovDir[x][y] = (can_turn_left || !can_turn_right ? left_dir : right_dir);
+ else if (move_pattern == MV_TURNING_RIGHT_LEFT)
+ MovDir[x][y] = (can_turn_right || !can_turn_left ? right_dir : left_dir);
+ else if (move_pattern == MV_TURNING_RANDOM)
+ MovDir[x][y] = (can_turn_left && !can_turn_right ? left_dir :
+ can_turn_right && !can_turn_left ? right_dir :
+ RND(2) ? left_dir : right_dir);
+ else if (can_turn_left && can_turn_right)
+ MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
+ else if (can_turn_left)
+ MovDir[x][y] = (RND(2) ? left_dir : back_dir);
+ else if (can_turn_right)
+ MovDir[x][y] = (RND(2) ? right_dir : back_dir);
+ else
+ MovDir[x][y] = back_dir;
+
+ MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
+ }
+ else if (move_pattern == MV_HORIZONTAL ||
+ move_pattern == MV_VERTICAL)
+ {
+ if (move_pattern & old_move_dir)
+ MovDir[x][y] = back_dir;
+ else if (move_pattern == MV_HORIZONTAL)
+ MovDir[x][y] = (RND(2) ? MV_LEFT : MV_RIGHT);
+ else if (move_pattern == MV_VERTICAL)
+ MovDir[x][y] = (RND(2) ? MV_UP : MV_DOWN);
+
+ MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
+ }
+ else if (move_pattern & MV_ANY_DIRECTION)
+ {
+ MovDir[x][y] = move_pattern;
+ MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
+ }
+ else if (move_pattern == MV_ALONG_LEFT_SIDE)
+ {
+ if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y))
+ MovDir[x][y] = left_dir;
+ else if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y))
+ MovDir[x][y] = right_dir;
+
+ if (MovDir[x][y] != old_move_dir)
+ MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
+ }
+ else if (move_pattern == MV_ALONG_RIGHT_SIDE)
+ {
+ if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, right_x, right_y))
+ MovDir[x][y] = right_dir;
+ else if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y))
+ MovDir[x][y] = left_dir;
+
+ if (MovDir[x][y] != old_move_dir)
+ MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
+ }
+ else if (move_pattern == MV_TOWARDS_PLAYER ||
+ move_pattern == MV_AWAY_FROM_PLAYER)
+ {
+ int attr_x = -1, attr_y = -1;
+ int newx, newy;
+ boolean move_away = (move_pattern == MV_AWAY_FROM_PLAYER);
+
+ if (AllPlayersGone)
+ {
+ attr_x = ExitX;
+ attr_y = ExitY;
+ }
+ else
+ {
+ int i;
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ struct PlayerInfo *player = &stored_player[i];
+ int jx = player->jx, jy = player->jy;
+
+ if (!player->active)
+ continue;
+
+ if (attr_x == -1 ||
+ ABS(jx - x) + ABS(jy - y) < ABS(attr_x - x) + ABS(attr_y - y))
+ {
+ attr_x = jx;
+ attr_y = jy;
+ }
+ }
+ }
+
+ MovDir[x][y] = MV_NO_MOVING;
+ if (attr_x < x)
+ MovDir[x][y] |= (move_away ? MV_RIGHT : MV_LEFT);
+ else if (attr_x > x)
+ MovDir[x][y] |= (move_away ? MV_LEFT : MV_RIGHT);
+ if (attr_y < y)
+ MovDir[x][y] |= (move_away ? MV_DOWN : MV_UP);
+ else if (attr_y > y)
+ MovDir[x][y] |= (move_away ? MV_UP : MV_DOWN);
+
+ MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
+
+ if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL)
+ {
+ boolean first_horiz = RND(2);
+ int new_move_dir = MovDir[x][y];
+
+ MovDir[x][y] =
+ new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
+ Moving2Blocked(x, y, &newx, &newy);
+
+ if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, newx, newy))
+ return;
+
+ MovDir[x][y] =
+ new_move_dir & (!first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
+ Moving2Blocked(x, y, &newx, &newy);
+
+ if (CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, newx, newy))
+ return;
+
+ MovDir[x][y] = old_move_dir;
+ }
+ }
+ else if (move_pattern == MV_WHEN_PUSHED ||
+ move_pattern == MV_WHEN_DROPPED)
+ {
+ if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y))
+ MovDir[x][y] = MV_NO_MOVING;
+
+ MovDelay[x][y] = 0;
+ }
+ else if (move_pattern & MV_MAZE_RUNNER_STYLE)
+ {
+ static int test_xy[7][2] =
+ {
+ { 0, -1 },
+ { -1, 0 },
+ { +1, 0 },
+ { 0, +1 },
+ { 0, -1 },
+ { -1, 0 },
+ { +1, 0 },
+ };
+ static int test_dir[7] =
+ {
+ MV_UP,
+ MV_LEFT,
+ MV_RIGHT,
+ MV_DOWN,
+ MV_UP,
+ MV_LEFT,
+ MV_RIGHT,
+ };
+ boolean hunter_mode = (move_pattern == MV_MAZE_HUNTER);
+ int move_preference = -1000000; /* start with very low preference */
+ int new_move_dir = MV_NO_MOVING;
+ int start_test = RND(4);
+ int i;
+
+ for (i = 0; i < NUM_DIRECTIONS; i++)
+ {
+ int move_dir = test_dir[start_test + i];
+ int move_dir_preference;
+
+ xx = x + test_xy[start_test + i][0];
+ yy = y + test_xy[start_test + i][1];
+
+ if (hunter_mode && IN_LEV_FIELD(xx, yy) &&
+ (IS_PLAYER(xx, yy) || Feld[xx][yy] == EL_PLAYER_IS_LEAVING))
+ {
+ new_move_dir = move_dir;
+
+ break;
+ }
+
+ if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, xx, yy))
+ continue;
+
+ move_dir_preference = -1 * RunnerVisit[xx][yy];
+ if (hunter_mode && PlayerVisit[xx][yy] > 0)
+ move_dir_preference = PlayerVisit[xx][yy];
+
+ if (move_dir_preference > move_preference)
+ {
+ /* prefer field that has not been visited for the longest time */
+ move_preference = move_dir_preference;
+ new_move_dir = move_dir;
+ }
+ else if (move_dir_preference == move_preference &&
+ move_dir == old_move_dir)
+ {
+ /* prefer last direction when all directions are preferred equally */
+ move_preference = move_dir_preference;
+ new_move_dir = move_dir;
+ }
+ }
+
+ MovDir[x][y] = new_move_dir;
+ if (old_move_dir != new_move_dir)
+ {
+#if 1
+ MovDelay[x][y] = GET_NEW_MOVE_DELAY(element);
+#else
+ MovDelay[x][y] = 9;
+#endif
+ }
+ }
+}
+
+static void TurnRound(int x, int y)
+{
+ int direction = MovDir[x][y];
+
+#if 0
+ GfxDir[x][y] = MovDir[x][y];
+#endif
+
+ TurnRoundExt(x, y);
+
+#if 1
+ GfxDir[x][y] = MovDir[x][y];
+#endif
+
+ if (direction != MovDir[x][y])
+ GfxFrame[x][y] = 0;
+
+#if 1
+ if (MovDelay[x][y])
+ GfxAction[x][y] = ACTION_TURNING_FROM_LEFT + MV_DIR_BIT(direction);
+#else
+ if (MovDelay[x][y])
+ GfxAction[x][y] = ACTION_WAITING;
+#endif
+}
+
+static boolean JustBeingPushed(int x, int y)
+{
+ int i;
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ struct PlayerInfo *player = &stored_player[i];
+
+ if (player->active && player->is_pushing && player->MovPos)
+ {
+ int next_jx = player->jx + (player->jx - player->last_jx);
+ int next_jy = player->jy + (player->jy - player->last_jy);
+
+ if (x == next_jx && y == next_jy)
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+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];
+
+ if (Stop[x][y])
+ return;
+
+#if 1
+ if (MovDelay[x][y] == 0)
+ GfxAction[x][y] = ACTION_DEFAULT;
+#else
+ /* !!! this should be handled more generic (not only for mole) !!! */
+ if (element != EL_MOLE && GfxAction[x][y] != ACTION_DIGGING)
+ GfxAction[x][y] = ACTION_DEFAULT;
+#endif
+
+ if (CAN_FALL(element) && y < lev_fieldy - 1)
+ {
+ if ((x > 0 && IS_PLAYER(x - 1, y)) ||
+ (x < lev_fieldx - 1 && IS_PLAYER(x + 1, y)))
+ if (JustBeingPushed(x, y))
+ return;
+
+ if (element == EL_QUICKSAND_FULL)
+ {
+ if (IS_FREE(x, y + 1))
+ {
+ InitMovingField(x, y, MV_DOWN);
+ started_moving = TRUE;
+
+ Feld[x][y] = EL_QUICKSAND_EMPTYING;
+ Store[x][y] = EL_ROCK;
+#if 1
+ PlayLevelSoundAction(x, y, ACTION_EMPTYING);
+#else
+ PlayLevelSound(x, y, SND_QUICKSAND_EMPTYING);
+#endif
+ }
+ else if (Feld[x][y + 1] == EL_QUICKSAND_EMPTY)
+ {
+ if (!MovDelay[x][y])
+ MovDelay[x][y] = TILEY + 1;
+
+ if (MovDelay[x][y])
+ {
+ MovDelay[x][y]--;
+ if (MovDelay[x][y])
+ return;
+ }
+
+ Feld[x][y] = EL_QUICKSAND_EMPTY;
+ Feld[x][y + 1] = EL_QUICKSAND_FULL;
+ Store[x][y + 1] = Store[x][y];
+ Store[x][y] = 0;
+#if 1
+ PlayLevelSoundAction(x, y, ACTION_FILLING);
+#else
+ PlayLevelSound(x, y, SND_QUICKSAND_FILLING);
+#endif
+ }
+ }
+ else if ((element == EL_ROCK || element == EL_BD_ROCK) &&
+ Feld[x][y + 1] == EL_QUICKSAND_EMPTY)
+ {
+ InitMovingField(x, y, MV_DOWN);
+ started_moving = TRUE;
+
+ Feld[x][y] = EL_QUICKSAND_FILLING;
+ Store[x][y] = element;
+#if 1
+ PlayLevelSoundAction(x, y, ACTION_FILLING);
+#else
+ PlayLevelSound(x, y, SND_QUICKSAND_FILLING);
+#endif
+ }
+ else if (element == EL_MAGIC_WALL_FULL)
+ {
+ if (IS_FREE(x, y + 1))
+ {
+ InitMovingField(x, y, MV_DOWN);
+ started_moving = TRUE;
+
+ Feld[x][y] = EL_MAGIC_WALL_EMPTYING;
+ Store[x][y] = EL_CHANGED(Store[x][y]);
+ }
+ else if (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE)
+ {
+ if (!MovDelay[x][y])
+ MovDelay[x][y] = TILEY/4 + 1;
+
+ if (MovDelay[x][y])
+ {
+ MovDelay[x][y]--;
+ if (MovDelay[x][y])
+ return;
+ }
+
+ Feld[x][y] = EL_MAGIC_WALL_ACTIVE;
+ Feld[x][y + 1] = EL_MAGIC_WALL_FULL;
+ Store[x][y + 1] = EL_CHANGED(Store[x][y]);
+ Store[x][y] = 0;
+ }
+ }
+ else if (element == EL_BD_MAGIC_WALL_FULL)
+ {
+ if (IS_FREE(x, y + 1))
+ {
+ InitMovingField(x, y, MV_DOWN);
+ started_moving = TRUE;
+
+ Feld[x][y] = EL_BD_MAGIC_WALL_EMPTYING;
+ Store[x][y] = EL_CHANGED2(Store[x][y]);
+ }
+ else if (Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE)
+ {
+ if (!MovDelay[x][y])
+ MovDelay[x][y] = TILEY/4 + 1;
+
+ if (MovDelay[x][y])
+ {
+ MovDelay[x][y]--;
+ if (MovDelay[x][y])
+ return;
+ }
+
+ Feld[x][y] = EL_BD_MAGIC_WALL_ACTIVE;
+ Feld[x][y + 1] = EL_BD_MAGIC_WALL_FULL;
+ Store[x][y + 1] = EL_CHANGED2(Store[x][y]);
+ Store[x][y] = 0;
+ }
+ }
+ else if (CAN_PASS_MAGIC_WALL(element) &&
+ (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE ||
+ Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE))
+ {
+ InitMovingField(x, y, MV_DOWN);
+ started_moving = TRUE;
+
+ Feld[x][y] =
+ (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE ? EL_MAGIC_WALL_FILLING :
+ EL_BD_MAGIC_WALL_FILLING);
+ Store[x][y] = element;
+ }
+#if 0
+ else if (CAN_SMASH(element) && Feld[x][y + 1] == EL_ACID)
+#else
+ else if (CAN_FALL(element) && Feld[x][y + 1] == EL_ACID)
+#endif
+ {
+ SplashAcid(x, y + 1);
+
+ InitMovingField(x, y, MV_DOWN);
+ started_moving = TRUE;
+
+ Store[x][y] = EL_ACID;
+#if 0
+ /* !!! TEST !!! better use "_FALLING" etc. !!! */
+ GfxAction[x][y + 1] = ACTION_ACTIVE;
+#endif
+ }
+#if 1
+ else if ((game.engine_version >= VERSION_IDENT(3,1,0,0) &&
+ CheckCollision[x][y] && !IS_FREE(x, y + 1)) ||
+
+ (game.engine_version >= VERSION_IDENT(3,0,7,0) &&
+ CAN_SMASH(element) && WasJustFalling[x][y] &&
+ (Feld[x][y + 1] == EL_BLOCKED || IS_PLAYER(x, y + 1))) ||
+
+ (game.engine_version < VERSION_IDENT(2,2,0,7) &&
+ CAN_SMASH(element) && WasJustMoving[x][y] && !Pushed[x][y + 1] &&
+ (Feld[x][y + 1] == EL_BLOCKED)))
+
+#else
+#if 1
+ else if (game.engine_version < VERSION_IDENT(2,2,0,7) &&
+ CAN_SMASH(element) && Feld[x][y + 1] == EL_BLOCKED &&
+ WasJustMoving[x][y] && !Pushed[x][y + 1])
+#else
+ else if (CAN_SMASH(element) && Feld[x][y + 1] == EL_BLOCKED &&
+ WasJustMoving[x][y])
+#endif
+#endif
+
+ {
+ /* this is needed for a special case not covered by calling "Impact()"
+ from "ContinueMoving()": if an element moves to a tile directly below
+ another element which was just falling on that tile (which was empty
+ in the previous frame), the falling element above would just stop
+ instead of smashing the element below (in previous version, the above
+ element was just checked for "moving" instead of "falling", resulting
+ in incorrect smashes caused by horizontal movement of the above
+ element; also, the case of the player being the element to smash was
+ simply not covered here... :-/ ) */
+
+#if 0
+ WasJustMoving[x][y] = 0;
+ WasJustFalling[x][y] = 0;
+#endif
+
+ CheckCollision[x][y] = 0;
+
+#if 0
+ if (IS_PLAYER(x, y + 1))
+ printf("::: we ARE now killing the player [%d]\n", FrameCounter);
+#endif
+
+ Impact(x, y);
+ }
+ else if (IS_FREE(x, y + 1) && element == EL_SPRING && level.use_spring_bug)
+ {
+ if (MovDir[x][y] == MV_NO_MOVING)
+ {
+ InitMovingField(x, y, MV_DOWN);
+ started_moving = TRUE;
+ }
+ }
+ else if (IS_FREE(x, y + 1) || Feld[x][y + 1] == EL_DIAMOND_BREAKING)
+ {
+ if (WasJustFalling[x][y]) /* prevent animation from being restarted */
+ MovDir[x][y] = MV_DOWN;
+
+ InitMovingField(x, y, MV_DOWN);
+ started_moving = TRUE;
+ }
+ else if (element == EL_AMOEBA_DROP)
+ {
+ Feld[x][y] = EL_AMOEBA_GROWING;
+ Store[x][y] = EL_AMOEBA_WET;
+ }
+ /* Store[x][y + 1] must be zero, because:
+ (EL_QUICKSAND_FULL -> EL_ROCK): Store[x][y + 1] == EL_QUICKSAND_EMPTY
+ */
+#if 0
+#if OLD_GAME_BEHAVIOUR
+ else if (IS_SLIPPERY(Feld[x][y + 1]) && !Store[x][y + 1])
+#else
+ else if (IS_SLIPPERY(Feld[x][y + 1]) && !Store[x][y + 1] &&
+ !IS_FALLING(x, y + 1) && !WasJustMoving[x][y + 1] &&
+ element != EL_DX_SUPABOMB)
+#endif
+#else
+ else if (((IS_SLIPPERY(Feld[x][y + 1]) && !IS_PLAYER(x, y + 1)) ||
+ (IS_EM_SLIPPERY_WALL(Feld[x][y + 1]) && IS_GEM(element))) &&
+ !IS_FALLING(x, y + 1) && !WasJustMoving[x][y + 1] &&
+ element != EL_DX_SUPABOMB && element != EL_SP_DISK_ORANGE)
+#endif
+ {
+ boolean can_fall_left = (x > 0 && IS_FREE(x - 1, y) &&
+ (IS_FREE(x - 1, y + 1) ||
+ Feld[x - 1][y + 1] == EL_ACID));
+ boolean can_fall_right = (x < lev_fieldx - 1 && IS_FREE(x + 1, y) &&
+ (IS_FREE(x + 1, y + 1) ||
+ Feld[x + 1][y + 1] == EL_ACID));
+ boolean can_fall_any = (can_fall_left || can_fall_right);
+ boolean can_fall_both = (can_fall_left && can_fall_right);
+
+ if (can_fall_any && IS_CUSTOM_ELEMENT(Feld[x][y + 1]))
+ {
+ int slippery_type = element_info[Feld[x][y + 1]].slippery_type;
+
+ if (slippery_type == SLIPPERY_ONLY_LEFT)
+ can_fall_right = FALSE;
+ else if (slippery_type == SLIPPERY_ONLY_RIGHT)
+ can_fall_left = FALSE;
+ else if (slippery_type == SLIPPERY_ANY_LEFT_RIGHT && can_fall_both)
+ can_fall_right = FALSE;
+ else if (slippery_type == SLIPPERY_ANY_RIGHT_LEFT && can_fall_both)
+ can_fall_left = FALSE;
+
+ can_fall_any = (can_fall_left || can_fall_right);
+ can_fall_both = (can_fall_left && can_fall_right);
+ }
+
+#if USE_NEW_SP_SLIPPERY
+ /* !!! better use the same properties as for custom elements here !!! */
+ else if (game.engine_version >= VERSION_IDENT(3,1,1,0) &&
+ can_fall_both && IS_SP_ELEMENT(Feld[x][y + 1]))
+ {
+ can_fall_right = FALSE; /* slip down on left side */
+ can_fall_both = FALSE;
+ }
+#endif
+
+#if 1
+ if (can_fall_both)
+ {
+ if (game.emulation == EMU_BOULDERDASH ||
+ element == EL_BD_ROCK || element == EL_BD_DIAMOND)
+ can_fall_right = FALSE; /* slip down on left side */
+ else
+ can_fall_left = !(can_fall_right = RND(2));
+
+ can_fall_both = FALSE;
+ }
+#endif
+
+ if (can_fall_any)
+ {
+#if 0
+ if (can_fall_both &&
+ (game.emulation != EMU_BOULDERDASH &&
+ element != EL_BD_ROCK && element != EL_BD_DIAMOND))
+ can_fall_left = !(can_fall_right = RND(2));
+#endif
+
+ /* if not determined otherwise, prefer left side for slipping down */
+ InitMovingField(x, y, can_fall_left ? MV_LEFT : MV_RIGHT);
+ started_moving = TRUE;
+ }
+ }
+#if 0
+ else if (IS_BELT_ACTIVE(Feld[x][y + 1]) && !CAN_MOVE(element))
+#else
+ else if (IS_BELT_ACTIVE(Feld[x][y + 1]))
+#endif
+ {
+ boolean left_is_free = (x > 0 && IS_FREE(x - 1, y));
+ boolean right_is_free = (x < lev_fieldx - 1 && IS_FREE(x + 1, y));
+ int belt_nr = getBeltNrFromBeltActiveElement(Feld[x][y + 1]);
+ int belt_dir = game.belt_dir[belt_nr];
+
+ if ((belt_dir == MV_LEFT && left_is_free) ||
+ (belt_dir == MV_RIGHT && right_is_free))
+ {
+#if 1
+ int nextx = (belt_dir == MV_LEFT ? x - 1 : x + 1);
+#endif
+
+ InitMovingField(x, y, belt_dir);
+ started_moving = TRUE;
+
+#if 1
+ Pushed[x][y] = TRUE;
+ Pushed[nextx][y] = TRUE;
+#endif
+
+ GfxAction[x][y] = ACTION_DEFAULT;
+ }
+ else
+ {
+ MovDir[x][y] = 0; /* if element was moving, stop it */
+ }
+ }
+ }
+
+ /* not "else if" because of elements that can fall and move (EL_SPRING) */
+#if 0
+ if (CAN_MOVE(element) && !started_moving && MovDir[x][y] != MV_NO_MOVING)
+#else
+ if (CAN_MOVE(element) && !started_moving)
+#endif
+ {
+ int move_pattern = element_info[element].move_pattern;
+ int newx, newy;
+
+#if 0
+#if DEBUG
+ if (MovDir[x][y] == MV_NO_MOVING)
+ {
+ printf("StartMoving(): %d,%d: element %d ['%s'] not moving\n",
+ x, y, element, element_info[element].token_name);
+ printf("StartMoving(): This should never happen!\n");
+ }
+#endif
+#endif
+
+ Moving2Blocked(x, y, &newx, &newy);
+
+#if 1
+ if (IS_PUSHABLE(element) && JustBeingPushed(x, y))
+ return;
+#else
+ if ((element == EL_SATELLITE ||
+ element == EL_BALLOON ||
+ element == EL_SPRING)
+ && JustBeingPushed(x, y))
+ return;
+#endif
+
+#if 1
+
+#if 1
+ if (game.engine_version >= VERSION_IDENT(3,1,0,0) &&
+ CheckCollision[x][y] && !IN_LEV_FIELD_AND_IS_FREE(newx, newy))
+#else
+ if (game.engine_version >= VERSION_IDENT(3,1,0,0) &&
+ WasJustMoving[x][y] && IN_LEV_FIELD(newx, newy) &&
+ (Feld[newx][newy] == EL_BLOCKED || IS_PLAYER(newx, newy)))
+#endif
+ {
+#if 0
+ printf("::: element %d '%s' WasJustMoving %d [%d, %d, %d, %d]\n",
+ element, element_info[element].token_name,
+ WasJustMoving[x][y],
+ HAS_ANY_CHANGE_EVENT(element, CE_HITTING_SOMETHING),
+ HAS_ANY_CHANGE_EVENT(element, CE_HIT_BY_SOMETHING),
+ HAS_ANY_CHANGE_EVENT(element, CE_OTHER_IS_HITTING),
+ HAS_ANY_CHANGE_EVENT(element, CE_OTHER_GETS_HIT));
+#endif
+
+#if 1
+ WasJustMoving[x][y] = 0;
+#endif
+
+ CheckCollision[x][y] = 0;
+
+ TestIfElementHitsCustomElement(x, y, MovDir[x][y]);
+
+#if 0
+ if (Feld[x][y] != element) /* element has changed */
+ {
+ element = Feld[x][y];
+ move_pattern = element_info[element].move_pattern;
+
+ if (!CAN_MOVE(element))
+ return;
+ }
+#else
+ if (Feld[x][y] != element) /* element has changed */
+ return;
+#endif
+ }
+#endif
+
+#if 0
+#if 0
+ if (element == EL_SPRING && MovDir[x][y] == MV_DOWN)
+ Feld[x][y + 1] = EL_EMPTY; /* was set to EL_BLOCKED above */
+#else
+ if (element == EL_SPRING && MovDir[x][y] != MV_NO_MOVING)
+ {
+ Moving2Blocked(x, y, &newx, &newy);
+ if (Feld[newx][newy] == EL_BLOCKED)
+ Feld[newx][newy] = EL_EMPTY; /* was set to EL_BLOCKED above */
+ }
+#endif
+#endif
+
+#if 0
+ if (FrameCounter < 1 && x == 0 && y == 29)
+ printf(":1: %d/%d: %d [%d]\n", x, y, MovDir[x][y], FrameCounter);
+#endif
+
+ if (!MovDelay[x][y]) /* start new movement phase */
+ {
+ /* all objects that can change their move direction after each step
+ (YAMYAM, DARK_YAMYAM and PACMAN go straight until they hit a wall */
+
+ if (element != EL_YAMYAM &&
+ element != EL_DARK_YAMYAM &&
+ element != EL_PACMAN &&
+ !(move_pattern & MV_ANY_DIRECTION) &&
+ move_pattern != MV_TURNING_LEFT &&
+ move_pattern != MV_TURNING_RIGHT &&
+ move_pattern != MV_TURNING_LEFT_RIGHT &&
+ move_pattern != MV_TURNING_RIGHT_LEFT &&
+ move_pattern != MV_TURNING_RANDOM)
+ {
+ TurnRound(x, y);
+
+#if 0
+ if (FrameCounter < 1 && x == 0 && y == 29)
+ printf(":9: %d: %d [%d]\n", y, MovDir[x][y], FrameCounter);
+#endif
+
+ if (MovDelay[x][y] && (element == EL_BUG ||