rnd-20040117-1-src
[rocksndiamonds.git] / src / editor.c
index 5c9ab31734b3f5afe89f8640420f1862bc9a35c0..6dd5fd3fd62f502147301b1568c8e1b364a1b8c7 100644 (file)
                                         ED_GADGET_DISTANCE)
 /* custom element content */
 #define ED_AREA_ELEM_CONTENT4_XPOS     (29 * MINI_TILEX)
-#define ED_AREA_ELEM_CONTENT4_YPOS     (ED_SETTINGS_YPOS(12) + \
+#define ED_AREA_ELEM_CONTENT4_YPOS     (ED_SETTINGS_YPOS(13) + \
                                         ED_GADGET_DISTANCE - MINI_TILEY)
+/* movement enter/leave element */
+#define ED_AREA_ELEM_CONTENT4a_XPOS    (29 * MINI_TILEX)
+#define ED_AREA_ELEM_CONTENT4a_YPOS    (ED_SETTINGS_YPOS(7) + \
+                                        ED_GADGET_DISTANCE)
+#define ED_AREA_ELEM_CONTENT4b_XPOS    (29 * MINI_TILEX)
+#define ED_AREA_ELEM_CONTENT4b_YPOS    (ED_SETTINGS_YPOS(7) + \
+                                        ED_GADGET_DISTANCE)
 /* custom change trigger element */
 #define ED_AREA_ELEM_CONTENT5_YPOS     (ED_SETTINGS_YPOS(6) + \
                                         ED_GADGET_DISTANCE)
 #define ED_AREA_ELEM_CONTENT6_XPOS     (29 * MINI_TILEX)
 #define ED_AREA_ELEM_CONTENT6_YPOS     (ED_SETTINGS_YPOS(10) + \
                                         ED_GADGET_DISTANCE - MINI_TILEY)
+/* group element content */
+#define ED_AREA_GROUP_CONTENT_XPOS     ED_SETTINGS_XPOS(0)
+#define ED_AREA_GROUP_CONTENT_YPOS     (22 * MINI_TILEY)
 
 /* values for random placement background drawing area */
 #define ED_AREA_RANDOM_BACKGROUND_YPOS (31 * MINI_TILEY)
 #define GADGET_ID_CHANGE_CONT_RND_DOWN (GADGET_ID_COUNTER_FIRST + 57)
 #define GADGET_ID_CHANGE_CONT_RND_TEXT (GADGET_ID_COUNTER_FIRST + 58)
 #define GADGET_ID_CHANGE_CONT_RND_UP   (GADGET_ID_COUNTER_FIRST + 59)
+#define GADGET_ID_GROUP_CONTENT_DOWN   (GADGET_ID_COUNTER_FIRST + 60)
+#define GADGET_ID_GROUP_CONTENT_TEXT   (GADGET_ID_COUNTER_FIRST + 61)
+#define GADGET_ID_GROUP_CONTENT_UP     (GADGET_ID_COUNTER_FIRST + 62)
 
 /* drawing area identifiers */
-#define GADGET_ID_DRAWING_AREA_FIRST   (GADGET_ID_COUNTER_FIRST + 60)
+#define GADGET_ID_DRAWING_AREA_FIRST   (GADGET_ID_COUNTER_FIRST + 63)
 
 #define GADGET_ID_DRAWING_LEVEL                (GADGET_ID_DRAWING_AREA_FIRST + 0)
 #define GADGET_ID_ELEMENT_CONTENT_0    (GADGET_ID_DRAWING_AREA_FIRST + 1)
 #define GADGET_ID_AMOEBA_CONTENT       (GADGET_ID_DRAWING_AREA_FIRST + 9)
 #define GADGET_ID_CUSTOM_GRAPHIC       (GADGET_ID_DRAWING_AREA_FIRST + 10)
 #define GADGET_ID_CUSTOM_CONTENT       (GADGET_ID_DRAWING_AREA_FIRST + 11)
-#define GADGET_ID_CUSTOM_CHANGE_TARGET (GADGET_ID_DRAWING_AREA_FIRST + 12)
-#define GADGET_ID_CUSTOM_CHANGE_CONTENT        (GADGET_ID_DRAWING_AREA_FIRST + 13)
-#define GADGET_ID_CUSTOM_CHANGE_TRIGGER        (GADGET_ID_DRAWING_AREA_FIRST + 14)
-#define GADGET_ID_RANDOM_BACKGROUND    (GADGET_ID_DRAWING_AREA_FIRST + 15)
+#define GADGET_ID_CUSTOM_MOVE_ENTER    (GADGET_ID_DRAWING_AREA_FIRST + 12)
+#define GADGET_ID_CUSTOM_MOVE_LEAVE    (GADGET_ID_DRAWING_AREA_FIRST + 13)
+#define GADGET_ID_CUSTOM_CHANGE_TARGET (GADGET_ID_DRAWING_AREA_FIRST + 14)
+#define GADGET_ID_CUSTOM_CHANGE_CONTENT        (GADGET_ID_DRAWING_AREA_FIRST + 15)
+#define GADGET_ID_CUSTOM_CHANGE_TRIGGER        (GADGET_ID_DRAWING_AREA_FIRST + 16)
+#define GADGET_ID_GROUP_CONTENT                (GADGET_ID_DRAWING_AREA_FIRST + 17)
+#define GADGET_ID_RANDOM_BACKGROUND    (GADGET_ID_DRAWING_AREA_FIRST + 18)
 
 /* text input identifiers */
-#define GADGET_ID_TEXT_INPUT_FIRST     (GADGET_ID_DRAWING_AREA_FIRST + 16)
+#define GADGET_ID_TEXT_INPUT_FIRST     (GADGET_ID_DRAWING_AREA_FIRST + 19)
 
 #define GADGET_ID_LEVEL_NAME           (GADGET_ID_TEXT_INPUT_FIRST + 0)
 #define GADGET_ID_LEVEL_AUTHOR         (GADGET_ID_TEXT_INPUT_FIRST + 1)
 #define ED_COUNTER_ID_PUSH_DELAY_RND   14
 #define ED_COUNTER_ID_MOVE_DELAY_FIX   15
 #define ED_COUNTER_ID_MOVE_DELAY_RND   16
-#define ED_COUNTER_ID_CHANGE_DELAY_FIX 17
-#define ED_COUNTER_ID_CHANGE_DELAY_RND 18
-#define ED_COUNTER_ID_CHANGE_CONT_RND  19
+#define ED_COUNTER_ID_GROUP_CONTENT    17
+#define ED_COUNTER_ID_CHANGE_DELAY_FIX 18
+#define ED_COUNTER_ID_CHANGE_DELAY_RND 19
+#define ED_COUNTER_ID_CHANGE_CONT_RND  20
 
-#define ED_NUM_COUNTERBUTTONS          20
+#define ED_NUM_COUNTERBUTTONS          21
 
 #define ED_COUNTER_ID_LEVEL_FIRST      ED_COUNTER_ID_LEVEL_XSIZE
 #define ED_COUNTER_ID_LEVEL_LAST       ED_COUNTER_ID_LEVEL_RANDOM
 #define ED_DRAWING_ID_AMOEBA_CONTENT           9
 #define ED_DRAWING_ID_CUSTOM_GRAPHIC           10
 #define ED_DRAWING_ID_CUSTOM_CONTENT           11
-#define ED_DRAWING_ID_CUSTOM_CHANGE_TARGET     12
-#define ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT    13
-#define ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER    14
-#define ED_DRAWING_ID_RANDOM_BACKGROUND                15
+#define ED_DRAWING_ID_CUSTOM_MOVE_ENTER                12
+#define ED_DRAWING_ID_CUSTOM_MOVE_LEAVE                13
+#define ED_DRAWING_ID_CUSTOM_CHANGE_TARGET     14
+#define ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT    15
+#define ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER    16
+#define ED_DRAWING_ID_GROUP_CONTENT            17
+#define ED_DRAWING_ID_RANDOM_BACKGROUND                18
 
