rnd-20020315-2-src
[rocksndiamonds.git] / src / game.c
index d97223df2d51350d88ea3ade8ebdcdb3de0dd6e1..32e9e0d62989d82a0e4d93facacca99be36d9e82 100644 (file)
@@ -268,7 +268,7 @@ static void InitField(int x, int y, boolean init_game)
 
          StorePlayer[x][y] = Feld[x][y];
 
-         if (options.verbose)
+         if (options.debug)
          {
            printf("Player %d activated.\n", player->element_nr);
            printf("[Local player is %d and currently %s.]\n",
@@ -485,6 +485,7 @@ void InitGame()
 
     player->move_delay = 0;
     player->last_move_dir = MV_NO_MOVING;
+    player->is_moving = FALSE;
 
     player->move_delay_value =
       (level.double_speed ? MOVE_DELAY_HIGH_SPEED : MOVE_DELAY_NORMAL_SPEED);
@@ -658,7 +659,7 @@ void InitGame()
        tape.player_participates[i] = TRUE;
   }
 
-  if (options.verbose)
+  if (options.debug)
   {
     for (i=0; i<MAX_PLAYERS; i++)
     {
@@ -792,7 +793,7 @@ void InitGame()
 
   KeyboardAutoRepeatOff();
 
-  if (options.verbose)
+  if (options.debug)
   {
     for (i=0; i<4; i++)
       printf("Player %d %sactive.\n",
@@ -941,12 +942,12 @@ void GameWon()
 
   if (TimeLeft)
   {
-    if (setup.sound_loops)
+    if (!tape.playing && setup.sound_loops)
       PlaySoundExt(SND_SIRR, PSND_MAX_VOLUME, PSND_MAX_RIGHT, PSND_LOOP);
 
     while(TimeLeft > 0)
     {
-      if (!setup.sound_loops)
+      if (!tape.playing && !setup.sound_loops)
        PlaySoundStereo(SND_SIRR, PSND_MAX_RIGHT);
       if (TimeLeft > 0 && !(TimeLeft % 10))
        RaiseScore(level.score[SC_ZEITBONUS]);
@@ -956,20 +957,22 @@ void GameWon()
        TimeLeft--;
       DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
       BackToFront();
-      Delay(10);
+
+      if (!tape.playing)
+       Delay(10);
     }
 
-    if (setup.sound_loops)
+    if (!tape.playing && setup.sound_loops)
       StopSound(SND_SIRR);
   }
   else if (level.time == 0)            /* level without time limit */
   {
-    if (setup.sound_loops)
+    if (!tape.playing && setup.sound_loops)
       PlaySoundExt(SND_SIRR, PSND_MAX_VOLUME, PSND_MAX_RIGHT, PSND_LOOP);
 
     while(TimePlayed < 999)
     {
-      if (!setup.sound_loops)
+      if (!tape.playing && !setup.sound_loops)
        PlaySoundStereo(SND_SIRR, PSND_MAX_RIGHT);
       if (TimePlayed < 999 && !(TimePlayed % 10))
        RaiseScore(level.score[SC_ZEITBONUS]);
@@ -979,10 +982,12 @@ void GameWon()
        TimePlayed++;
       DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FS_SMALL, FC_YELLOW);
       BackToFront();
-      Delay(10);
+
+      if (!tape.playing)
+       Delay(10);
     }
 
-    if (setup.sound_loops)
+    if (!tape.playing && setup.sound_loops)
       StopSound(SND_SIRR);
   }
 
@@ -1021,13 +1026,19 @@ void GameWon()
     game_status = HALLOFFAME;
     DrawHallOfFame(hi_pos);
     if (raise_level)
+    {
       level_nr++;
+      TapeErase();
+    }
   }
   else
   {
     game_status = MAINMENU;
     if (raise_level)
+    {
       level_nr++;
+      TapeErase();
+    }
     DrawMainMenu();
   }
 
@@ -1463,6 +1474,9 @@ void Explode(int ex, int ey, int phase, int mode)
     if (CAN_MOVE(element) || COULD_MOVE(element))
       InitMovDir(x, y);
     DrawLevelField(x, y);
+
+    if (IS_PLAYER(x, y) && !PLAYERINFO(x,y)->present)
+      StorePlayer[x][y] = 0;
   }
   else if (!(phase % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
   {
@@ -1476,7 +1490,15 @@ void Explode(int ex, int ey, int phase, int mode)
     if (phase == delay)
       ErdreichAnbroeckeln(SCREENX(x), SCREENY(y));
 
-    DrawGraphic(SCREENX(x), SCREENY(y), graphic + (phase / delay - 1));
+    graphic += (phase / delay - 1);
+
+    if (IS_PFORTE(Store[x][y]))
+    {
+      DrawLevelElement(x, y, Store[x][y]);
+      DrawGraphicThruMask(SCREENX(x), SCREENY(y), graphic);
+    }
+    else
+      DrawGraphic(SCREENX(x), SCREENY(y), graphic);
   }
 }
 
@@ -2056,7 +2078,7 @@ void TurnRound(int x, int y)
 
   if (element == EL_KAEFER || element == EL_BUTTERFLY)
   {
-    TestIfBadThingHitsOtherBadThing(x, y);
+    TestIfBadThingTouchesOtherBadThing(x, y);
 
     if (IN_LEV_FIELD(right_x, right_y) &&
        IS_FREE(right_x, right_y))
@@ -2073,7 +2095,7 @@ void TurnRound(int x, int y)
   else if (element == EL_FLIEGER || element == EL_FIREFLY ||
           element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
   {
-    TestIfBadThingHitsOtherBadThing(x, y);
+    TestIfBadThingTouchesOtherBadThing(x, y);
 
     if (IN_LEV_FIELD(left_x, left_y) &&
        IS_FREE(left_x, left_y))
@@ -2737,7 +2759,7 @@ void StartMoving(int x, int y)
     {
 
 #if 1
-      TestIfBadThingHitsHero(x, y);
+      TestIfBadThingRunsIntoHero(x, y, MovDir[x][y]);
       return;
 #else
       /* enemy got the player */
@@ -2927,7 +2949,7 @@ void StartMoving(int x, int y)
        DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL);
 
       if (DONT_TOUCH(element))
-       TestIfBadThingHitsHero(x, y);
+       TestIfBadThingTouchesHero(x, y);
 
       return;
     }
@@ -3069,12 +3091,12 @@ void ContinueMoving(int x, int y)
 
     if (DONT_TOUCH(element))   /* object may be nasty to player or others */
     {
-      TestIfBadThingHitsHero(newx, newy);
-      TestIfBadThingHitsFriend(newx, newy);
-      TestIfBadThingHitsOtherBadThing(newx, newy);
+      TestIfBadThingTouchesHero(newx, newy);
+      TestIfBadThingTouchesFriend(newx, newy);
+      TestIfBadThingTouchesOtherBadThing(newx, newy);
     }
     else if (element == EL_PINGUIN)
-      TestIfFriendHitsBadThing(newx, newy);
+      TestIfFriendTouchesBadThing(newx, newy);
 
     if (CAN_SMASH(element) && direction == MV_DOWN &&
        (newy == lev_fieldy-1 || !IS_FREE(x, newy+1)))
@@ -4189,9 +4211,10 @@ static void PlayerActions(struct PlayerInfo *player, byte player_action)
 {
   static byte stored_player_action[MAX_PLAYERS];
   static int num_stored_actions = 0;
+#if 0
   static boolean save_tape_entry = FALSE;
+#endif
   boolean moved = FALSE, snapped = FALSE, bombed = FALSE;
-  int jx = player->jx, jy = player->jy;
   int left     = player_action & JOY_LEFT;
   int right    = player_action & JOY_RIGHT;
   int up       = player_action & JOY_UP;
@@ -4209,7 +4232,9 @@ static void PlayerActions(struct PlayerInfo *player, byte player_action)
 
   if (player_action)
   {
+#if 0
     save_tape_entry = TRUE;
+#endif
     player->frame_reset_delay = 0;
 
     if (button1)
@@ -4221,15 +4246,20 @@ static void PlayerActions(struct PlayerInfo *player, byte player_action)
       moved = MoveFigure(player, dx, dy);
     }
 
+#if 0
     if (tape.recording && (moved || snapped || bombed))
     {
       if (bombed && !moved)
        player_action &= JOY_BUTTON;
 
       stored_player_action[player->index_nr] = player_action;
+      save_tape_entry = TRUE;
     }
     else if (tape.playing && snapped)
       SnapField(player, 0, 0);                 /* stop snapping */
+#else
+    stored_player_action[player->index_nr] = player_action;
+#endif
   }
   else
   {
@@ -4239,20 +4269,49 @@ static void PlayerActions(struct PlayerInfo *player, byte player_action)
     SnapField(player, 0, 0);
     CheckGravityMovement(player);
 
+#if 1
+    if (player->MovPos == 0)   /* needed for tape.playing */
+      player->is_moving = FALSE;
+#endif
+#if 0
+    if (player->MovPos == 0)   /* needed for tape.playing */
+      player->last_move_dir = MV_NO_MOVING;
+
+    /* !!! CHECK THIS AGAIN !!!
+       (Seems to be needed for some EL_ROBOT stuff, but breaks
+       tapes when walking through pipes!)
+    */
+
+    /* it seems that "player->last_move_dir" is misused as some sort of
+       "player->is_just_moving_in_this_moment", which is needed for the
+       robot stuff (robots don't kill players when they are moving)
+    */
+#endif 
+
     if (++player->frame_reset_delay > player->move_delay_value)
       player->Frame = 0;
   }
 
+#if 0
   if (tape.recording && num_stored_actions >= MAX_PLAYERS && save_tape_entry)
   {
     TapeRecordAction(stored_player_action);
     num_stored_actions = 0;
     save_tape_entry = FALSE;
   }
+#else
+  if (tape.recording && num_stored_actions >= MAX_PLAYERS)
+  {
+    TapeRecordAction(stored_player_action);
+    num_stored_actions = 0;
+  }
+#endif
 
+#if 0
   if (tape.playing && !tape.pausing && !player_action &&
       tape.counter < tape.length)
   {
+    int jx = player->jx, jy = player->jy;
     int next_joy =
       tape.pos[tape.counter].action[player->index_nr] & (JOY_LEFT|JOY_RIGHT);
 
@@ -4276,6 +4335,7 @@ static void PlayerActions(struct PlayerInfo *player, byte player_action)
       }
     }
   }
+#endif
 }
 
 void GameActions()
@@ -4443,7 +4503,7 @@ void GameActions()
       AmoebeWaechst(x, y);
     else if (element == EL_DEAMOEBING)
       AmoebeSchrumpft(x, y);
-#if 1
+#if 0
     else if (IS_AMOEBALIVE(element))
       AmoebeAbleger(x, y);
 #endif
@@ -4530,7 +4590,7 @@ void GameActions()
     }
   }
 
