rnd-20040221-1-src
authorHolger Schemel <info@artsoft.org>
Sat, 21 Feb 2004 16:57:12 +0000 (17:57 +0100)
committerHolger Schemel <info@artsoft.org>
Sat, 30 Aug 2014 08:45:55 +0000 (10:45 +0200)
* "spring push bug" reintroduced as configurable element property

ChangeLog
src/conftime.h
src/editor.c
src/files.c
src/game.c
src/init.c
src/init.h
src/main.c
src/main.h

index e2a771a293bcae1070b795cda5689e1125437c9c..da30093f4289dbf1901684bf63b53ed45bfc596f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,6 @@
+2004-02-21
+       * "spring push bug" reintroduced as configurable element property
+
 2004-02-17
        * fixed bug which caused all CE change pages to be ignored which had
          the same change event, but used a different element side
index 693dd203032fd514c059422cf7d9a7c1eaaebaa7..8b877d77dd0c95734727812714d2eb37d6bcf8e0 100644 (file)
@@ -1 +1 @@
-#define COMPILE_DATE_STRING "[2004-02-18 20:22]"
+#define COMPILE_DATE_STRING "[2004-02-21 13:33]"
index 9cd163a506eb7891c9f726b2606432424f655804..4a96432c60557924e851baadb885314699ea13b3 100644 (file)
 #define ED_SETTINGS_YOFFSET            (3 * MINI_TILEY / 2)
 
 #define ED_SETTINGS_XPOS(n)            (ED_SETTINGS_XSTART + \
-                                        n * ED_SETTINGS_XOFFSET)
+                                        (n) * ED_SETTINGS_XOFFSET)
 #define ED_SETTINGS_YPOS(n)            (ED_SETTINGS_YSTART + \
-                                        n * ED_SETTINGS_YOFFSET)
+                                        (n) * ED_SETTINGS_YOFFSET)
 
 #define ED_SETTINGS1_YPOS              MINI_TILEY
 #define ED_SETTINGS2_XPOS              MINI_TILEX
 #define ED_COUNTER_YSTART              (ED_SETTINGS1_YPOS + 2 * TILEY)
 #define ED_COUNTER_YDISTANCE           (3 * MINI_TILEY)
 #define ED_COUNTER_YPOS(n)             (ED_COUNTER_YSTART + \
-                                        n * ED_COUNTER_YDISTANCE)
+                                        (n) * ED_COUNTER_YDISTANCE)
 #define ED_COUNTER2_YPOS(n)            (ED_COUNTER_YSTART + \
-                                        n * ED_COUNTER_YDISTANCE - 2)
+                                        (n) * ED_COUNTER_YDISTANCE - 2)
 
 /* values for element content drawing areas */
 /* amoeba content */
 
 /* yamyam content */
 #define ED_AREA_YAMYAM_CONTENT_XPOS(n) (2 * MINI_TILEX + \
-                                        5 * (n % 4) * MINI_TILEX)
-#define ED_AREA_YAMYAM_CONTENT_YPOS(n) (22 * MINI_TILEY + \
-                                        6 * (n / 4) * MINI_TILEY)
+                                        5 * ((n) % 4) * MINI_TILEX)
+#define ED_AREA_YAMYAM_CONTENT_YPOS(n) (17 * MINI_TILEY + \
+                                        6 * ((n) / 4) * MINI_TILEY)
 
 /* custom change target */
 #define ED_AREA_ELEM_CONTENT2_YPOS     (ED_SETTINGS_YPOS(1) + \
 #define GADGET_ID_GRAVITY              (GADGET_ID_CHECKBUTTON_FIRST + 4)
 #define GADGET_ID_STICK_ELEMENT                (GADGET_ID_CHECKBUTTON_FIRST + 5)
 #define GADGET_ID_EM_SLIPPERY_GEMS     (GADGET_ID_CHECKBUTTON_FIRST + 6)
