rnd-20030210-2-src
[rocksndiamonds.git] / src / game.c
index 0ae6ce5159a9821c9740e9d404a1280ba808a3b1..f86dffae3620dba97bb42b44651eb822562bb30c 100644 (file)
@@ -89,6 +89,8 @@
 #define DOUBLE_PLAYER_SPEED(p) (HALVE_MOVE_DELAY((p)->move_delay_value))
 #define HALVE_PLAYER_SPEED(p)  (DOUBLE_MOVE_DELAY((p)->move_delay_value))
 
+#define        INIT_GFX_RANDOM()       (SimpleRND(1000000))
+
 /* game button identifiers */
 #define GAME_CTRL_ID_STOP              0
 #define GAME_CTRL_ID_PAUSE             1
 #define NUM_GAME_BUTTONS               6
 
 /* forward declaration for internal use */
+#if 0
+static void ResetGfxAnimation(int, int);
+#endif
+
 static void InitBeltMovement(void);
 static void CloseAllOpenTimegates(void);
 static void CheckGravityMovement(struct PlayerInfo *);
@@ -115,9 +121,6 @@ static void HandleGameButtons(struct GadgetInfo *);
 
 static struct GadgetInfo *game_gadget[NUM_GAME_BUTTONS];
 
-#define IS_ANIMATED(g)         (graphic_info[g].anim_frames > 1)
-#define IS_LOOP_SOUND(s)       (sound_info[s].loop)
-
 
 /* ------------------------------------------------------------------------- */
 /* definition of elements that automatically change to other elements after  */
@@ -161,6 +164,9 @@ static struct ChangingElementInfo changing_element_list[] =
   { EL_TIMEGATE_OPENING,       EL_TIMEGATE_OPEN,       29, NULL, NULL, NULL },
   { EL_TIMEGATE_CLOSING,       EL_TIMEGATE_CLOSED,     29, NULL, NULL, NULL },
 
+  { EL_ACID_SPLASH_LEFT,       EL_EMPTY,                8, NULL, NULL, NULL },
+  { EL_ACID_SPLASH_RIGHT,      EL_EMPTY,                8, NULL, NULL, NULL },
+
   { EL_SP_BUGGY_BASE,          EL_SP_BUGGY_BASE_ACTIVATING, 0,
     InitBuggyBase, NULL, NULL },
   { EL_SP_BUGGY_BASE_ACTIVATING,EL_SP_BUGGY_BASE_ACTIVE, 0,
@@ -187,60 +193,6 @@ static struct ChangingElementInfo changing_element[MAX_NUM_ELEMENTS];
 #define IS_AUTO_CHANGING(e)  (changing_element[e].base_element != EL_UNDEFINED)
 
 
-
-#ifdef DEBUG
-#if 0
-static unsigned int getStateCheckSum(int counter)
-{
-  int x, y;
-  unsigned int mult = 1;
-  unsigned int checksum = 0;
-  /*
-  static short lastFeld[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-  */
-  static boolean first_game = TRUE;
-
-  for (y=0; y<lev_fieldy; y++) for(x=0; x<lev_fieldx; x++)
-  {
-    /*
-    if (counter == 3)
-    {
-      if (first_game)
-       lastFeld[x][y] = Feld[x][y];
-      else if (lastFeld[x][y] != Feld[x][y])
-       printf("DIFF: [%d][%d]: lastFeld == %d != %d == Feld\n",
-              x, y, lastFeld[x][y], Feld[x][y]);
-    }
-    */
-
-    checksum += mult++ * Ur[x][y];
-    checksum += mult++ * Feld[x][y];
-
-    /*
-    checksum += mult++ * MovPos[x][y];
-    checksum += mult++ * MovDir[x][y];
-    checksum += mult++ * MovDelay[x][y];
-    checksum += mult++ * Store[x][y];
-    checksum += mult++ * Store2[x][y];
-    checksum += mult++ * StorePlayer[x][y];
-    checksum += mult++ * ExplodePhase[x][y];
-    checksum += mult++ * AmoebaNr[x][y];
-    checksum += mult++ * JustStopped[x][y];
-    checksum += mult++ * Stop[x][y];
-    */
-  }
-
-  if (counter == 3 && first_game)
-    first_game = FALSE;
-
-  return checksum;
-}
-#endif
-#endif
-
-
-
-
 void GetPlayerConfig()
 {
   if (!audio.sound_available)
@@ -773,6 +725,7 @@ void InitGame()
 
       GfxFrame[x][y] = 0;
       GfxAction[x][y] = ACTION_DEFAULT;
+      GfxRandom[x][y] = INIT_GFX_RANDOM();
     }
   }
 
@@ -1301,6 +1254,35 @@ int NewHiScore()
   return position;
 }
 
