added editor settings if Sokoban fields and objects need to be solved
authorHolger Schemel <info@artsoft.org>
Mon, 29 Oct 2018 19:32:07 +0000 (20:32 +0100)
committerHolger Schemel <info@artsoft.org>
Mon, 29 Oct 2018 19:32:07 +0000 (20:32 +0100)
src/editor.c
src/files.c
src/game.c
src/main.h

index 55e8104bb85263429867e28151aa4d53a86f513f..57c791326e3321ace5af05976834fbdc7823684d 100644 (file)
@@ -642,6 +642,8 @@ enum
   GADGET_ID_RANDOM_BALL_CONTENT,
   GADGET_ID_INITIAL_BALL_STATE,
   GADGET_ID_GROW_INTO_DIGGABLE,
+  GADGET_ID_SB_FIELDS_NEEDED,
+  GADGET_ID_SB_OBJECTS_NEEDED,
   GADGET_ID_AUTO_EXIT_SOKOBAN,
   GADGET_ID_SOLVED_BY_ONE_PLAYER,
   GADGET_ID_CONTINUOUS_SNAPPING,
@@ -945,6 +947,8 @@ enum
   ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT,
   ED_CHECKBUTTON_ID_INITIAL_BALL_STATE,
   ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE,
+  ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED,
+  ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED,
   ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN,
   ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER,
   ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING,
@@ -3068,6 +3072,20 @@ static struct
   },
   {
     ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(0),
+    GADGET_ID_SB_FIELDS_NEEDED,                GADGET_ID_NONE,
+    &level.sb_fields_needed,
+    NULL, NULL,
+    "all fields need to be filled",    "require all SB fields to be solved"
+  },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(0),
+    GADGET_ID_SB_OBJECTS_NEEDED,       GADGET_ID_NONE,
+    &level.sb_objects_needed,
+    NULL, NULL,
+    "all objects need to be placed",   "require all SB objects to be solved"
+  },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
     GADGET_ID_AUTO_EXIT_SOKOBAN,       GADGET_ID_NONE,
     &level.auto_exit_sokoban,
     NULL, NULL,
@@ -9931,10 +9949,22 @@ static void DrawPropertiesConfig(void)
     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE);
   }
 
+  if (properties_element == EL_SOKOBAN_FIELD_EMPTY)
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED);
+
+  if (properties_element == EL_SOKOBAN_OBJECT)
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED);
+
   if (properties_element == EL_SOKOBAN_OBJECT ||
       properties_element == EL_SOKOBAN_FIELD_EMPTY ||
       properties_element == EL_SOKOBAN_FIELD_FULL)
+  {
+    checkbutton_info[ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN].y =
+      ED_ELEMENT_SETTINGS_XPOS(properties_element == EL_SOKOBAN_FIELD_FULL ?
+                              0 : 1);
+
     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN);
+  }
 
   if (IS_BALLOON_ELEMENT(properties_element))
     MapSelectboxGadget(ED_SELECTBOX_ID_WIND_DIRECTION);
index 0b0c37d340981bac3395684ad0d48a4c0262fe19..58af05974d722b160b2db2860372a23d99b070a6 100644 (file)
@@ -818,6 +818,18 @@ static struct LevelFileConfigInfo chunk_config_ELEM[] =
     &li.num_ball_contents,             4, MAX_ELEMENT_CONTENTS
   },
 
+  {
+    EL_SOKOBAN_FIELD_EMPTY,            -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &li.sb_fields_needed,              TRUE
+  },
+
+  {
+    EL_SOKOBAN_OBJECT,                 -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
+    &li.sb_objects_needed,             TRUE
+  },
+
   {
     EL_MM_MCDUFFIN,                    -1,
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(1),
index 4a3d1eef4d4e63bbe088da3b3209f31ce03088ad..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,11 +1816,11 @@ static void InitField(int x, int y, boolean init_game)
       break;
 
     case EL_SOKOBAN_FIELD_EMPTY:
-      local_player->sokoban_fields_still_needed++;
+      IncrementPlayerSokobanFieldsNeeded(local_player);
       break;
 
     case EL_SOKOBAN_OBJECT:
-      local_player->sokoban_objects_still_needed++;
+      IncrementPlayerSokobanObjectsNeeded(local_player);
       break;
 
     case EL_STONEBLOCK:
@@ -13948,15 +13972,17 @@ static int DigField(struct PlayerInfo *player,
       if (element == EL_SOKOBAN_FIELD_FULL)
       {
        Back[x][y] = EL_SOKOBAN_FIELD_EMPTY;
-       local_player->sokoban_fields_still_needed++;
-       local_player->sokoban_objects_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->sokoban_fields_still_needed--;
-       local_player->sokoban_objects_still_needed--;
+
+       DecrementPlayerSokobanFieldsNeeded(local_player);
+       DecrementPlayerSokobanObjectsNeeded(local_player);
 
        // sokoban object was pushed from empty field to sokoban field
        if (Back[x][y] == EL_EMPTY)
index 8cf8642a02b72c87c4fb553ef69d386fe326da5c..b645a73c93e77d6575351266ff051b2ef7bd1915 100644 (file)
@@ -3097,6 +3097,8 @@ struct LevelInfo
   boolean lazy_relocation;     // only redraw off-screen player relocation
   boolean can_pass_to_walkable;        // player can pass to empty or walkable tile
   boolean grow_into_diggable;  // amoeba can grow into anything diggable
+  boolean sb_fields_needed;    // all Sokoban fields must be solved
+  boolean sb_objects_needed;   // all Sokoban objects must be solved
   boolean auto_exit_sokoban;   // automatically finish solved Sokoban levels
   boolean solved_by_one_player;        // level is solved if one player enters exit