-#define ED_NUM_DRAWING_AREAS                   16
+#define ED_NUM_DRAWING_AREAS                   19
 
 
 /*
@@ -795,6 +815,7 @@ static boolean stick_element_properties_window = FALSE;
 static boolean custom_element_properties[NUM_ELEMENT_PROPERTIES];
 static boolean custom_element_change_events[NUM_CHANGE_EVENTS];
 static struct ElementChangeInfo custom_element_change;
+static struct ElementGroupInfo group_element_info;
 static struct ElementInfo custom_element;
 
 static struct
@@ -902,7 +923,7 @@ static struct
     NULL,                              " ", "height",
   },
 
-  /* ---------- element settings: configure (custom elements) ------------- */
+  /* ---------- element settings: configure (custom elements) -------------- */
 
   {
     ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(3),
@@ -937,7 +958,7 @@ static struct
     NULL,                              "+random", NULL
   },
   {
-    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(7),
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(9),
     0,                                 999,
     GADGET_ID_MOVE_DELAY_FIX_DOWN,     GADGET_ID_MOVE_DELAY_FIX_UP,
     GADGET_ID_MOVE_DELAY_FIX_TEXT,     GADGET_ID_NONE,
@@ -945,7 +966,7 @@ static struct
     NULL,                              "move delay", NULL
   },
   {
-    -1,                                        ED_SETTINGS_YPOS(7),
+    -1,                                        ED_SETTINGS_YPOS(9),
     0,                                 999,
     GADGET_ID_MOVE_DELAY_RND_DOWN,     GADGET_ID_MOVE_DELAY_RND_UP,
     GADGET_ID_MOVE_DELAY_RND_TEXT,     GADGET_ID_MOVE_DELAY_FIX_UP,
@@ -953,6 +974,17 @@ static struct
     NULL,                              "+random", NULL
   },
 
+  /* ---------- element settings: configure (group elements) --------------- */
+
+  {
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(6),
+    MIN_ELEMENTS_IN_GROUP,             MAX_ELEMENTS_IN_GROUP,
+    GADGET_ID_GROUP_CONTENT_DOWN,      GADGET_ID_GROUP_CONTENT_UP,
+    GADGET_ID_GROUP_CONTENT_TEXT,      GADGET_ID_NONE,
+    &group_element_info.num_elements,
+    NULL,                              NULL, "number of elements in group"
+  },
+
   /* ---------- element settings: advanced (custom elements) --------------- */
 
   {
@@ -1074,12 +1106,11 @@ static struct ValueTextInfo options_move_pattern[] =
   { MV_TURNING_RIGHT_LEFT,     "turning right, left"           },
   { MV_TURNING_RANDOM,         "turning random"                },
   { MV_WHEN_PUSHED,            "when pushed"                   },
+  { MV_WHEN_DROPPED,           "when dropped"                  },
 #if 1
   { MV_MAZE_RUNNER,            "maze runner style"             },
   { MV_MAZE_HUNTER,            "maze hunter style"             },
 #endif
-  { MV_PROJECTILE,             "projectile style"              },
-  { MV_PROJECTILE,             "projectile style"              },
   { -1,                                NULL                            }
 };
 
@@ -1134,6 +1165,7 @@ static struct ValueTextInfo options_deadliness[] =
 static struct ValueTextInfo options_consistency[] =
 {
   { EP_CAN_EXPLODE_3X3,                "can explode 3x3"               },
+  { EP_CAN_EXPLODE_DYNA,       "can explode 3+3"               },
   { EP_CAN_EXPLODE_1X1,                "can explode 1x1"               },
   { EP_INDESTRUCTIBLE,         "indestructible"                },
   { -1,                                NULL                            }
@@ -1155,11 +1187,11 @@ static struct ValueTextInfo options_change_direct_action[] =
   { CE_LEFT_BY_PLAYER,         "left by player ..."            },
   { CE_DROPPED_BY_PLAYER,      "dropped by player"             },
   { CE_SWITCHED,               "switched ..."                  },
-#if 0
-  { CE_COLLISION_ACTIVE,       "hitting something ..."         },
-  { CE_COLLISION_PASSIVE,      "hit by something ..."          },
+#if 1
+  { CE_HITTING_SOMETHING,      "hitting something ..."         },
+  { CE_HIT_BY_SOMETHING,       "hit by something ..."          },
 #else
-  { CE_COLLISION_ACTIVE,       "collision ..."                 },
+  { CE_HITTING_SOMETHING,      "collision ..."                 },
 #endif
   { CE_IMPACT,                 "impact (on something)"         },
   { CE_SMASHED,                        "smashed (from above)"          },
@@ -1177,9 +1209,9 @@ static struct ValueTextInfo options_change_other_action[] =
   { CE_OTHER_GETS_COLLECTED,   "player collects"               },
   { CE_OTHER_GETS_DROPPED,     "player drops"                  },
   { CE_OTHER_IS_TOUCHING,      "touching ..."                  },
-#if 0
-  { CE_OTHER_IS_COLL_ACTIVE,   "hitting ..."                   },
-  { CE_OTHER_IS_COLL_PASSIVE,  "hit by ..."                    },
+#if 1
+  { CE_OTHER_IS_HITTING,       "hitting ..."                   },
+  { CE_OTHER_GETS_HIT,         "hit by ..."                    },
 #endif
   { CE_OTHER_IS_SWITCHING,     "switch of ..."                 },
   { CE_OTHER_IS_CHANGING,      "change of"                     },
@@ -1275,7 +1307,7 @@ static struct
     "move/fall speed", NULL,           "speed of element movement"
   },
   {
-    -1,                                        ED_SETTINGS_YPOS(9),
+    -1,                                        ED_SETTINGS_YPOS(10),
     GADGET_ID_CUSTOM_SMASH_TARGETS,    GADGET_ID_CUSTOM_CAN_SMASH,
     -1,
     options_smash_targets,
@@ -1283,7 +1315,7 @@ static struct
     "can smash", NULL,                 "elements that can be smashed"
   },
   {
-    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(10),
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(11),
     GADGET_ID_CUSTOM_SLIPPERY_TYPE,    GADGET_ID_NONE,
     -1,
     options_slippery_type,
@@ -1291,7 +1323,7 @@ static struct
     "slippery", NULL,                  "where other elements fall down"
   },
   {
-    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(11),
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(12),
     GADGET_ID_CUSTOM_DEADLINESS,       GADGET_ID_NONE,
     -1,
     options_deadliness,
@@ -1299,7 +1331,7 @@ static struct
     "deadly when", NULL,               "deadliness of element"
   },
   {
-    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(12),
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(13),
     GADGET_ID_CUSTOM_CONSISTENCY,      GADGET_ID_NONE,
     -1,
     options_consistency,
@@ -1611,49 +1643,49 @@ static struct
     NULL, NULL,                                "element can move in some direction"
   },
   {
-    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(9),
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(10),
     GADGET_ID_CUSTOM_CAN_FALL,         GADGET_ID_NONE,
     &custom_element_properties[EP_CAN_FALL],
     NULL, "can fall",                  "element can fall down"
   },
   {
-    -1,                                        ED_SETTINGS_YPOS(9),
+    -1,                                        ED_SETTINGS_YPOS(10),
     GADGET_ID_CUSTOM_CAN_SMASH,                GADGET_ID_CUSTOM_CAN_FALL,
     &custom_element_properties[EP_CAN_SMASH],
     " ", NULL,                         "element can smash other elements"
   },
   {
-    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(10),
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(11),
     GADGET_ID_CUSTOM_SLIPPERY,         GADGET_ID_NONE,
     &custom_element_properties[EP_SLIPPERY],
     NULL, NULL,                                "other elements can fall down from it"
   },
   {
-    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(11),
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(12),
     GADGET_ID_CUSTOM_DEADLY,           GADGET_ID_NONE,
     &custom_element_properties[EP_DEADLY],
     NULL, NULL,                                "element can kill the player"
   },
   {
-    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(12),
+    ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(13),
     GADGET_ID_CUSTOM_EXPLODE_RESULT,   GADGET_ID_NONE,
     &custom_element_properties[EP_EXPLODE_RESULT],
     NULL, NULL,                                "set consistency/destructibility"
   },
   {
-    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(13),
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(14),
     GADGET_ID_CUSTOM_EXPLODE_FIRE,     GADGET_ID_NONE,
     &custom_element.can_explode_by_fire,
     NULL, "by fire",                   "element can explode by fire/explosion"
   },
   {
-    -1,                                        ED_SETTINGS_YPOS(13),
+    -1,                                        ED_SETTINGS_YPOS(14),
     GADGET_ID_CUSTOM_EXPLODE_SMASH,    GADGET_ID_CUSTOM_EXPLODE_FIRE,
     &custom_element.can_explode_smashed,
     " ", "smashed",                    "element can explode when smashed"
   },
   {
-    -1,                                        ED_SETTINGS_YPOS(13),
+    -1,                                        ED_SETTINGS_YPOS(14),
     GADGET_ID_CUSTOM_EXPLODE_IMPACT,   GADGET_ID_CUSTOM_EXPLODE_SMASH,
     &custom_element.can_explode_impact,
     " ", "impact",                     "element can explode on impact"
@@ -1819,6 +1851,22 @@ static struct
     "content:", NULL,                  NULL
   },
 
