rnd-20040319-1-src
[rocksndiamonds.git] / src / game.c
index 2e4bc054f79cad0f0d20f931aeac0a6698212212..ac8eced7871f3c3f5c04b49ea4a199d2a8b063f0 100644 (file)
@@ -1201,6 +1201,10 @@ static void InitGameEngine()
     ei->change->post_change_function = ch_delay->post_change_function;
 
     ei->change_events |= CH_EVENT_BIT(CE_DELAY);
+
+#if 1
+    SET_PROPERTY(ch_delay->element, EP_CAN_CHANGE, TRUE);
+#endif
   }
 
 #if 1
@@ -1649,7 +1653,7 @@ void InitGame()
     if (!IS_CUSTOM_ELEMENT(i))
     {
       int num_phase = 8;
-      int delay = ((IS_SP_ELEMENT(i) &&
+      int delay = (((IS_SP_ELEMENT(i) && i != EL_EMPTY_SPACE) &&
                    game.engine_version >= VERSION_IDENT(3,1,0,0)) ||
                   game.emulation == EMU_SUPAPLEX ? 3 : 2);
       int last_phase = (num_phase + 1) * delay;
@@ -2652,6 +2656,40 @@ void RelocatePlayer(int x, int y, int element_raw)
 
   if (level.instant_relocation)
   {
+#if 1
+    int offset = (setup.scroll_delay ? 3 : 0);
+    int jx = local_player->jx;
+    int jy = local_player->jy;
+
+    if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
+    {
+      scroll_x = (local_player->jx < SBX_Left  + MIDPOSX ? SBX_Left :
+                 local_player->jx > SBX_Right + MIDPOSX ? SBX_Right :
+                 local_player->jx - MIDPOSX);
+
+      scroll_y = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
+                 local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
+                 local_player->jy - MIDPOSY);
+    }
+    else
+    {
+      if ((player->MovDir == MV_LEFT  && scroll_x > jx - MIDPOSX + offset) ||
+         (player->MovDir == MV_RIGHT && scroll_x < jx - MIDPOSX - offset))
+       scroll_x = jx - MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset);
+
+      if ((player->MovDir == MV_UP  && scroll_y > jy - MIDPOSY + offset) ||
+         (player->MovDir == MV_DOWN && scroll_y < jy - MIDPOSY - offset))
+       scroll_y = jy - MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset);
+
+      /* don't scroll over playfield boundaries */
+      if (scroll_x < SBX_Left || scroll_x > SBX_Right)
+       scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right);
+
+      /* don't scroll over playfield boundaries */
+      if (scroll_y < SBY_Upper || scroll_y > SBY_Lower)
+       scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower);
+    }
+#else
     scroll_x += (local_player->jx - old_jx);
     scroll_y += (local_player->jy - old_jy);
 
@@ -2662,11 +2700,65 @@ void RelocatePlayer(int x, int y, int element_raw)
     /* don't scroll over playfield boundaries */
     if (scroll_y < SBY_Upper || scroll_y > SBY_Lower)
       scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower);
+#endif
 
     RedrawPlayfield(TRUE, 0,0,0,0);
   }
   else
   {
+#if 1
+#if 0
+    int offset = (setup.scroll_delay ? 3 : 0);
+    int jx = local_player->jx;
+    int jy = local_player->jy;
+#endif
+    int scroll_xx = -999, scroll_yy = -999;
+
+    ScrollScreen(NULL, SCROLL_GO_ON);  /* scroll last frame to full tile */
+
+    while (scroll_xx != scroll_x || scroll_yy != scroll_y)
+    {
+      int dx = 0, dy = 0;
+      int fx = FX, fy = FY;
+
+      scroll_xx = (local_player->jx < SBX_Left  + MIDPOSX ? SBX_Left :
+                  local_player->jx > SBX_Right + MIDPOSX ? SBX_Right :
+                  local_player->jx - MIDPOSX);
+
+      scroll_yy = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
+                  local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
+                  local_player->jy - MIDPOSY);
+
+      dx = (scroll_xx < scroll_x ? +1 : scroll_xx > scroll_x ? -1 : 0);
+      dy = (scroll_yy < scroll_y ? +1 : scroll_yy > scroll_y ? -1 : 0);
+
+#if 1
+      if (dx == 0 && dy == 0)          /* no scrolling needed at all */
+       break;
+#else
+      if (scroll_xx == scroll_x && scroll_yy == scroll_y)
+       break;
+#endif
+
+      scroll_x -= dx;
+      scroll_y -= dy;
+
+      fx += dx * TILEX / 2;
+      fy += dy * TILEY / 2;
+
+      ScrollLevel(dx, dy);
+      DrawAllPlayers();
+
+      /* scroll in two steps of half tile size to make things smoother */
+      BlitBitmap(drawto_field, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
+      FlushDisplay();
+      Delay(wait_delay_value);
+
+      /* scroll second step to align at full tile size */
+      BackToFront();
+      Delay(wait_delay_value);
+    }
+#else
     int scroll_xx = -999, scroll_yy = -999;
 
     ScrollScreen(NULL, SCROLL_GO_ON);  /* scroll last frame to full tile */
@@ -2713,6 +2805,7 @@ void RelocatePlayer(int x, int y, int element_raw)
       BackToFront();
       Delay(wait_delay_value);
     }
+#endif
   }
 }
 