+static void ResetRandomAnimationValue(int x, int y)
+{
+  GfxRandom[x][y] = INIT_GFX_RANDOM();
+}
+
+static void ResetGfxAnimation(int x, int y)
+{
+#if 0
+#if 1
+  int element = Feld[x][y];
+  int graphic = el2img(element);
+
+  /* reset random value not until one full delay cycle was reached */
+  if (ANIM_MODE(graphic) == ANIM_RANDOM &&
+      GfxFrame[x][y] > ANIM_DELAY(graphic))
+#endif
+    ResetRandomAnimationValue(x, y);
+#endif
+
+  GfxFrame[x][y] = 0;
+  GfxAction[x][y] = ACTION_DEFAULT;
+
+#if 0
+  if (Feld[x][y] == EL_ROCK)
+    printf("ResetGfxAnimation: EL_ROCK [%d, %d]\n",
+          JustStopped[x][y], MovDir[x][y]);
+#endif
+}
+
 void InitMovingField(int x, int y, int direction)
 {
   int element = Feld[x][y];
@@ -1308,10 +1290,9 @@ void InitMovingField(int x, int y, int direction)
   int newy = y + (direction == MV_UP   ? -1 : direction == MV_DOWN  ? +1 : 0);
 
   if (!JustStopped[x][y] || direction != MovDir[x][y])
-    GfxFrame[x][y] = 0;
+    ResetGfxAnimation(x, y);
 
-  MovDir[x][y] = direction;
-  MovDir[newx][newy] = direction;
+  MovDir[newx][newy] = MovDir[x][y] = direction;
 
   if (Feld[newx][newy] == EL_EMPTY)
     Feld[newx][newy] = EL_BLOCKED;
@@ -1320,6 +1301,10 @@ void InitMovingField(int x, int y, int direction)
     GfxAction[x][y] = ACTION_FALLING;
   else
     GfxAction[x][y] = ACTION_MOVING;
+
+  GfxFrame[newx][newy] = GfxFrame[x][y];
+  GfxAction[newx][newy] = GfxAction[x][y];
+  GfxRandom[newx][newy] = GfxRandom[x][y];
 }
 
 void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y)
@@ -1460,17 +1445,15 @@ void DrawDynamite(int x, int y)
 
 void CheckDynamite(int x, int y)
 {
-  int element = Feld[x][y];
-
   if (MovDelay[x][y] != 0)     /* dynamite is still waiting to explode */
   {
     MovDelay[x][y]--;
 
     if (MovDelay[x][y] != 0)
     {
-      if (checkDrawLevelGraphicAnimation(x, y, el2img(element)))
-       DrawDynamite(x, y);
+      DrawDynamite(x, y);
 
+      /* !!! correct: "PlaySoundLevelActionIfLoop" etc. !!! */
       PlaySoundLevelAction(x, y, ACTION_ACTIVE);
 
       return;
@@ -1802,27 +1785,27 @@ void Bang(int x, int y)
   }
 }
 
-void Blurb(int x, int y)
+void SplashAcid(int x, int y)
 {
   int element = Feld[x][y];
 
   if (element != EL_ACID_SPLASH_LEFT &&
-      element != EL_ACID_SPLASH_RIGHT) /* start */
+      element != EL_ACID_SPLASH_RIGHT)
   {
     PlaySoundLevel(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_RIGHT;
-    }
   }
+
+#if 0
   else                                                         /* go on */
   {
     int graphic = (element == EL_ACID_SPLASH_LEFT ?
@@ -1849,6 +1832,7 @@ void Blurb(int x, int y)
       }
     }
   }
+#endif
 }
 
 static void InitBeltMovement()
@@ -2163,18 +2147,29 @@ void Impact(int x, int y)
       return;
 
     object_hit = (!IS_FREE(x, y+1) && (!IS_MOVING(x, y+1) ||
-                                     MovDir[x][y+1]!=MV_DOWN ||
-                                     MovPos[x][y+1]<=TILEY/2));
+                                     MovDir[x][y+1] != MV_DOWN ||
+                                     MovPos[x][y+1] <= TILEY / 2));
     if (object_hit)
       smashed = MovingOrBlocked2Element(x, y+1);
   }
 
   if (!lastline && smashed == EL_ACID) /* element falls into acid */
   {
-    Blurb(x, y);
+    SplashAcid(x, y);
     return;
   }
 
+#if 1
+  if (lastline || object_hit)
+  {
+#if 0
+    MovDir[x][y] = 0;
+#endif
+    ResetGfxAnimation(x, y);
+    DrawLevelField(x, y);
+  }
+#endif
+
   if ((element == EL_BOMB ||
        element == EL_SP_DISK_ORANGE ||
        element == EL_DX_SUPABOMB) &&
@@ -2200,6 +2195,8 @@ void Impact(int x, int y)
     {
       Feld[x][y] = EL_AMOEBA_CREATING;
       Store[x][y] = EL_AMOEBA_WET;
+
+      ResetRandomAnimationValue(x, y);
     }
     return;
   }