-#define GADGET_ID_BLOCK_LAST_FIELD     (GADGET_ID_CHECKBUTTON_FIRST + 7)
-#define GADGET_ID_SP_BLOCK_LAST_FIELD  (GADGET_ID_CHECKBUTTON_FIRST + 8)
-#define GADGET_ID_CUSTOM_EXPLODE_RESULT        (GADGET_ID_CHECKBUTTON_FIRST + 9)
-#define GADGET_ID_CUSTOM_EXPLODE_FIRE  (GADGET_ID_CHECKBUTTON_FIRST + 10)
-#define GADGET_ID_CUSTOM_EXPLODE_SMASH (GADGET_ID_CHECKBUTTON_FIRST + 11)
-#define GADGET_ID_CUSTOM_EXPLODE_IMPACT        (GADGET_ID_CHECKBUTTON_FIRST + 12)
-#define GADGET_ID_CUSTOM_WALK_TO_OBJECT        (GADGET_ID_CHECKBUTTON_FIRST + 13)
-#define GADGET_ID_CUSTOM_DEADLY                (GADGET_ID_CHECKBUTTON_FIRST + 14)
-#define GADGET_ID_CUSTOM_CAN_MOVE      (GADGET_ID_CHECKBUTTON_FIRST + 15)
-#define GADGET_ID_CUSTOM_CAN_FALL      (GADGET_ID_CHECKBUTTON_FIRST + 16)
-#define GADGET_ID_CUSTOM_CAN_SMASH     (GADGET_ID_CHECKBUTTON_FIRST + 17)
-#define GADGET_ID_CUSTOM_SLIPPERY      (GADGET_ID_CHECKBUTTON_FIRST + 18)
-#define GADGET_ID_CUSTOM_ACCESSIBLE    (GADGET_ID_CHECKBUTTON_FIRST + 19)
-#define GADGET_ID_CUSTOM_USE_GRAPHIC   (GADGET_ID_CHECKBUTTON_FIRST + 20)
-#define GADGET_ID_CUSTOM_USE_TEMPLATE  (GADGET_ID_CHECKBUTTON_FIRST + 21)
-#define GADGET_ID_CUSTOM_CAN_CHANGE    (GADGET_ID_CHECKBUTTON_FIRST + 22)
-#define GADGET_ID_CHANGE_USE_CONTENT   (GADGET_ID_CHECKBUTTON_FIRST + 23)
-#define GADGET_ID_CHANGE_USE_EXPLOSION (GADGET_ID_CHECKBUTTON_FIRST + 24)
-#define GADGET_ID_CHANGE_ONLY_COMPLETE (GADGET_ID_CHECKBUTTON_FIRST + 25)
-#define GADGET_ID_CHANGE_USE_RANDOM    (GADGET_ID_CHECKBUTTON_FIRST + 26)
-#define GADGET_ID_CHANGE_DELAY         (GADGET_ID_CHECKBUTTON_FIRST + 27)
-#define GADGET_ID_CHANGE_BY_DIRECT_ACT (GADGET_ID_CHECKBUTTON_FIRST + 28)
-#define GADGET_ID_CHANGE_BY_OTHER_ACT  (GADGET_ID_CHECKBUTTON_FIRST + 29)
+#define GADGET_ID_USE_SPRING_BUG       (GADGET_ID_CHECKBUTTON_FIRST + 7)
+#define GADGET_ID_BLOCK_LAST_FIELD     (GADGET_ID_CHECKBUTTON_FIRST + 8)
+#define GADGET_ID_SP_BLOCK_LAST_FIELD  (GADGET_ID_CHECKBUTTON_FIRST + 9)
+#define GADGET_ID_CAN_MOVE_INTO_ACID   (GADGET_ID_CHECKBUTTON_FIRST + 10)
+#define GADGET_ID_CUSTOM_EXPLODE_RESULT        (GADGET_ID_CHECKBUTTON_FIRST + 11)
+#define GADGET_ID_CUSTOM_EXPLODE_FIRE  (GADGET_ID_CHECKBUTTON_FIRST + 12)
+#define GADGET_ID_CUSTOM_EXPLODE_SMASH (GADGET_ID_CHECKBUTTON_FIRST + 13)
+#define GADGET_ID_CUSTOM_EXPLODE_IMPACT        (GADGET_ID_CHECKBUTTON_FIRST + 14)
+#define GADGET_ID_CUSTOM_WALK_TO_OBJECT        (GADGET_ID_CHECKBUTTON_FIRST + 15)
+#define GADGET_ID_CUSTOM_DEADLY                (GADGET_ID_CHECKBUTTON_FIRST + 16)
+#define GADGET_ID_CUSTOM_CAN_MOVE      (GADGET_ID_CHECKBUTTON_FIRST + 17)
+#define GADGET_ID_CUSTOM_CAN_FALL      (GADGET_ID_CHECKBUTTON_FIRST + 18)
+#define GADGET_ID_CUSTOM_CAN_SMASH     (GADGET_ID_CHECKBUTTON_FIRST + 19)
+#define GADGET_ID_CUSTOM_SLIPPERY      (GADGET_ID_CHECKBUTTON_FIRST + 20)
+#define GADGET_ID_CUSTOM_ACCESSIBLE    (GADGET_ID_CHECKBUTTON_FIRST + 21)
+#define GADGET_ID_CUSTOM_USE_GRAPHIC   (GADGET_ID_CHECKBUTTON_FIRST + 22)
+#define GADGET_ID_CUSTOM_USE_TEMPLATE  (GADGET_ID_CHECKBUTTON_FIRST + 23)
+#define GADGET_ID_CUSTOM_CAN_CHANGE    (GADGET_ID_CHECKBUTTON_FIRST + 24)
+#define GADGET_ID_CHANGE_USE_CONTENT   (GADGET_ID_CHECKBUTTON_FIRST + 25)
+#define GADGET_ID_CHANGE_USE_EXPLOSION (GADGET_ID_CHECKBUTTON_FIRST + 26)
+#define GADGET_ID_CHANGE_ONLY_COMPLETE (GADGET_ID_CHECKBUTTON_FIRST + 27)
+#define GADGET_ID_CHANGE_USE_RANDOM    (GADGET_ID_CHECKBUTTON_FIRST + 28)
+#define GADGET_ID_CHANGE_DELAY         (GADGET_ID_CHECKBUTTON_FIRST + 29)
+#define GADGET_ID_CHANGE_BY_DIRECT_ACT (GADGET_ID_CHECKBUTTON_FIRST + 30)
+#define GADGET_ID_CHANGE_BY_OTHER_ACT  (GADGET_ID_CHECKBUTTON_FIRST + 31)
 
 /* gadgets for buttons in element list */
-#define GADGET_ID_ELEMENTLIST_FIRST    (GADGET_ID_CHECKBUTTON_FIRST + 30)
+#define GADGET_ID_ELEMENTLIST_FIRST    (GADGET_ID_CHECKBUTTON_FIRST + 32)
 #define GADGET_ID_ELEMENTLIST_LAST     (GADGET_ID_ELEMENTLIST_FIRST +  \
                                        ED_NUM_ELEMENTLIST_BUTTONS - 1)
 
 #define ED_CHECKBUTTON_ID_RANDOM_RESTRICTED    2
 #define ED_CHECKBUTTON_ID_STICK_ELEMENT                3
 #define ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS     4