@@ -3125,6 +3218,10 @@ void Explode(int ex, int ey, int phase, int mode)
   {
     int element;
 
+#if 0
+  printf("::: done: phase == %d\n", phase);
+#endif
+
 #if 0
     printf("::: explosion %d,%d done [%d]\n", x, y, FrameCounter);
 #endif
@@ -5723,11 +5820,14 @@ void ContinueMoving(int x, int y)
   MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
   MovDelay[newx][newy] = 0;
 
-  /* copy element change control values to new field */
-  ChangeDelay[newx][newy] = ChangeDelay[x][y];
-  ChangePage[newx][newy] = ChangePage[x][y];
-  Changed[newx][newy] = Changed[x][y];
-  ChangeEvent[newx][newy] = ChangeEvent[x][y];
+  if (CAN_CHANGE(element))
+  {
+    /* copy element change control values to new field */
+    ChangeDelay[newx][newy] = ChangeDelay[x][y];
+    ChangePage[newx][newy]  = ChangePage[x][y];
+    Changed[newx][newy]     = Changed[x][y];
+    ChangeEvent[newx][newy] = ChangeEvent[x][y];
+  }
 
   ChangeDelay[x][y] = 0;
   ChangePage[x][y] = -1;
@@ -7021,9 +7121,8 @@ static void ChangeElement(int x, int y, int page)
   struct ElementInfo *ei = &element_info[element];
   struct ElementChangeInfo *change = &ei->change_page[page];
 
-#if 0
 #ifdef DEBUG
-  if (!CAN_CHANGE(element))
+  if (!CAN_CHANGE(element) && !CAN_CHANGE(Back[x][y]))
   {
     printf("\n\n");
     printf("ChangeElement(): %d,%d: element = %d ('%s')\n",
@@ -7032,8 +7131,18 @@ static void ChangeElement(int x, int y, int page)
     printf("\n\n");
   }
 #endif
+
+  /* this can happen with classic bombs on walkable, changing elements */
+  if (!CAN_CHANGE(element))
+  {
+#if 0
+    if (!CAN_CHANGE(Back[x][y]))       /* prevent permanent repetition */
+      ChangeDelay[x][y] = 0;
 #endif
 
+    return;
+  }
+
   if (ChangeDelay[x][y] == 0)          /* initialize element change */
   {
     ChangeDelay[x][y] = (    change->delay_fixed  * change->delay_frames +
@@ -7177,6 +7286,20 @@ static boolean CheckElementChangeExt(int x, int y,
     element = Feld[x][y];
   }
 
+#if 1
+  if (Feld[x][y] != element)   /* check if element has already changed */
+  {
+#if 0
+    printf("::: %d ('%s') != %d ('%s') [%d]\n",
+          Feld[x][y], element_info[Feld[x][y]].token_name,
+          element, element_info[element].token_name,
+          trigger_event);
+#endif
+
+    return FALSE;
+  }
+#endif
+
 #if 1
   if (trigger_page < 0)
   {
@@ -8431,11 +8554,13 @@ static void CheckGravityMovement(struct PlayerInfo *player)
        !(element_info[Feld[jx][jy]].access_direction & MV_DOWN)));
 
 #if 0
-    printf("::: checking gravity NOW [%d, %d, %d] [%d] ...\n",
+    printf("::: checking gravity NOW [%d, %d, %d] [%d] [%d / %d] ...\n",
           player_can_fall_down,
           player_is_standing_on_valid_field,
           player_is_moving_to_valid_field,
-          (player_is_moving_to_valid_field ? Feld[new_jx][new_jy] : -1));
+          (player_is_moving_to_valid_field ? Feld[new_jx][new_jy] : -1),
+          player->effective_action,
+          player->can_fall_into_acid);
 #endif
 
     if (player_can_fall_down &&
@@ -8694,7 +8819,7 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
     {
       if (jx != old_jx)                /* player has moved horizontally */
       {
-       if ((player->MovDir == MV_LEFT && scroll_x > jx - MIDPOSX + offset) ||
+       if ((player->MovDir == MV_LEFT  && scroll_x > jx - MIDPOSX + offset) ||
            (player->MovDir == MV_RIGHT && scroll_x < jx - MIDPOSX - offset))
          scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset);
 
@@ -8706,13 +8831,13 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
        scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x);
 
        /* don't scroll against the player's moving direction */
-       if ((player->MovDir == MV_LEFT && scroll_x > old_scroll_x) ||
+       if ((player->MovDir == MV_LEFT  && scroll_x > old_scroll_x) ||
            (player->MovDir == MV_RIGHT && scroll_x < old_scroll_x))
          scroll_x = old_scroll_x;
       }
       else                     /* player has moved vertically */
       {
-       if ((player->MovDir == MV_UP && scroll_y > jy - MIDPOSY + offset) ||
+       if ((player->MovDir == MV_UP   && scroll_y > jy - MIDPOSY + offset) ||
            (player->MovDir == MV_DOWN && scroll_y < jy - MIDPOSY - offset))
          scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset);
 
@@ -8724,7 +8849,7 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
        scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y);
 
        /* don't scroll against the player's moving direction */
-       if ((player->MovDir == MV_UP && scroll_y > old_scroll_y) ||
+       if ((player->MovDir == MV_UP   && scroll_y > old_scroll_y) ||
            (player->MovDir == MV_DOWN && scroll_y < old_scroll_y))
          scroll_y = old_scroll_y;
       }