-#if 0
+#if 1
   /* new experimental amoeba growth stuff*/
 #if 1
   if (!(FrameCounter % 8))
@@ -4538,9 +4598,9 @@ void GameActions()
   {
     static unsigned long random = 1684108901;
 
-    for (i = 0; i < level.amoeba_speed * 4; i++)
+    for (i = 0; i < level.amoeba_speed * 28 / 8; i++)
     {
-#if 1
+#if 0
       x = (random >> 10) % lev_fieldx;
       y = (random >> 20) % lev_fieldy;
 #else
@@ -4845,7 +4905,7 @@ boolean MoveFigureOneStep(struct PlayerInfo *player,
       BuryHero(player);
     }
     else
-      TestIfBadThingHitsHero(new_jx, new_jy);
+      TestIfHeroRunsIntoBadThing(jx, jy, player->MovDir);
 
     return MF_MOVING;
   }
@@ -4878,9 +4938,15 @@ boolean MoveFigure(struct PlayerInfo *player, int dx, int dy)
   if (!player->active || (!dx && !dy))
     return FALSE;
 
+#if 0
   if (!FrameReached(&player->move_delay, player->move_delay_value) &&
       !tape.playing)
     return FALSE;
+#else
+  if (!FrameReached(&player->move_delay, player->move_delay_value) &&
+      !(tape.playing && tape.file_version < FILE_VERSION_2_0))
+    return FALSE;
+#endif
 
   /* remove the last programmed player action */
   player->programmed_action = 0;
@@ -5009,15 +5075,19 @@ boolean MoveFigure(struct PlayerInfo *player, int dx, int dy)
     DrawLevelField(jx, jy);    /* for "ErdreichAnbroeckeln()" */
 
     player->last_move_dir = player->MovDir;
+    player->is_moving = TRUE;
   }
   else
   {
     CheckGravityMovement(player);
 
+    /*
     player->last_move_dir = MV_NO_MOVING;
+    */
+    player->is_moving = FALSE;
   }
 