-#define ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD     5
-#define ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD  6
-#define ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC   7
-#define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE  8
-#define ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE    9
-#define ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT        10
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE      11
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL      12
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH     13
-#define ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY      14
-#define ED_CHECKBUTTON_ID_CUSTOM_DEADLY                15
-#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_RESULT        16
-#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE  17
-#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH 18
-#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT        19
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE    20
-#define ED_CHECKBUTTON_ID_CHANGE_DELAY         21
-#define ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT 22
-#define ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT  23
-#define ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION 24
-#define ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT   25
-#define ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE 26
-#define ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM    27
-
-#define ED_NUM_CHECKBUTTONS                    28
+#define ED_CHECKBUTTON_ID_USE_SPRING_BUG       5
+#define ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD     6
+#define ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD  7
+#define ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID   8
+#define ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC   9
+#define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE  10
+#define ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE    11
+#define ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT        12
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE      13
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL      14
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH     15
+#define ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY      16
+#define ED_CHECKBUTTON_ID_CUSTOM_DEADLY                17
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_RESULT        18
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE  19
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH 20
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT        21
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE    22
+#define ED_CHECKBUTTON_ID_CHANGE_DELAY         23
+#define ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT 24
+#define ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT  25
+#define ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION 26
+#define ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT   27
+#define ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE 28
+#define ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM    29
+
+#define ED_NUM_CHECKBUTTONS                    30
 
 #define ED_CHECKBUTTON_ID_LEVEL_FIRST  ED_CHECKBUTTON_ID_DOUBLE_SPEED
 #define ED_CHECKBUTTON_ID_LEVEL_LAST   ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
@@ -943,7 +947,7 @@ static struct
     NULL,                              NULL, NULL
   },
   {
-    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(6),
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(3),
     MIN_ELEMENT_CONTENTS,              MAX_ELEMENT_CONTENTS,
     GADGET_ID_ELEMENT_CONTENT_DOWN,    GADGET_ID_ELEMENT_CONTENT_UP,
     GADGET_ID_ELEMENT_CONTENT_TEXT,    GADGET_ID_NONE,
@@ -1799,6 +1803,13 @@ static struct
     NULL,
     "slip down from certain flat walls","use EM style slipping behaviour"
   },
+  {
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(0),
+    GADGET_ID_USE_SPRING_BUG,          GADGET_ID_NONE,
+    &level.use_spring_bug,
+    NULL,
+    "use spring pushing bug",          "use odd spring pushing behaviour"
+  },
   {
     ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(0),
     GADGET_ID_BLOCK_LAST_FIELD,                GADGET_ID_NONE,
@@ -1807,12 +1818,19 @@ static struct
     "block last field when moving",    "player blocks last field when moving"
   },
   {
-    ED_SETTINGS_XPOS(0),               ED_COUNTER_YPOS(4),
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(0),
     GADGET_ID_SP_BLOCK_LAST_FIELD,     GADGET_ID_NONE,
     &level.sp_block_last_field,
     NULL,
     "block last field when moving",    "player blocks last field when moving"
   },
+  {
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(0),
+    GADGET_ID_CAN_MOVE_INTO_ACID,      GADGET_ID_NONE,
+    &custom_element_properties[EP_CAN_MOVE_INTO_ACID],
+    NULL,
+    "can move into acid",              "element can move into acid pool"
+  },
 
   /* ---------- element settings: configure 1 (custom elements) ----------- */
 
@@ -2143,7 +2161,7 @@ static void DrawDrawingWindow();
 static void DrawLevelInfoWindow();
 static void DrawPropertiesWindow();
 static void UpdateCustomElementGraphicGadgets();
-static boolean checkPropertiesConfig();
+static boolean checkPropertiesConfig(int);
 static void CopyLevelToUndoBuffer(int);
 static void HandleDrawingAreas(struct GadgetInfo *);
 static void HandleCounterButtons(struct GadgetInfo *);
@@ -5073,10 +5091,14 @@ static void MapCheckbuttonGadget(int id)
   int x_right = gi->x + gi->width + xoffset_right;
   int y = gi->y + yoffset;
 
-  /* special case needed for "sticky" gadget */
-  ModifyGadget(gi, GDI_CHECKED, *checkbutton_info[id].value,
-              GDI_Y, SY + checkbutton_info[id].y, GDI_END);
-  y = gi->y + yoffset;
+  /* special case needed for "stickybutton" and "can move into acid" gadgets */
+  if (id == ED_CHECKBUTTON_ID_STICK_ELEMENT ||
+      id == ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID)
+  {
+    ModifyGadget(gi, GDI_CHECKED, *checkbutton_info[id].value,
+                GDI_Y, SY + checkbutton_info[id].y, GDI_END);
+    y = gi->y + yoffset;
+  }
 
   if (checkbutton_info[id].text_left)
     DrawText(x_left, y, checkbutton_info[id].text_left, FONT_TEXT_1);
@@ -5640,12 +5662,26 @@ static void CopyGroupElementPropertiesToEditor(int element)
   custom_element = element_info[element];      /* needed for description */
 }
 
+static void CopyClassicElementPropertiesToEditor(int element)
+{
+  if (COULD_MOVE_INTO_ACID(element))
+  {
+    int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
+
+    if (bit_nr > -1)
+      custom_element_properties[EP_CAN_MOVE_INTO_ACID] =
+       ((level.can_move_into_acid & (1 << bit_nr)) != 0);
+  }
+}
+
 static void CopyElementPropertiesToEditor(int element)
 {
   if (IS_CUSTOM_ELEMENT(element))
     CopyCustomElementPropertiesToEditor(element);
   else if (IS_GROUP_ELEMENT(element))
     CopyGroupElementPropertiesToEditor(element);
+  else
+    CopyClassicElementPropertiesToEditor(element);
 }
 
 static void CopyCustomElementPropertiesToGame(int element)
@@ -5794,12 +5830,30 @@ static void CopyGroupElementPropertiesToGame(int element)
   element_info[element].modified_settings = TRUE;
 }
 