+  /* ---------- custom enter and leave element (when moving) --------------- */
+
+  {
+    ED_SETTINGS_XPOS(1),               ED_AREA_ELEM_CONTENT4a_YPOS,
+    1, 1,
+    GADGET_ID_CUSTOM_MOVE_ENTER,       GADGET_ID_NONE,
+    "can dig:", " ",                   NULL
+  },
+
+  {
+    -1,                                        ED_AREA_ELEM_CONTENT4b_YPOS,
+    1, 1,
+    GADGET_ID_CUSTOM_MOVE_LEAVE,       GADGET_ID_CUSTOM_MOVE_ENTER,
+    "can leave behind:", NULL,         NULL
+  },
+
   /* ---------- custom change target --------------------------------------- */
 
   {
@@ -1846,6 +1894,15 @@ static struct
     NULL, NULL,                                NULL
   },
 
+  /* ---------- group element content -------------------------------------- */
+
+  {
+    ED_AREA_GROUP_CONTENT_XPOS,                ED_AREA_GROUP_CONTENT_YPOS,
+    MAX_ELEMENTS_IN_GROUP, 1,
+    GADGET_ID_GROUP_CONTENT,           GADGET_ID_NONE,
+    "content:", NULL,                  NULL
+  },
+
   /* ---------- random background (for random painting) -------------------- */
 
   {
@@ -1885,6 +1942,7 @@ static int new_element3 = EL_SAND;
 static void ModifyEditorCounter(int, int);
 static void ModifyEditorCounterLimits(int, int, int);
 static void ModifyEditorSelectbox(int, int);
+static void ModifyEditorDrawingArea(int, int, int);
 static void ModifyEditorElementList();
 static void RedrawDrawingElements();
 static void DrawDrawingWindow();
@@ -2151,11 +2209,7 @@ static int editor_el_more[] =
   EL_BD_FIREFLY,
 
   EL_MOLE_LEFT,
-#if 0
-  EL_MAZE_RUNNER,
-#else
   EL_EMPTY,
-#endif
   EL_MOLE_RIGHT,
   EL_PACMAN,
 
@@ -2212,7 +2266,7 @@ static int editor_el_sokoban[] =
   EL_SOKOBAN_OBJECT,
   EL_SOKOBAN_FIELD_EMPTY,
   EL_SOKOBAN_FIELD_FULL,
-  EL_STEELWALL,
+  EL_SOKOBAN_FIELD_PLAYER,
 };
 static int *editor_hl_sokoban_ptr = editor_hl_sokoban;
 static int *editor_el_sokoban_ptr = editor_el_sokoban;
@@ -2904,6 +2958,87 @@ static int *editor_el_custom_more_ptr = editor_el_custom_more;
 static int num_editor_hl_custom_more = SIZEOF_ARRAY_INT(editor_hl_custom_more);
 static int num_editor_el_custom_more = SIZEOF_ARRAY_INT(editor_el_custom_more);
 
+static int editor_hl_group[] =
+{
+  EL_CHAR('G'),
+  EL_CHAR('R'),
+  EL_CHAR('O'),
+  EL_CHAR('U'),
+
+  EL_CHAR('P'),
+  EL_CHAR(' '),
+  EL_CHAR(' '),
+  EL_CHAR(' '),
+
+  EL_CHAR('E'),
+  EL_CHAR('L'),
+  EL_CHAR('E'),
+  EL_CHAR('M'),
+
+  EL_CHAR('E'),
+  EL_CHAR('N'),
+  EL_CHAR('T'),
+  EL_CHAR('S'),
+};
+
+static int editor_el_group[] =
+{
+  EL_GROUP_START + 0,
+  EL_GROUP_START + 1,
+  EL_GROUP_START + 2,
+  EL_GROUP_START + 3,
+
+  EL_GROUP_START + 4,
+  EL_GROUP_START + 5,
+  EL_GROUP_START + 6,
+  EL_GROUP_START + 7,
+
+  EL_GROUP_START + 8,
+  EL_GROUP_START + 9,
+  EL_GROUP_START + 10,
+  EL_GROUP_START + 11,
+
+  EL_GROUP_START + 12,
+  EL_GROUP_START + 13,
+  EL_GROUP_START + 14,
+  EL_GROUP_START + 15
+};
+static int *editor_hl_group_ptr = editor_hl_group;
+static int *editor_el_group_ptr = editor_el_group;
+static int num_editor_hl_group = SIZEOF_ARRAY_INT(editor_hl_group);
+static int num_editor_el_group = SIZEOF_ARRAY_INT(editor_el_group);
+
+static int editor_hl_group_more[] =
+{
+};
+
+static int editor_el_group_more[] =
+{
+  EL_GROUP_START + 16,
+  EL_GROUP_START + 17,
+  EL_GROUP_START + 18,
+  EL_GROUP_START + 19,
+
+  EL_GROUP_START + 20,
+  EL_GROUP_START + 21,
+  EL_GROUP_START + 22,
+  EL_GROUP_START + 23,
+
+  EL_GROUP_START + 24,
+  EL_GROUP_START + 25,
+  EL_GROUP_START + 26,
+  EL_GROUP_START + 27,
+
+  EL_GROUP_START + 28,
+  EL_GROUP_START + 29,
+  EL_GROUP_START + 30,
+  EL_GROUP_START + 31
+};
+static int *editor_hl_group_more_ptr = editor_hl_group_more;
+static int *editor_el_group_more_ptr = editor_el_group_more;
+static int num_editor_hl_group_more = SIZEOF_ARRAY_INT(editor_hl_group_more);
+static int num_editor_el_group_more = SIZEOF_ARRAY_INT(editor_el_group_more);
+
 static int editor_hl_user_defined[] =
 {
   EL_CHAR('U'),
@@ -3004,6 +3139,16 @@ editor_elements_info[] =
     &editor_hl_custom_more_ptr,                &num_editor_hl_custom_more,
     &editor_el_custom_more_ptr,                &num_editor_el_custom_more
   },
