rnd-20061029-1-src
[rocksndiamonds.git] / src / game.c
index 9ad7d0330d8a20add3851b06e7e9194ea6e5cf82..61d5d6b2f313b7586c73527b7bafd7a19da749dd 100644 (file)
@@ -56,6 +56,9 @@
 #define USE_GFX_RESET_ONLY_WHEN_MOVING (USE_NEW_STUFF          * 1)
 #define USE_GFX_RESET_PLAYER_ARTWORK   (USE_NEW_STUFF          * 1)
 
+#define USE_FIX_KILLED_BY_NON_WALKABLE (USE_NEW_STUFF          * 1)
+#define USE_FIX_IMPACT_COLLISION       (USE_NEW_STUFF          * 1)
+
 
 /* for DigField() */
 #define DF_NO_PUSH             0
 
 /* values for delayed check of falling and moving elements and for collision */
 #define CHECK_DELAY_MOVING     3
-#define CHECK_DELAY_FALLING    3
+#define CHECK_DELAY_FALLING    CHECK_DELAY_MOVING
 #define CHECK_DELAY_COLLISION  2
+#define CHECK_DELAY_IMPACT     CHECK_DELAY_COLLISION
 
 /* values for initial player move delay (initial delay counter value) */
 #define INITIAL_MOVE_DELAY_OFF -1
@@ -2035,6 +2039,7 @@ void InitGame()
     WasJustMoving[x][y] = 0;
     WasJustFalling[x][y] = 0;
     CheckCollision[x][y] = 0;
+    CheckImpact[x][y] = 0;
     Stop[x][y] = FALSE;
     Pushed[x][y] = FALSE;
 
@@ -2486,7 +2491,7 @@ void InitMovDir(int x, int y)
     { MV_LEFT,  MV_RIGHT, MV_UP, MV_DOWN }
   };
 
-  switch(element)
+  switch (element)
   {
     case EL_BUG_RIGHT:
     case EL_BUG_UP:
@@ -2729,35 +2734,38 @@ void GameWon()
       DrawGameValue_Score(score);
     }
 
-    if (ExitX >= 0 && ExitY >= 0)      /* local player has left the level */
+    if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
     {
-      /* close exit door after last player */
-      if (AllPlayersGone &&
-         (Feld[ExitX][ExitY] == EL_EXIT_OPEN ||
-          Feld[ExitX][ExitY] == EL_SP_EXIT_OPEN))
+      if (ExitX >= 0 && ExitY >= 0)    /* local player has left the level */
       {
-       int element = Feld[ExitX][ExitY];
-
-       Feld[ExitX][ExitY] = (element == EL_EXIT_OPEN ? EL_EXIT_CLOSING :
-                             EL_SP_EXIT_CLOSING);
+       /* close exit door after last player */
+       if (AllPlayersGone &&
+           (Feld[ExitX][ExitY] == EL_EXIT_OPEN ||
+            Feld[ExitX][ExitY] == EL_SP_EXIT_OPEN))
+       {
+         int element = Feld[ExitX][ExitY];
 
-       PlayLevelSoundElementAction(ExitX, ExitY, element, ACTION_CLOSING);
-      }
+         Feld[ExitX][ExitY] = (element == EL_EXIT_OPEN ? EL_EXIT_CLOSING :
+                               EL_SP_EXIT_CLOSING);
 
-      /* player disappears */
-      DrawLevelField(ExitX, ExitY);
-    }
+         PlayLevelSoundElementAction(ExitX, ExitY, element, ACTION_CLOSING);
+       }
 
-    for (i = 0; i < MAX_PLAYERS; i++)
-    {
-      struct PlayerInfo *player = &stored_player[i];
+       /* player disappears */
+       DrawLevelField(ExitX, ExitY);
+      }
 
-      if (player->present)
+      for (i = 0; i < MAX_PLAYERS; i++)
       {
-       RemovePlayer(player);
+       struct PlayerInfo *player = &stored_player[i];
 
-       /* player disappears */
-       DrawLevelField(player->jx, player->jy);
+       if (player->present)
+       {
+         RemovePlayer(player);
+
+         /* player disappears */
+         DrawLevelField(player->jx, player->jy);
+       }
       }
     }
 
@@ -3920,7 +3928,7 @@ void Bang(int x, int y)
     }
   }
 
-  switch(element)
+  switch (element)
   {
     case EL_BUG:
     case EL_SPACESHIP:
@@ -5632,9 +5640,14 @@ void StartMoving(int x, int y)
 
       Store[x][y] = EL_ACID;
     }
-    else if ((game.engine_version >= VERSION_IDENT(3,1,0,0) &&
+    else if (
+#if USE_FIX_IMPACT_COLLISION
+            (game.engine_version >= VERSION_IDENT(3,1,0,0) &&
+             CheckImpact[x][y] && !IS_FREE(x, y + 1)) ||
+#else
+            (game.engine_version >= VERSION_IDENT(3,1,0,0) &&
              CheckCollision[x][y] && !IS_FREE(x, y + 1)) ||
-
+#endif
             (game.engine_version >= VERSION_IDENT(3,0,7,0) &&
              CAN_FALL(element) && WasJustFalling[x][y] &&
              (Feld[x][y + 1] == EL_BLOCKED || IS_PLAYER(x, y + 1))) ||
@@ -5654,6 +5667,7 @@ void StartMoving(int x, int y)
         simply not covered here... :-/ ) */
 
       CheckCollision[x][y] = 0;
+      CheckImpact[x][y] = 0;
 
       Impact(x, y);
     }
@@ -6598,6 +6612,11 @@ void ContinueMoving(int x, int y)
 
     if ((!CAN_FALL(element) || direction == MV_DOWN) && check_collision_again)
       CheckCollision[newx][newy] = CHECK_DELAY_COLLISION;
+
+#if USE_FIX_IMPACT_COLLISION
+    if (CAN_FALL(element) && direction == MV_DOWN && check_collision_again)
+      CheckImpact[newx][newy] = CHECK_DELAY_IMPACT;
+#endif
   }
 
   if (DONT_TOUCH(element))     /* object may be nasty to player or others */
