added editor settings if Sokoban fields and objects need to be solved
[rocksndiamonds.git] / src / game.c
index 2eb944d2580343058ec85b5b42d25c96a2c72a6a..2fb1b686c7ae07a5482a68cc21e459993164d4b1 100644 (file)
@@ -1683,6 +1683,30 @@ int GetElementFromGroupElement(int element)
   return element;
 }
 
+static void IncrementPlayerSokobanFieldsNeeded(struct PlayerInfo *player)
+{
+  if (level.sb_fields_needed)
+    player->sokoban_fields_still_needed++;
+}
+
+static void IncrementPlayerSokobanObjectsNeeded(struct PlayerInfo *player)
+{
+  if (level.sb_objects_needed)
+    player->sokoban_objects_still_needed++;
+}
+
+static void DecrementPlayerSokobanFieldsNeeded(struct PlayerInfo *player)
+{
+  if (player->sokoban_fields_still_needed > 0)
+    player->sokoban_fields_still_needed--;
+}
+
+static void DecrementPlayerSokobanObjectsNeeded(struct PlayerInfo *player)
+{
+  if (player->sokoban_objects_still_needed > 0)
+    player->sokoban_objects_still_needed--;
+}
+
 static void InitPlayerField(int x, int y, int element, boolean init_game)
 {
   if (element == EL_SP_MURPHY)
@@ -1792,7 +1816,11 @@ static void InitField(int x, int y, boolean init_game)
       break;
 
     case EL_SOKOBAN_FIELD_EMPTY:
-      local_player->sokobanfields_still_needed++;
+      IncrementPlayerSokobanFieldsNeeded(local_player);
+      break;
+
+    case EL_SOKOBAN_OBJECT:
+      IncrementPlayerSokobanObjectsNeeded(local_player);
       break;
 
     case EL_STONEBLOCK:
@@ -2212,7 +2240,8 @@ static void UpdateGameControlValues(void)
                     game_mm.kettles_still_needed > 0 ||
                     game_mm.lights_still_needed > 0 :
                     local_player->gems_still_needed > 0 ||
-                    local_player->sokobanfields_still_needed > 0 ||
+                    local_player->sokoban_fields_still_needed > 0 ||
+                    local_player->sokoban_objects_still_needed > 0 ||
                     local_player->lights_still_needed > 0);
   int health = (local_player->LevelSolved ?
                local_player->LevelSolved_CountingHealth :
@@ -2381,9 +2410,9 @@ static void UpdateGameControlValues(void)
     local_player->friends_still_needed;
 
   game_panel_controls[GAME_PANEL_SOKOBAN_OBJECTS].value =
-    local_player->sokobanfields_still_needed;
+    local_player->sokoban_objects_still_needed;
   game_panel_controls[GAME_PANEL_SOKOBAN_FIELDS].value =
-    local_player->sokobanfields_still_needed;
+    local_player->sokoban_fields_still_needed;
 
   game_panel_controls[GAME_PANEL_ROBOT_WHEEL].value =
     (game.robot_wheel_active ? EL_ROBOT_WHEEL_ACTIVE : EL_ROBOT_WHEEL);
@@ -3389,7 +3418,8 @@ void InitGame(void)
     player->health_final = MAX_HEALTH;
 
     player->gems_still_needed = level.gems_needed;
-    player->sokobanfields_still_needed = 0;
+    player->sokoban_fields_still_needed = 0;
+    player->sokoban_objects_still_needed = 0;
     player->lights_still_needed = 0;
     player->players_still_needed = 0;
     player->friends_still_needed = 0;
@@ -9053,7 +9083,8 @@ static void ActivateMagicBall(int bx, int by)
 static void CheckExit(int x, int y)
 {
   if (local_player->gems_still_needed > 0 ||
-      local_player->sokobanfields_still_needed > 0 ||
+      local_player->sokoban_fields_still_needed > 0 ||
+      local_player->sokoban_objects_still_needed > 0 ||
       local_player->lights_still_needed > 0)
   {
     int element = Feld[x][y];
@@ -9076,7 +9107,8 @@ static void CheckExit(int x, int y)
 static void CheckExitEM(int x, int y)
 {
   if (local_player->gems_still_needed > 0 ||
-      local_player->sokobanfields_still_needed > 0 ||
+      local_player->sokoban_fields_still_needed > 0 ||
+      local_player->sokoban_objects_still_needed > 0 ||
       local_player->lights_still_needed > 0)
   {
     int element = Feld[x][y];
@@ -9099,7 +9131,8 @@ static void CheckExitEM(int x, int y)
 static void CheckExitSteel(int x, int y)
 {
   if (local_player->gems_still_needed > 0 ||
-      local_player->sokobanfields_still_needed > 0 ||
+      local_player->sokoban_fields_still_needed > 0 ||
+      local_player->sokoban_objects_still_needed > 0 ||
       local_player->lights_still_needed > 0)
   {
     int element = Feld[x][y];
@@ -9122,7 +9155,8 @@ static void CheckExitSteel(int x, int y)
 static void CheckExitSteelEM(int x, int y)
 {
   if (local_player->gems_still_needed > 0 ||
-      local_player->sokobanfields_still_needed > 0 ||
+      local_player->sokoban_fields_still_needed > 0 ||
+      local_player->sokoban_objects_still_needed > 0 ||
       local_player->lights_still_needed > 0)
   {
     int element = Feld[x][y];
@@ -13933,16 +13967,26 @@ static int DigField(struct PlayerInfo *player,
 
     if (IS_SB_ELEMENT(element))
     {
+      boolean sokoban_task_solved = FALSE;
+
       if (element == EL_SOKOBAN_FIELD_FULL)
       {
        Back[x][y] = EL_SOKOBAN_FIELD_EMPTY;
-       local_player->sokobanfields_still_needed++;
+
+       IncrementPlayerSokobanFieldsNeeded(local_player);
+       IncrementPlayerSokobanObjectsNeeded(local_player);
       }
 
       if (Feld[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY)
       {
        Back[nextx][nexty] = EL_SOKOBAN_FIELD_EMPTY;
-       local_player->sokobanfields_still_needed--;
+
+       DecrementPlayerSokobanFieldsNeeded(local_player);
+       DecrementPlayerSokobanObjectsNeeded(local_player);
+
+       // sokoban object was pushed from empty field to sokoban field
+       if (Back[x][y] == EL_EMPTY)
+         sokoban_task_solved = TRUE;
       }
 
       Feld[x][y] = EL_SOKOBAN_OBJECT;
@@ -13956,12 +14000,14 @@ static int DigField(struct PlayerInfo *player,
        PlayLevelSoundElementAction(nextx, nexty, EL_SOKOBAN_FIELD_EMPTY,
                                    ACTION_FILLING);
 
-      if (local_player->sokobanfields_still_needed == 0 &&
+      if (sokoban_task_solved &&
+         local_player->sokoban_fields_still_needed == 0 &&
+         local_player->sokoban_objects_still_needed == 0 &&
          (game.emulation == EMU_SOKOBAN || level.auto_exit_sokoban))
       {
        local_player->players_still_needed = 0;
 
-       PlayerWins(player);
+       PlayerWins(local_player);
 
        PlayLevelSound(x, y, SND_GAME_SOKOBAN_SOLVING);
       }