+  {
+    &setup.editor.el_custom,
+    &editor_hl_group_ptr,              &num_editor_hl_group,
+    &editor_el_group_ptr,              &num_editor_el_group
+  },
+  {
+    &setup.editor.el_custom_more,
+    &editor_hl_group_more_ptr,         &num_editor_hl_group_more,
+    &editor_el_group_more_ptr,         &num_editor_el_group_more
+  },
   {
     &setup.editor.el_user_defined,
     &editor_hl_user_defined_ptr,       &num_editor_hl_user_defined,
@@ -3225,8 +3370,8 @@ static void DrawElementBorder(int dest_x, int dest_y, int width, int height,
     (input ? IMG_EDITOR_ELEMENT_BORDER_INPUT : IMG_EDITOR_ELEMENT_BORDER);
   Bitmap *src_bitmap;
   int src_x, src_y;
-  int num_mini_tilex = width / MINI_TILEX + 1;
-  int num_mini_tiley = width / MINI_TILEY + 1;
+  int num_mini_tilex = width  / MINI_TILEX + 1;
+  int num_mini_tiley = height / MINI_TILEY + 1;
   int x, y;
 
   getMiniGraphicSource(border_graphic, &src_bitmap, &src_x, &src_y);
@@ -3259,6 +3404,12 @@ static void DrawDrawingArea(int id)
        DrawMiniGraphicExt(drawto,
                           gi->x + x * MINI_TILEX, gi->y + y * MINI_TILEY,
                           el2edimg(custom_element.content[x][y]));
+  else if (id == ED_DRAWING_ID_CUSTOM_MOVE_ENTER)
+    DrawMiniGraphicExt(drawto, gi->x, gi->y,
+                      el2edimg(custom_element.move_enter_element));
+  else if (id == ED_DRAWING_ID_CUSTOM_MOVE_LEAVE)
+    DrawMiniGraphicExt(drawto, gi->x, gi->y,
+                      el2edimg(custom_element.move_leave_element));
   else if (id == ED_DRAWING_ID_CUSTOM_CHANGE_TARGET)
     DrawMiniGraphicExt(drawto, gi->x, gi->y,
                       el2edimg(custom_element_change.target_element));
@@ -3271,6 +3422,10 @@ static void DrawDrawingArea(int id)
   else if (id == ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER)
     DrawMiniGraphicExt(drawto, gi->x, gi->y,
                       el2edimg(custom_element_change.trigger_element));
+  else if (id == ED_DRAWING_ID_GROUP_CONTENT)
+    for (x = 0; x < group_element_info.num_elements; x++)
+      DrawMiniGraphicExt(drawto, gi->x + x * MINI_TILEX, gi->y,
+                        el2edimg(group_element_info.element[x]));
   else if (id >= ED_DRAWING_ID_ELEMENT_CONTENT_0 &&
           id <= ED_DRAWING_ID_ELEMENT_CONTENT_7)
   {
@@ -4627,7 +4782,7 @@ static void UnmapLevelEditorToolboxDrawingGadgets()
 
 static void UnmapDrawingArea(int id)
 {
-  UnmapGadget(level_editor_gadget[id]);
+  UnmapGadget(level_editor_gadget[drawingarea_info[id].gadget_id]);
 }
 
 static void UnmapLevelEditorWindowGadgets()
@@ -4721,6 +4876,40 @@ static int setSelectboxValue(int selectbox_id, int new_value)
 
 static void copy_custom_element_settings(int element_from, int element_to)
 {
+#if 1
+  struct ElementInfo ei_to_old = element_info[element_to];
+  struct ElementInfo *ei_from = &element_info[element_from];
+  struct ElementInfo *ei_to = &element_info[element_to];
+  int i;
+
+  /* ---------- copy whole element structure ---------- */
+  *ei_to = *ei_from;
+
+  /* ---------- restore structure pointers which cannot be copied ---------- */
+  ei_to->token_name         = ei_to_old.token_name;
+  ei_to->class_name         = ei_to_old.class_name;
+  ei_to->editor_description = ei_to_old.editor_description;
+  ei_to->custom_description = ei_to_old.custom_description;
+  ei_to->change_page        = ei_to_old.change_page;
+  ei_to->change             = ei_to_old.change;
+  ei_to->group              = ei_to_old.group;
+
+  /* ---------- copy element base properties ---------- */
+  Properties[element_to][EP_BITFIELD_BASE] =
+    Properties[element_from][EP_BITFIELD_BASE];
+
+  /* ---------- reinitialize and copy change pages ---------- */
+  setElementChangePages(ei_to, ei_to->num_change_pages);
+
+  for (i=0; i < ei_to->num_change_pages; i++)
+    ei_to->change_page[i] = ei_from->change_page[i];
+
+  /* ---------- copy group element info ---------- */
+  if (ei_from->group != NULL && ei_to->group != NULL)  /* group or internal */
+    *ei_to->group = *ei_from->group;
+
+#else
+
   struct ElementInfo *ei_from = &element_info[element_from];
   struct ElementInfo *ei_to = &element_info[element_to];
   int i, x, y;
@@ -4793,6 +4982,7 @@ static void copy_custom_element_settings(int element_from, int element_to)
 
     change_to->sides = change_from->sides;
   }
+#endif
 
   /* mark this custom element as modified */
   ei_to->modified_settings = TRUE;
@@ -4812,7 +5002,7 @@ static void replace_custom_element_in_settings(int element_from,
        if (ei->content[x][y] == element_from)
          ei->content[x][y] = element_to;
 
-    for (j=0; j < ei->num_change_pages; j++)
+    for (j = 0; j < ei->num_change_pages; j++)
     {
       struct ElementChangeInfo *change = &ei->change_page[j];
 
@@ -4827,6 +5017,11 @@ static void replace_custom_element_in_settings(int element_from,
          if (change->content[x][y] == element_from)
            change->content[x][y] = element_to;
     }
+
+    if (ei->group != NULL)                             /* group or internal */
+      for (j = 0; j < MAX_ELEMENTS_IN_GROUP; j++)
+       if (ei->group->element[j] == element_from)
+         ei->group->element[j] = element_to;
   }
 }
 
@@ -4841,8 +5036,22 @@ static void replace_custom_element_in_playfield(int element_from,
        Feld[x][y] = element_to;
 }
 
-static void CopyCustomElement(int element_old, int element_new, int copy_mode)
+static boolean CopyCustomElement(int element_old, int element_new,
+                                int copy_mode)
 {
+  if (IS_CUSTOM_ELEMENT(element_old) && !IS_CUSTOM_ELEMENT(element_new))
+  {
+    Request("Please choose custom element !", REQ_CONFIRM);
+
+    return FALSE;
+  }
+  else if (IS_GROUP_ELEMENT(element_old) && !IS_GROUP_ELEMENT(element_new))
+  {
+    Request("Please choose group element !", REQ_CONFIRM);
+
+    return FALSE;
+  }
+
   if (copy_mode == GADGET_ID_CUSTOM_COPY_FROM)
   {
     copy_custom_element_settings(element_new, element_old);
@@ -4853,21 +5062,23 @@ static void CopyCustomElement(int element_old, int element_new, int copy_mode)
   }
   else if (copy_mode == GADGET_ID_CUSTOM_EXCHANGE)
   {
-    copy_custom_element_settings(element_old, EL_DUMMY);
+    copy_custom_element_settings(element_old, EL_INTERNAL_EDITOR);
     copy_custom_element_settings(element_new, element_old);
-    copy_custom_element_settings(EL_DUMMY, element_new);
+    copy_custom_element_settings(EL_INTERNAL_EDITOR, element_new);
 
-    replace_custom_element_in_settings(element_old, EL_DUMMY);
+    replace_custom_element_in_settings(element_old, EL_INTERNAL_EDITOR);
     replace_custom_element_in_settings(element_new, element_old);
-    replace_custom_element_in_settings(EL_DUMMY, element_new);
+    replace_custom_element_in_settings(EL_INTERNAL_EDITOR, element_new);
 
-    replace_custom_element_in_playfield(element_old, EL_DUMMY);
+    replace_custom_element_in_playfield(element_old, EL_INTERNAL_EDITOR);
     replace_custom_element_in_playfield(element_new, element_old);
-    replace_custom_element_in_playfield(EL_DUMMY, element_new);
+    replace_custom_element_in_playfield(EL_INTERNAL_EDITOR, element_new);
   }
 
   UpdateCustomElementGraphicGadgets();
   DrawPropertiesWindow();
+
+  return TRUE;
 }
 
 static void CopyCustomElementPropertiesToEditor(int element)
@@ -4963,11 +5174,13 @@ static void CopyCustomElementPropertiesToEditor(int element)
     (IS_INDESTRUCTIBLE(element) ? EP_INDESTRUCTIBLE :
      CAN_EXPLODE_1X1(element) ? EP_CAN_EXPLODE_1X1 :
      CAN_EXPLODE_3X3(element) ? EP_CAN_EXPLODE_3X3 :
+     CAN_EXPLODE_DYNA(element) ? EP_CAN_EXPLODE_DYNA :
      custom_element.consistency);
   custom_element_properties[EP_EXPLODE_RESULT] =
     (IS_INDESTRUCTIBLE(element) ||
      CAN_EXPLODE_1X1(element) ||
-     CAN_EXPLODE_3X3(element));
+     CAN_EXPLODE_3X3(element) ||
+     CAN_EXPLODE_DYNA(element));
 
   /* special case: sub-settings dependent from main setting */
   if (CAN_EXPLODE_BY_FIRE(element))
@@ -4988,8 +5201,8 @@ static void CopyCustomElementPropertiesToEditor(int element)
      HAS_CHANGE_EVENT(element, CE_LEFT_BY_PLAYER) ? CE_LEFT_BY_PLAYER :
      HAS_CHANGE_EVENT(element, CE_DROPPED_BY_PLAYER) ? CE_DROPPED_BY_PLAYER :
      HAS_CHANGE_EVENT(element, CE_SWITCHED) ? CE_SWITCHED :
-     HAS_CHANGE_EVENT(element, CE_COLLISION_ACTIVE) ? CE_COLLISION_ACTIVE :
-     HAS_CHANGE_EVENT(element, CE_COLLISION_PASSIVE) ? CE_COLLISION_PASSIVE :
+     HAS_CHANGE_EVENT(element, CE_HITTING_SOMETHING) ? CE_HITTING_SOMETHING :
+     HAS_CHANGE_EVENT(element, CE_HIT_BY_SOMETHING) ? CE_HIT_BY_SOMETHING :
      HAS_CHANGE_EVENT(element, CE_IMPACT) ? CE_IMPACT :
      HAS_CHANGE_EVENT(element, CE_SMASHED) ? CE_SMASHED :
      custom_element_change.direct_action);
@@ -5005,14 +5218,28 @@ static void CopyCustomElementPropertiesToEditor(int element)
      HAS_CHANGE_EVENT(element, CE_OTHER_GETS_COLLECTED) ? CE_OTHER_GETS_COLLECTED :
      HAS_CHANGE_EVENT(element, CE_OTHER_GETS_DROPPED) ? CE_OTHER_GETS_DROPPED :
      HAS_CHANGE_EVENT(element, CE_OTHER_IS_TOUCHING) ? CE_OTHER_IS_TOUCHING :
-     HAS_CHANGE_EVENT(element, CE_OTHER_IS_COLL_ACTIVE) ? CE_OTHER_IS_COLL_ACTIVE :
-     HAS_CHANGE_EVENT(element, CE_OTHER_IS_COLL_PASSIVE) ? CE_OTHER_IS_COLL_PASSIVE :
+     HAS_CHANGE_EVENT(element, CE_OTHER_IS_HITTING) ? CE_OTHER_IS_HITTING :
+     HAS_CHANGE_EVENT(element, CE_OTHER_GETS_HIT) ? CE_OTHER_GETS_HIT :
      HAS_CHANGE_EVENT(element, CE_OTHER_IS_SWITCHING) ? CE_OTHER_IS_SWITCHING :
      HAS_CHANGE_EVENT(element, CE_OTHER_IS_CHANGING) ? CE_OTHER_IS_CHANGING :
      HAS_CHANGE_EVENT(element, CE_OTHER_IS_EXPLODING) ? CE_OTHER_IS_EXPLODING :
      custom_element_change.other_action);
 }
 