@@ -2330,6 +2327,13 @@ void Impact(int x, int y)
     return;
   }
 
+#if 0
+  printf("::: -> %d,%d [%d]\n", element, ACTION_IMPACT,
+        element_info[element].sound[ACTION_IMPACT]);
+
+  PlaySound(177);
+#endif
+
   /* play sound of object that hits the ground */
   if (lastline || object_hit)
     PlaySoundLevelElementAction(x, y, element, ACTION_IMPACT);
@@ -2903,9 +2907,13 @@ void StartMoving(int x, int y)
         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
     {
-      Blurb(x, y);
+      SplashAcid(x, y);
 
       InitMovingField(x, y, MV_DOWN);
       started_moving = TRUE;
@@ -2927,6 +2935,9 @@ void StartMoving(int x, int y)
     }
     else if (IS_FREE(x, y+1))
     {
+      if (JustStopped[x][y])   /* prevent animation from being restarted */
+       MovDir[x][y] = MV_DOWN;
+
       InitMovingField(x, y, MV_DOWN);
       started_moving = TRUE;
     }
@@ -3044,8 +3055,12 @@ void StartMoving(int x, int y)
       MovDelay[x][y]--;
 
       if (element == EL_ROBOT ||
-         element == EL_YAMYAM || element == EL_DARK_YAMYAM)
+         element == EL_YAMYAM ||
+         element == EL_DARK_YAMYAM)
       {
+#if 1
+       DrawLevelElementAnimationIfNeeded(x, y, element);
+#else
        if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
        {
          int graphic = el2img(element);
@@ -3053,7 +3068,11 @@ void StartMoving(int x, int y)
 
          DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
        }
+#endif
 
+#if 1
+       PlaySoundLevelAction(x, y, ACTION_WAITING);
+#else
        if (MovDelay[x][y] % 4 == 3)
        {
          if (element == EL_YAMYAM)
@@ -3061,9 +3080,10 @@ void StartMoving(int x, int y)
          else if (element == EL_DARK_YAMYAM)
            PlaySoundLevel(x, y, SND_DARK_YAMYAM_WAITING);
        }
+#endif
       }
       else if (element == EL_SP_ELECTRON)
-       DrawLevelElementAnimation(x, y, element);
+       DrawLevelElementAnimationIfNeeded(x, y, element);
       else if (element == EL_DRAGON)
       {
        int i;
@@ -3140,7 +3160,7 @@ void StartMoving(int x, int y)
             IN_LEV_FIELD(newx, newy) &&
             MovDir[x][y] == MV_DOWN && Feld[newx][newy] == EL_ACID)
     {
-      Blurb(x, y);
+      SplashAcid(x, y);
       Store[x][y] = EL_ACID;
     }
     else if (element == EL_PENGUIN && IN_LEV_FIELD(newx, newy))
@@ -3321,11 +3341,11 @@ void StartMoving(int x, int y)
               element == EL_SP_SNIKSNAK || element == EL_MOLE)
        DrawLevelField(x, y);
       else if (element == EL_BD_BUTTERFLY || element == EL_BD_FIREFLY)
-       DrawLevelElementAnimation(x, y, element);
+       DrawLevelElementAnimationIfNeeded(x, y, element);
       else if (element == EL_SATELLITE)
-       DrawLevelElementAnimation(x, y, element);
+       DrawLevelElementAnimationIfNeeded(x, y, element);
       else if (element == EL_SP_ELECTRON)
-       DrawLevelElementAnimation(x, y, element);
+       DrawLevelElementAnimationIfNeeded(x, y, element);
 
       if (DONT_TOUCH(element))
        TestIfBadThingTouchesHero(x, y);
@@ -3460,9 +3480,20 @@ void ContinueMoving(int x, int y)
     MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
     MovDelay[newx][newy] = 0;
 
+#if 0
+    /* all done in "InitMovingField()" */
     GfxAction[newx][newy] = GfxAction[x][y];   /* keep action one frame */
-    GfxAction[x][y] = ACTION_DEFAULT;
+    GfxRandom[newx][newy] = GfxRandom[x][y];   /* keep same random value */
+#endif
+
+    /* copy animation control values to new field */
+    GfxFrame[newx][newy]  = GfxFrame[x][y];
+    GfxAction[newx][newy] = GfxAction[x][y];
+    GfxRandom[newx][newy] = GfxRandom[x][y];
 
+    ResetGfxAnimation(x, y);   /* reset animation values for old field */
+
+#if 1
 #if 0
     if (!CAN_MOVE(element))
       MovDir[newx][newy] = 0;
@@ -3475,6 +3506,7 @@ void ContinueMoving(int x, int y)
     if (!CAN_MOVE(element) ||
        (element == EL_SPRING && MovDir[newx][newy] == MV_DOWN))
       MovDir[newx][newy] = 0;