@@ -6665,7 +6684,7 @@ void ContinueMoving(int x, int y)
   if (IS_CUSTOM_ELEMENT(element) && ei->move_enter_element != EL_EMPTY &&
       IS_EQUAL_OR_IN_GROUP(stored_new, ei->move_enter_element))
     CheckElementChangeBySide(newx, newy, element, stored_new, CE_DIGGING_X,
-                                     MV_DIR_OPPOSITE(direction));
+                            MV_DIR_OPPOSITE(direction));
 }
 
 int AmoebeNachbarNr(int ax, int ay)
@@ -7715,7 +7734,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page)
 
   /* ---------- execute action  -------------------------------------------- */
 
-  switch(action_type)
+  switch (action_type)
   {
     case CA_NO_ACTION:
     {
@@ -8055,6 +8074,7 @@ static void CreateFieldExt(int x, int y, int element, boolean is_change)
 #if USE_NEW_CUSTOM_VALUE
   int last_ce_value = CustomValue[x][y];
 #endif
+  boolean player_explosion_protected = PLAYER_EXPLOSION_PROTECTED(x, y);
   boolean new_element_is_player = ELEM_IS_PLAYER(new_element);
   boolean add_player_onto_element = (new_element_is_player &&
 #if USE_CODE_THAT_BREAKS_SNAKE_BITE
@@ -8118,6 +8138,15 @@ static void CreateFieldExt(int x, int y, int element, boolean is_change)
   /* 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 USE_FIX_KILLED_BY_NON_WALKABLE
+  if (IS_PLAYER(x, y) && !player_explosion_protected &&
+      IS_ACCESSIBLE(old_element) && !IS_ACCESSIBLE(new_element))
+  {
+    Bang(x, y);
+
+    return;
+  }
+#else
   if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y) &&
       IS_ACCESSIBLE(old_element) && !IS_ACCESSIBLE(new_element))
   {
@@ -8125,6 +8154,7 @@ static void CreateFieldExt(int x, int y, int element, boolean is_change)
 
     return;
   }
+#endif
 #endif
 
   /* "ChangeCount" not set yet to allow "entered by player" change one time */
@@ -8631,10 +8661,18 @@ static boolean CheckElementChangeExt(int x, int y,
   {
     struct ElementChangeInfo *change = &element_info[element].change_page[p];
 
+    /* check trigger element for all events where the element that is checked
+       for changing interacts with a directly adjacent element -- this is
+       different to element changes that affect other elements to change on the
+       whole playfield (which is handeld by CheckTriggeredElementChangeExt()) */
     boolean check_trigger_element =
       (trigger_event == CE_TOUCHING_X ||
        trigger_event == CE_HITTING_X ||
-       trigger_event == CE_HIT_BY_X);
+       trigger_event == CE_HIT_BY_X ||
+#if 1
+       /* this one was forgotten until 3.2.3 */
+       trigger_event == CE_DIGGING_X);
+#endif
 
     if (change->can_change_or_has_action &&
        change->has_event[trigger_event] &&
@@ -9408,6 +9446,8 @@ void GameActions_RND()
       WasJustFalling[x][y]--;
     if (CheckCollision[x][y] > 0)
       CheckCollision[x][y]--;
+    if (CheckImpact[x][y] > 0)
+      CheckImpact[x][y]--;
 
     GfxFrame[x][y]++;
 
@@ -12044,7 +12084,13 @@ boolean DropElement(struct PlayerInfo *player)
     nexty = dropy + GET_DY_FROM_DIR(move_direction);
 
     ChangeCount[dropx][dropy] = 0;     /* allow at least one more change */
+
+#if USE_FIX_IMPACT_COLLISION
+    /* do not cause impact style collision by dropping elements that can fall */
+    CheckCollision[dropx][dropy] = CHECK_DELAY_COLLISION;
+#else
     CheckCollision[dropx][dropy] = CHECK_DELAY_COLLISION;
+#endif
   }
 
   player->drop_delay = GET_NEW_DROP_DELAY(drop_element);
@@ -12371,7 +12417,7 @@ void RaiseScore(int value)
 
 void RaiseScoreElement(int element)
 {
-  switch(element)
+  switch (element)
   {
     case EL_EMERALD:
     case EL_BD_DIAMOND:
@@ -12670,6 +12716,9 @@ void SaveEngineSnapshot()
 {
   FreeEngineSnapshot();                /* free previous snapshot, if needed */
 
+  if (level_editor_test_game)  /* do not save snapshots from editor */
+    return;
+
   /* copy some special values to a structure better suited for the snapshot */
 
   SaveEngineSnapshotValues_RND();
@@ -12723,6 +12772,7 @@ void SaveEngineSnapshot()
   SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(WasJustMoving));
   SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(WasJustFalling));
   SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(CheckCollision));
+  SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(CheckImpact));
   SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Stop));
   SaveEngineSnapshotBuffer(ARGS_ADDRESS_AND_SIZEOF(Pushed));