+static void CopyGroupElementPropertiesToEditor(int element)
+{
+  group_element_info = *element_info[element].group;
+  custom_element = element_info[element];      /* needed for description */
+}
+
+static void CopyElementPropertiesToEditor(int element)
+{
+  if (IS_CUSTOM_ELEMENT(element))
+    CopyCustomElementPropertiesToEditor(element);
+  else if (IS_GROUP_ELEMENT(element))
+    CopyGroupElementPropertiesToEditor(element);
+}
+
 static void CopyCustomElementPropertiesToGame(int element)
 {
   int i;
@@ -5081,6 +5308,7 @@ static void CopyCustomElementPropertiesToGame(int element)
   custom_element_properties[EP_INDESTRUCTIBLE] = FALSE;
   custom_element_properties[EP_CAN_EXPLODE_1X1] = FALSE;
   custom_element_properties[EP_CAN_EXPLODE_3X3] = FALSE;
+  custom_element_properties[EP_CAN_EXPLODE_DYNA] = FALSE;
   custom_element_properties[EP_CAN_EXPLODE_BY_FIRE] = FALSE;
   custom_element_properties[EP_CAN_EXPLODE_SMASHED] = FALSE;
   custom_element_properties[EP_CAN_EXPLODE_IMPACT] = FALSE;
@@ -5088,8 +5316,9 @@ static void CopyCustomElementPropertiesToGame(int element)
     custom_element_properties[EP_EXPLODE_RESULT];
 
   /* special case: sub-settings dependent from main setting */
-  if (custom_element_properties[EP_CAN_EXPLODE_3X3] ||
-      custom_element_properties[EP_CAN_EXPLODE_1X1])
+  if (custom_element_properties[EP_CAN_EXPLODE_1X1] ||
+      custom_element_properties[EP_CAN_EXPLODE_3X3] ||
+      custom_element_properties[EP_CAN_EXPLODE_DYNA])
   {
     custom_element_properties[EP_CAN_EXPLODE_BY_FIRE] =
       custom_element.can_explode_by_fire;
@@ -5109,8 +5338,8 @@ static void CopyCustomElementPropertiesToGame(int element)
   custom_element_change_events[CE_LEFT_BY_PLAYER] = FALSE;
   custom_element_change_events[CE_DROPPED_BY_PLAYER] = FALSE;
   custom_element_change_events[CE_SWITCHED] = FALSE;
-  custom_element_change_events[CE_COLLISION_ACTIVE] = FALSE;
-  custom_element_change_events[CE_COLLISION_PASSIVE] = FALSE;
+  custom_element_change_events[CE_HITTING_SOMETHING] = FALSE;
+  custom_element_change_events[CE_HIT_BY_SOMETHING] = FALSE;
   custom_element_change_events[CE_IMPACT] = FALSE;
   custom_element_change_events[CE_SMASHED] = FALSE;
   custom_element_change_events[custom_element_change.direct_action] =
@@ -5126,8 +5355,8 @@ static void CopyCustomElementPropertiesToGame(int element)
   custom_element_change_events[CE_OTHER_GETS_COLLECTED] = FALSE;
   custom_element_change_events[CE_OTHER_GETS_DROPPED] = FALSE;
   custom_element_change_events[CE_OTHER_IS_TOUCHING] = FALSE;
-  custom_element_change_events[CE_OTHER_IS_COLL_ACTIVE] = FALSE;
-  custom_element_change_events[CE_OTHER_IS_COLL_PASSIVE] = FALSE;
+  custom_element_change_events[CE_OTHER_IS_HITTING] = FALSE;
+  custom_element_change_events[CE_OTHER_GETS_HIT] = FALSE;
   custom_element_change_events[CE_OTHER_IS_SWITCHING] = FALSE;
   custom_element_change_events[CE_OTHER_IS_CHANGING] = FALSE;
   custom_element_change_events[CE_OTHER_IS_EXPLODING] = FALSE;
@@ -5145,6 +5374,23 @@ static void CopyCustomElementPropertiesToGame(int element)
   custom_element_change = *element_info[element].change;
 }
 
+static void CopyGroupElementPropertiesToGame(int element)
+{
+  element_info[element] = custom_element;
+  *element_info[element].group = group_element_info;
+
+  /* mark that this group element has been modified */
+  element_info[element].modified_settings = TRUE;
+}
+
+static void CopyElementPropertiesToGame(int element)
+{
+  if (IS_CUSTOM_ELEMENT(element))
+    CopyCustomElementPropertiesToGame(element);
+  else if (IS_GROUP_ELEMENT(element))
+    CopyGroupElementPropertiesToGame(element);
+}
+
 void DrawLevelEd()
 {
   CloseDoor(DOOR_CLOSE_ALL);
@@ -5336,6 +5582,14 @@ static void ModifyEditorSelectbox(int selectbox_id, int new_value)
   ModifyGadget(gi, GDI_SELECTBOX_INDEX, new_index_value, GDI_END);
 }
 
+static void ModifyEditorDrawingArea(int drawingarea_id, int xsize, int ysize)
+{
+  int gadget_id = drawingarea_info[drawingarea_id].gadget_id;
+  struct GadgetInfo *gi = level_editor_gadget[gadget_id];
+
+  ModifyGadget(gi, GDI_AREA_SIZE, xsize, ysize, GDI_END);
+}
+
 static void ModifyEditorElementList()
 {
   int i;
@@ -5502,7 +5756,7 @@ static void DrawElementContentAreas()
       DrawBackground(SX + drawingarea_info[id].x - MINI_TILEX / 2,
                     SY + drawingarea_info[id].y - MINI_TILEY / 2,
                     4 * MINI_TILEX,
-                    4 * MINI_TILEX + ED_GADGET_TEXT_DISTANCE + font_height);
+                    4 * MINI_TILEY + ED_GADGET_TEXT_DISTANCE + font_height);
     }
   }
 