+#endif
 #endif
 
     DrawLevelField(x, y);
@@ -3999,38 +4031,6 @@ static void StopRobotWheel(int x, int y)
     ZX = ZY = -1;
 }
 
-#if 1
-void RobotWheel(int x, int y)
-{
-  if (!MovDelay[x][y])         /* next animation frame */
-    MovDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
-
-  if (MovDelay[x][y])          /* wait some time before next frame */
-  {
-    MovDelay[x][y]--;
-    if (MovDelay[x][y])
-    {
-      if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-      {
-       int frame = getGraphicAnimationFrame(IMG_ROBOT_WHEEL_ACTIVE, -1);
-
-       DrawGraphic(SCREENX(x), SCREENY(y), IMG_ROBOT_WHEEL_ACTIVE, frame);
-      }
-
-      PlaySoundLevel(x, y, SND_ROBOT_WHEEL_ACTIVE);
-
-      return;
-    }
-  }
-
-  Feld[x][y] = EL_ROBOT_WHEEL;
-  DrawLevelField(x, y);
-
-  if (ZX == x && ZY == y)
-    ZX = ZY = -1;
-}
-#endif
-
 static void InitTimegateWheel(int x, int y)
 {
   MovDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
@@ -4041,106 +4041,6 @@ static void RunTimegateWheel(int x, int y)
   PlaySoundLevel(x, y, SND_TIMEGATE_SWITCH_ACTIVE);
 }
 
