rnd-20030628-2-src
[rocksndiamonds.git] / src / game.c
index 4318a1aea73572056c8dee289725c6879ddad6d7..30af0fcbbd7a50affb604b234f7da58d87e9e1bd 100644 (file)
                                        (condition)))
 
 #define ELEMENT_CAN_ENTER_FIELD(e, x, y)                               \
-       ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, 1)
+       ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, 0)
 
 #define ELEMENT_CAN_ENTER_FIELD_OR_ACID(e, x, y)                       \
        ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, (Feld[x][y] == EL_ACID))
 
 #define PENGUIN_CAN_ENTER_FIELD(x, y)                                  \
                (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) ||                \
-                                       IS_FOOD_PIG(Feld[x][y]) ||      \
+                                       IS_FOOD_PENGUIN(Feld[x][y]) ||  \
                                        Feld[x][y] == EL_EXIT_OPEN ||   \
                                        Feld[x][y] == EL_ACID))
 
@@ -750,6 +750,33 @@ static void InitGameEngine()
     if (HAS_CHANGE_EVENT(i, CE_BY_OTHER))
       trigger_events[element_info[i].change.trigger] |=
        element_info[i].change.events;
+
+  /* set push delay value for all non-custom elements */
+  for (i=0; i<MAX_NUM_ELEMENTS; i++)
+  {
+    if (!IS_CUSTOM_ELEMENT(i))
+    {
+      if (i == EL_SPRING ||
+         i == EL_BALLOON)
+      {
+       element_info[i].push_delay_fixed = 0;
+       element_info[i].push_delay_random = 0;
+      }
+      else if (i == EL_SOKOBAN_OBJECT ||
+              i == EL_SOKOBAN_FIELD_FULL ||
+              i == EL_SATELLITE ||
+              i == EL_SP_DISK_YELLOW)
+      {
+       element_info[i].push_delay_fixed = 2;
+       element_info[i].push_delay_random = 0;
+      }
+      else
+      {
+       element_info[i].push_delay_fixed = 2;
+       element_info[i].push_delay_random = 8;
+      }
+    }
+  }
 }
 
 
@@ -828,7 +855,6 @@ void InitGame()
     player->actual_frame_counter = 0;
 
     player->last_move_dir = MV_NO_MOVING;
-    player->is_moving = FALSE;
 
     player->is_moving = FALSE;
     player->is_waiting = FALSE;
@@ -908,6 +934,7 @@ void InitGame()
       AmoebaNr[x][y] = 0;
       JustStopped[x][y] = 0;
       Stop[x][y] = FALSE;
+      Pushed[x][y] = FALSE;
       ExplodePhase[x][y] = 0;
       ExplodeField[x][y] = EX_NO_EXPLOSION;
 
@@ -1212,7 +1239,9 @@ void InitMovDir(int x, int y)
       {
        if (element_info[element].move_direction_initial != MV_NO_MOVING)
          MovDir[x][y] = element_info[element].move_direction_initial;
-       else if (element_info[element].move_pattern == MV_ALL_DIRECTIONS)
+       else if (element_info[element].move_pattern == MV_ALL_DIRECTIONS ||
+                element_info[element].move_pattern == MV_TURNING_LEFT ||
+                element_info[element].move_pattern == MV_TURNING_RIGHT)
          MovDir[x][y] = 1 << RND(4);
        else if (element_info[element].move_pattern == MV_HORIZONTAL)
          MovDir[x][y] = (RND(2) ? MV_LEFT : MV_RIGHT);
@@ -1505,8 +1534,10 @@ static void ResetGfxAnimation(int x, int y)
 void InitMovingField(int x, int y, int direction)
 {
   int element = Feld[x][y];
-  int newx = x + (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
-  int newy = y + (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
+  int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
+  int dy = (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
+  int newx = x + dx;
+  int newy = y + dy;
 
   if (!JustStopped[x][y] || direction != MovDir[x][y])
     ResetGfxAnimation(x, y);
@@ -1600,6 +1631,7 @@ static void RemoveField(int x, int y)
   MovDir[x][y] = 0;
   MovDelay[x][y] = 0;
   ChangeDelay[x][y] = 0;
+  Pushed[x][y] = FALSE;
 }
 
 void RemoveMovingField(int x, int y)
@@ -3015,12 +3047,18 @@ void TurnRound(int x, int y)
       }
     }
   }
-  else if (element_info[element].move_pattern == MV_ALL_DIRECTIONS)
+  else if (element_info[element].move_pattern == MV_ALL_DIRECTIONS ||
+          element_info[element].move_pattern == MV_TURNING_LEFT ||
+          element_info[element].move_pattern == MV_TURNING_RIGHT)
   {
     boolean can_turn_left  = ELEMENT_CAN_ENTER_FIELD(element, left_x, left_y);
     boolean can_turn_right = ELEMENT_CAN_ENTER_FIELD(element, right_x,right_y);
 
-    if (can_turn_left && can_turn_right)
+    if (element_info[element].move_pattern == MV_TURNING_LEFT)
+      MovDir[x][y] = left_dir;
+    else if (element_info[element].move_pattern == MV_TURNING_RIGHT)
+      MovDir[x][y] = 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);
@@ -3313,11 +3351,26 @@ void StartMoving(int x, int y)
       GfxAction[x][y + 1] = ACTION_ACTIVE;
 #endif
     }