+static void CopyClassicElementPropertiesToGame(int element)
+{
+  if (COULD_MOVE_INTO_ACID(element))
+  {
+    int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
+
+    if (bit_nr > -1)
+    {
+      level.can_move_into_acid &= ~(1 << bit_nr);
+
+      if (custom_element_properties[EP_CAN_MOVE_INTO_ACID])
+       level.can_move_into_acid |= (1 << bit_nr);
+    }
+  }
+}
+
 static void CopyElementPropertiesToGame(int element)
 {
   if (IS_CUSTOM_ELEMENT(element))
     CopyCustomElementPropertiesToGame(element);
   else if (IS_GROUP_ELEMENT(element))
     CopyGroupElementPropertiesToGame(element);
+  else
+    CopyClassicElementPropertiesToGame(element);
 }
 
 void DrawLevelEd()
@@ -6564,19 +6618,23 @@ static struct
   { EL_DIAMOND,                &level.score[SC_DIAMOND],       TEXT_COLLECTING },
   { EL_CRYSTAL,                &level.score[SC_CRYSTAL],       TEXT_COLLECTING },
   { EL_PEARL,          &level.score[SC_PEARL],         TEXT_COLLECTING },
+  { EL_BUG,            &level.score[SC_BUG],           TEXT_SMASHING   },
   { EL_BUG_RIGHT,      &level.score[SC_BUG],           TEXT_SMASHING   },
   { EL_BUG_UP,         &level.score[SC_BUG],           TEXT_SMASHING   },
   { EL_BUG_LEFT,       &level.score[SC_BUG],           TEXT_SMASHING   },
   { EL_BUG_DOWN,       &level.score[SC_BUG],           TEXT_SMASHING   },
+  { EL_BD_BUTTERFLY,   &level.score[SC_BUG],           TEXT_SMASHING   },
   { EL_BD_BUTTERFLY_RIGHT,&level.score[SC_BUG],                TEXT_SMASHING   },
   { EL_BD_BUTTERFLY_UP,   &level.score[SC_BUG],                TEXT_SMASHING   },
   { EL_BD_BUTTERFLY_LEFT, &level.score[SC_BUG],                TEXT_SMASHING   },
   { EL_BD_BUTTERFLY_DOWN, &level.score[SC_BUG],                TEXT_SMASHING   },
   { EL_SP_ELECTRON,    &level.score[SC_BUG],           TEXT_SMASHING   },