-#if 1
-void TimegateWheel(int x, int y)
-{
-  if (!MovDelay[x][y])         /* next animation frame */
-    MovDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND;
-
-  if (MovDelay[x][y])          /* wait some time before next frame */
-  {
-    MovDelay[x][y]--;
-    if (MovDelay[x][y])
-    {
-      if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-      {
-       int frame = getGraphicAnimationFrame(IMG_TIMEGATE_SWITCH_ACTIVE, -1);
-
-       DrawGraphic(SCREENX(x), SCREENY(y), IMG_TIMEGATE_SWITCH_ACTIVE, frame);
-      }
-
-      PlaySoundLevel(x, y, SND_TIMEGATE_SWITCH_ACTIVE);
-
-      return;
-    }
-  }
-
-  Feld[x][y] = EL_TIMEGATE_SWITCH;
-  DrawLevelField(x, y);
-
-  /* THIS HAS NO EFFECT AT ALL! */
-#if 1
-  /* !!! THIS LOOKS WRONG !!! */
-  if (ZX == x && ZY == y)
-    ZX = ZY = -1;
-#endif
-
-}
-#endif
-
-#if 1
-void NussKnacken(int x, int y)
-{
-  if (!MovDelay[x][y])         /* next animation frame */
-    MovDelay[x][y] = 7;
-
-  if (MovDelay[x][y])          /* wait some time before next frame */
-  {
-    MovDelay[x][y]--;
-    if (MovDelay[x][y])
-    {
-      if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-      {
-       int frame = getGraphicAnimationFrame(IMG_NUT_CRACKING,
-                                            6 - MovDelay[x][y]);
-
-       DrawGraphic(SCREENX(x), SCREENY(y), IMG_NUT_CRACKING, frame);
-      }
-
-      return;
-    }
-  }
-
-  Feld[x][y] = EL_EMERALD;
-  DrawLevelField(x, y);
-}
-#endif
-
-#if 1
-void BreakingPearl(int x, int y)
-{
-  if (!MovDelay[x][y])         /* next animation frame */
-    MovDelay[x][y] = 9;
-
-  if (MovDelay[x][y])          /* wait some time before next frame */
-  {
-    MovDelay[x][y]--;
-    if (MovDelay[x][y])
-    {
-      if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-      {
-       int frame = getGraphicAnimationFrame(IMG_PEARL_BREAKING,
-                                            8 - MovDelay[x][y]);
-
-       DrawGraphic(SCREENX(x), SCREENY(y), IMG_PEARL_BREAKING, frame);
-      }
-
-      return;
-    }
-  }
-
-  Feld[x][y] = EL_EMPTY;
-  DrawLevelField(x, y);
-}
-#endif
-
-void SiebAktivieren(int x, int y, int type)
-{
-  int graphic = (type == 1 ? IMG_MAGIC_WALL_FULL : IMG_BD_MAGIC_WALL_FULL);
-
-  DrawLevelGraphicAnimation(x, y, graphic);
-}
-
 void CheckExit(int x, int y)
 {
   if (local_player->gems_still_needed > 0 ||
@@ -4163,169 +4063,6 @@ void CheckExitSP(int x, int y)
   PlaySoundLevelNearest(x, y, SND_SP_EXIT_OPENING);
 }
 
-#if 1
-void AusgangstuerOeffnen(int x, int y)
-{
-  int delay = 6;
-
-  if (!MovDelay[x][y])         /* next animation frame */
-    MovDelay[x][y] = 5 * delay;
-
-  if (MovDelay[x][y])          /* wait some time before next frame */
-  {
-    int tuer;
-
-    MovDelay[x][y]--;
-    tuer = MovDelay[x][y] / delay;
-
-    if (!(MovDelay[x][y] % delay))
-    {
-      if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-      {
-       int frame = getGraphicAnimationFrame(IMG_EXIT_OPENING,
-                                            29 - MovDelay[x][y]);
-
-       DrawGraphic(SCREENX(x), SCREENY(y), IMG_EXIT_OPENING, frame);
-      }
-    }
-
-    if (MovDelay[x][y])
-      return;
-  }
-
-  Feld[x][y] = EL_EXIT_OPEN;
-  DrawLevelField(x, y);
-}
-#endif
-
-#if 1
-void OpenSwitchgate(int x, int y)
-{
-  int delay = 6;
-
-  if (!MovDelay[x][y])         /* next animation frame */
-    MovDelay[x][y] = 5 * delay;
-
-  if (MovDelay[x][y])          /* wait some time before next frame */
-  {
-    MovDelay[x][y]--;
-
-    if (!(MovDelay[x][y] % delay))
-    {
-      if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-      {
-       int frame = getGraphicAnimationFrame(IMG_SWITCHGATE_OPENING,
-                                            29 - MovDelay[x][y]);
-
-       DrawGraphic(SCREENX(x), SCREENY(y), IMG_SWITCHGATE_OPENING, frame);
-      }
-    }
-
-    if (MovDelay[x][y])
-      return;
-  }
-
-  Feld[x][y] = EL_SWITCHGATE_OPEN;
-  DrawLevelField(x, y);
-}
-#endif
-
-#if 1
-void CloseSwitchgate(int x, int y)
-{
-  int delay = 6;
-
-  if (!MovDelay[x][y])         /* next animation frame */
-    MovDelay[x][y] = 5 * delay;
-
-  if (MovDelay[x][y])          /* wait some time before next frame */
-  {
-    MovDelay[x][y]--;
-
-    if (!(MovDelay[x][y] % delay))
-    {
-      if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-      {
-       int frame = getGraphicAnimationFrame(IMG_SWITCHGATE_CLOSING,
-                                            29 - MovDelay[x][y]);
-
-       DrawGraphic(SCREENX(x), SCREENY(y), IMG_SWITCHGATE_CLOSING, frame);
-      }
-    }
-
-    if (MovDelay[x][y])
-      return;
-  }
-
-  Feld[x][y] = EL_SWITCHGATE_CLOSED;
-  DrawLevelField(x, y);
-}
-#endif
-
-#if 1
-void OpenTimegate(int x, int y)
-{
-  int delay = 6;
-
-  if (!MovDelay[x][y])         /* next animation frame */
-    MovDelay[x][y] = 5 * delay;
-
-  if (MovDelay[x][y])          /* wait some time before next frame */
-  {
-    MovDelay[x][y]--;
-
-    if (!(MovDelay[x][y] % delay))
-    {
-      if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-      {
-       int frame = getGraphicAnimationFrame(IMG_TIMEGATE_OPENING,
-                                            29 - MovDelay[x][y]);
-
-       DrawGraphic(SCREENX(x), SCREENY(y), IMG_TIMEGATE_OPENING, frame);
-      }
-    }
-
-    if (MovDelay[x][y])
-      return;
-  }
-
-  Feld[x][y] = EL_TIMEGATE_OPEN;
-  DrawLevelField(x, y);
-}
-#endif
-
-#if 1
-void CloseTimegate(int x, int y)
-{
-  int delay = 6;
-
-  if (!MovDelay[x][y])         /* next animation frame */
-    MovDelay[x][y] = 5 * delay;
-
-  if (MovDelay[x][y])          /* wait some time before next frame */
-  {
-    MovDelay[x][y]--;
-
-    if (!(MovDelay[x][y] % delay))
-    {
-      if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
-      {
-       int frame = getGraphicAnimationFrame(IMG_TIMEGATE_CLOSING,
-                                            29 - MovDelay[x][y]);
-
-       DrawGraphic(SCREENX(x), SCREENY(y), IMG_TIMEGATE_CLOSING, frame);
-      }
-    }
-
-    if (MovDelay[x][y])
-      return;
-  }
-
-  Feld[x][y] = EL_TIMEGATE_CLOSED;
-  DrawLevelField(x, y);
-}
-#endif
-
 static void CloseAllOpenTimegates()
 {
   int x, y;
@@ -4634,79 +4371,6 @@ static void WarnBuggyBase(int x, int y)
   }
 }
 
