fixed broken player option "no centering when relocating"
[rocksndiamonds.git] / src / game.c
index 2372aac5f4106df0f5eb1610271cc96df6c1bc9e..09c7fa096b0d8edfae177c88fac18735f44a343f 100644 (file)
@@ -3195,6 +3195,17 @@ static void InitGameEngine(void)
     SET_PROPERTY(ch_delay->element, EP_CAN_CHANGE_OR_HAS_ACTION, TRUE);
   }
 
+  // ---------- initialize if element can trigger global animations -----------
+
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+  {
+    struct ElementInfo *ei = &element_info[i];
+
+    ei->has_anim_event = FALSE;
+  }
+
+  InitGlobalAnimEventsForCustomElements();
+
   // ---------- initialize internal run-time variables ------------------------
 
   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
@@ -3505,10 +3516,10 @@ static void InitGameEngine(void)
     {
       int element = EL_CUSTOM_START + i;
 
-      if (HAS_CHANGE_EVENT(element, CE_CLICKED_BY_MOUSE) ||
-         HAS_CHANGE_EVENT(element, CE_PRESSED_BY_MOUSE) ||
-         HAS_CHANGE_EVENT(element, CE_MOUSE_CLICKED_ON_X) ||
-         HAS_CHANGE_EVENT(element, CE_MOUSE_PRESSED_ON_X))
+      if (HAS_ANY_CHANGE_EVENT(element, CE_CLICKED_BY_MOUSE) ||
+         HAS_ANY_CHANGE_EVENT(element, CE_PRESSED_BY_MOUSE) ||
+         HAS_ANY_CHANGE_EVENT(element, CE_MOUSE_CLICKED_ON_X) ||
+         HAS_ANY_CHANGE_EVENT(element, CE_MOUSE_PRESSED_ON_X))
        game.use_mouse_actions = TRUE;
     }
   }
@@ -3618,6 +3629,10 @@ void InitGame(void)
     // force restarting global animations displayed during game play
     RestartGlobalAnimsByStatus(GAME_MODE_PSEUDO_RESTARTING);
 
+    // this is required for "transforming" fade modes like cross-fading
+    // (else global animations will be stopped, but not restarted here)
+    SetAnimStatusBeforeFading(GAME_MODE_PSEUDO_RESTARTING);
+
     SetGameStatus(GAME_MODE_PLAYING);
   }
 
@@ -5659,14 +5674,13 @@ static void DrawRelocateScreen(int old_x, int old_y, int x, int y,
   {
     // relocation _without_ centering of screen
 
-    int center_scroll_x = SCROLL_POSITION_X(old_x);
-    int center_scroll_y = SCROLL_POSITION_Y(old_y);
-    int offset_x = x + (scroll_x - center_scroll_x);
-    int offset_y = y + (scroll_y - center_scroll_y);
+    // apply distance between old and new player position to scroll position
+    int shifted_scroll_x = scroll_x + (x - old_x);
+    int shifted_scroll_y = scroll_y + (y - old_y);
 
-    // for new screen position, apply previous offset to center position
-    new_scroll_x = SCROLL_POSITION_X(offset_x);
-    new_scroll_y = SCROLL_POSITION_Y(offset_y);
+    // make sure that shifted scroll position does not scroll beyond screen
+    new_scroll_x = SCROLL_POSITION_X(shifted_scroll_x + MIDPOSX);
+    new_scroll_y = SCROLL_POSITION_Y(shifted_scroll_y + MIDPOSY);
   }
 
   if (quick_relocation)
@@ -10626,17 +10640,26 @@ static void CreateFieldExt(int x, int y, int element, boolean is_change)
 
     if (GFX_CRUMBLED(new_element))
       TEST_DrawLevelFieldCrumbledNeighbours(x, y);
-  }
 
-  // check if element under the player changes from accessible to unaccessible
-  // (needed for special case of dropping element which then changes)
-  // (must be checked after creating new element for walkable group elements)
-  if (IS_PLAYER(x, y) && !player_explosion_protected &&
-      IS_ACCESSIBLE(old_element) && !IS_ACCESSIBLE(new_element))
-  {
-    Bang(x, y);
+    if (old_element == EL_EXPLOSION)
+    {
+      Store[x][y] = Store2[x][y] = 0;
 
-    return;
+      // check if new element replaces an exploding player, requiring cleanup
+      if (IS_PLAYER(x, y) && !PLAYERINFO(x, y)->present)
+       StorePlayer[x][y] = 0;
+    }
+
+    // check if element under the player changes from accessible to unaccessible
+    // (needed for special case of dropping element which then changes)
+    // (must be checked after creating new element for walkable group elements)
+    if (IS_PLAYER(x, y) && !player_explosion_protected &&
+       IS_ACCESSIBLE(old_element) && !IS_ACCESSIBLE(new_element))
+    {
+      KillPlayer(PLAYERINFO(x, y));
+
+      return;
+    }
   }
 
   // "ChangeCount" not set yet to allow "entered by player" change one time
@@ -10704,6 +10727,9 @@ static boolean ChangeElement(int x, int y, int element, int page)
 
   ChangeCount[x][y]++;         // count number of changes in the same frame
 
+  if (ei->has_anim_event)
+    HandleGlobalAnimEventByElementChange(element, page, x, y);
+
   if (change->explode)
   {
     Bang(x, y);
@@ -13447,8 +13473,9 @@ void TestIfPlayerTouchesCustomElement(int x, int y)
           incorrectly give EL_PLAYER_1 for "player->element_nr") */
        int player_element = PLAYERINFO(x, y)->initial_element;
 
+       // as element "X" is the player here, check opposite (center) side
        CheckElementChangeBySide(xx, yy, border_element, player_element,
-                                CE_TOUCHING_X, border_side);
+                                CE_TOUCHING_X, center_side);
       }
     }
     else if (IS_PLAYER(xx, yy))                // player found at border element
@@ -13474,8 +13501,9 @@ void TestIfPlayerTouchesCustomElement(int x, int y)
           incorrectly give EL_PLAYER_1 for "player->element_nr") */
        int player_element = PLAYERINFO(xx, yy)->initial_element;
 
+       // as element "X" is the player here, check opposite (border) side
        CheckElementChangeBySide(x, y, center_element, player_element,
-                                CE_TOUCHING_X, center_side);
+                                CE_TOUCHING_X, border_side);
       }
 
       break;
@@ -13582,7 +13610,7 @@ void TestIfElementTouchesCustomElement(int x, int y)
     CheckElementChangeBySide(xx, yy, border_element, center_element,
                             CE_TOUCHING_X, center_side);
 
-    // (center element cannot be player, so we dont have to check this here)
+    // (center element cannot be player, so we don't have to check this here)
   }
 
   for (i = 0; i < NUM_DIRECTIONS; i++)
@@ -13609,6 +13637,7 @@ void TestIfElementTouchesCustomElement(int x, int y)
         incorrectly give EL_PLAYER_1 for "player->element_nr") */
       int player_element = PLAYERINFO(xx, yy)->initial_element;
 
+      // as element "X" is the player here, check opposite (border) side
       CheckElementChangeBySide(x, y, center_element, player_element,
                               CE_TOUCHING_X, border_side);
     }