+  { EL_SPACESHIP,      &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
   { EL_SPACESHIP_RIGHT,        &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
   { EL_SPACESHIP_UP,   &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
   { EL_SPACESHIP_LEFT, &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
   { EL_SPACESHIP_DOWN, &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
+  { EL_BD_FIREFLY,     &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
   { EL_BD_FIREFLY_RIGHT,&level.score[SC_SPACESHIP],    TEXT_SMASHING   },
   { EL_BD_FIREFLY_UP,  &level.score[SC_SPACESHIP],     TEXT_SMASHING   },
   { EL_BD_FIREFLY_LEFT, &level.score[SC_SPACESHIP],    TEXT_SMASHING   },
@@ -6585,6 +6643,7 @@ static struct
   { EL_YAMYAM,         &level.score[SC_YAMYAM],        TEXT_SMASHING   },
   { EL_DARK_YAMYAM,    &level.score[SC_YAMYAM],        TEXT_SMASHING   },
   { EL_ROBOT,          &level.score[SC_ROBOT],         TEXT_SMASHING   },
+  { EL_PACMAN,         &level.score[SC_PACMAN],        TEXT_SMASHING   },
   { EL_PACMAN_RIGHT,   &level.score[SC_PACMAN],        TEXT_SMASHING   },
   { EL_PACMAN_UP,      &level.score[SC_PACMAN],        TEXT_SMASHING   },
   { EL_PACMAN_LEFT,    &level.score[SC_PACMAN],        TEXT_SMASHING   },
@@ -6621,20 +6680,22 @@ static struct
   { -1,                        NULL,                           NULL            }
 };
 
-static boolean checkPropertiesConfig()
+static boolean checkPropertiesConfig(int element)
 {
   int i;
 
-  if (IS_GEM(properties_element) ||
-      IS_CUSTOM_ELEMENT(properties_element) ||
-      IS_GROUP_ELEMENT(properties_element) ||
-      IS_ENVELOPE(properties_element) ||
-      ELEM_IS_PLAYER(properties_element) ||
-      HAS_CONTENT(properties_element))
+  if (IS_GEM(element) ||
+      IS_CUSTOM_ELEMENT(element) ||
+      IS_GROUP_ELEMENT(element) ||
+      IS_ENVELOPE(element) ||
+      ELEM_IS_PLAYER(element) ||
+      HAS_CONTENT(element) ||
+      COULD_MOVE_INTO_ACID(element) ||
+      element == EL_SPRING)
     return TRUE;
   else
     for (i = 0; elements_with_counter[i].element != -1; i++)
-      if (elements_with_counter[i].element == properties_element)
+      if (elements_with_counter[i].element == element)
        return TRUE;
 
   return FALSE;
@@ -6644,7 +6705,7 @@ static void DrawPropertiesConfig()
 {
   int i;
 
-  if (!checkPropertiesConfig())
+  if (!checkPropertiesConfig(properties_element))
   {
     PrintInfoText("No configuration options available.", FONT_TEXT_1, 0);
 
@@ -6658,10 +6719,9 @@ static void DrawPropertiesConfig()
     {
       int counter_id = ED_COUNTER_ID_ELEMENT_SCORE;
 
-      if (HAS_CONTENT(properties_element))     /* needs stickybutton */
-       counterbutton_info[counter_id].y = ED_SETTINGS_YPOS(1);
-      else
-       counterbutton_info[counter_id].y = ED_SETTINGS_YPOS(0);
+      counterbutton_info[counter_id].y =
+       ED_SETTINGS_YPOS((HAS_CONTENT(properties_element) ? 1 : 0) +
+                        (COULD_MOVE_INTO_ACID(properties_element) ? 1 : 0));
 
       counterbutton_info[counter_id].value = elements_with_counter[i].value;
       counterbutton_info[counter_id].text_right= elements_with_counter[i].text;
@@ -6683,14 +6743,26 @@ static void DrawPropertiesConfig()
       DrawElementContentAreas();
   }
 
-  if (IS_GEM(properties_element))
-    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS);
-
   if (ELEM_IS_PLAYER(properties_element))
     MapCheckbuttonGadget(properties_element == EL_SP_MURPHY ?
                         ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD :
                         ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD);
 
+  if (IS_GEM(properties_element))
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS);
+
+  if (COULD_MOVE_INTO_ACID(properties_element) &&
+      !IS_CUSTOM_ELEMENT(properties_element))
+  {
+    checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].y =
+      ED_SETTINGS_YPOS(HAS_CONTENT(properties_element) ? 1 : 0);
+
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID);
+  }
+
+  if (properties_element == EL_SPRING)
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_SPRING_BUG);
+
   if (IS_ENVELOPE(properties_element))
   {
     int counter1_id = ED_COUNTER_ID_ENVELOPE_XSIZE;
@@ -8137,11 +8209,12 @@ static void HandleCheckbuttons(struct GadgetInfo *gi)
 
   *checkbutton_info[type_id].value ^= TRUE;
 
-  if (((type_id >= ED_CHECKBUTTON_ID_CUSTOM_FIRST &&
-       type_id <= ED_CHECKBUTTON_ID_CUSTOM_LAST) ||
-       (type_id >= ED_CHECKBUTTON_ID_CHANGE_FIRST &&
-       type_id <= ED_CHECKBUTTON_ID_CHANGE_LAST)) &&
-      type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE)
+  if (type_id == ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID ||
+      (((type_id >= ED_CHECKBUTTON_ID_CUSTOM_FIRST &&
+        type_id <= ED_CHECKBUTTON_ID_CUSTOM_LAST) ||
+       (type_id >= ED_CHECKBUTTON_ID_CHANGE_FIRST &&
+        type_id <= ED_CHECKBUTTON_ID_CHANGE_LAST)) &&
+       type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE))
   {
     CopyElementPropertiesToGame(properties_element);
   }
index 356d8a4b11dca6581e77f39a6b118acbf1391978..52116aa9d3ac98b9d063d378fa06eb1556fb6c7e 100644 (file)
@@ -29,7 +29,7 @@
 #define CHUNK_SIZE_NONE                -1      /* do not write chunk size    */
 #define FILE_VERS_CHUNK_SIZE   8       /* size of file version chunk */
 #define LEVEL_HEADER_SIZE      80      /* size of level file header  */
-#define LEVEL_HEADER_UNUSED    11      /* unused level header bytes  */
+#define LEVEL_HEADER_UNUSED    10      /* unused level header bytes  */
 #define LEVEL_CHUNK_CNT2_SIZE  160     /* size of level CNT2 chunk   */
 #define LEVEL_CHUNK_CNT2_UNUSED        11      /* unused CNT2 chunk bytes    */
 #define LEVEL_CHUNK_CNT3_HEADER        16      /* size of level CNT3 header  */
@@ -121,6 +121,14 @@ void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
   change->post_change_function = NULL;
 }
 
+static void setMoveIntoAcid(struct LevelInfo *level, int element)
+{
+  int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
+
+  if (bit_nr > -1)
+    level->can_move_into_acid |= (1 << bit_nr);
+}
+
 static void setLevelInfoToDefaults(struct LevelInfo *level)
 {
   int i, j, x, y;
@@ -141,17 +149,24 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
 
   level->time = 100;
   level->gems_needed = 0;
+
   level->amoeba_speed = 10;
+
   level->time_magic_wall = 10;
   level->time_wheel = 10;
   level->time_light = 10;
   level->time_timegate = 10;
+
   level->amoeba_content = EL_DIAMOND;
+
   level->double_speed = FALSE;
   level->initial_gravity = FALSE;
   level->em_slippery_gems = FALSE;
   level->block_last_field = FALSE;
   level->sp_block_last_field = TRUE;
+  level->use_spring_bug = FALSE;
+
+  level->can_move_into_acid = ~0;      /* everything can move into acid */
 
   level->use_custom_template = FALSE;
 
@@ -639,6 +654,8 @@ static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
   level->block_last_field      = (getFile8Bit(file) == 1 ? TRUE : FALSE);
   level->sp_block_last_field   = (getFile8Bit(file) == 1 ? TRUE : FALSE);
 
+  level->use_spring_bug                = (getFile8Bit(file) == 1 ? TRUE : FALSE);
+
   ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED);
 
   return chunk_size;
@@ -2021,6 +2038,19 @@ static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
     /* Default behaviour for EM style gems was "slippery" only in 2.0.1 */
     if (level->game_version == VERSION_IDENT(2,0,1,0))
       level->em_slippery_gems = TRUE;
+
+    if (level->game_version < VERSION_IDENT(2,2,0,0))
+      level->use_spring_bug = TRUE;
+
+    if (level->game_version < VERSION_IDENT(3,0,9,0))
+    {
+      level->can_move_into_acid = 0;   /* nothing can move into acid */
+
+      setMoveIntoAcid(level, EL_ROBOT);
+      setMoveIntoAcid(level, EL_SATELLITE);
+      setMoveIntoAcid(level, EL_PENGUIN);
+      setMoveIntoAcid(level, EL_BALLOON);
+    }
   }
   else
   {
@@ -2287,6 +2317,8 @@ static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
   putFile8Bit(file, (level->block_last_field ? 1 : 0));
   putFile8Bit(file, (level->sp_block_last_field ? 1 : 0));
 
+  putFile8Bit(file, (level->use_spring_bug ? 1 : 0));
+
   WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
 }
 
@@ -2814,6 +2846,7 @@ void DumpLevel(struct LevelInfo *level)
   printf("EM style slippery gems:      %s\n", (level->em_slippery_gems ? "yes" : "no"));
   printf("Player blocks last field:    %s\n", (level->block_last_field ? "yes" : "no"));
   printf("SP player blocks last field: %s\n", (level->sp_block_last_field ? "yes" : "no"));
+  printf("use spring bug: %s\n", (level->use_spring_bug ? "yes" : "no"));
 
   printf_line("-", 79);
 }
index c81c860348d9a261e18471ca5b17671fbf545a22..5da67f0d79398325f4bb20e6b969d7f694569691 100644 (file)
@@ -862,6 +862,36 @@ static void InitField(int x, int y, boolean init_game)
   }
 }
 