-#if 1
-void CheckBuggyBase(int x, int y)
-{
-  int element = Feld[x][y];
-
-  if (element == EL_SP_BUGGY_BASE)
-  {
-    if (MovDelay[x][y] == 0)   /* wait some time before activating base */
-    {
-      GfxFrame[x][y] = 0;
-
-      InitBuggyBase(x, y);
-    }
-
-    MovDelay[x][y]--;
-
-    if (MovDelay[x][y] != 0)
-    {
-      DrawLevelElementAnimation(x, y, element);
-    }
-    else
-    {
-      Feld[x][y] = EL_SP_BUGGY_BASE_ACTIVATING;
-      DrawLevelField(x, y);
-    }
-  }
-  else if (element == EL_SP_BUGGY_BASE_ACTIVATING)
-  {
-    if (MovDelay[x][y] == 0)   /* display activation warning of buggy base */
-    {
-      GfxFrame[x][y] = 0;
-
-      InitBuggyBase(x, y);
-    }
-
-    MovDelay[x][y]--;
-
-    if (MovDelay[x][y] != 0)
-    {
-      DrawLevelElementAnimation(x, y, element);
-    }
-    else
-    {
-      Feld[x][y] = EL_SP_BUGGY_BASE_ACTIVE;
-      DrawLevelField(x, y);
-    }
-  }
-  else if (element == EL_SP_BUGGY_BASE_ACTIVE)
-  {
-    if (MovDelay[x][y] == 0)   /* start activating buggy base */
-    {
-      GfxFrame[x][y] = 0;
-
-      InitBuggyBase(x, y);
-    }
-
-    MovDelay[x][y]--;
-
-    if (MovDelay[x][y] != 0)
-    {
-      DrawLevelElementAnimation(x, y, element);
-
-      WarnBuggyBase(x, y);
-    }
-    else
-    {
-      Feld[x][y] = EL_SP_BUGGY_BASE;
-      DrawLevelField(x, y);
-    }
-  }
-}
-#endif
-
 static void InitTrap(int x, int y)
 {
   MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND);
@@ -4721,77 +4385,11 @@ static void ChangeActiveTrap(int x, int y)
 {
   int graphic = IMG_TRAP_ACTIVE;
 
-  /* if animation frame already drawn, correct crumbled sand border */
-  if (IS_ANIMATED(graphic))
-    if (checkDrawLevelGraphicAnimation(x, y, graphic))
-      DrawCrumbledSand(SCREENX(x), SCREENY(y));
+  /* if new animation frame was drawn, correct crumbled sand border */
+  if (IS_NEW_FRAME(GfxFrame[x][y], graphic))
+    DrawCrumbledSand(SCREENX(x), SCREENY(y));
 }
 