+#if 1
+#if 1
+    else if (game.engine_version < RELEASE_IDENT(2,2,0,7) &&
+            CAN_SMASH(element) && Feld[x][y + 1] == EL_BLOCKED &&
+            JustStopped[x][y] && !Pushed[x][y + 1])
+#else
     else if (CAN_SMASH(element) && Feld[x][y + 1] == EL_BLOCKED &&
             JustStopped[x][y])
+#endif
     {
+      /* calling "Impact()" here is not only completely unneccessary
+        (because it already gets called from "ContinueMoving()" in
+        all relevant situations), but also completely bullshit, because
+        "JustStopped" also indicates a finished *horizontal* movement;
+        we must keep this trash for backwards compatibility with older
+        tapes */
+
       Impact(x, y);
     }
+#endif
     else if (IS_FREE(x, y + 1) && element == EL_SPRING && use_spring_bug)
     {
       if (MovDir[x][y] == MV_NO_MOVING)
@@ -3351,7 +3404,7 @@ void StartMoving(int x, int y)
             element != EL_DX_SUPABOMB)
 #endif
 #else
-    else if ((IS_SLIPPERY(Feld[x][y + 1]) ||
+    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) && !JustStopped[x][y + 1] &&
             element != EL_DX_SUPABOMB && element != EL_SP_DISK_ORANGE)
@@ -3371,6 +3424,11 @@ void StartMoving(int x, int y)
 
        InitMovingField(x, y, left ? MV_LEFT : MV_RIGHT);
        started_moving = TRUE;
+
+#if 0
+       if (element == EL_BOMB)
+         printf("::: SLIP DOWN [%d]\n", FrameCounter);
+#endif
       }
     }
     else if (IS_BELT_ACTIVE(Feld[x][y + 1]))
@@ -3391,7 +3449,7 @@ void StartMoving(int x, int y)
     }
   }
 
