changed how custom elements change to player if they are walkable
authorHolger Schemel <info@artsoft.org>
Fri, 11 Jun 2021 15:01:50 +0000 (17:01 +0200)
committerHolger Schemel <info@artsoft.org>
Fri, 11 Jun 2021 15:01:50 +0000 (17:01 +0200)
Before this change, if a walkable CE changes to the player, the player
is placed on the CE, which will be kept under the player (so it does
not really change to the player, but just adds the player). This is
probably not the expected behaviour when changing a CE to the player
(but may make sense when using the "extended change target", placing
the player on one of the surrounding elements if they are walkable).

This change fixes this behaviour, so by default a CE that "changes to
the player" is replaced by the player, and not just adds the player.
However, a config option was added to the player element to explicitly
request the previous behaviour (which is used by the "Zelda II" level
set, for example).

src/editor.c
src/files.c
src/game.c
src/main.h

index 1713f04d9119d1044d351c73d42d4a3301ebbe30..9fb3157e1f0bc922e6a0c0eee212335fdfca4d82 100644 (file)
@@ -657,6 +657,7 @@ enum
   GADGET_ID_AUTO_EXIT_SOKOBAN,
   GADGET_ID_SOLVED_BY_ONE_PLAYER,
   GADGET_ID_FINISH_DIG_COLLECT,
+  GADGET_ID_KEEP_WALKABLE_CE,
   GADGET_ID_CONTINUOUS_SNAPPING,
   GADGET_ID_BLOCK_SNAP_FIELD,
   GADGET_ID_BLOCK_LAST_FIELD,
@@ -967,6 +968,7 @@ enum
   ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN,
   ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER,
   ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT,
+  ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE,
   ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING,
   ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD,
   ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD,
@@ -3170,6 +3172,13 @@ static struct
     NULL, NULL,
     "CE action on finished dig/collect", "only finished dig/collect triggers CE"
   },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(4),
+    GADGET_ID_KEEP_WALKABLE_CE,                GADGET_ID_NONE,
+    &level.keep_walkable_ce,
+    NULL, NULL,
+    "keep walkable CE changed to player", "keep CE changing to player if walkable"
+  },
   {
     ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(9),
     GADGET_ID_CONTINUOUS_SNAPPING,     GADGET_ID_NONE,
@@ -10044,6 +10053,7 @@ static void DrawPropertiesConfig(void)
       // draw checkbutton gadgets
       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY);
       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT);
+      MapCheckbuttonGadget(ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE);
 
       // draw counter gadgets
       MapCounterButtons(ED_COUNTER_ID_INVENTORY_SIZE);
index 83efc95803ba9dd0324b153219d81728ad06d33c..aaafe68a64aba2ef4db5d69a4354e371b6fdb4ff 100644 (file)
@@ -327,6 +327,11 @@ static struct LevelFileConfigInfo chunk_config_ELEM[] =
     TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(16),
     &li.finish_dig_collect,            TRUE
   },
+  {
+    EL_PLAYER_1,                       -1,
+    TYPE_BOOLEAN,                      CONF_VALUE_8_BIT(17),
+    &li.keep_walkable_ce,              FALSE
+  },
 
   // (these values are different for each player)
   {
@@ -6463,6 +6468,10 @@ static void LoadLevel_InitVersion(struct LevelInfo *level)
   // CE actions were triggered by unfinished digging/collecting up to 4.2.2.0
   if (level->game_version <= VERSION_IDENT(4,2,2,0))
     level->finish_dig_collect = FALSE;
+
+  // CE changing to player was kept under the player if walkable up to 4.2.3.1
+  if (level->game_version <= VERSION_IDENT(4,2,3,1))
+    level->keep_walkable_ce = TRUE;
 }
 
 static void LoadLevel_InitStandardElements(struct LevelInfo *level)
index be192e4fecda551a84af7b27346773c0571ae37c..3d99a11322b18df7d8daf4c8501b405f18633b2c 100644 (file)
@@ -10832,6 +10832,10 @@ static boolean ChangeElement(int x, int y, int element, int page)
       Store[x][y] = EL_EMPTY;
     }
 
+    // special case: element changes to player (and may be kept if walkable)
+    if (ELEM_IS_PLAYER(target_element) && !level.keep_walkable_ce)
+      CreateElementFromChange(x, y, EL_EMPTY);
+
     CreateElementFromChange(x, y, target_element);
 
     PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING);
index 2c2125f4ce2ea115b32e84deba925cfd95810073..a77d6eeedcafb0b0310ca097295aebda0f6cdffd 100644 (file)
@@ -3213,6 +3213,7 @@ struct LevelInfo
   boolean auto_exit_sokoban;   // automatically finish solved Sokoban levels
   boolean solved_by_one_player;        // level is solved if one player enters exit
   boolean finish_dig_collect;  // only finished dig/collect triggers ce action
+  boolean keep_walkable_ce;    // keep walkable CE if it changes to the player
 
   boolean continuous_snapping; // repeated snapping without releasing key
   boolean block_snap_field;    // snapping blocks field to show animation