-#if 1
-void CheckTrap(int x, int y)
-{
-  int element = Feld[x][y];
-
-  if (element == EL_TRAP)
-  {
-    if (MovDelay[x][y] == 0)   /* wait some time before activating trap */
-      MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND);
-
-    MovDelay[x][y]--;
-
-    if (MovDelay[x][y] != 0)
-    {
-      /* do nothing while waiting */
-    }
-    else
-    {
-      Feld[x][y] = EL_TRAP_ACTIVE;
-      PlaySoundLevel(x, y, SND_TRAP_ACTIVATING);
-    }
-  }
-  else if (element == EL_TRAP_ACTIVE)
-  {
-    int delay = 4;
-    int num_frames = 8;
-
-    if (MovDelay[x][y] == 0)   /* start activating trap */
-    {
-      MovDelay[x][y] = num_frames * delay;
-      GfxFrame[x][y] = 0;
-    }
-
-    MovDelay[x][y]--;
-
-    if (MovDelay[x][y] != 0)
-    {
-      if (DrawLevelElementAnimation(x, y, element))
-       DrawCrumbledSand(SCREENX(x), SCREENY(y));
-    }
-    else
-    {
-      Feld[x][y] = EL_TRAP;
-      DrawLevelField(x, y);
-    }
-  }
-}
-#endif
-
-#if 1
-static void DrawBeltAnimation(int x, int y, int element)
-{
-  int belt_nr = getBeltNrFromBeltActiveElement(element);
-  int belt_dir = game.belt_dir[belt_nr];
-
-  if (belt_dir != MV_NO_MOVING)
-  {
-    DrawLevelElementAnimation(x, y, element);
-
-    if (!(FrameCounter % 2))
-      PlaySoundLevelAction(x, y, ACTION_ACTIVE);
-  }
-}
-#endif
-
 static void ChangeElement(int x, int y)
 {
   int element = Feld[x][y];
@@ -4799,7 +4397,9 @@ static void ChangeElement(int x, int y)
   if (MovDelay[x][y] == 0)             /* initialize element change */
   {
     MovDelay[x][y] = changing_element[element].change_delay + 1;
-    GfxFrame[x][y] = 0;
+
+    ResetGfxAnimation(x, y);
+    ResetRandomAnimationValue(x, y);
 
     if (changing_element[element].pre_change_function)
       changing_element[element].pre_change_function(x, y);
@@ -4810,7 +4410,7 @@ static void ChangeElement(int x, int y)
   if (MovDelay[x][y] != 0)             /* continue element change */
   {
     if (IS_ANIMATED(el2img(element)))
-      DrawLevelElementAnimation(x, y, element);
+      DrawLevelElementAnimationIfNeeded(x, y, element);
 
     if (changing_element[element].change_function)
       changing_element[element].change_function(x, y);
@@ -4818,7 +4418,9 @@ static void ChangeElement(int x, int y)
   else                                 /* finish element change */
   {
     Feld[x][y] = changing_element[element].next_element;
-    GfxFrame[x][y] = 0;
+
+    ResetGfxAnimation(x, y);
+    ResetRandomAnimationValue(x, y);
 
     DrawLevelField(x, y);
 
@@ -4972,7 +4574,7 @@ void GameActions()
 {
   static unsigned long action_delay = 0;
   unsigned long action_delay_value;
-  int sieb_x = 0, sieb_y = 0;
+  int magic_wall_x = 0, magic_wall_y = 0;
   int i, x, y, element, graphic;
   byte *recorded_player_action;
   byte summarized_player_action = 0;
@@ -5110,12 +4712,23 @@ void GameActions()
     element = Feld[x][y];
     graphic = el2img(element);
 
+#if 1
+    if (graphic_info[graphic].anim_global_sync)
+      GfxFrame[x][y] = FrameCounter;
+#endif
+
+    if (ANIM_MODE(graphic) == ANIM_RANDOM &&
+       IS_NEXT_FRAME(GfxFrame[x][y], graphic))
+      ResetRandomAnimationValue(x, y);
+
+    SetRandomAnimationValue(x, y);
+
     if (IS_INACTIVE(element))
     {
 
 #if 1
       if (IS_ANIMATED(graphic))
-       DrawLevelGraphicAnimation(x, y, graphic);
+       DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
 #endif
 
       continue;
@@ -5125,18 +4738,10 @@ void GameActions()
     {
       StartMoving(x, y);
 
-#if 1
-#if 0
-      if (Feld[x][y] == EL_EMERALD &&
-         IS_ANIMATED(graphic) &&
-         !IS_MOVING(x, y))
-       DrawLevelGraphicAnimation(x, y, graphic);
-#else
       if (IS_ANIMATED(graphic) &&
-         !IS_MOVING(x, y))
-       DrawLevelGraphicAnimation(x, y, graphic);
-#endif
-#endif
+         !IS_MOVING(x, y) &&
+         !Stop[x][y])
+       DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
 
       if (IS_GEM(element) || element == EL_SP_INFOTRON)
        EdelsteinFunkeln(x, y);
@@ -5152,7 +4757,7 @@ void GameActions()
              element == EL_SHIELD_NORMAL ||
              element == EL_SHIELD_DEADLY) &&
             IS_ANIMATED(graphic))
-      DrawLevelGraphicAnimation(x, y, graphic);
+      DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
 #endif
 
     else if (IS_MOVING(x, y))
@@ -5181,9 +4786,11 @@ void GameActions()
     else if (element == EL_TIMEGATE_SWITCH_ACTIVE)
       TimegateWheel(x, y);
 #endif
+#if 0
     else if (element == EL_ACID_SPLASH_LEFT ||
             element == EL_ACID_SPLASH_RIGHT)
-      Blurb(x, y);
+      SplashAcid(x, y);
+#endif
 #if 0
     else if (element == EL_NUT_CRACKING)
       NussKnacken(x, y);
@@ -5234,7 +4841,7 @@ void GameActions()
     else if (element == EL_EXPLOSION)
       ;        /* drawing of correct explosion animation is handled separately */
     else if (IS_ANIMATED(graphic))
-      DrawLevelGraphicAnimation(x, y, graphic);
+      DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
 #endif
 
     if (IS_BELT_ACTIVE(element))
@@ -5242,29 +4849,19 @@ void GameActions()
 
     if (game.magic_wall_active)
     {
-      boolean sieb = FALSE;
       int jx = local_player->jx, jy = local_player->jy;
 
-      if (element == EL_MAGIC_WALL_FULL ||
-         element == EL_MAGIC_WALL_ACTIVE ||
-         element == EL_MAGIC_WALL_EMPTYING)
-      {
-       SiebAktivieren(x, y, 1);
-       sieb = TRUE;
-      }
-      else if (element == EL_BD_MAGIC_WALL_FULL ||
-              element == EL_BD_MAGIC_WALL_ACTIVE ||
-              element == EL_BD_MAGIC_WALL_EMPTYING)
-      {
-       SiebAktivieren(x, y, 2);
-       sieb = TRUE;
-      }
-
       /* play the element sound at the position nearest to the player */
-      if (sieb && ABS(x-jx)+ABS(y-jy) < ABS(sieb_x-jx)+ABS(sieb_y-jy))
+      if ((element == EL_MAGIC_WALL_FULL ||
+          element == EL_MAGIC_WALL_ACTIVE ||
+          element == EL_MAGIC_WALL_EMPTYING ||
+          element == EL_BD_MAGIC_WALL_FULL ||
+          element == EL_BD_MAGIC_WALL_ACTIVE ||
+          element == EL_BD_MAGIC_WALL_EMPTYING) &&
+         ABS(x-jx) + ABS(y-jy) < ABS(magic_wall_x-jx) + ABS(magic_wall_y-jy))
       {
-       sieb_x = x;
-       sieb_y = y;
+       magic_wall_x = x;
+       magic_wall_y = y;
       }
     }
   }
@@ -5332,14 +4929,14 @@ void GameActions()
   {
     if (!(game.magic_wall_time_left % 4))
     {
-      int element = Feld[sieb_x][sieb_y];
+      int element = Feld[magic_wall_x][magic_wall_y];
 
       if (element == EL_BD_MAGIC_WALL_FULL ||
          element == EL_BD_MAGIC_WALL_ACTIVE ||
          element == EL_BD_MAGIC_WALL_EMPTYING)
-       PlaySoundLevel(sieb_x, sieb_y, SND_BD_MAGIC_WALL_ACTIVE);
+       PlaySoundLevel(magic_wall_x, magic_wall_y, SND_BD_MAGIC_WALL_ACTIVE);
       else
-       PlaySoundLevel(sieb_x, sieb_y, SND_MAGIC_WALL_ACTIVE);
+       PlaySoundLevel(magic_wall_x, magic_wall_y, SND_MAGIC_WALL_ACTIVE);
     }
 
     if (game.magic_wall_time_left > 0)
@@ -5588,7 +5185,7 @@ boolean MoveFigureOneStep(struct PlayerInfo *player,
   {
     if (element == EL_ACID && dx == 0 && dy == 1)
     {
-      Blurb(jx, jy);
+      SplashAcid(jx, jy);
       Feld[jx][jy] = EL_PLAYER1;
       InitMovingField(jx, jy, MV_DOWN);
       Store[jx][jy] = EL_ACID;
@@ -6478,7 +6075,9 @@ int DigField(struct PlayerInfo *player,
     case EL_SPRING:
       if (mode == DF_SNAP)
        return MF_NO_ACTION;
+
       /* no "break" -- fall through to next case */
+
       /* the following elements can be pushed by "snapping" */
     case EL_BD_ROCK:
       if (dy)
@@ -6499,7 +6098,8 @@ int DigField(struct PlayerInfo *player,
        player->push_delay = FrameCounter;
 #if 0
       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
-         !tape.playing && element != EL_SPRING)
+         !tape.playing &&
+         element != EL_SPRING)
        return MF_NO_ACTION;
 #else
       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
@@ -6810,6 +6410,48 @@ int DigField(struct PlayerInfo *player,
       break;
 
     default:
+      if (IS_PUSHABLE(element))
+      {
+       if (mode == DF_SNAP)
+         return MF_NO_ACTION;
+
+       if (CAN_FALL(element) && dy)
+         return MF_NO_ACTION;
+
+       player->Pushing = TRUE;
+
+       if (!IN_LEV_FIELD(x+dx, y+dy) || !IS_FREE(x+dx, y+dy))
+         return MF_NO_ACTION;
+
+       if (dx && real_dy)
+       {
+         if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
+           return MF_NO_ACTION;
+       }
+       else if (dy && real_dx)
+       {
+         if (IN_LEV_FIELD(jx+real_dx, jy) && !IS_SOLID(Feld[jx+real_dx][jy]))
+           return MF_NO_ACTION;
+       }
+
+       if (player->push_delay == 0)
+         player->push_delay = FrameCounter;
+
+       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
+           !(tape.playing && tape.file_version < FILE_VERSION_2_0))
+         return MF_NO_ACTION;
+
+       RemoveField(x, y);
+       Feld[x + dx][y + dy] = element;
+
+       player->push_delay_value = 2 + RND(8);
+
+       DrawLevelField(x + dx, y + dy);
+       PlaySoundLevelElementAction(x, y, element, ACTION_PUSHING);
+
+       break;
+      }
+
       return MF_NO_ACTION;
   }
 
@@ -6874,7 +6516,9 @@ boolean PlaceBomb(struct PlayerInfo *player)
     Store[jx][jy] = element;
 
   MovDelay[jx][jy] = 96;
-  GfxFrame[jx][jy] = 0;
+
+  ResetGfxAnimation(jx, jy);
+  ResetRandomAnimationValue(jx, jy);
 
   if (player->dynamite)
   {