-  TestIfHeroHitsBadThing(jx, jy);
+  TestIfHeroTouchesBadThing(jx, jy);
 
   if (!player->active)
     RemoveHero(player);
@@ -5112,17 +5182,17 @@ void ScrollScreen(struct PlayerInfo *player, int mode)
     ScreenMovDir = MV_NO_MOVING;
 }
 
-void TestIfGoodThingHitsBadThing(int goodx, int goody)
+void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir)
 {
-  int i, killx = goodx, killy = goody;
-  static int xy[4][2] =
+  int i, kill_x = -1, kill_y = -1;
+  static int test_xy[4][2] =
   {
     { 0, -1 },
     { -1, 0 },
     { +1, 0 },
     { 0, +1 }
   };
-  static int harmless[4] =
+  static int test_dir[4] =
   {
     MV_UP,
     MV_LEFT,
@@ -5132,57 +5202,62 @@ void TestIfGoodThingHitsBadThing(int goodx, int goody)
 
   for (i=0; i<4; i++)
   {
-    int x, y, element;
+    int test_x, test_y, test_move_dir, test_element;
 
-    x = goodx + xy[i][0];
-    y = goody + xy[i][1];
-    if (!IN_LEV_FIELD(x, y))
+    test_x = good_x + test_xy[i][0];
+    test_y = good_y + test_xy[i][1];
+    if (!IN_LEV_FIELD(test_x, test_y))
       continue;
 
+    test_move_dir =
+      (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NO_MOVING);
+
 #if 0
-    element = Feld[x][y];
+    test_element = Feld[test_x][test_y];
 #else
-    element = MovingOrBlocked2ElementIfNotLeaving(x, y);
+    test_element = MovingOrBlocked2ElementIfNotLeaving(test_x, test_y);
 #endif
 
-    if (DONT_TOUCH(element))
+    /* 1st case: good thing is moving towards DONT_GO_TO style bad thing;
+       2nd case: DONT_TOUCH style bad thing does not move away from good thing
+    */
+    if ((DONT_GO_TO(test_element) && good_move_dir == test_dir[i]) ||
+       (DONT_TOUCH(test_element) && test_move_dir != test_dir[i]))
     {
-      if (MovDir[x][y] == harmless[i])
-       continue;
-
-      killx = x;
-      killy = y;
+      kill_x = test_x;
+      kill_y = test_y;
       break;
     }
   }
 
-  if (killx != goodx || killy != goody)
+  if (kill_x != -1 || kill_y != -1)
   {
-    if (IS_PLAYER(goodx, goody))
+    if (IS_PLAYER(good_x, good_y))
     {
-      struct PlayerInfo *player = PLAYERINFO(goodx, goody);
+      struct PlayerInfo *player = PLAYERINFO(good_x, good_y);
 
       if (player->shield_active_time_left > 0)
-       Bang(killx, killy);
-      else if (!PLAYER_PROTECTED(goodx, goody))
+       Bang(kill_x, kill_y);
+      else if (!PLAYER_PROTECTED(good_x, good_y))
        KillHero(player);
     }
     else
-      Bang(goodx, goody);
+      Bang(good_x, good_y);
   }
 }
 
-void TestIfBadThingHitsGoodThing(int badx, int bady)
+void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir)
 {
-  int i, killx = badx, killy = bady;
-  static int xy[4][2] =
+  int i, kill_x = -1, kill_y = -1;
+  int bad_element = Feld[bad_x][bad_y];
+  static int test_xy[4][2] =
   {
     { 0, -1 },
     { -1, 0 },
     { +1, 0 },
     { 0, +1 }
   };
-  static int harmless[4] =
+  static int test_dir[4] =
   {
     MV_UP,
     MV_LEFT,
@@ -5190,76 +5265,117 @@ void TestIfBadThingHitsGoodThing(int badx, int bady)
     MV_DOWN
   };
 
-  if (Feld[badx][bady] == EL_EXPLODING)        /* skip just exploding bad things */
+  if (bad_element == EL_EXPLODING)     /* skip just exploding bad things */
     return;
 
   for (i=0; i<4; i++)
   {
-    int x, y, element;
+    int test_x, test_y, test_move_dir, test_element;
 
-    x = badx + xy[i][0];
-    y = bady + xy[i][1];
-    if (!IN_LEV_FIELD(x, y))
+    test_x = bad_x + test_xy[i][0];
+    test_y = bad_y + test_xy[i][1];
+    if (!IN_LEV_FIELD(test_x, test_y))
       continue;
 
-    element = Feld[x][y];
+    test_move_dir =
+      (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NO_MOVING);
 
-    if (IS_PLAYER(x, y))
-    {
-      killx = x;
-      killy = y;
-      break;
-    }
-    else if (element == EL_PINGUIN)
+    test_element = Feld[test_x][test_y];
+
+    /* 1st case: good thing is moving towards DONT_GO_TO style bad thing;
+       2nd case: DONT_TOUCH style bad thing does not move away from good thing
+    */
+    if ((DONT_GO_TO(bad_element) &&  bad_move_dir == test_dir[i]) ||
+       (DONT_TOUCH(bad_element) && test_move_dir != test_dir[i]))
     {
-      if (MovDir[x][y] == harmless[i] && IS_MOVING(x, y))
-       continue;
+      /* good thing is player or penguin that does not move away */
+      if (IS_PLAYER(test_x, test_y))
+      {
+       struct PlayerInfo *player = PLAYERINFO(test_x, test_y);
 
-      killx = x;
-      killy = y;
-      break;
+       if (bad_element == EL_ROBOT && player->is_moving)
+         continue;     /* robot does not kill player if he is moving */
+
+       kill_x = test_x;
+       kill_y = test_y;
+       break;
+      }
+      else if (test_element == EL_PINGUIN)
+      {
+       kill_x = test_x;
+       kill_y = test_y;
+       break;
+      }
     }
   }
 
-  if (killx != badx || killy != bady)
+  if (kill_x != -1 || kill_y != -1)
   {
-    if (IS_PLAYER(killx, killy))
+    if (IS_PLAYER(kill_x, kill_y))
     {
-      struct PlayerInfo *player = PLAYERINFO(killx, killy);
+      struct PlayerInfo *player = PLAYERINFO(kill_x, kill_y);
+
+#if 0
+      int dir = player->MovDir;
+      int newx = player->jx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
+      int newy = player->jy + (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
+
+      if (Feld[bad_x][bad_y] == EL_ROBOT && player->is_moving &&
+         newx != bad_x && newy != bad_y)
+       ;       /* robot does not kill player if he is moving */
+      else
+       printf("-> %d\n", player->MovDir);
+
+      if (Feld[bad_x][bad_y] == EL_ROBOT && player->is_moving &&
+         newx != bad_x && newy != bad_y)
+       ;       /* robot does not kill player if he is moving */
+      else
+       ;
+#endif
 
       if (player->shield_active_time_left > 0)
-       Bang(badx, bady);
-      else if (!PLAYER_PROTECTED(killx, killy))
+       Bang(bad_x, bad_y);
+      else if (!PLAYER_PROTECTED(kill_x, kill_y))
        KillHero(player);
     }
     else
-      Bang(killx, killy);
+      Bang(kill_x, kill_y);
   }
 }
 
-void TestIfHeroHitsBadThing(int x, int y)
+void TestIfHeroTouchesBadThing(int x, int y)
+{
+  TestIfGoodThingHitsBadThing(x, y, MV_NO_MOVING);
+}
+
+void TestIfHeroRunsIntoBadThing(int x, int y, int move_dir)
 {
-  TestIfGoodThingHitsBadThing(x, y);
+  TestIfGoodThingHitsBadThing(x, y, move_dir);
 }
 
-void TestIfBadThingHitsHero(int x, int y)
+void TestIfBadThingTouchesHero(int x, int y)
 {
-  TestIfBadThingHitsGoodThing(x, y);
+  TestIfBadThingHitsGoodThing(x, y, MV_NO_MOVING);
 }
 
-void TestIfFriendHitsBadThing(int x, int y)
+void TestIfBadThingRunsIntoHero(int x, int y, int move_dir)
 {
-  TestIfGoodThingHitsBadThing(x, y);
+  TestIfBadThingHitsGoodThing(x, y, move_dir);
 }
 
-void TestIfBadThingHitsFriend(int x, int y)
+void TestIfFriendTouchesBadThing(int x, int y)
 {
-  TestIfBadThingHitsGoodThing(x, y);
+  TestIfGoodThingHitsBadThing(x, y, MV_NO_MOVING);
 }
 
-void TestIfBadThingHitsOtherBadThing(int badx, int bady)
+void TestIfBadThingTouchesFriend(int x, int y)
 {
-  int i, killx = badx, killy = bady;
+  TestIfBadThingHitsGoodThing(x, y, MV_NO_MOVING);
+}
+
+void TestIfBadThingTouchesOtherBadThing(int bad_x, int bad_y)
+{
+  int i, kill_x = bad_x, kill_y = bad_y;
   static int xy[4][2] =
   {
     { 0, -1 },
@@ -5272,8 +5388,8 @@ void TestIfBadThingHitsOtherBadThing(int badx, int bady)
   {
     int x, y, element;
 
-    x=badx + xy[i][0];
-    y=bady + xy[i][1];
+    x = bad_x + xy[i][0];
+    y = bad_y + xy[i][1];
     if (!IN_LEV_FIELD(x, y))
       continue;
 
@@ -5281,14 +5397,14 @@ void TestIfBadThingHitsOtherBadThing(int badx, int bady)
     if (IS_AMOEBOID(element) || element == EL_LIFE ||
        element == EL_AMOEBING || element == EL_TROPFEN)
     {
-      killx = x;
-      killy = y;
+      kill_x = x;
+      kill_y = y;
       break;
     }
   }
 
-  if (killx != badx || killy != bady)
-    Bang(badx, bady);
+  if (kill_x != bad_x || kill_y != bad_y)
+    Bang(bad_x, bad_y);
 }
 
 void KillHero(struct PlayerInfo *player)
@@ -5337,7 +5453,8 @@ void RemoveHero(struct PlayerInfo *player)
   player->present = FALSE;
   player->active = FALSE;
 
-  StorePlayer[jx][jy] = 0;
+  if (!ExplodeField[jx][jy])
+    StorePlayer[jx][jy] = 0;
 
   for (i=0; i<MAX_PLAYERS; i++)
     if (stored_player[i].active)
@@ -5679,9 +5796,16 @@ int DigField(struct PlayerInfo *player,
 
       if (player->push_delay == 0)
        player->push_delay = FrameCounter;
+#if 0
       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
          !tape.playing && element != EL_SPRING)
        return MF_NO_ACTION;
+#else
+      if (!FrameReached(&player->push_delay, player->push_delay_value) &&
+         !(tape.playing && tape.file_version < FILE_VERSION_2_0) &&
+         element != EL_SPRING)
+       return MF_NO_ACTION;
+#endif
 
       RemoveField(x, y);
       Feld[x+dx][y+dy] = element;
@@ -5914,9 +6038,16 @@ int DigField(struct PlayerInfo *player,
 
       if (player->push_delay == 0)
        player->push_delay = FrameCounter;
+#if 0
       if (!FrameReached(&player->push_delay, player->push_delay_value) &&
          !tape.playing && element != EL_BALLOON)
        return MF_NO_ACTION;
+#else
+      if (!FrameReached(&player->push_delay, player->push_delay_value) &&
+         !(tape.playing && tape.file_version < FILE_VERSION_2_0) &&
+         element != EL_BALLOON)
+       return MF_NO_ACTION;
+#endif
 
       if (IS_SB_ELEMENT(element))
       {