@@ -5511,6 +5765,28 @@ static void DrawElementContentAreas()
   DrawText(x, y + 2 * MINI_TILEY, "smashed", FONT_TEXT_1);
 }
 
+static void DrawGroupElementArea(int element)
+{
+  int num_elements = group_element_info.num_elements;
+  int id = ED_DRAWING_ID_GROUP_CONTENT;
+  int sx = SX + drawingarea_info[id].x - MINI_TILEX / 2;
+  int sy = SY + drawingarea_info[id].y - MINI_TILEY / 2;
+  int xsize = MAX_ELEMENTS_IN_GROUP;
+  int ysize = 1;
+
+  if (drawingarea_info[id].text_left != NULL)
+    sx += getTextWidthForDrawingArea(drawingarea_info[id].text_left);
+
+  UnmapDrawingArea(id);
+
+  ModifyEditorDrawingArea(id, num_elements, 1);
+
+  /* delete content areas in case of reducing number of them */
+  DrawBackground(sx, sy, (xsize + 1) * MINI_TILEX, (ysize + 1) * MINI_TILEY);
+
+  MapDrawingArea(id);
+}
+
 static void DrawEnvelopeTextArea(int envelope_nr)
 {
   int id = ED_TEXTAREA_ID_ENVELOPE_INFO;
@@ -5694,7 +5970,8 @@ static void DrawPropertiesTabulatorGadgets()
   int i;
 
   /* draw additional "advanced" tabulator for custom elements */
-  if (IS_CUSTOM_ELEMENT(properties_element))
+  if (IS_CUSTOM_ELEMENT(properties_element) ||
+      IS_GROUP_ELEMENT(properties_element))
     id_last = ED_TEXTBUTTON_ID_PROPERTIES_ADVANCED;
 
   for (i = id_first; i <= id_last; i++)
@@ -5796,6 +6073,12 @@ static void DrawPropertiesInfo()
              "[Custom Element %d]", properties_element - EL_CUSTOM_START + 1);
     screen_line++;
   }
+  else if (IS_GROUP_ELEMENT(properties_element))
+  {
+    DrawTextF(pad_x, pad_y + screen_line++ * font2_height, FONT_TEXT_3,
+             "[Group Element %d]", properties_element - EL_GROUP_START + 1);
+    screen_line++;
+  }
 #endif
 
   /* ----- print number of elements / percentage of this element in level */
@@ -5928,6 +6211,7 @@ static boolean checkPropertiesConfig()
 
   if (IS_GEM(properties_element) ||
       IS_CUSTOM_ELEMENT(properties_element) ||
+      IS_GROUP_ELEMENT(properties_element) ||
       IS_ENVELOPE(properties_element) ||
       HAS_CONTENT(properties_element))
     return TRUE;
@@ -6019,6 +6303,24 @@ static void DrawPropertiesConfig()
 
     /* draw drawing area gadgets */
     DrawCustomContentArea();
+    MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_ENTER);
+    MapDrawingArea(ED_DRAWING_ID_CUSTOM_MOVE_LEAVE);
+
+    /* draw text input gadgets */
+    MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
+  }
+  else if (IS_GROUP_ELEMENT(properties_element))
+  {
+    /* draw stickybutton gadget */
+    i = ED_CHECKBUTTON_ID_STICK_ELEMENT;
+    checkbutton_info[i].y = ED_SETTINGS_YPOS(0);
+    MapCheckbuttonGadget(i);
+
+    /* draw counter gadgets */
+    MapCounterButtons(ED_COUNTER_ID_GROUP_CONTENT);
+
+    /* draw drawing area gadgets */
+    DrawGroupElementArea(properties_element);
 
     /* draw text input gadgets */
     MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
@@ -6028,10 +6330,14 @@ static void DrawPropertiesConfig()
 static void DrawPropertiesAdvancedDrawingAreas()
 {
   MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
-  MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TARGET);
-  MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER);
 
-  DrawCustomChangeContentArea();
+  if (IS_CUSTOM_ELEMENT(properties_element))
+  {
+    MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TARGET);
+    MapDrawingArea(ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER);
+
+    DrawCustomChangeContentArea();
+  }
 
   redraw_mask |= REDRAW_FIELD;
 }
@@ -6045,27 +6351,42 @@ static void DrawPropertiesAdvanced()
   checkbutton_info[i].y = ED_SETTINGS_YPOS(0);
   MapCheckbuttonGadget(i);
 
-  /* draw checkbutton gadgets */
-  for (i =  ED_CHECKBUTTON_ID_CHANGE_FIRST;
-       i <= ED_CHECKBUTTON_ID_CHANGE_LAST; i++)
+  if (IS_CUSTOM_ELEMENT(properties_element))
+  {
+    /* draw checkbutton gadgets */
+    for (i =  ED_CHECKBUTTON_ID_CHANGE_FIRST;
+        i <= ED_CHECKBUTTON_ID_CHANGE_LAST; i++)
     MapCheckbuttonGadget(i);
 
-  /* draw counter gadgets */
-  for (i = ED_COUNTER_ID_CHANGE_FIRST; i <= ED_COUNTER_ID_CHANGE_LAST; i++)
-    MapCounterButtons(i);
+    /* draw counter gadgets */
+    for (i =  ED_COUNTER_ID_CHANGE_FIRST;
+        i <= ED_COUNTER_ID_CHANGE_LAST; i++)
+      MapCounterButtons(i);
 
-  /* draw selectbox gadgets */
-  for (i = ED_SELECTBOX_ID_CHANGE_FIRST; i <= ED_SELECTBOX_ID_CHANGE_LAST; i++)
-    MapSelectboxGadget(i);
+    /* draw selectbox gadgets */
+    for (i =  ED_SELECTBOX_ID_CHANGE_FIRST;
+        i <= ED_SELECTBOX_ID_CHANGE_LAST; i++)
+      MapSelectboxGadget(i);
 
-  /* draw textbutton gadgets */
-  for (i=ED_TEXTBUTTON_ID_CHANGE_FIRST; i <= ED_TEXTBUTTON_ID_CHANGE_LAST; i++)
-    MapTextbuttonGadget(i);
+    /* draw textbutton gadgets */
+    for (i =  ED_TEXTBUTTON_ID_CHANGE_FIRST;
+        i <= ED_TEXTBUTTON_ID_CHANGE_LAST; i++)
+      MapTextbuttonGadget(i);
 
-  /* draw graphicbutton gadgets */
-  for (i =  ED_GRAPHICBUTTON_ID_CHANGE_FIRST;
-       i <= ED_GRAPHICBUTTON_ID_CHANGE_LAST; i++)
-    MapGraphicbuttonGadget(i);
+    /* draw graphicbutton gadgets */
+    for (i =  ED_GRAPHICBUTTON_ID_CHANGE_FIRST;
+        i <= ED_GRAPHICBUTTON_ID_CHANGE_LAST; i++)
+      MapGraphicbuttonGadget(i);
+  }
+  else if (IS_GROUP_ELEMENT(properties_element))
+  {
+    /* draw checkbutton gadgets */
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE);
+
+    /* draw textbutton gadgets */
+    MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE);
+  }
 
   /* draw drawing area gadgets */
   DrawPropertiesAdvancedDrawingAreas();
@@ -6125,17 +6446,18 @@ static void DrawPropertiesWindow()
 
   /* make sure that previous properties edit mode exists for this element */
   if (edit_mode_properties == ED_MODE_PROPERTIES_ADVANCED &&
-      !IS_CUSTOM_ELEMENT(properties_element))
+      !IS_CUSTOM_ELEMENT(properties_element) &&
+      !IS_GROUP_ELEMENT(properties_element))
     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG;
 