+static inline void InitField_WithBug1(int x, int y, boolean init_game)
+{
+  InitField(x, y, init_game);
+
+  /* not needed to call InitMovDir() -- already done by InitField()! */
+  if (game.engine_version < VERSION_IDENT(3,0,9,0) &&
+      CAN_MOVE(Feld[x][y]))
+    InitMovDir(x, y);
+}
+
+static inline void InitField_WithBug2(int x, int y, boolean init_game)
+{
+  int old_element = Feld[x][y];
+
+  InitField(x, y, init_game);
+
+  /* not needed to call InitMovDir() -- already done by InitField()! */
+  if (game.engine_version < VERSION_IDENT(3,0,9,0) &&
+      CAN_MOVE(old_element) &&
+      (old_element < EL_MOLE_LEFT || old_element > EL_MOLE_DOWN))
+    InitMovDir(x, y);
+
+  /* this case is in fact a combination of not less than three bugs:
+     first, it calls InitMovDir() for elements that can move, although this is
+     already done by InitField(); then, it checks the element that was at this
+     field _before_ the call to InitField() (which can change it)
+
+ */
+}
+
 void DrawGameDoorValues()
 {
   int i, j;
@@ -2866,11 +2896,21 @@ void Explode(int ex, int ey, int phase, int mode)
     ChangeDelay[x][y] = 0;
     ChangePage[x][y] = -1;
 
+#if 1
+    InitField_WithBug2(x, y, FALSE);
+#else
     InitField(x, y, FALSE);
 #if 1
     /* !!! not needed !!! */
+#if 1
+    if (game.engine_version < VERSION_IDENT(3,0,9,0) &&
+       CAN_MOVE(Feld[x][y]) && Feld[x][y] != EL_MOLE)
+      InitMovDir(x, y);
+#else
     if (CAN_MOVE(element))
       InitMovDir(x, y);
+#endif
+#endif
 #endif
     DrawLevelField(x, y);
 
@@ -4347,7 +4387,9 @@ static boolean JustBeingPushed(int x, int y)
 
 void StartMoving(int x, int y)
 {
+#if 0
   boolean use_spring_bug = (game.engine_version < VERSION_IDENT(2,2,0,0));
+#endif
   boolean started_moving = FALSE;      /* some elements can fall _and_ move */
   int element = Feld[x][y];
 
@@ -4544,7 +4586,7 @@ void StartMoving(int x, int y)
 
       Impact(x, y);
     }
-    else if (IS_FREE(x, y + 1) && element == EL_SPRING && use_spring_bug)
+    else if (IS_FREE(x, y + 1) && element == EL_SPRING && level.use_spring_bug)
     {
       if (MovDir[x][y] == MV_NO_MOVING)
       {
@@ -5228,22 +5270,22 @@ void ContinueMoving(int x, int y)
   int nextx = newx + dx, nexty = newy + dy;
 #endif
 #if 1
-  boolean pushed = (Pushed[x][y] && IS_PLAYER(x, y));
+  boolean pushed_by_player   = (Pushed[x][y] && IS_PLAYER(x, y));
   boolean pushed_by_conveyor = (Pushed[x][y] && !IS_PLAYER(x, y));
 #else
-  boolean pushed = Pushed[x][y];
+  boolean pushed_by_player = Pushed[x][y];
 #endif
 
   MovPos[x][y] += getElementMoveStepsize(x, y);
 
 #if 0
-  if (pushed && IS_PLAYER(x, y))
+  if (pushed_by_player && IS_PLAYER(x, y))
   {
     /* special case: moving object pushed by player */
     MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x,y)->MovPos));
   }
 #else
-  if (pushed)          /* special case: moving object pushed by player */
+  if (pushed_by_player)        /* special case: moving object pushed by player */
     MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x,y)->MovPos));
 #endif
 
@@ -5397,7 +5439,7 @@ void ContinueMoving(int x, int y)
   Stop[newx][newy] = TRUE;     /* ignore this element until the next frame */
 
   /* prevent pushed element from moving on in pushed direction */