-  /* not "else if" because of EL_SPRING */
+  /* not "else if" because of elements that can fall and move (EL_SPRING) */
   if (CAN_MOVE(element) && !started_moving)
   {
     int newx, newy;
@@ -3424,7 +3482,9 @@ void StartMoving(int x, int y)
       if (element != EL_YAMYAM &&
          element != EL_DARK_YAMYAM &&
          element != EL_PACMAN &&
-         !(element_info[element].move_pattern & MV_ANY_DIRECTION))
+         !(element_info[element].move_pattern & MV_ANY_DIRECTION) &&
+         element_info[element].move_pattern != MV_TURNING_LEFT &&
+         element_info[element].move_pattern != MV_TURNING_RIGHT)
       {
        TurnRound(x, y);
 
@@ -3778,6 +3838,17 @@ void ContinueMoving(int x, int y)
   int horiz_move = (dx != 0);
   int newx = x + dx, newy = y + dy;
   int step = (horiz_move ? dx : dy) * TILEX / MOVE_DELAY_NORMAL_SPEED;
+  struct PlayerInfo *player = (IS_PLAYER(x, y) ? PLAYERINFO(x, y) : NULL);
+#if 0
+  boolean pushing = (player != NULL && player->Pushing && player->MovPos != 0);
+#else
+  boolean pushing = (player != NULL && player->Pushing && player->is_moving);
+#endif
+
+#if 0
+  if (player && player->is_moving && player->MovPos == 0)
+    printf("::: !!!\n");
+#endif
 
   if (element == EL_AMOEBA_DROP || element == EL_AMOEBA_DROPPING)
     step /= 2;
@@ -3804,6 +3875,30 @@ void ContinueMoving(int x, int y)
 
   MovPos[x][y] += step;
 
+#if 1
+#if 1
+  if (Pushed[x][y])    /* special case: moving object pushed by player */
+#else
+  if (pushing)         /* special case: moving object pushed by player */
+#endif
+#if 1
+    MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x,y)->MovPos));
+#else
+    MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x,y)->GfxPos));
+#endif
+#endif
+
+#if 0
+  if (element == EL_SPRING)
+    printf("::: spring moves %d [%d: %d, %d, %d/%d]\n",
+          MovPos[x][y],
+          pushing,
+          (player?player->Pushing:-42),
+          (player?player->is_moving:-42),
+          (player?player->MovPos:-42),
+          (player?player->GfxPos:-42));
+#endif
+
   if (ABS(MovPos[x][y]) >= TILEX)      /* object reached its destination */
   {
     Feld[x][y] = EL_EMPTY;
@@ -3879,6 +3974,16 @@ void ContinueMoving(int x, int y)
       Feld[x][y] = get_next_element(element);
       element = Feld[newx][newy] = Store[x][y];
     }
+    else if (element == EL_SOKOBAN_OBJECT)
+    {
+      if (Back[x][y])
+       Feld[x][y] = Back[x][y];
+
+      if (Back[newx][newy])
+       Feld[newx][newy] = EL_SOKOBAN_FIELD_FULL;
+
+      Back[x][y] = Back[newx][newy] = 0;
+    }
     else if (Store[x][y] == EL_ACID)
     {
       element = Feld[newx][newy] = EL_ACID;
@@ -3896,29 +4001,47 @@ void ContinueMoving(int x, int y)
     GfxAction[newx][newy] = GfxAction[x][y];   /* keep action one frame */
     GfxRandom[newx][newy] = GfxRandom[x][y];   /* keep same random value */
 
+    Pushed[x][y] = Pushed[newx][newy] = FALSE;
+
     ResetGfxAnimation(x, y);   /* reset animation values for old field */
 
 #if 1
 #if 0
+    /* 2.1.1 (does not work correctly for spring) */
     if (!CAN_MOVE(element))
       MovDir[newx][newy] = 0;
 #else
-    /*
+
+#if 0
+    /* (does not work for falling objects that slide horizontally) */
     if (CAN_FALL(element) && MovDir[newx][newy] == MV_DOWN)
       MovDir[newx][newy] = 0;
+#else
+    /*
+    if (!CAN_MOVE(element) ||
+       (element == EL_SPRING && MovDir[newx][newy] == MV_DOWN))
+      MovDir[newx][newy] = 0;
     */
 
     if (!CAN_MOVE(element) ||
-       (element == EL_SPRING && MovDir[newx][newy] == MV_DOWN))
+       (CAN_FALL(element) && MovDir[newx][newy] == MV_DOWN))
       MovDir[newx][newy] = 0;
 #endif
+
+#endif
 #endif
 
     DrawLevelField(x, y);
     DrawLevelField(newx, newy);
 