-  if (IS_CUSTOM_ELEMENT(properties_element))
-    CopyCustomElementPropertiesToEditor(properties_element);
+  CopyElementPropertiesToEditor(properties_element);
 
   UnmapLevelEditorWindowGadgets();
   UnmapLevelEditorToolboxDrawingGadgets();
   UnmapLevelEditorToolboxCustomGadgets();
 
-  if (IS_CUSTOM_ELEMENT(properties_element))
+  if (IS_CUSTOM_ELEMENT(properties_element) ||
+      IS_GROUP_ELEMENT(properties_element))
     MapLevelEditorToolboxCustomGadgets();
 
   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
@@ -6915,7 +7237,7 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
          new_element = GFX_ELEMENT(new_element);
          custom_element.gfx_element = new_element;
 
-         CopyCustomElementPropertiesToGame(properties_element);
+         CopyElementPropertiesToGame(properties_element);
 
          UpdateCustomElementGraphicGadgets();
 
@@ -6927,6 +7249,18 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
 
          CopyCustomElementPropertiesToGame(properties_element);
        }
+       else if (id == GADGET_ID_CUSTOM_MOVE_ENTER)
+       {
+         custom_element.move_enter_element = new_element;
+
+         CopyCustomElementPropertiesToGame(properties_element);
+       }
+       else if (id == GADGET_ID_CUSTOM_MOVE_LEAVE)
+       {
+         custom_element.move_leave_element = new_element;
+
+         CopyCustomElementPropertiesToGame(properties_element);
+       }
        else if (id == GADGET_ID_CUSTOM_CHANGE_TARGET)
        {
          custom_element_change.target_element = new_element;
@@ -6945,6 +7279,12 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
 
          CopyCustomElementPropertiesToGame(properties_element);
        }
+       else if (id == GADGET_ID_GROUP_CONTENT)
+       {
+         group_element_info.element[sx] = new_element;
+
+         CopyGroupElementPropertiesToGame(properties_element);
+       }
        else if (id == GADGET_ID_RANDOM_BACKGROUND)
          random_placement_background_element = new_element;
        else if (id >= GADGET_ID_ELEMENT_CONTENT_0 &&
@@ -7055,12 +7395,18 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
        PickDrawingElement(button, custom_element.gfx_element);
       else if (id == GADGET_ID_CUSTOM_CONTENT)
        PickDrawingElement(button, custom_element.content[sx][sy]);
+      else if (id == GADGET_ID_CUSTOM_MOVE_ENTER)
+       PickDrawingElement(button, custom_element.move_enter_element);
+      else if (id == GADGET_ID_CUSTOM_MOVE_LEAVE)
+       PickDrawingElement(button, custom_element.move_leave_element);
       else if (id == GADGET_ID_CUSTOM_CHANGE_TARGET)
        PickDrawingElement(button, custom_element_change.target_element);
       else if (id == GADGET_ID_CUSTOM_CHANGE_CONTENT)
        PickDrawingElement(button, custom_element_change.content[sx][sy]);
       else if (id == GADGET_ID_CUSTOM_CHANGE_TRIGGER)
        PickDrawingElement(button, custom_element_change.trigger_element);
+      else if (id == GADGET_ID_GROUP_CONTENT)
+       PickDrawingElement(button, group_element_info.element[sx]);
       else if (id == GADGET_ID_RANDOM_BACKGROUND)
        PickDrawingElement(button, random_placement_background_element);
       else if (id >= GADGET_ID_ELEMENT_CONTENT_0 &&
@@ -7116,6 +7462,11 @@ static void HandleCounterButtons(struct GadgetInfo *gi)
       DrawElementContentAreas();
       break;
 
+    case ED_COUNTER_ID_GROUP_CONTENT:
+      DrawGroupElementArea(properties_element);
+      CopyGroupElementPropertiesToGame(properties_element);
+      break;
+
     case ED_COUNTER_ID_ENVELOPE_XSIZE:
     case ED_COUNTER_ID_ENVELOPE_YSIZE:
       DrawEnvelopeTextArea(-1);
@@ -7142,7 +7493,7 @@ static void HandleCounterButtons(struct GadgetInfo *gi)
        counter_id <= ED_COUNTER_ID_CUSTOM_LAST) ||
       (counter_id >= ED_COUNTER_ID_CHANGE_FIRST &&
        counter_id <= ED_COUNTER_ID_CHANGE_LAST))
-    CopyCustomElementPropertiesToGame(properties_element);
+    CopyElementPropertiesToGame(properties_element);
 }
 
 static void HandleTextInputGadgets(struct GadgetInfo *gi)
@@ -7153,7 +7504,7 @@ static void HandleTextInputGadgets(struct GadgetInfo *gi)
 
   if (type_id == ED_TEXTINPUT_ID_ELEMENT_NAME)
   {
-    CopyCustomElementPropertiesToGame(properties_element);
+    CopyElementPropertiesToGame(properties_element);
 
     ModifyEditorElementList(); /* update changed button info text */
   }
@@ -7183,7 +7534,7 @@ static void HandleSelectboxGadgets(struct GadgetInfo *gi)
            type_id <= ED_SELECTBOX_ID_CUSTOM_LAST) ||
           (type_id >= ED_SELECTBOX_ID_CHANGE_FIRST &&
            type_id <= ED_SELECTBOX_ID_CHANGE_LAST))
-    CopyCustomElementPropertiesToGame(properties_element);
+    CopyElementPropertiesToGame(properties_element);
 }
 
 static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
@@ -7200,7 +7551,8 @@ static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
   }
   else if (type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE)
   {
-    boolean new_template = (!LevelFileExists(-1));
+    char *template_filename = getDefaultLevelFilename(-1);
+    boolean new_template = !fileExists(template_filename);
 
     if (new_template ||
        Request("Save this template and kill the old ?", REQ_ASK))
@@ -7279,7 +7631,7 @@ static void HandleCheckbuttons(struct GadgetInfo *gi)
        type_id <= ED_CHECKBUTTON_ID_CHANGE_LAST &&
        type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE))
   {
-    CopyCustomElementPropertiesToGame(properties_element);
+    CopyElementPropertiesToGame(properties_element);
   }
 
   if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC)