-  if (pushed && CAN_MOVE(element) &&
+  if (pushed_by_player && CAN_MOVE(element) &&
       element_info[element].move_pattern & MV_ANY_DIRECTION &&
       !(element_info[element].move_pattern & direction))
     TurnRound(newx, newy);
@@ -5409,7 +5451,7 @@ void ContinueMoving(int x, int y)
     MovDir[newx][newy] = 0;
 #endif
 
-  if (!pushed) /* special case: moving object pushed by player */
+  if (!pushed_by_player)
   {
     WasJustMoving[newx][newy] = 3;
 
@@ -6439,9 +6481,13 @@ static void ChangeElementNowExt(int x, int y, int target_element)
   if (element_info[Feld[x][y]].move_direction_initial == MV_START_PREVIOUS)
     MovDir[x][y] = previous_move_direction;
 
+#if 1
+  InitField_WithBug1(x, y, FALSE);
+#else
   InitField(x, y, FALSE);
   if (CAN_MOVE(Feld[x][y]))
     InitMovDir(x, y);
+#endif
 
   DrawLevelField(x, y);
 
@@ -7239,7 +7285,19 @@ void GameActions()
 #endif
 
 #if 1
+  /* for downwards compatibility, the following code emulates a fixed bug that
+     occured when pushing elements (causing elements that just made their last
+     pushing step to already (if possible) make their first falling step in the
+     same game frame, which is bad); this code is also needed to use the famous
+     "spring push bug" which is used in older levels and might be wanted to be
+     used also in newer levels, but in this case the buggy pushing code is only
+     affecting the "spring" element and no other elements */
+
+#if 1
+  if (game.engine_version < VERSION_IDENT(2,2,0,7) || level.use_spring_bug)
+#else
   if (game.engine_version < VERSION_IDENT(2,2,0,7))
+#endif
   {
     for (i = 0; i < MAX_PLAYERS; i++)
     {
@@ -7247,8 +7305,15 @@ void GameActions()
       int x = player->jx;
       int y = player->jy;
 
+#if 1
+      if (player->active && player->is_pushing && player->is_moving &&
+         IS_MOVING(x, y) &&
+         (game.engine_version < VERSION_IDENT(2,2,0,7) ||
+          Feld[x][y] == EL_SPRING))
+#else
       if (player->active && player->is_pushing && player->is_moving &&
          IS_MOVING(x, y))
+#endif
       {
        ContinueMoving(x, y);
 
@@ -8972,7 +9037,9 @@ int DigField(struct PlayerInfo *player,
     CH_SIDE_BOTTOM,    /* moving up    */
     CH_SIDE_TOP,       /* moving down  */
   };
+#if 0
   boolean use_spring_bug = (game.engine_version < VERSION_IDENT(2,2,0,0));
+#endif
   int jx = oldx, jy = oldy;
   int dx = x - jx, dy = y - jy;
   int nextx = x + dx, nexty = y + dy;
@@ -9386,7 +9453,7 @@ int DigField(struct PlayerInfo *player,
          return MF_NO_ACTION;
 
        if (CAN_FALL(element) && IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1) &&
-           !(element == EL_SPRING && use_spring_bug))
+           !(element == EL_SPRING && level.use_spring_bug))
          return MF_NO_ACTION;
 
 #if 1
@@ -9803,9 +9870,13 @@ boolean DropElement(struct PlayerInfo *player)
 
   if (Feld[jx][jy] == new_element)     /* uninitialized unless CE change */
   {
+#if 1
+    InitField_WithBug1(jx, jy, FALSE);
+#else
     InitField(jx, jy, FALSE);
     if (CAN_MOVE(Feld[jx][jy]))
       InitMovDir(jx, jy);
+#endif
   }
 
   new_element = Feld[jx][jy];
index a7bb5979831043fc3de891b4317283c2601ece35..e0d97ccab822c581e225aa93bba967f701084be4 100644 (file)
@@ -2935,6 +2935,13 @@ void InitElementPropertiesStatic()
       EL_PACMAN_LEFT,          EL_PACMAN_RIGHT,
       EL_PACMAN_UP,            EL_PACMAN_DOWN
     },
+#if 1
+    {
+      EL_MOLE,
+      EL_MOLE_LEFT,            EL_MOLE_RIGHT,
+      EL_MOLE_UP,              EL_MOLE_DOWN
+    },
+#endif
     {
       -1,
       -1, -1, -1, -1
@@ -3021,6 +3028,7 @@ void InitElementPropertiesEngine(int engine_version)
     EP_ACTIVE_BOMB,
 
     EP_ACCESSIBLE,
+
     -1
   };
 
@@ -3162,6 +3170,9 @@ void InitElementPropertiesEngine(int engine_version)
     SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
                                                  i == EL_BLACK_ORB));
 
+    /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
+    SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (CAN_MOVE(i) && i != EL_SPRING));
+
     /* ---------- SP_PORT -------------------------------------------------- */
     SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
                                 IS_PASSABLE_INSIDE(i)));
@@ -3273,6 +3284,69 @@ void InitElementPropertiesEngine(int engine_version)
     InitElementGraphicInfo();
 }
 