-    Stop[newx][newy] = TRUE;
-    JustStopped[newx][newy] = 3;
+#if 0
+    if (game.engine_version >= RELEASE_IDENT(2,2,0,7) || !pushing)
+#endif
+      Stop[newx][newy] = TRUE; /* ignore this element until the next frame */
+#if 1
+    if (!pushing)
+#endif
+      JustStopped[newx][newy] = 3;
 
     if (DONT_TOUCH(element))   /* object may be nasty to player or others */
     {
@@ -4961,16 +5084,12 @@ static void CheckPlayerElementChange(int x, int y, int element,
   if (!CAN_CHANGE(element) || !HAS_CHANGE_EVENT(element, trigger_event))
     return;
 
-  if (trigger_event == CE_PUSHED_BY_PLAYER)
-  {
-#if 0
-    /* !!! does not work -- debug !!! */
-    ChangeDelay[x][y] = 2;     /* give one frame (+1) to start pushing */
-    ChangeElement(x, y);
+#if 1
+  ChangeDelay[x][y] = 1;
+  ChangeElement(x, y);
+#else
+  ChangeElementDoIt(x, y, element_info[element].change.successor);
 #endif
-  }
-  else
-    ChangeElementDoIt(x, y, element_info[element].change.successor);
 }
 
 static void PlayerActions(struct PlayerInfo *player, byte player_action)
@@ -5139,6 +5258,30 @@ void GameActions()
     stored_player[i].Frame++;
 #endif
 
+#if 1
+  if (game.engine_version < RELEASE_IDENT(2,2,0,7))
+  {
+    for (i=0; i<MAX_PLAYERS; i++)
+    {
+      struct PlayerInfo *player = &stored_player[i];
+      int x = player->jx;
+      int y = player->jy;
+
+      if (player->active && player->Pushing && player->is_moving &&
+         IS_MOVING(x, y))
+      {
+       ContinueMoving(x, y);
+
+       /* continue moving after pushing (this is actually a bug) */
+       if (!IS_MOVING(x, y))
+       {
+         Stop[x][y] = FALSE;
+       }
+      }
+    }
+  }
+#endif
+
   for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
   {
     Stop[x][y] = FALSE;
@@ -6302,6 +6445,7 @@ static boolean checkDiagonalPushing(struct PlayerInfo *player,
 int DigField(struct PlayerInfo *player,
             int x, int y, int real_dx, int real_dy, int mode)
 {
+  boolean use_spring_bug = (game.engine_version < VERSION_IDENT(2,2,0));
   int jx = player->jx, jy = player->jy;
   int dx = x - jx, dy = y - jy;
   int move_direction = (dx == -1 ? MV_LEFT :
@@ -6328,7 +6472,14 @@ int DigField(struct PlayerInfo *player,
   }
 
   if (IS_MOVING(x, y) || IS_PLAYER(x, y))
+  {
+#if 0
+    if (FrameCounter == 437)
+      printf("::: ---> IS_MOVING %d\n", MovDir[x][y]);
+#endif
+
     return MF_NO_ACTION;
+  }
 
 #if 0
   if (IS_TUBE(Feld[jx][jy]) || IS_TUBE(Back[jx][jy]))
@@ -6689,6 +6840,8 @@ int DigField(struct PlayerInfo *player,
       return MF_ACTION;
       break;
 
+#if 0
+
       /* the following elements cannot be pushed by "snapping" */
     case EL_ROCK:
     case EL_BOMB:
@@ -6708,6 +6861,10 @@ int DigField(struct PlayerInfo *player,
       if (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))
+       return MF_NO_ACTION;
+
       player->Pushing = TRUE;
 
 #if 0
@@ -6722,8 +6879,14 @@ int DigField(struct PlayerInfo *player,
       if (!checkDiagonalPushing(player, x, y, real_dx, real_dy))
        return MF_NO_ACTION;
 
+
       if (player->push_delay == 0)
        player->push_delay = FrameCounter;
+
+#if 0
+      printf("want push... %d [%d]\n", FrameCounter, player->push_delay_value);
+#endif
+
 #if 0
       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
          !tape.playing &&
@@ -6743,15 +6906,29 @@ int DigField(struct PlayerInfo *player,
       }
       else
       {
+#if 1
+       InitMovingField(x, y, (dx < 0 ? MV_LEFT :
+                              dx > 0 ? MV_RIGHT :
+                              dy < 0 ? MV_UP : MV_DOWN));
+       MovPos[x][y] = (dx != 0 ? dx : dy);
+#else
        RemoveField(x, y);
        Feld[x + dx][y + dy] = element;
+#endif
       }
 
+#if 0
+      printf("pushing %d/%d ... %d [%d]\n", dx, dy,
+            FrameCounter, player->push_delay_value);
+#endif
+
+#if 0
       if (element == EL_SPRING)
       {
        Feld[x + dx][y + dy] = EL_SPRING;
        MovDir[x + dx][y + dy] = move_direction;
       }
+#endif
 
       player->push_delay_value = (element == EL_SPRING ? 0 : 2 + RND(8));
 
@@ -6762,6 +6939,8 @@ int DigField(struct PlayerInfo *player,
 
       break;
 
+#endif
+
     case EL_GATE_1:
     case EL_GATE_2:
     case EL_GATE_3:
@@ -6946,6 +7125,8 @@ int DigField(struct PlayerInfo *player,
       return MF_ACTION;
       break;
 
+#if 0
+
 #if 0
     case EL_SOKOBAN_FIELD_EMPTY:
       break;
@@ -6985,6 +7166,44 @@ int DigField(struct PlayerInfo *player,
 
       if (IS_SB_ELEMENT(element))
       {
+#if 1
+       if (element == EL_SOKOBAN_FIELD_FULL)
+       {
+         Back[x][y] = EL_SOKOBAN_FIELD_EMPTY;
+         local_player->sokobanfields_still_needed++;
+       }
+
+       if (Feld[x + dx][y + dy] == EL_SOKOBAN_FIELD_EMPTY)
+       {
+         Back[x + dx][y + dy] = EL_SOKOBAN_FIELD_EMPTY;
+         local_player->sokobanfields_still_needed--;
+       }
+
+       Feld[x][y] = EL_SOKOBAN_OBJECT;
+
+       if (Back[x][y] == Back[x + dx][y + dy])
+         PlaySoundLevelAction(x, y, ACTION_PUSHING);
+       else if (Back[x][y] != 0)
+         PlaySoundLevelElementAction(x, y, EL_SOKOBAN_FIELD_FULL,
+                                     ACTION_EMPTYING);
+       else
+         PlaySoundLevelElementAction(x + dx, y + dy, EL_SOKOBAN_FIELD_EMPTY,
+                                     ACTION_FILLING);
+
+       InitMovingField(x, y, (dx < 0 ? MV_LEFT :
+                              dx > 0 ? MV_RIGHT :
+                              dy < 0 ? MV_UP : MV_DOWN));
+       MovPos[x][y] = (dx != 0 ? dx : dy);
+
+#if 0
+       printf("::: %s -> %s [%s -> %s]\n",
+              element_info[Feld[x][y]].token_name,
+              element_info[Feld[x + dx][y + dy]].token_name,
+              element_info[Back[x][y]].token_name,
+              element_info[Back[x + dx][y + dy]].token_name);
+#endif
+
+#else
        if (element == EL_SOKOBAN_FIELD_FULL)
        {
          Feld[x][y] = EL_SOKOBAN_FIELD_EMPTY;
@@ -7026,11 +7245,19 @@ int DigField(struct PlayerInfo *player,
            PlaySoundLevel(x, y, SND_SOKOBAN_OBJECT_PUSHING);
 #endif
        }
+#endif
       }
       else
       {
+#if 1
+       InitMovingField(x, y, (dx < 0 ? MV_LEFT :
+                              dx > 0 ? MV_RIGHT :
+                              dy < 0 ? MV_UP : MV_DOWN));
+       MovPos[x][y] = (dx != 0 ? dx : dy);
+#else
        RemoveField(x, y);
-       Feld[x+dx][y+dy] = element;
+       Feld[x + dx][y + dy] = element;
+#endif
        PlaySoundLevelElementAction(x, y, element, ACTION_PUSHING);
       }
 
@@ -7051,6 +7278,8 @@ int DigField(struct PlayerInfo *player,
 
       break;
 
+#endif
+
     case EL_PENGUIN:
     case EL_PIG:
     case EL_DRAGON:
@@ -7098,19 +7327,29 @@ int DigField(struct PlayerInfo *player,
       }
       else if (IS_PUSHABLE(element))
       {
-       if (mode == DF_SNAP)
+       if (mode == DF_SNAP && element != EL_BD_ROCK)
          return MF_NO_ACTION;
 
        if (CAN_FALL(element) && 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))
+         return MF_NO_ACTION;
+
+       if (element == EL_SPRING && MovDir[x][y] != MV_NO_MOVING)
+         return MF_NO_ACTION;
+
        if (!player->Pushing &&
            game.engine_version >= RELEASE_IDENT(2,2,0,7))
          player->push_delay_value = GET_NEW_PUSH_DELAY(element);
 
        player->Pushing = TRUE;
 
-       if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy))
+       if (!(IN_LEV_FIELD(x + dx, y + dy) &&
+             (IS_FREE(x + dx, y + dy) ||
+              (Feld[x + dx][y + dy] == EL_SOKOBAN_FIELD_EMPTY &&
+               IS_SB_ELEMENT(element)))))
          return MF_NO_ACTION;
 
        if (!checkDiagonalPushing(player, x, y, real_dx, real_dy))
@@ -7120,21 +7359,57 @@ int DigField(struct PlayerInfo *player,
          player->push_delay = FrameCounter;
 
        if (!FrameReached(&player->push_delay, player->push_delay_value) &&
-           !(tape.playing && tape.file_version < FILE_VERSION_2_0))
+           !(tape.playing && tape.file_version < FILE_VERSION_2_0) &&
+           element != EL_SPRING && element != EL_BALLOON)
          return MF_NO_ACTION;
 
-       RemoveField(x, y);
-       Feld[x + dx][y + dy] = element;
+       if (IS_SB_ELEMENT(element))
+       {
+         if (element == EL_SOKOBAN_FIELD_FULL)
+         {
+           Back[x][y] = EL_SOKOBAN_FIELD_EMPTY;
+           local_player->sokobanfields_still_needed++;
+         }
+
+         if (Feld[x + dx][y + dy] == EL_SOKOBAN_FIELD_EMPTY)
+         {
+           Back[x + dx][y + dy] = EL_SOKOBAN_FIELD_EMPTY;
+           local_player->sokobanfields_still_needed--;
+         }
+
+         Feld[x][y] = EL_SOKOBAN_OBJECT;
+
+         if (Back[x][y] == Back[x + dx][y + dy])
+           PlaySoundLevelAction(x, y, ACTION_PUSHING);
+         else if (Back[x][y] != 0)
+           PlaySoundLevelElementAction(x, y, EL_SOKOBAN_FIELD_FULL,
+                                       ACTION_EMPTYING);
+         else
+           PlaySoundLevelElementAction(x + dx, y + dy, EL_SOKOBAN_FIELD_EMPTY,
+                                       ACTION_FILLING);
+
+         if (local_player->sokobanfields_still_needed == 0 &&
+             game.emulation == EMU_SOKOBAN)
+         {
+           player->LevelSolved = player->GameOver = TRUE;
+           PlaySoundLevel(x, y, SND_GAME_SOKOBAN_SOLVING);
+         }
+       }
+       else
+         PlaySoundLevelElementAction(x, y, element, ACTION_PUSHING);
+
+       InitMovingField(x, y, move_direction);
+
+       if (mode == DF_SNAP)
+         ContinueMoving(x, y);
+       else
+         MovPos[x][y] = (dx != 0 ? dx : dy);
+
+       Pushed[x][y] = TRUE;
+       Pushed[x + dx][y + dy] = TRUE;
 
-#if 1
        if (game.engine_version < RELEASE_IDENT(2,2,0,7))
          player->push_delay_value = GET_NEW_PUSH_DELAY(element);
-#else
-       player->push_delay_value = 2 + RND(8);
-#endif
-
-       DrawLevelField(x + dx, y + dy);
-       PlaySoundLevelElementAction(x, y, element, ACTION_PUSHING);
 
        CheckTriggeredElementChange(element, CE_OTHER_PUSHING);
        CheckPlayerElementChange(x, y, element, CE_PUSHED_BY_PLAYER);