@@ -7288,7 +7640,9 @@ static void HandleCheckbuttons(struct GadgetInfo *gi)
   }
   else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE)
   {
-    if (level.use_custom_template && !LevelFileExists(-1))
+    char *template_filename = getDefaultLevelFilename(-1);
+
+    if (level.use_custom_template && !fileExists(template_filename))
     {
       Request("No level template found !", REQ_CONFIRM);
 
@@ -7330,6 +7684,10 @@ static void HandleControlButtons(struct GadgetInfo *gi)
     edit_mode = ED_MODE_DRAWING;
   }
 
+  /* element copy mode active, but no element button pressed => deactivate */
+  if (last_custom_copy_mode != -1 && id < ED_NUM_CTRL_BUTTONS)
+    last_custom_copy_mode = -1;
+
   switch (id)
   {
     case GADGET_ID_SCROLL_LEFT:
@@ -7571,7 +7929,8 @@ static void HandleControlButtons(struct GadgetInfo *gi)
        Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
       else
       {
-       boolean new_level = (!LevelFileExists(level_nr));
+       char *level_filename = getDefaultLevelFilename(level_nr);
+       boolean new_level = !fileExists(level_filename);
 
        if (new_level ||
            Request("Save this level and kill the old ?", REQ_ASK))
@@ -7627,13 +7986,14 @@ static void HandleControlButtons(struct GadgetInfo *gi)
 
        if (last_custom_copy_mode != -1)
        {
-         CopyCustomElement(properties_element, new_element,
-                           last_custom_copy_mode);
-
-         ClickOnGadget(level_editor_gadget[last_drawing_function],
-                       MB_LEFTBUTTON);
+         if (CopyCustomElement(properties_element, new_element,
+                               last_custom_copy_mode))
+         {
+           ClickOnGadget(level_editor_gadget[last_drawing_function],
+                         MB_LEFTBUTTON);
 
-         last_custom_copy_mode = -1;
+           last_custom_copy_mode = -1;
+         }
 
          break;
        }
@@ -7821,7 +8181,6 @@ void HandleEditorGadgetInfoText(void *ptr)
 static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
 {
   static int start_lx, start_ly;
-  char *infotext;
   int id = gi->custom_id;
   int sx = gi->event.x;
   int sy = gi->event.y;
@@ -7831,6 +8190,11 @@ static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
   int max_sx = gi->drawing.area_xsize - 1;
   int max_sy = gi->drawing.area_ysize - 1;
   int actual_drawing_function = drawing_function;
+  int max_infotext_len = getMaxInfoTextLength();
+  char infotext[MAX_OUTPUT_LINESIZE + 1];
+  char *text;
+
+  infotext[0] = '\0';          /* start with empty info text */
 
   /* pressed Control key: simulate picking element */
   if (GetKeyModState() & KMOD_Control)
@@ -7878,41 +8242,48 @@ static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
        switch (actual_drawing_function)
        {
          case GADGET_ID_SINGLE_ITEMS:
-           infotext = "Drawing single items";
+           text = "Drawing single items";
            break;
          case GADGET_ID_CONNECTED_ITEMS:
-           infotext = "Drawing connected items";
+           text = "Drawing connected items";
            break;
          case GADGET_ID_LINE:
-           infotext = "Drawing line";
+           text = "Drawing line";
            break;
          case GADGET_ID_ARC:
-           infotext = "Drawing arc";
+           text = "Drawing arc";
            break;
          case GADGET_ID_TEXT:
-           infotext = "Setting text cursor";
+           text = "Setting text cursor";
            break;
          case GADGET_ID_RECTANGLE:
-           infotext = "Drawing rectangle";
+           text = "Drawing rectangle";
            break;
          case GADGET_ID_FILLED_BOX:
-           infotext = "Drawing filled box";
+           text = "Drawing filled box";
            break;
          case GADGET_ID_FLOOD_FILL:
-           infotext = "Flood fill";
+           text = "Flood fill";
            break;
          case GADGET_ID_GRAB_BRUSH:
-           infotext = "Grabbing brush";
+           text = "Grabbing brush";
            break;
          case GADGET_ID_PICK_ELEMENT:
-           infotext = "Picking element";
+           text = "Picking element";
            break;
 
          default:
-           infotext = "Drawing position";
+           text = "Drawing position";
            break;
        }
 
+#if 1
+       if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
+         sprintf(infotext, "%s: %d, %d", text, lx, ly);
+       else
+         sprintf(infotext, "%s: %d, %d", text,
+                 ABS(lx - start_lx) + 1, ABS(ly - start_ly) + 1);
+#else
        if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
          DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
                    "%s: %d, %d", infotext, lx, ly);
@@ -7920,13 +8291,21 @@ static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
          DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
                    "%s: %d, %d", infotext,
                    ABS(lx - start_lx) + 1, ABS(ly - start_ly) + 1);
+#endif
       }
+#if 1
+      else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
+       strncpy(infotext, getElementInfoText(Feld[lx][ly]), max_infotext_len);
+      else
+       sprintf(infotext, "Level position: %d, %d", lx, ly);
+#else
       else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
        DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
                  "%s", getElementInfoText(Feld[lx][ly]));
       else
        DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
                  "Level position: %d, %d", lx, ly);
+#endif
     }
 
     /* misuse this function to draw brush cursor, if needed */
@@ -7940,65 +8319,66 @@ static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
   }
   else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
   {
+    int element = EL_EMPTY;
+
     if (id == GADGET_ID_AMOEBA_CONTENT)
-      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
-               getElementInfoText(level.amoeba_content));
+      element = level.amoeba_content;
     else if (id == GADGET_ID_CUSTOM_GRAPHIC)
-      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
-               getElementInfoText(custom_element.gfx_element));
+      element = custom_element.gfx_element;
     else if (id == GADGET_ID_CUSTOM_CONTENT)
-      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
-               getElementInfoText(custom_element.content[sx][sy]));
+      element = custom_element.content[sx][sy];
+    else if (id == GADGET_ID_CUSTOM_MOVE_ENTER)
+      element = custom_element.move_enter_element;
+    else if (id == GADGET_ID_CUSTOM_MOVE_LEAVE)
+      element = custom_element.move_leave_element;
     else if (id == GADGET_ID_CUSTOM_CHANGE_TARGET)
-      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
-               getElementInfoText(custom_element_change.target_element));
+      element = custom_element_change.target_element;
     else if (id == GADGET_ID_CUSTOM_CHANGE_CONTENT)
-      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
-               getElementInfoText(custom_element_change.content[sx][sy]));
+      element = custom_element_change.content[sx][sy];
     else if (id == GADGET_ID_CUSTOM_CHANGE_TRIGGER)
-      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
-               getElementInfoText(custom_element_change.trigger_element));
+      element = custom_element_change.trigger_element;
+    else if (id == GADGET_ID_GROUP_CONTENT)
+      element = group_element_info.element[sx];
     else if (id == GADGET_ID_RANDOM_BACKGROUND)
-      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
-               getElementInfoText(random_placement_background_element));
+      element = random_placement_background_element;
     else if (id >= GADGET_ID_ELEMENT_CONTENT_0 &&
             id <= GADGET_ID_ELEMENT_CONTENT_7)
-    {
-      int i = id - GADGET_ID_ELEMENT_CONTENT_0;
+      element = level.yamyam_content[id - GADGET_ID_ELEMENT_CONTENT_0][sx][sy];
 
-      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, "%s",
-               getElementInfoText(level.yamyam_content[i][sx][sy]));
-    }
+    strncpy(infotext, getElementInfoText(element), max_infotext_len);
   }
   else
   {
     if (id == GADGET_ID_AMOEBA_CONTENT)
-      DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
-               "Amoeba content");
+      strcpy(infotext, "Amoeba content");
     else if (id == GADGET_ID_CUSTOM_GRAPHIC)
-      DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
-               "Custom graphic element");
+      strcpy(infotext, "Custom graphic element");
     else if (id == GADGET_ID_CUSTOM_CONTENT)
-      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
-               "Custom element content position: %d, %d", sx, sy);
+      sprintf(infotext, "Custom element content position: %d, %d", sx, sy);
+    else if (id == GADGET_ID_CUSTOM_MOVE_ENTER)
+      strcpy(infotext, "Element that can be digged/collected");
+    else if (id == GADGET_ID_CUSTOM_MOVE_LEAVE)
+      strcpy(infotext, "Element that will be left behind");
     else if (id == GADGET_ID_CUSTOM_CHANGE_TARGET)
-      DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
-               "New element after change");
+      strcpy(infotext, "New element after change");
     else if (id == GADGET_ID_CUSTOM_CHANGE_CONTENT)
-      DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
-               "New extended elements after change");
+      strcpy(infotext, "New extended elements after change");
     else if (id == GADGET_ID_CUSTOM_CHANGE_TRIGGER)
-      DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
-               "Other element triggering change");
+      strcpy(infotext, "Other element triggering change");
+    else if (id == GADGET_ID_GROUP_CONTENT)
+      sprintf(infotext, "Group element position: %d", sx + 1);
     else if (id == GADGET_ID_RANDOM_BACKGROUND)
-      DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
-               "Random placement background");
+      strcpy(infotext, "Random placement background");
     else if (id >= GADGET_ID_ELEMENT_CONTENT_0 &&
             id <= GADGET_ID_ELEMENT_CONTENT_7)
-      DrawTextF(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2,
-               "Content area %d position: %d, %d",
-               id - GADGET_ID_ELEMENT_CONTENT_0 + 1, sx, sy);
+      sprintf(infotext, "Content area %d position: %d, %d",
+             id - GADGET_ID_ELEMENT_CONTENT_0 + 1, sx, sy);
   }
+
+  infotext[max_infotext_len] = '\0';
+
+  if (strlen(infotext) > 0)
+    DrawTextS(INFOTEXT_XPOS - SX, INFOTEXT_YPOS - SY, FONT_TEXT_2, infotext);
 }
 
 void RequestExitLevelEditor(boolean ask_if_level_has_changed)