+int get_special_property_bit(int element, int base_property_bit)
+{
+  static struct
+  {
+    int element;
+    int bit_nr;
+  } pb_can_move_into_acid[] =
+  {
+    { EL_BUG,                  0 },
+    { EL_BUG_LEFT,             0 },
+    { EL_BUG_RIGHT,            0 },
+    { EL_BUG_UP,               0 },
+    { EL_BUG_DOWN,             0 },
+    { EL_SPACESHIP,            0 },
+    { EL_SPACESHIP_LEFT,       0 },
+    { EL_SPACESHIP_RIGHT,      0 },
+    { EL_SPACESHIP_UP,         0 },
+    { EL_SPACESHIP_DOWN,       0 },
+    { EL_BD_BUTTERFLY,         1 },
+    { EL_BD_BUTTERFLY_LEFT,    1 },
+    { EL_BD_BUTTERFLY_RIGHT,   1 },
+    { EL_BD_BUTTERFLY_UP,      1 },
+    { EL_BD_BUTTERFLY_DOWN,    1 },
+    { EL_BD_FIREFLY,           1 },
+    { EL_BD_FIREFLY_LEFT,      1 },
+    { EL_BD_FIREFLY_RIGHT,     1 },
+    { EL_BD_FIREFLY_UP,                1 },
+    { EL_BD_FIREFLY_DOWN,      1 },
+    { EL_YAMYAM,               2 },
+    { EL_DARK_YAMYAM,          2 },
+    { EL_ROBOT,                        3 },
+    { EL_PACMAN,               4 },
+    { EL_PACMAN_LEFT,          4 },
+    { EL_PACMAN_RIGHT,         4 },
+    { EL_PACMAN_UP,            4 },
+    { EL_PACMAN_DOWN,          4 },
+    { EL_MOLE,                 4 },
+    { EL_MOLE_LEFT,            4 },
+    { EL_MOLE_RIGHT,           4 },
+    { EL_MOLE_UP,              4 },
+    { EL_MOLE_DOWN,            4 },
+    { EL_PENGUIN,              5 },
+    { EL_PIG,                  6 },
+    { EL_DRAGON,               6 },
+    { EL_SATELLITE,            7 },
+    { EL_SP_SNIKSNAK,          8 },
+    { EL_SP_ELECTRON,          8 },
+    { EL_BALLOON,              9 },
+
+    { -1,                      0 },
+  };
+  int i;
+
+  if (base_property_bit != EP_CAN_MOVE_INTO_ACID)
+    return -1;
+
+  for (i = 0; pb_can_move_into_acid[i].element != -1; i++)
+    if (pb_can_move_into_acid[i].element == element)
+      return pb_can_move_into_acid[i].bit_nr;
+
+  return -1;
+}
+
 static void InitGlobal()
 {
   global.autoplay_leveldir = NULL;
index 79880f11b256847386b83b4395bc15421ad5456b..7440123ff90e4f0bdecc9f52da76f1a5693dcf65 100644 (file)
@@ -18,6 +18,7 @@
 
 void InitElementPropertiesStatic(void);
 void InitElementPropertiesEngine(int);
+int get_special_property_bit(int, int);
 
 void ReloadCustomArtwork(int);
 
index 5e5e5f67c62464497e7507595c27b1867d22962f..5729b9314fc98f2d773ba0160354a163def177bb 100644 (file)
@@ -658,7 +658,7 @@ struct ElementInfo element_info[MAX_NUM_ELEMENTS + 1] =
   {
     "black_orb",
     "black_orb",
-    "bomb"
+    "black orb bomb"
   },
   {
     "amoeba_to_diamond",
index d87087a2047cb87b171b07fbaf3091b5253755aa..3036ea425a5c3278d8e8a90970b3c943e3a943fa 100644 (file)
@@ -88,6 +88,7 @@
 #define EP_PUSHABLE            24
 #define EP_CAN_EXPLODE_DYNA    25
 #define EP_PROTECTED           26
+#define EP_CAN_MOVE_INTO_ACID  27
 
 /* values for pre-defined properties */
 #define EP_PLAYER              32
 #define EP_SP_PORT             72
 #define EP_CAN_EXPLODE_BY_DRAGONFIRE 73
 #define EP_CAN_EXPLODE_BY_EXPLOSION  74
+#define EP_COULD_MOVE_INTO_ACID        75
 
 /* values for internal purpose only (level editor) */
-#define EP_EXPLODE_RESULT      75
-#define EP_WALK_TO_OBJECT      76
-#define EP_DEADLY              77
+#define EP_EXPLODE_RESULT      76
+#define EP_WALK_TO_OBJECT      77
+#define EP_DEADLY              78
 
-#define NUM_ELEMENT_PROPERTIES 78
+#define NUM_ELEMENT_PROPERTIES 79
 
 #define NUM_EP_BITFIELDS       ((NUM_ELEMENT_PROPERTIES + 31) / 32)
 #define EP_BITFIELD_BASE       0
 #define IS_PUSHABLE(e)         HAS_PROPERTY(e, EP_PUSHABLE)
 #define CAN_EXPLODE_DYNA(e)    HAS_PROPERTY(e, EP_CAN_EXPLODE_DYNA)
 #define IS_PROTECTED(e)                HAS_PROPERTY(e, EP_PROTECTED)
+#define CAN_MOVE_INTO_ACID(e)  HAS_PROPERTY(e, EP_CAN_MOVE_INTO_ACID)
 
 /* macros for special configurable properties */
 #define IS_EM_SLIPPERY_WALL(e) HAS_PROPERTY(e, EP_EM_SLIPPERY_WALL)
                                HAS_PROPERTY(e, EP_CAN_EXPLODE_BY_DRAGONFIRE)
 #define CAN_EXPLODE_BY_EXPLOSION(e)    \
                                HAS_PROPERTY(e, EP_CAN_EXPLODE_BY_EXPLOSION)
+#define COULD_MOVE_INTO_ACID(e)        HAS_PROPERTY(e, EP_COULD_MOVE_INTO_ACID)
 
 /* special macros used in game engine */
 #define IS_CUSTOM_ELEMENT(e)   ((e) >= EL_CUSTOM_START &&              \
@@ -1376,26 +1380,37 @@ struct LevelInfo
   boolean encoding_16bit_amoeba;       /* amoeba contains 16-bit elements */
 
   int fieldx, fieldy;
+
   int time;
   int gems_needed;
+
   char name[MAX_LEVEL_NAME_LEN + 1];
   char author[MAX_LEVEL_AUTHOR_LEN + 1];
+
   char envelope_text[4][MAX_ENVELOPE_TEXT_LEN + 1];
   int envelope_xsize[4], envelope_ysize[4];
+
   int score[LEVEL_SCORE_ELEMENTS];
+
   int yamyam_content[MAX_ELEMENT_CONTENTS][3][3];
   int num_yamyam_contents;
+
   int amoeba_speed;
   int amoeba_content;
+
   int time_magic_wall;
   int time_wheel;
   int time_light;
   int time_timegate;
+
+  int can_move_into_acid;      /* bits indicate property for element groups */
+
   boolean double_speed;
   boolean initial_gravity;
   boolean em_slippery_gems;    /* EM style "gems slip from wall" behaviour */
   boolean block_last_field;    /* player blocks previous field while moving */
   boolean sp_block_last_field; /* player blocks previous field while moving */
+  boolean use_spring_bug;      /* for compatibility with old levels */
 
   short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY];