rnd-20030210-1-src
[rocksndiamonds.git] / src / game.c
index 7f239043076b8a3eaceabd78469b603bd4e92a37..5f3f9689f3cdbd505d7c56a5e3533afdb358337e 100644 (file)
 #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);
@@ -1254,21 +1256,31 @@ int NewHiScore()
 
 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 has reached */
+  /* reset random value not until one full delay cycle was reached */
   if (ANIM_MODE(graphic) == ANIM_RANDOM &&
       GfxFrame[x][y] > ANIM_DELAY(graphic))
-    GfxRandom[x][y] = INIT_GFX_RANDOM();
-}
-
-static void ResetGfxAnimation(int x, int y)
-{
-  ResetRandomAnimationValue(x, y);
+#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)
@@ -1280,8 +1292,7 @@ void InitMovingField(int x, int y, int direction)
   if (!JustStopped[x][y] || direction != MovDir[x][y])
     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;
@@ -1290,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)
@@ -1430,21 +1445,15 @@ void DrawDynamite(int x, int y)
 
 void CheckDynamite(int x, int y)
 {
-#if 0
-  int element = Feld[x][y];
-#endif
-
   if (MovDelay[x][y] != 0)     /* dynamite is still waiting to explode */
   {
     MovDelay[x][y]--;
 
     if (MovDelay[x][y] != 0)
     {
-#if 0
-      if (checkDrawLevelGraphicAnimation(x, y, el2img(element)))
-#endif
-       DrawDynamite(x, y);
+      DrawDynamite(x, y);
 
+      /* !!! correct: "PlaySoundLevelActionIfLoop" etc. !!! */
       PlaySoundLevelAction(x, y, ACTION_ACTIVE);
 
       return;
@@ -2138,8 +2147,8 @@ 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);
   }
@@ -2150,6 +2159,17 @@ void Impact(int x, int 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) &&
@@ -2175,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;
   }
@@ -2878,7 +2900,11 @@ 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
     {
       SplashAcid(x, y);
 
@@ -2902,6 +2928,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;
     }
@@ -3023,7 +3052,7 @@ void StartMoving(int x, int y)
          element == EL_DARK_YAMYAM)
       {
 #if 1
-       ContinueLevelElementAnimation(x, y, element);
+       DrawLevelElementAnimationIfNeeded(x, y, element);
 #else
        if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
        {
@@ -3047,7 +3076,7 @@ void StartMoving(int x, int y)
 #endif
       }
       else if (element == EL_SP_ELECTRON)
-       ContinueLevelElementAnimation(x, y, element);
+       DrawLevelElementAnimationIfNeeded(x, y, element);
       else if (element == EL_DRAGON)
       {
        int i;
@@ -3305,11 +3334,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)
-       ContinueLevelElementAnimation(x, y, element);
+       DrawLevelElementAnimationIfNeeded(x, y, element);
       else if (element == EL_SATELLITE)
-       ContinueLevelElementAnimation(x, y, element);
+       DrawLevelElementAnimationIfNeeded(x, y, element);
       else if (element == EL_SP_ELECTRON)
-       ContinueLevelElementAnimation(x, y, element);
+       DrawLevelElementAnimationIfNeeded(x, y, element);
 
       if (DONT_TOUCH(element))
        TestIfBadThingTouchesHero(x, y);
@@ -3444,10 +3473,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 */
     GfxRandom[newx][newy] = GfxRandom[x][y];   /* keep same random value */
-    GfxAction[x][y] = ACTION_DEFAULT;
+#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;
@@ -3460,6 +3499,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);
@@ -3994,13 +4034,6 @@ static void RunTimegateWheel(int x, int y)
   PlaySoundLevel(x, y, SND_TIMEGATE_SWITCH_ACTIVE);
 }
 
-void SiebAktivieren(int x, int y, int type)
-{
-  int graphic = (type == 1 ? IMG_MAGIC_WALL_FULL : IMG_BD_MAGIC_WALL_FULL);
-
-  ContinueLevelGraphicAnimation(x, y, graphic);
-}
-
 void CheckExit(int x, int y)
 {
   if (local_player->gems_still_needed > 0 ||
@@ -4345,10 +4378,9 @@ 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));
 }
 
 static void ChangeElement(int x, int y)
@@ -4360,6 +4392,7 @@ static void ChangeElement(int x, int y)
     MovDelay[x][y] = changing_element[element].change_delay + 1;
 
     ResetGfxAnimation(x, y);
+    ResetRandomAnimationValue(x, y);
 
     if (changing_element[element].pre_change_function)
       changing_element[element].pre_change_function(x, y);
@@ -4370,7 +4403,7 @@ static void ChangeElement(int x, int y)
   if (MovDelay[x][y] != 0)             /* continue element change */
   {
     if (IS_ANIMATED(el2img(element)))
-      ContinueLevelElementAnimation(x, y, element);
+      DrawLevelElementAnimationIfNeeded(x, y, element);
 
     if (changing_element[element].change_function)
       changing_element[element].change_function(x, y);
@@ -4380,6 +4413,7 @@ static void ChangeElement(int x, int y)
     Feld[x][y] = changing_element[element].next_element;
 
     ResetGfxAnimation(x, y);
+    ResetRandomAnimationValue(x, y);
 
     DrawLevelField(x, y);
 
@@ -4533,7 +4567,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;
@@ -4671,8 +4705,13 @@ 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_NEW_FRAME(GfxFrame[x][y], graphic))
+       IS_NEXT_FRAME(GfxFrame[x][y], graphic))
       ResetRandomAnimationValue(x, y);
 
     SetRandomAnimationValue(x, y);
@@ -4682,7 +4721,7 @@ void GameActions()
 
 #if 1
       if (IS_ANIMATED(graphic))
-       ContinueLevelGraphicAnimation(x, y, graphic);
+       DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
 #endif
 
       continue;
@@ -4692,18 +4731,10 @@ void GameActions()
     {
       StartMoving(x, y);
 
-#if 1
-#if 0
-      if (Feld[x][y] == EL_EMERALD &&
-         IS_ANIMATED(graphic) &&
-         !IS_MOVING(x, y))
-       ContinueLevelGraphicAnimation(x, y, graphic);
-#else
       if (IS_ANIMATED(graphic) &&
-         !IS_MOVING(x, y))
-       ContinueLevelGraphicAnimation(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);
@@ -4719,7 +4750,7 @@ void GameActions()
              element == EL_SHIELD_NORMAL ||
              element == EL_SHIELD_DEADLY) &&
             IS_ANIMATED(graphic))
-      ContinueLevelGraphicAnimation(x, y, graphic);
+      DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
 #endif
 
     else if (IS_MOVING(x, y))
@@ -4803,7 +4834,7 @@ void GameActions()
     else if (element == EL_EXPLOSION)
       ;        /* drawing of correct explosion animation is handled separately */
     else if (IS_ANIMATED(graphic))
-      ContinueLevelGraphicAnimation(x, y, graphic);
+      DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
 #endif
 
     if (IS_BELT_ACTIVE(element))
@@ -4811,29 +4842,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;
       }
     }
   }
@@ -4901,14 +4922,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)
@@ -6047,7 +6068,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)
@@ -6068,7 +6091,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) &&
@@ -6379,6 +6403,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;
   }
 
@@ -6445,6 +6511,7 @@ boolean PlaceBomb(struct PlayerInfo *player)
   MovDelay[jx][jy] = 96;
 
   ResetGfxAnimation(jx, jy);
+  ResetRandomAnimationValue(jx, jy);
 
   if (player->dynamite)
   {