added optional button to restart game (door, panel and touch variants)
[rocksndiamonds.git] / src / editor.c
index 2bf5543c8314fa4f345ebc88a4a2968a2141e9cd..671ac61de7551324c23e7c14ecf4d6dd8b83eb3d 100644 (file)
@@ -4,7 +4,7 @@
 // (c) 1995-2014 by Artsoft Entertainment
 //                         Holger Schemel
 //                 info@artsoft.org
-//                 http://www.artsoft.org/
+//                 https://www.artsoft.org/
 // ----------------------------------------------------------------------------
 // editor.c
 // ============================================================================
 #define ED_ELEMENTLIST_YPOS            (editor.palette.y)
 #define ED_ELEMENTLIST_XSIZE           (graphic_info[IMG_EDITOR_PALETTE_BUTTON].width)
 #define ED_ELEMENTLIST_YSIZE           (graphic_info[IMG_EDITOR_PALETTE_BUTTON].height)
-#define ED_ELEMENTLIST_BUTTONS_HORIZ   (editor.palette.cols)
-#define ED_ELEMENTLIST_BUTTONS_VERT    (editor.palette.rows)
+#define ED_ELEMENTLIST_COLS            MAX(1, editor.palette.cols)
+#define ED_ELEMENTLIST_ROWS            MAX(1, editor.palette.rows)
+#define ED_ELEMENTLIST_BUTTONS_HORIZ   (ED_ELEMENTLIST_COLS)
+#define ED_ELEMENTLIST_BUTTONS_VERT    (ED_ELEMENTLIST_ROWS)
 #define ED_NUM_ELEMENTLIST_BUTTONS     (ED_ELEMENTLIST_BUTTONS_HORIZ * \
                                         ED_ELEMENTLIST_BUTTONS_VERT)
 
@@ -380,7 +382,7 @@ enum
   GADGET_ID_PICK_ELEMENT,
 
   GADGET_ID_UNDO,
-  GADGET_ID_INFO,
+  GADGET_ID_CONF,
   GADGET_ID_SAVE,
   GADGET_ID_CLEAR,
   GADGET_ID_TEST,
@@ -457,6 +459,9 @@ enum
   GADGET_ID_INVENTORY_SIZE_DOWN,
   GADGET_ID_INVENTORY_SIZE_TEXT,
   GADGET_ID_INVENTORY_SIZE_UP,
+  GADGET_ID_MM_BALL_CONTENT_DOWN,
+  GADGET_ID_MM_BALL_CONTENT_TEXT,
+  GADGET_ID_MM_BALL_CONTENT_UP,
   GADGET_ID_CUSTOM_SCORE_DOWN,
   GADGET_ID_CUSTOM_SCORE_TEXT,
   GADGET_ID_CUSTOM_SCORE_UP,
@@ -487,6 +492,12 @@ enum
   GADGET_ID_MOVE_DELAY_RND_DOWN,
   GADGET_ID_MOVE_DELAY_RND_TEXT,
   GADGET_ID_MOVE_DELAY_RND_UP,
+  GADGET_ID_STEP_DELAY_FIX_DOWN,
+  GADGET_ID_STEP_DELAY_FIX_TEXT,
+  GADGET_ID_STEP_DELAY_FIX_UP,
+  GADGET_ID_STEP_DELAY_RND_DOWN,
+  GADGET_ID_STEP_DELAY_RND_TEXT,
+  GADGET_ID_STEP_DELAY_RND_UP,
   GADGET_ID_EXPLOSION_DELAY_DOWN,
   GADGET_ID_EXPLOSION_DELAY_TEXT,
   GADGET_ID_EXPLOSION_DELAY_UP,
@@ -531,6 +542,7 @@ enum
   GADGET_ID_ARTWORK_ELEMENT,
   GADGET_ID_EXPLOSION_ELEMENT,
   GADGET_ID_INVENTORY_CONTENT,
+  GADGET_ID_MM_BALL_CONTENT,
   GADGET_ID_CUSTOM_GRAPHIC,
   GADGET_ID_CUSTOM_CONTENT,
   GADGET_ID_CUSTOM_MOVE_ENTER,
@@ -557,10 +569,12 @@ enum
   // selectbox identifiers
 
   GADGET_ID_TIME_OR_STEPS,
+  GADGET_ID_TIME_SCORE_BASE,
   GADGET_ID_GAME_ENGINE_TYPE,
   GADGET_ID_LEVELSET_SAVE_MODE,
   GADGET_ID_WIND_DIRECTION,
   GADGET_ID_PLAYER_SPEED,
+  GADGET_ID_MM_BALL_CHOICE_MODE,
   GADGET_ID_CUSTOM_WALK_TO_ACTION,
   GADGET_ID_CUSTOM_EXPLOSION_TYPE,
   GADGET_ID_CUSTOM_DEADLINESS,
@@ -589,9 +603,9 @@ enum
 
   // textbutton identifiers
 
-  GADGET_ID_LEVELINFO_LEVEL,
-  GADGET_ID_LEVELINFO_LEVELSET,
-  GADGET_ID_LEVELINFO_EDITOR,
+  GADGET_ID_LEVELCONFIG_LEVEL,
+  GADGET_ID_LEVELCONFIG_LEVELSET,
+  GADGET_ID_LEVELCONFIG_EDITOR,
   GADGET_ID_PROPERTIES_INFO,
   GADGET_ID_PROPERTIES_CONFIG,
   GADGET_ID_PROPERTIES_CONFIG_1,
@@ -628,6 +642,7 @@ enum
   // checkbuttons/radiobuttons for level/element properties
 
   GADGET_ID_AUTO_COUNT_GEMS,
+  GADGET_ID_RATE_TIME_OVER_SCORE,
   GADGET_ID_USE_LEVELSET_ARTWORK,
   GADGET_ID_COPY_LEVEL_TEMPLATE,
   GADGET_ID_RANDOM_PERCENTAGE,
@@ -640,12 +655,14 @@ enum
   GADGET_ID_USE_TIME_ORB_BUG,
   GADGET_ID_USE_LIFE_BUGS,
   GADGET_ID_RANDOM_BALL_CONTENT,
-  GADGET_ID_INITIAL_BALL_STATE,
+  GADGET_ID_INITIAL_BALL_ACTIVE,
   GADGET_ID_GROW_INTO_DIGGABLE,
   GADGET_ID_SB_FIELDS_NEEDED,
   GADGET_ID_SB_OBJECTS_NEEDED,
   GADGET_ID_AUTO_EXIT_SOKOBAN,
   GADGET_ID_SOLVED_BY_ONE_PLAYER,
+  GADGET_ID_FINISH_DIG_COLLECT,
+  GADGET_ID_KEEP_WALKABLE_CE,
   GADGET_ID_CONTINUOUS_SNAPPING,
   GADGET_ID_BLOCK_SNAP_FIELD,
   GADGET_ID_BLOCK_LAST_FIELD,
@@ -670,6 +687,8 @@ enum
   GADGET_ID_DF_LASER_RED,
   GADGET_ID_DF_LASER_GREEN,
   GADGET_ID_DF_LASER_BLUE,
+  GADGET_ID_ROTATE_MM_BALL_CONTENT,
+  GADGET_ID_EXPLODE_MM_BALL,
   GADGET_ID_CUSTOM_INDESTRUCTIBLE,
   GADGET_ID_CUSTOM_CAN_EXPLODE,
   GADGET_ID_CUSTOM_EXPLODE_FIRE,
@@ -738,6 +757,7 @@ enum
   ED_COUNTER_ID_ENVELOPE_XSIZE,
   ED_COUNTER_ID_ENVELOPE_YSIZE,
   ED_COUNTER_ID_INVENTORY_SIZE,
+  ED_COUNTER_ID_MM_BALL_CONTENT,
   ED_COUNTER_ID_CUSTOM_SCORE,
   ED_COUNTER_ID_CUSTOM_GEMCOUNT,
   ED_COUNTER_ID_CUSTOM_VALUE_FIX,
@@ -748,6 +768,8 @@ enum
   ED_COUNTER_ID_DROP_DELAY_RND,
   ED_COUNTER_ID_MOVE_DELAY_FIX,
   ED_COUNTER_ID_MOVE_DELAY_RND,
+  ED_COUNTER_ID_STEP_DELAY_FIX,
+  ED_COUNTER_ID_STEP_DELAY_RND,
   ED_COUNTER_ID_EXPLOSION_DELAY,
   ED_COUNTER_ID_IGNITION_DELAY,
   ED_COUNTER_ID_GROUP_CONTENT,
@@ -837,10 +859,12 @@ enum
 enum
 {
   ED_SELECTBOX_ID_TIME_OR_STEPS,
+  ED_SELECTBOX_ID_TIME_SCORE_BASE,
   ED_SELECTBOX_ID_GAME_ENGINE_TYPE,
   ED_SELECTBOX_ID_LEVELSET_SAVE_MODE,
   ED_SELECTBOX_ID_WIND_DIRECTION,
   ED_SELECTBOX_ID_PLAYER_SPEED,
+  ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE,
   ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE,
   ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER,
   ED_SELECTBOX_ID_CUSTOM_ACCESS_PROTECTED,
@@ -889,9 +913,9 @@ enum
 // values for textbutton gadgets
 enum
 {
-  ED_TEXTBUTTON_ID_LEVELINFO_LEVEL,
-  ED_TEXTBUTTON_ID_LEVELINFO_LEVELSET,
-  ED_TEXTBUTTON_ID_LEVELINFO_EDITOR,
+  ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL,
+  ED_TEXTBUTTON_ID_LEVELCONFIG_LEVELSET,
+  ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR,
   ED_TEXTBUTTON_ID_PROPERTIES_INFO,
   ED_TEXTBUTTON_ID_PROPERTIES_CONFIG,
   ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_1,
@@ -906,8 +930,8 @@ enum
   ED_NUM_TEXTBUTTONS
 };
 
-#define ED_TAB_BUTTON_ID_LEVELINFO_FIRST ED_TEXTBUTTON_ID_LEVELINFO_LEVEL
-#define ED_TAB_BUTTON_ID_LEVELINFO_LAST  ED_TEXTBUTTON_ID_LEVELINFO_EDITOR
+#define ED_TAB_BUTTON_ID_LEVELCONFIG_FIRST ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL
+#define ED_TAB_BUTTON_ID_LEVELCONFIG_LAST  ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR
 
 #define ED_TAB_BUTTON_ID_PROPERTIES_FIRST ED_TEXTBUTTON_ID_PROPERTIES_INFO
 #define ED_TAB_BUTTON_ID_PROPERTIES_LAST  ED_TEXTBUTTON_ID_PROPERTIES_CHANGE
@@ -933,6 +957,7 @@ enum
 enum
 {
   ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS,
+  ED_CHECKBUTTON_ID_RATE_TIME_OVER_SCORE,
   ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK,
   ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE,
   ED_CHECKBUTTON_ID_RANDOM_RESTRICTED,
@@ -945,12 +970,14 @@ enum
   ED_CHECKBUTTON_ID_USE_TIME_ORB_BUG,
   ED_CHECKBUTTON_ID_USE_LIFE_BUGS,
   ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT,
-  ED_CHECKBUTTON_ID_INITIAL_BALL_STATE,
+  ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE,
   ED_CHECKBUTTON_ID_GROW_INTO_DIGGABLE,
   ED_CHECKBUTTON_ID_SB_FIELDS_NEEDED,
   ED_CHECKBUTTON_ID_SB_OBJECTS_NEEDED,
   ED_CHECKBUTTON_ID_AUTO_EXIT_SOKOBAN,
   ED_CHECKBUTTON_ID_SOLVED_BY_ONE_PLAYER,
+  ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT,
+  ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE,
   ED_CHECKBUTTON_ID_CONTINUOUS_SNAPPING,
   ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD,
   ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD,
@@ -975,6 +1002,8 @@ enum
   ED_CHECKBUTTON_ID_DF_LASER_RED,
   ED_CHECKBUTTON_ID_DF_LASER_GREEN,
   ED_CHECKBUTTON_ID_DF_LASER_BLUE,
+  ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT,
+  ED_CHECKBUTTON_ID_EXPLODE_MM_BALL,
   ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC,
   ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1,
   ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE,
@@ -1005,7 +1034,7 @@ enum
 };
 
 #define ED_CHECKBUTTON_ID_LEVEL_FIRST  ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS
-#define ED_CHECKBUTTON_ID_LEVEL_LAST   ED_CHECKBUTTON_ID_AUTO_COUNT_GEMS
+#define ED_CHECKBUTTON_ID_LEVEL_LAST   ED_CHECKBUTTON_ID_RATE_TIME_OVER_SCORE
 
 #define ED_CHECKBUTTON_ID_LEVELSET_FIRST ED_CHECKBUTTON_ID_USE_LEVELSET_ARTWORK
 #define ED_CHECKBUTTON_ID_LEVELSET_LAST         ED_CHECKBUTTON_ID_COPY_LEVEL_TEMPLATE
@@ -1061,6 +1090,7 @@ enum
   ED_DRAWING_ID_ARTWORK_ELEMENT,
   ED_DRAWING_ID_EXPLOSION_ELEMENT,
   ED_DRAWING_ID_INVENTORY_CONTENT,
+  ED_DRAWING_ID_MM_BALL_CONTENT,
   ED_DRAWING_ID_CUSTOM_GRAPHIC,
   ED_DRAWING_ID_CUSTOM_CONTENT,
   ED_DRAWING_ID_CUSTOM_MOVE_ENTER,
@@ -1096,14 +1126,14 @@ enum
 
 // screens in the level editor
 #define ED_MODE_DRAWING                        0
-#define ED_MODE_INFO                   1
+#define ED_MODE_LEVELCONFIG            1
 #define ED_MODE_PROPERTIES             2
 #define ED_MODE_PALETTE                        3
 
 // sub-screens in the global settings section
-#define ED_MODE_LEVELINFO_LEVEL                ED_TEXTBUTTON_ID_LEVELINFO_LEVEL
-#define ED_MODE_LEVELINFO_LEVELSET     ED_TEXTBUTTON_ID_LEVELINFO_LEVELSET
-#define ED_MODE_LEVELINFO_EDITOR       ED_TEXTBUTTON_ID_LEVELINFO_EDITOR
+#define ED_MODE_LEVELCONFIG_LEVEL      ED_TEXTBUTTON_ID_LEVELCONFIG_LEVEL
+#define ED_MODE_LEVELCONFIG_LEVELSET   ED_TEXTBUTTON_ID_LEVELCONFIG_LEVELSET
+#define ED_MODE_LEVELCONFIG_EDITOR     ED_TEXTBUTTON_ID_LEVELCONFIG_EDITOR
 
 // sub-screens in the element properties section
 #define ED_MODE_PROPERTIES_INFO                ED_TEXTBUTTON_ID_PROPERTIES_INFO
@@ -1244,9 +1274,9 @@ static struct
     "undo/redo last operation",                        'u'
   },
   {
-    IMG_GFX_EDITOR_BUTTON_CONF,                        GADGET_ID_INFO,
+    IMG_GFX_EDITOR_BUTTON_CONF,                        GADGET_ID_CONF,
     &editor.button.conf,                       GD_TYPE_NORMAL_BUTTON,
-    "properties of level",                     'I'
+    "level and editor settings",               'I'
   },
   {
     IMG_GFX_EDITOR_BUTTON_SAVE,                        GADGET_ID_SAVE,
@@ -1406,10 +1436,10 @@ static struct
     GADGET_ID_LEVEL_TIMESCORE_DOWN,    GADGET_ID_LEVEL_TIMESCORE_UP,
     GADGET_ID_LEVEL_TIMESCORE_TEXT,    GADGET_ID_NONE,
     &level.score[SC_TIME_BONUS],
-    "score for each second/step left:",        NULL, NULL
+    "score for time or steps left:",   NULL, NULL
   },
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(12),
+    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(13),
     0,                                 9999,
     GADGET_ID_LEVEL_RANDOM_SEED_DOWN,  GADGET_ID_LEVEL_RANDOM_SEED_UP,
     GADGET_ID_LEVEL_RANDOM_SEED_TEXT,  GADGET_ID_NONE,
@@ -1515,6 +1545,14 @@ static struct
     &level.initial_inventory_size[0],
     NULL,                              NULL, "number of inventory elements"
   },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(3),
+    MIN_ELEMENTS_IN_GROUP,             MAX_MM_BALL_CONTENTS,
+    GADGET_ID_MM_BALL_CONTENT_DOWN,    GADGET_ID_MM_BALL_CONTENT_UP,
+    GADGET_ID_MM_BALL_CONTENT_TEXT,    GADGET_ID_NONE,
+    &level.num_mm_ball_contents,
+    NULL,                              NULL, "number of content elements"
+  },
 
   // ---------- element settings: configure 1 (custom elements) ---------------
 
@@ -1602,7 +1640,23 @@ static struct
     NULL,                              "+random", NULL
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(12),
+    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(6),
+    0,                                 999,
+    GADGET_ID_STEP_DELAY_FIX_DOWN,     GADGET_ID_STEP_DELAY_FIX_UP,
+    GADGET_ID_STEP_DELAY_FIX_TEXT,     GADGET_ID_NONE,
+    &custom_element.step_delay_fixed,
+    NULL,                              "step delay", NULL
+  },
+  {
+    -1,                                        ED_ELEMENT_SETTINGS_YPOS(6),
+    0,                                 999,
+    GADGET_ID_STEP_DELAY_RND_DOWN,     GADGET_ID_STEP_DELAY_RND_UP,
+    GADGET_ID_STEP_DELAY_RND_TEXT,     GADGET_ID_STEP_DELAY_FIX_UP,
+    &custom_element.step_delay_random,
+    NULL,                              "+random", NULL
+  },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(13),
     0,                                 999,
     GADGET_ID_EXPLOSION_DELAY_DOWN,    GADGET_ID_EXPLOSION_DELAY_UP,
     GADGET_ID_EXPLOSION_DELAY_TEXT,    GADGET_ID_NONE,
@@ -1610,7 +1664,7 @@ static struct
     NULL,                              "explosion delay", NULL
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(13),
+    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(14),
     0,                                 999,
     GADGET_ID_IGNITION_DELAY_DOWN,     GADGET_ID_IGNITION_DELAY_UP,
     GADGET_ID_IGNITION_DELAY_TEXT,     GADGET_ID_NONE,
@@ -1709,7 +1763,7 @@ static struct
   int gadget_id;
   int xsize, ysize;
   char *value;
-  char *text_above, *infotext;
+  char *text_above, *text_above_cropped, *infotext;
 } textarea_info[ED_NUM_TEXTAREAS] =
 {
   {
@@ -1717,7 +1771,7 @@ static struct
     GADGET_ID_ENVELOPE_INFO,
     MAX_ENVELOPE_XSIZE, MAX_ENVELOPE_YSIZE,
     NULL,
-    "Envelope Content:", "Envelope Content"
+    "Envelope Content:", "Envelope Content (cropped):", "Envelope Content"
   }
 };
 
@@ -1729,6 +1783,14 @@ static struct ValueTextInfo options_time_or_steps[] =
   { -1,                                NULL                            }
 };
 
+static struct ValueTextInfo options_time_score_base[] =
+{
+  { 1,                         "per second/step"               },
+  { 10,                                "per 10 seconds/steps"          },
+
+  { -1,                                NULL                            }
+};
+
 static struct ValueTextInfo options_game_engine_type[] =
 {
   { GAME_ENGINE_TYPE_RND,      "Rocks'n'Diamonds"              },
@@ -1963,6 +2025,13 @@ static struct ValueTextInfo options_change_direct_action[] =
 #endif
   { CE_VALUE_GETS_ZERO,                "CE value gets 0"               },
   { CE_SCORE_GETS_ZERO,                "CE score gets 0"               },
+  { CE_UNDEFINED,              " "                             },
+  { CE_HEADLINE_SPECIAL_EVENTS,        "[mouse events]"                },
+  { CE_CLICKED_BY_MOUSE,       "clicked by mouse"              },
+  { CE_PRESSED_BY_MOUSE,       "pressed by mouse"              },
+  { CE_UNDEFINED,              " "                             },
+  { CE_HEADLINE_SPECIAL_EVENTS,        "[static states]"               },
+  { CE_NEXT_TO_PLAYER,         "next to player"                },
 
   { -1,                                NULL                            }
 };
@@ -1992,6 +2061,14 @@ static struct ValueTextInfo options_change_other_action[] =
   { CE_SCORE_CHANGES_OF_X,     "CE score changes of"           },
   { CE_VALUE_GETS_ZERO_OF_X,   "CE value gets 0 of"            },
   { CE_SCORE_GETS_ZERO_OF_X,   "CE score gets 0 of"            },
+  { CE_UNDEFINED,              " "                             },
+  { CE_HEADLINE_SPECIAL_EVENTS,        "[mouse events]"                },
+  { CE_MOUSE_CLICKED_ON_X,     "mouse clicked on"              },
+  { CE_MOUSE_PRESSED_ON_X,     "mouse pressed on"              },
+  { CE_UNDEFINED,              " "                             },
+  { CE_HEADLINE_SPECIAL_EVENTS,        "[static states]"               },
+  { CE_PLAYER_NEXT_TO_X,       "player next to"                },
+  { CE_NEXT_TO_X,              "next to"                       },
 
   { -1,                                NULL                            }
 };
@@ -2022,38 +2099,38 @@ static struct ValueTextInfo options_change_trigger_player[] =
 
 static struct ValueTextInfo options_change_trigger_page[] =
 {
-  { (1 << 0),                  "1"                             },
-  { (1 << 1),                  "2"                             },
-  { (1 << 2),                  "3"                             },
-  { (1 << 3),                  "4"                             },
-  { (1 << 4),                  "5"                             },
-  { (1 << 5),                  "6"                             },
-  { (1 << 6),                  "7"                             },
-  { (1 << 7),                  "8"                             },
-  { (1 << 8),                  "9"                             },
-  { (1 << 9),                  "10"                            },
-  { (1 << 10),                 "11"                            },
-  { (1 << 11),                 "12"                            },
-  { (1 << 12),                 "13"                            },
-  { (1 << 13),                 "14"                            },
-  { (1 << 14),                 "15"                            },
-  { (1 << 15),                 "16"                            },
-  { (1 << 16),                 "17"                            },
-  { (1 << 17),                 "18"                            },
-  { (1 << 18),                 "19"                            },
-  { (1 << 19),                 "20"                            },
-  { (1 << 20),                 "21"                            },
-  { (1 << 21),                 "22"                            },
-  { (1 << 22),                 "23"                            },
-  { (1 << 23),                 "24"                            },
-  { (1 << 24),                 "25"                            },
-  { (1 << 25),                 "26"                            },
-  { (1 << 26),                 "27"                            },
-  { (1 << 27),                 "28"                            },
-  { (1 << 28),                 "29"                            },
-  { (1 << 29),                 "30"                            },
-  { (1 << 30),                 "31"                            },
-  { (1 << 31),                 "32"                            },
+  { (1u << 0),                 "1"                             },
+  { (1u << 1),                 "2"                             },
+  { (1u << 2),                 "3"                             },
+  { (1u << 3),                 "4"                             },
+  { (1u << 4),                 "5"                             },
+  { (1u << 5),                 "6"                             },
+  { (1u << 6),                 "7"                             },
+  { (1u << 7),                 "8"                             },
+  { (1u << 8),                 "9"                             },
+  { (1u << 9),                 "10"                            },
+  { (1u << 10),                        "11"                            },
+  { (1u << 11),                        "12"                            },
+  { (1u << 12),                        "13"                            },
+  { (1u << 13),                        "14"                            },
+  { (1u << 14),                        "15"                            },
+  { (1u << 15),                        "16"                            },
+  { (1u << 16),                        "17"                            },
+  { (1u << 17),                        "18"                            },
+  { (1u << 18),                        "19"                            },
+  { (1u << 19),                        "20"                            },
+  { (1u << 20),                        "21"                            },
+  { (1u << 21),                        "22"                            },
+  { (1u << 22),                        "23"                            },
+  { (1u << 23),                        "24"                            },
+  { (1u << 24),                        "25"                            },
+  { (1u << 25),                        "26"                            },
+  { (1u << 26),                        "27"                            },
+  { (1u << 27),                        "28"                            },
+  { (1u << 28),                        "29"                            },
+  { (1u << 29),                        "30"                            },
+  { (1u << 30),                        "31"                            },
+  { (1u << 31),                        "32"                            },
   { CH_PAGE_ANY,               "any"                           },
 
   { -1,                                NULL                            }
@@ -2082,10 +2159,11 @@ static struct ValueTextInfo options_action_type[] =
   { CA_SET_LEVEL_SCORE,                "set score"                     },
   { CA_SET_LEVEL_GEMS,         "set gems"                      },
   { CA_SET_LEVEL_WIND,         "set wind dir."                 },
-  { CA_SET_LEVEL_RANDOM_SEED,  "set rand. seed"                },
+  { CA_SET_LEVEL_RANDOM_SEED,  "set random seed"               },
   { CA_UNDEFINED,              " "                             },
   { CA_HEADLINE_PLAYER_ACTIONS,        "[player]"                      },
   { CA_MOVE_PLAYER,            "move player"                   },
+  { CA_MOVE_PLAYER_NEW,                "move player new"               },
   { CA_EXIT_PLAYER,            "exit player"                   },
   { CA_KILL_PLAYER,            "kill player"                   },
   { CA_SET_PLAYER_KEYS,                "set keys"                      },
@@ -2387,6 +2465,7 @@ static struct ValueTextInfo options_group_choice_mode[] =
   { ANIM_LINEAR,               "linear"                        },
   { ANIM_PINGPONG,             "pingpong"                      },
   { ANIM_PINGPONG2,            "pingpong 2"                    },
+  { ANIM_LEVEL_NR,             "level number"                  },
 
   { -1,                                NULL                            }
 };
@@ -2411,6 +2490,7 @@ action_arg_options[] =
   { CA_EXIT_PLAYER,            0,      options_action_arg_player,      },
   { CA_KILL_PLAYER,            0,      options_action_arg_player,      },
   { CA_MOVE_PLAYER,            0,      options_action_arg_direction,   },
+  { CA_MOVE_PLAYER_NEW,                0,      options_action_arg_direction,   },
   { CA_RESTART_LEVEL,          0,      options_action_arg_none,        },
   { CA_SHOW_ENVELOPE,          0,      options_action_arg_envelope,    },
   { CA_SET_LEVEL_TIME,         3,      options_action_arg_number,      },
@@ -2454,7 +2534,15 @@ static struct
     NULL, NULL, "(0 => no limit)",     "time or step limit"
   },
   {
-    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(11),
+    -1,                                        ED_LEVEL_SETTINGS_YPOS(10),
+    GADGET_ID_TIME_SCORE_BASE,         GADGET_ID_LEVEL_TIMESCORE_UP,
+    -1,
+    options_time_score_base,
+    &level.time_score_base,
+    NULL, NULL, NULL,                  "time score for 1 or 10 seconds/steps"
+  },
+  {
+    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(12),
     GADGET_ID_GAME_ENGINE_TYPE,                GADGET_ID_NONE,
     -1,
     options_game_engine_type,
@@ -2488,6 +2576,14 @@ static struct
     &level.initial_player_stepsize[0],
     NULL, "initial player speed:", NULL,       "initial player speed"
   },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(4),
+    GADGET_ID_MM_BALL_CHOICE_MODE,     GADGET_ID_NONE,
+    -1,
+    options_group_choice_mode,
+    &level.mm_ball_choice_mode,
+    NULL, "choice type:", NULL,                "type of content choice"
+  },
 
   // ---------- element settings: configure 1 (custom elements) ---------------
 
@@ -2570,7 +2666,7 @@ static struct
     NULL, "            can", ":",      "leave behind or change element"
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(7),
+    -1,                                        ED_ELEMENT_SETTINGS_YPOS(8),
     GADGET_ID_CUSTOM_SMASH_TARGETS,    GADGET_ID_CUSTOM_CAN_SMASH,
     -1,
     options_smash_targets,
@@ -2578,7 +2674,7 @@ static struct
     NULL, "can smash", NULL,           "elements that can be smashed"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(8),
+    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(9),
     GADGET_ID_CUSTOM_SLIPPERY_TYPE,    GADGET_ID_NONE,
     -1,
     options_slippery_type,
@@ -2586,7 +2682,7 @@ static struct
     NULL, "slippery", NULL,            "where other elements fall down"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(9),
+    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(10),
     GADGET_ID_CUSTOM_DEADLINESS,       GADGET_ID_NONE,
     -1,
     options_deadliness,
@@ -2594,7 +2690,7 @@ static struct
     NULL, "deadly when", NULL,         "deadliness of element"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(10),
+    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(11),
     GADGET_ID_CUSTOM_EXPLOSION_TYPE,   GADGET_ID_NONE,
     -1,
     options_explosion_type,
@@ -2663,7 +2759,7 @@ static struct
   {
     ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(13),
     GADGET_ID_ACTION_TYPE,             GADGET_ID_NONE,
-    -1,
+    15,
     options_action_type,
     &custom_element_change.action_type,
     NULL, NULL, NULL,                  "action on specified condition"
@@ -2719,21 +2815,21 @@ static struct
 
   {
     ED_LEVEL_TABS_XPOS(0),             ED_LEVEL_TABS_YPOS(0),
-    GADGET_ID_LEVELINFO_LEVEL,         GADGET_ID_NONE,
+    GADGET_ID_LEVELCONFIG_LEVEL,       GADGET_ID_NONE,
     8,                                 "Level",
-    NULL, NULL, NULL,                  "Configure level properties"
+    NULL, NULL, NULL,                  "Configure level settings"
   },
   {
     -1,                                        -1,
-    GADGET_ID_LEVELINFO_LEVELSET,      GADGET_ID_LEVELINFO_LEVEL,
+    GADGET_ID_LEVELCONFIG_LEVELSET,    GADGET_ID_LEVELCONFIG_LEVEL,
     8,                                 "Levelset",
     NULL, NULL, NULL,                  "Update this or create new level set"
   },
   {
     -1,                                        -1,
-    GADGET_ID_LEVELINFO_EDITOR,                GADGET_ID_LEVELINFO_LEVELSET,
+    GADGET_ID_LEVELCONFIG_EDITOR,      GADGET_ID_LEVELCONFIG_LEVELSET,
     8,                                 "Editor",
-    NULL, NULL, NULL,                  "Configure editor properties"
+    NULL, NULL, NULL,                  "Configure editor settings"
   },
 
   // ---------- element settings (tabs) ---------------------------------------
@@ -2969,6 +3065,13 @@ static struct
     NULL, NULL,
     "automatically count gems needed", "set counter to number of gems"
   },
+  {
+    ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(11),
+    GADGET_ID_RATE_TIME_OVER_SCORE,    GADGET_ID_NONE,
+    &level.rate_time_over_score,
+    NULL, NULL,
+    "rate time/steps used over score", "sort high scores by playing time/steps"
+  },
   {
     ED_LEVEL_SETTINGS_XPOS(0),         ED_LEVEL_SETTINGS_YPOS(7),
     GADGET_ID_USE_LEVELSET_ARTWORK,    GADGET_ID_NONE,
@@ -3058,8 +3161,8 @@ static struct
   },
   {
     ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(1),
-    GADGET_ID_INITIAL_BALL_STATE,      GADGET_ID_NONE,
-    &level.ball_state_initial,
+    GADGET_ID_INITIAL_BALL_ACTIVE,     GADGET_ID_NONE,
+    &level.ball_active_initial,
     NULL, NULL,
     "magic ball initially activated",  "activate magic ball after level start"
   },
@@ -3098,6 +3201,20 @@ static struct
     NULL, NULL,
     "only one player must enter exit", "level solved by first player in exit"
   },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(3),
+    GADGET_ID_FINISH_DIG_COLLECT,      GADGET_ID_NONE,
+    &level.finish_dig_collect,
+    NULL, NULL,
+    "CE action on finished dig/collect", "only finished dig/collect triggers CE"
+  },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(4),
+    GADGET_ID_KEEP_WALKABLE_CE,                GADGET_ID_NONE,
+    &level.keep_walkable_ce,
+    NULL, NULL,
+    "keep walkable CE changed to player", "keep CE changing to player if walkable"
+  },
   {
     ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(9),
     GADGET_ID_CONTINUOUS_SNAPPING,     GADGET_ID_NONE,
@@ -3266,6 +3383,20 @@ static struct
     NULL, NULL,
     "blue",                            "use blue color components in laser"
   },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(5),
+    GADGET_ID_ROTATE_MM_BALL_CONTENT,  GADGET_ID_NONE,
+    &level.rotate_mm_ball_content,
+    NULL, NULL,
+    "randomly rotate created content", "randomly rotate newly created content"
+  },
+  {
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(6),
+    GADGET_ID_EXPLODE_MM_BALL,         GADGET_ID_NONE,
+    &level.explode_mm_ball,
+    NULL, NULL,
+    "explode ball instead of melting", "use explosion to release ball content"
+  },
 
   // ---------- element settings: configure 1 (custom elements) ---------------
 
@@ -3329,56 +3460,56 @@ static struct
     NULL,                              "element can move with some pattern"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(7),
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(8),
     GADGET_ID_CUSTOM_CAN_FALL,         GADGET_ID_NONE,
     &custom_element_properties[EP_CAN_FALL],
     NULL, NULL,
     "can fall",                                "element can fall down"
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(7),
+    -1,                                        ED_ELEMENT_SETTINGS_YPOS(8),
     GADGET_ID_CUSTOM_CAN_SMASH,                GADGET_ID_CUSTOM_CAN_FALL,
     &custom_element_properties[EP_CAN_SMASH],
     NULL, " ",
     NULL,                              "element can smash other elements"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(8),
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(9),
     GADGET_ID_CUSTOM_SLIPPERY,         GADGET_ID_NONE,
     &custom_element_properties[EP_SLIPPERY],
     NULL, NULL,
     NULL,                              "other elements can fall down from it"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(9),
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(10),
     GADGET_ID_CUSTOM_DEADLY,           GADGET_ID_NONE,
     &custom_element_properties[EP_DEADLY],
     NULL, NULL,
     NULL,                              "element can kill the player"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(10),
+    ED_ELEMENT_SETTINGS_XPOS(0),       ED_ELEMENT_SETTINGS_YPOS(11),
     GADGET_ID_CUSTOM_CAN_EXPLODE,      GADGET_ID_NONE,
     &custom_element_properties[EP_CAN_EXPLODE],
     NULL, NULL,
     NULL,                              "element can explode"
   },
   {
-    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(11),
+    ED_ELEMENT_SETTINGS_XPOS(1),       ED_ELEMENT_SETTINGS_YPOS(12),
     GADGET_ID_CUSTOM_EXPLODE_FIRE,     GADGET_ID_NONE,
     &custom_element_properties[EP_EXPLODES_BY_FIRE],
     NULL, NULL,
     "by fire",                         "element can explode by fire/explosion"
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(11),
+    -1,                                        ED_ELEMENT_SETTINGS_YPOS(12),
     GADGET_ID_CUSTOM_EXPLODE_SMASH,    GADGET_ID_CUSTOM_EXPLODE_FIRE,
     &custom_element_properties[EP_EXPLODES_SMASHED],
     NULL, " ",
     "smashed",                         "element can explode when smashed"
   },
   {
-    -1,                                        ED_ELEMENT_SETTINGS_YPOS(11),
+    -1,                                        ED_ELEMENT_SETTINGS_YPOS(12),
     GADGET_ID_CUSTOM_EXPLODE_IMPACT,   GADGET_ID_CUSTOM_EXPLODE_SMASH,
     &custom_element_properties[EP_EXPLODES_IMPACT],
     NULL, " ",
@@ -3460,7 +3591,7 @@ static struct
   int gadget_id_align;
   int *value;
   int area_xsize, area_ysize;
-  char *text_left, *text_right, *text_below, *infotext;
+  char *text_left, *text_right, *text_above, *text_below, *infotext;
 } drawingarea_info[ED_NUM_DRAWING_AREAS] =
 {
   // ---------- level playfield content ---------------------------------------
@@ -3471,7 +3602,7 @@ static struct
     GADGET_ID_DRAWING_LEVEL,           GADGET_ID_NONE,
     NULL,
     -1, -1,    // these values are not constant, but can change at runtime
-    NULL, NULL, NULL,                  NULL
+    NULL, NULL, NULL, NULL,            NULL
   },
 
   // ---------- yam yam content -----------------------------------------------
@@ -3481,56 +3612,56 @@ static struct
     ED_AREA_YAMYAM_CONTENT_XOFF(0),    ED_AREA_YAMYAM_CONTENT_YOFF(0),
     GADGET_ID_YAMYAM_CONTENT_0,                GADGET_ID_NONE,
     &level.yamyam_content[0].e[0][0],  3, 3,
-    NULL, NULL, "1",                   NULL
+    NULL, NULL, NULL, "1",             NULL
   },
   {
     ED_AREA_YAMYAM_CONTENT_XPOS,       ED_AREA_YAMYAM_CONTENT_YPOS,
     ED_AREA_YAMYAM_CONTENT_XOFF(1),    ED_AREA_YAMYAM_CONTENT_YOFF(1),
     GADGET_ID_YAMYAM_CONTENT_1,                GADGET_ID_NONE,
     &level.yamyam_content[1].e[0][0],  3, 3,
-    NULL, NULL, "2",                   NULL
+    NULL, NULL, NULL, "2",             NULL
   },
   {
     ED_AREA_YAMYAM_CONTENT_XPOS,       ED_AREA_YAMYAM_CONTENT_YPOS,
     ED_AREA_YAMYAM_CONTENT_XOFF(2),    ED_AREA_YAMYAM_CONTENT_YOFF(2),
     GADGET_ID_YAMYAM_CONTENT_2,                GADGET_ID_NONE,
     &level.yamyam_content[2].e[0][0],  3, 3,
-    NULL, NULL, "3",                   NULL
+    NULL, NULL, NULL, "3",             NULL
   },
   {
     ED_AREA_YAMYAM_CONTENT_XPOS,       ED_AREA_YAMYAM_CONTENT_YPOS,
     ED_AREA_YAMYAM_CONTENT_XOFF(3),    ED_AREA_YAMYAM_CONTENT_YOFF(3),
     GADGET_ID_YAMYAM_CONTENT_3,                GADGET_ID_NONE,
     &level.yamyam_content[3].e[0][0],  3, 3,
-    NULL, NULL, "4",                   NULL
+    NULL, NULL, NULL, "4",             NULL
   },
   {
     ED_AREA_YAMYAM_CONTENT_XPOS,       ED_AREA_YAMYAM_CONTENT_YPOS,
     ED_AREA_YAMYAM_CONTENT_XOFF(4),    ED_AREA_YAMYAM_CONTENT_YOFF(4),
     GADGET_ID_YAMYAM_CONTENT_4,                GADGET_ID_NONE,
     &level.yamyam_content[4].e[0][0],  3, 3,
-    NULL, NULL, "5",                   NULL
+    NULL, NULL, NULL, "5",             NULL
   },
   {
     ED_AREA_YAMYAM_CONTENT_XPOS,       ED_AREA_YAMYAM_CONTENT_YPOS,
     ED_AREA_YAMYAM_CONTENT_XOFF(5),    ED_AREA_YAMYAM_CONTENT_YOFF(5),
     GADGET_ID_YAMYAM_CONTENT_5,                GADGET_ID_NONE,
     &level.yamyam_content[5].e[0][0],  3, 3,
-    NULL, NULL, "6",                   NULL
+    NULL, NULL, NULL, "6",             NULL
   },
   {
     ED_AREA_YAMYAM_CONTENT_XPOS,       ED_AREA_YAMYAM_CONTENT_YPOS,
     ED_AREA_YAMYAM_CONTENT_XOFF(6),    ED_AREA_YAMYAM_CONTENT_YOFF(6),
     GADGET_ID_YAMYAM_CONTENT_6,                GADGET_ID_NONE,
     &level.yamyam_content[6].e[0][0],  3, 3,
-    NULL, NULL, "7",                   NULL
+    NULL, NULL, NULL, "7",             NULL
   },
   {
     ED_AREA_YAMYAM_CONTENT_XPOS,       ED_AREA_YAMYAM_CONTENT_YPOS,
     ED_AREA_YAMYAM_CONTENT_XOFF(7),    ED_AREA_YAMYAM_CONTENT_YOFF(7),
     GADGET_ID_YAMYAM_CONTENT_7,                GADGET_ID_NONE,
     &level.yamyam_content[7].e[0][0],  3, 3,
-    NULL, NULL, "8",                   NULL
+    NULL, NULL, NULL, "8",             NULL
   },
 
   // ---------- magic ball content --------------------------------------------
@@ -3540,66 +3671,66 @@ static struct
     ED_AREA_MAGIC_BALL_CONTENT_XOFF(0),        ED_AREA_MAGIC_BALL_CONTENT_YOFF(0),
     GADGET_ID_MAGIC_BALL_CONTENT_0,    GADGET_ID_NONE,
     &level.ball_content[0].e[0][0],    3, 3,
-    NULL, NULL, "1",                   NULL
+    NULL, NULL, NULL, "1",             NULL
   },
   {
     ED_AREA_MAGIC_BALL_CONTENT_XPOS,   ED_AREA_MAGIC_BALL_CONTENT_YPOS,
     ED_AREA_MAGIC_BALL_CONTENT_XOFF(1),        ED_AREA_MAGIC_BALL_CONTENT_YOFF(1),
     GADGET_ID_MAGIC_BALL_CONTENT_1,    GADGET_ID_NONE,
     &level.ball_content[1].e[0][0],    3, 3,
-    NULL, NULL, "2",                   NULL
+    NULL, NULL, NULL, "2",             NULL
   },
   {
     ED_AREA_MAGIC_BALL_CONTENT_XPOS,   ED_AREA_MAGIC_BALL_CONTENT_YPOS,
     ED_AREA_MAGIC_BALL_CONTENT_XOFF(2),        ED_AREA_MAGIC_BALL_CONTENT_YOFF(2),
     GADGET_ID_MAGIC_BALL_CONTENT_2,    GADGET_ID_NONE,
     &level.ball_content[2].e[0][0],    3, 3,
-    NULL, NULL, "3",                   NULL
+    NULL, NULL, NULL, "3",             NULL
   },
   {
     ED_AREA_MAGIC_BALL_CONTENT_XPOS,   ED_AREA_MAGIC_BALL_CONTENT_YPOS,
     ED_AREA_MAGIC_BALL_CONTENT_XOFF(3),        ED_AREA_MAGIC_BALL_CONTENT_YOFF(3),
     GADGET_ID_MAGIC_BALL_CONTENT_3,    GADGET_ID_NONE,
     &level.ball_content[3].e[0][0],    3, 3,
-    NULL, NULL, "4",                   NULL
+    NULL, NULL, NULL, "4",             NULL
   },
   {
     ED_AREA_MAGIC_BALL_CONTENT_XPOS,   ED_AREA_MAGIC_BALL_CONTENT_YPOS,
     ED_AREA_MAGIC_BALL_CONTENT_XOFF(4),        ED_AREA_MAGIC_BALL_CONTENT_YOFF(4),
     GADGET_ID_MAGIC_BALL_CONTENT_4,    GADGET_ID_NONE,
     &level.ball_content[4].e[0][0],    3, 3,
-    NULL, NULL, "5",                   NULL
+    NULL, NULL, NULL, "5",             NULL
   },
   {
     ED_AREA_MAGIC_BALL_CONTENT_XPOS,   ED_AREA_MAGIC_BALL_CONTENT_YPOS,
     ED_AREA_MAGIC_BALL_CONTENT_XOFF(5),        ED_AREA_MAGIC_BALL_CONTENT_YOFF(5),
     GADGET_ID_MAGIC_BALL_CONTENT_5,    GADGET_ID_NONE,
     &level.ball_content[5].e[0][0],    3, 3,
-    NULL, NULL, "6",                   NULL
+    NULL, NULL, NULL, "6",             NULL
   },
   {
     ED_AREA_MAGIC_BALL_CONTENT_XPOS,   ED_AREA_MAGIC_BALL_CONTENT_YPOS,
     ED_AREA_MAGIC_BALL_CONTENT_XOFF(6),        ED_AREA_MAGIC_BALL_CONTENT_YOFF(6),
     GADGET_ID_MAGIC_BALL_CONTENT_6,    GADGET_ID_NONE,
     &level.ball_content[6].e[0][0],    3, 3,
-    NULL, NULL, "7",                   NULL
+    NULL, NULL, NULL, "7",             NULL
   },
   {
     ED_AREA_MAGIC_BALL_CONTENT_XPOS,   ED_AREA_MAGIC_BALL_CONTENT_YPOS,
     ED_AREA_MAGIC_BALL_CONTENT_XOFF(7),        ED_AREA_MAGIC_BALL_CONTENT_YOFF(7),
     GADGET_ID_MAGIC_BALL_CONTENT_7,    GADGET_ID_NONE,
     &level.ball_content[7].e[0][0],    3, 3,
-    NULL, NULL, "8",                   NULL
+    NULL, NULL, NULL, "8",             NULL
   },
 
   // ---------- android content -----------------------------------------------
 
   {
-    ED_AREA_1X1_SETTINGS_XPOS(0),      ED_AREA_1X1_SETTINGS_YPOS(5),
+    ED_AREA_1X1_SETTINGS_XPOS(0),      ED_AREA_1X1_SETTINGS_YPOS(6),
     ED_AREA_1X1_SETTINGS_XOFF,         ED_AREA_1X1_SETTINGS_YOFF,
     GADGET_ID_ANDROID_CONTENT,         GADGET_ID_NONE,
     &level.android_clone_element[0],   MAX_ANDROID_ELEMENTS, 1,
-    "elements:", NULL, NULL,           "elements android can clone"
+    NULL, NULL, "elements:", NULL,     "elements android can clone"
   },
 
   // ---------- amoeba content ------------------------------------------------
@@ -3609,7 +3740,7 @@ static struct
     ED_AREA_1X1_SETTINGS_XOFF,         ED_AREA_1X1_SETTINGS_YOFF,
     GADGET_ID_AMOEBA_CONTENT,          GADGET_ID_NONE,
     &level.amoeba_content,             1, 1,
-    "content:", NULL, NULL,            "amoeba content"
+    "content:", NULL, NULL, NULL,      "amoeba content"
   },
 
   // ---------- level start element -------------------------------------------
@@ -3619,7 +3750,7 @@ static struct
     0,                                 ED_AREA_1X1_SETTINGS_YOFF,
     GADGET_ID_START_ELEMENT,           GADGET_ID_USE_START_ELEMENT,
     &level.start_element[0],           1, 1,
-    NULL, NULL, NULL,                  "level start element"
+    NULL, NULL, NULL, NULL,            "level start element"
   },
 
   // ---------- player artwork element ----------------------------------------
@@ -3629,7 +3760,7 @@ static struct
     0,                                 ED_AREA_1X1_SETTINGS_YOFF,
     GADGET_ID_ARTWORK_ELEMENT,         GADGET_ID_USE_ARTWORK_ELEMENT,
     &level.artwork_element[0],         1, 1,
-    NULL, NULL, NULL,                  "element for player artwork"
+    NULL, NULL, NULL, NULL,            "element for player artwork"
   },
 
   // ---------- player explosion element --------------------------------------
@@ -3639,7 +3770,7 @@ static struct
     0,                                 ED_AREA_1X1_SETTINGS_YOFF,
     GADGET_ID_EXPLOSION_ELEMENT,       GADGET_ID_USE_EXPLOSION_ELEMENT,
     &level.explosion_element[0],       1, 1,
-    NULL, NULL, NULL,                  "element for player explosion"
+    NULL, NULL, NULL, NULL,            "element for player explosion"
   },
 
   // ---------- player initial inventory --------------------------------------
@@ -3649,7 +3780,17 @@ static struct
     0,                                 ED_AREA_1X1_SETTINGS_YOFF,
     GADGET_ID_INVENTORY_CONTENT,       GADGET_ID_USE_INITIAL_INVENTORY,
     &level.initial_inventory_content[0][0], MAX_INITIAL_INVENTORY_SIZE, 1,
-    NULL, NULL, NULL,                  "content for initial inventory"
+    NULL, NULL, NULL, NULL,            "content for initial inventory"
+  },
+
+  // ---------- gray ball content -----------------------------------------
+
+  {
+    ED_AREA_1X1_SETTINGS_XPOS(0),      ED_AREA_1X1_SETTINGS_YPOS(2),
+    ED_AREA_1X1_SETTINGS_XOFF,         ED_AREA_1X1_SETTINGS_YOFF,
+    GADGET_ID_MM_BALL_CONTENT,         GADGET_ID_NONE,
+    &level.mm_ball_content[0],         MAX_MM_BALL_CONTENTS, 1,
+    "content:", NULL, NULL, NULL,      "content for gray ball"
   },
 
   // ---------- element settings: configure 1 (custom elements) ---------------
@@ -3660,8 +3801,8 @@ static struct
     -1,                                        ED_AREA_1X1_SETTINGS_YPOS(1),
     0,                                 ED_AREA_1X1_SETTINGS_YOFF,
     GADGET_ID_CUSTOM_GRAPHIC,          GADGET_ID_CUSTOM_USE_GRAPHIC,
-    &custom_element.gfx_element_initial,1, 1,
-    NULL, NULL, NULL,                  "custom graphic element"
+    &custom_element.gfx_element_initial, 1, 1,
+    NULL, NULL, NULL, NULL,            "custom graphic element"
   },
 
   // ---------- element settings: configure 2 (custom elements) ---------------
@@ -3669,11 +3810,11 @@ static struct
   // ---------- custom content (when exploding) -------------------------------
 
   {
-    -1,                                        ED_AREA_3X3_SETTINGS_YPOS(10),
+    -1,                                        ED_AREA_3X3_SETTINGS_YPOS(11),
     0,                                 ED_AREA_3X3_SETTINGS_YOFF,
     GADGET_ID_CUSTOM_CONTENT,          GADGET_ID_NONE, // align three rows
     &custom_element.content.e[0][0],   3, 3,
-    "content:", NULL, NULL,            NULL
+    "content:", NULL, NULL, NULL,      NULL
   },
 
   // ---------- custom enter and leave element (when moving) ------------------
@@ -3683,14 +3824,14 @@ static struct
     ED_AREA_1X1_SETTINGS_XOFF,         ED_AREA_1X1_SETTINGS_YOFF,
     GADGET_ID_CUSTOM_MOVE_ENTER,       GADGET_ID_NONE,
     &custom_element.move_enter_element,        1, 1,
-    "can dig:", " ", NULL,             "element that can be digged/collected"
+    "can dig:", " ", NULL, NULL,       "element that can be digged/collected"
   },
   {
     -1,                                        ED_AREA_1X1_SETTINGS_YPOS(3),
     0,                                 ED_AREA_1X1_SETTINGS_YOFF,
     GADGET_ID_CUSTOM_MOVE_LEAVE,       GADGET_ID_CUSTOM_MOVE_LEAVE_TYPE,
     &custom_element.move_leave_element,        1, 1,
-    NULL, NULL, NULL,                  "element that will be left behind"
+    NULL, NULL, NULL, NULL,            "element that will be left behind"
   },
 
   // ---------- element settings: advanced (custom elements) ------------------
@@ -3702,7 +3843,7 @@ static struct
     0,                                 ED_AREA_1X1_SETTINGS_YOFF,
     GADGET_ID_CUSTOM_CHANGE_TARGET,    GADGET_ID_CUSTOM_CAN_CHANGE,
     &custom_element_change.target_element, 1, 1,
-    NULL, "after/when:", NULL,         "new target element after change"
+    NULL, "after/when:", NULL, NULL,   "new target element after change"
   },
 
   // ---------- custom change content (extended change target) ----------------
@@ -3712,7 +3853,7 @@ static struct
     0,                                 ED_AREA_3X3_SETTINGS_YOFF,
     GADGET_ID_CUSTOM_CHANGE_CONTENT,   GADGET_ID_NONE, // align three rows
     &custom_element_change.target_content.e[0][0], 3, 3,
-    NULL, NULL, NULL,                  "new extended elements after change"
+    NULL, NULL, NULL, NULL,            "new extended elements after change"
   },
 
   // ---------- custom change trigger (element causing change) ----------------
@@ -3722,7 +3863,7 @@ static struct
     0,                                 ED_AREA_1X1_SETTINGS_YOFF,
     GADGET_ID_CUSTOM_CHANGE_TRIGGER,   GADGET_ID_CHANGE_OTHER_ACTION,
     &custom_element_change.initial_trigger_element, 1, 1,
-    NULL, NULL, NULL,                  "other element triggering change"
+    NULL, NULL, NULL, NULL,            "other element triggering change"
   },
 
   // ---------- custom change action (element used for action) ----------------
@@ -3732,7 +3873,7 @@ static struct
     0,                                 ED_AREA_1X1_SETTINGS_YOFF,
     GADGET_ID_CUSTOM_CHANGE_ACTION,    GADGET_ID_ACTION_ARG,
     &custom_element_change.action_element, 1, 1,
-    NULL, NULL, NULL,                  "element used as action parameter"
+    NULL, NULL, NULL, NULL,            "element used as action parameter"
   },
 
   // ---------- group element content -----------------------------------------
@@ -3742,7 +3883,7 @@ static struct
     ED_AREA_1X1_SETTINGS_XOFF,         ED_AREA_1X1_SETTINGS_YOFF,
     GADGET_ID_GROUP_CONTENT,           GADGET_ID_NONE,
     &group_element_info.element[0],    MAX_ELEMENTS_IN_GROUP, 1,
-    "content:", NULL, NULL,            NULL
+    "content:", NULL, NULL, NULL,      NULL
   },
 
   // ---------- random background (for random painting) -----------------------
@@ -3752,7 +3893,7 @@ static struct
     0,                                 ED_AREA_1X1_LSETTINGS_YOFF,
     GADGET_ID_RANDOM_BACKGROUND,       GADGET_ID_RANDOM_RESTRICTED,
     &random_placement_background_element, 1, 1,
-    NULL, NULL, NULL,                  "random placement background"
+    NULL, NULL, NULL, NULL,            "random placement background"
   },
 };
 
@@ -3774,7 +3915,7 @@ static int level_xpos = -1, level_ypos = -1;
 static int ed_tilesize = DEFAULT_EDITOR_TILESIZE;
 static int ed_tilesize_default = DEFAULT_EDITOR_TILESIZE;
 
-#define IN_ED_FIELD(x,y)       IN_FIELD(x, y, ed_fieldx, ed_fieldy)
+#define IN_ED_FIELD(x, y)      IN_FIELD(x, y, ed_fieldx, ed_fieldy)
 
 // drawing elements on the three mouse buttons
 static int new_element1 = EL_WALL;
@@ -3808,7 +3949,7 @@ static void AdjustElementListScrollbar(void);
 static void RedrawDrawingElements(void);
 static void DrawDrawingWindowExt(boolean);
 static void DrawDrawingWindow(void);
-static void DrawLevelInfoWindow(void);
+static void DrawLevelConfigWindow(void);
 static void DrawPropertiesWindow(void);
 static void DrawPaletteWindow(void);
 static void UpdateCustomElementGraphicGadgets(void);
@@ -3833,6 +3974,7 @@ static boolean getDrawModeHiRes(void);
 static int getTabulatorBarWidth(void);
 static int getTabulatorBarHeight(void);
 static Pixel getTabulatorBarColor(void);
+static int numHiresTiles(int);
 
 static int num_editor_gadgets = 0;     // dynamically determined
 
@@ -3844,7 +3986,7 @@ static int last_drawing_function = GADGET_ID_SINGLE_ITEMS;
 static boolean draw_with_brush = FALSE;
 static int properties_element = 0;
 
-static short FieldBackup[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+static short TileBackup[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 static short UndoBuffer[NUM_UNDO_STEPS][MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 static short IntelliDrawBuffer[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 static int undo_buffer_position = 0;
@@ -3852,7 +3994,7 @@ static int undo_buffer_steps = 0;
 static int redo_buffer_steps = 0;
 
 static int edit_mode;
-static int edit_mode_levelinfo;
+static int edit_mode_levelconfig;
 static int edit_mode_properties;
 
 static int element_shift = 0;
@@ -4044,13 +4186,13 @@ static int editor_el_emerald_mine_club[] =
 
   EL_EMC_MAGIC_BALL,
   EL_EMC_MAGIC_BALL_SWITCH,
-  EL_SPRING,
-  EL_EMC_SPRING_BUMPER,
-
   EL_EMC_LENSES,
   EL_EMC_MAGNIFIER,
-  EL_EMPTY,
-  EL_EMPTY,
+
+  EL_SPRING_LEFT,
+  EL_SPRING,
+  EL_SPRING_RIGHT,
+  EL_EMC_SPRING_BUMPER,
 
   EL_BALLOON,
   EL_YAMYAM_UP,
@@ -4522,7 +4664,12 @@ static int editor_el_mirror_magic[] =
   EL_MM_WOODEN_GRID_FIXED_1,
   EL_MM_WOODEN_GRID_FIXED_2,
   EL_MM_WOODEN_GRID_FIXED_3,
-  EL_MM_WOODEN_GRID_FIXED_4
+  EL_MM_WOODEN_GRID_FIXED_4,
+
+  EL_MM_ENVELOPE_1,
+  EL_MM_ENVELOPE_2,
+  EL_MM_ENVELOPE_3,
+  EL_MM_ENVELOPE_4
 };
 static int *editor_hl_mirror_magic_ptr = editor_hl_mirror_magic;
 static int *editor_el_mirror_magic_ptr = editor_el_mirror_magic;
@@ -4551,8 +4698,8 @@ static int editor_el_deflektor[] =
 
   EL_DF_MIRROR_START,
   EL_DF_MIRROR_ROTATING_START,
+  EL_DF_MIRROR_FIXED_START,
   EL_DF_CELL,
-  EL_DF_MINE,
 
   EL_DF_FIBRE_OPTIC_RED_1,
   EL_DF_FIBRE_OPTIC_YELLOW_1,
@@ -4567,7 +4714,12 @@ static int editor_el_deflektor[] =
   EL_DF_STEEL_WALL,
   EL_DF_WOODEN_WALL,
   EL_DF_REFRACTOR,
-  EL_EMPTY
+  EL_DF_MINE,
+
+  EL_DF_SLOPE_1,
+  EL_DF_SLOPE_2,
+  EL_DF_SLOPE_3,
+  EL_DF_SLOPE_4
 };
 static int *editor_hl_deflektor_ptr = editor_hl_deflektor;
 static int *editor_el_deflektor_ptr = editor_el_deflektor;
@@ -5184,6 +5336,41 @@ static int *editor_el_group_ptr = editor_el_group;
 static int num_editor_hl_group = ARRAY_SIZE(editor_hl_group);
 static int num_editor_el_group = ARRAY_SIZE(editor_el_group);
 
+static int editor_hl_empty_space[] =
+{
+  EL_INTERNAL_CASCADE_ES_ACTIVE,
+  EL_CHAR('E'),
+  EL_CHAR('S'),
+  EL_EMPTY,
+};
+
+static int editor_el_empty_space[] =
+{
+  EL_EMPTY_SPACE_1,
+  EL_EMPTY_SPACE_2,
+  EL_EMPTY_SPACE_3,
+  EL_EMPTY_SPACE_4,
+
+  EL_EMPTY_SPACE_5,
+  EL_EMPTY_SPACE_6,
+  EL_EMPTY_SPACE_7,
+  EL_EMPTY_SPACE_8,
+
+  EL_EMPTY_SPACE_9,
+  EL_EMPTY_SPACE_10,
+  EL_EMPTY_SPACE_11,
+  EL_EMPTY_SPACE_12,
+
+  EL_EMPTY_SPACE_13,
+  EL_EMPTY_SPACE_14,
+  EL_EMPTY_SPACE_15,
+  EL_EMPTY_SPACE_16
+};
+static int *editor_hl_empty_space_ptr = editor_hl_empty_space;
+static int *editor_el_empty_space_ptr = editor_el_empty_space;
+static int num_editor_hl_empty_space = ARRAY_SIZE(editor_hl_empty_space);
+static int num_editor_el_empty_space = ARRAY_SIZE(editor_el_empty_space);
+
 static int editor_hl_reference[] =
 {
   EL_INTERNAL_CASCADE_REF_ACTIVE,
@@ -5396,6 +5583,12 @@ editor_elements_info[] =
     &editor_hl_group_ptr,              &num_editor_hl_group,
     &editor_el_group_ptr,              &num_editor_el_group
   },
+  {
+    &setup_editor_el_custom,
+    &setup.editor_cascade.el_es,
+    &editor_hl_empty_space_ptr,                &num_editor_hl_empty_space,
+    &editor_el_empty_space_ptr,                &num_editor_el_empty_space
+  },
   {
     &setup_editor_el_custom,
     &setup.editor_cascade.el_ref,
@@ -5428,6 +5621,14 @@ editor_elements_info[] =
   }
 };
 
+static struct XY xy_directions[] =
+{
+  { -1,  0 },
+  { +1,  0 },
+  {  0, -1 },
+  {  0, +1 }
+};
+
 
 // ----------------------------------------------------------------------------
 // functions
@@ -5481,7 +5682,7 @@ static char *getElementInfoText(int element)
 
 static char *getElementDescriptionFilenameExt(char *basename)
 {
-  char *elements_subdir = "elements";
+  char *elements_subdir = ELEMENTS_DIRECTORY;
   static char *elements_subdir2 = NULL;
   static char *filename = NULL;
 
@@ -5522,6 +5723,11 @@ static char *getElementDescriptionFilename(int element)
   if (filename != NULL)
     return filename;
 
+  // 3rd try: look for generic fallback text file for any element
+  filename = getElementDescriptionFilenameExt(FALLBACK_TEXT_FILENAME);
+  if (filename != NULL)
+    return filename;
+
   return NULL;
 }
 
@@ -5543,9 +5749,18 @@ static void InitDynamicEditorElementList(int **elements, int *num_elements)
 
   // find all elements used in current level
   for (y = 0; y < lev_fieldy; y++)
+  {
     for (x = 0; x < lev_fieldx; x++)
-      if (Feld[x][y] < NUM_FILE_ELEMENTS)      // should always be true
-       element_found[Feld[x][y]] = TRUE;
+    {
+      if (Tile[x][y] >= NUM_FILE_ELEMENTS)     // should never happen
+       continue;
+
+      if (IS_MM_WALL(Tile[x][y]))
+       element_found[map_mm_wall_element(Tile[x][y])] = TRUE;
+      else
+       element_found[Tile[x][y]] = TRUE;
+    }
+  }
 
   *num_elements = 0;
 
@@ -5565,14 +5780,18 @@ static void InitDynamicEditorElementList(int **elements, int *num_elements)
 
   *num_elements = 0;
 
-  // add all elements used in current level (non-custom/group elements)
+  // add all elements used in current level (non-custom/group/empty elements)
   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
-    if (element_found[i] && !(IS_CUSTOM_ELEMENT(i) || IS_GROUP_ELEMENT(i)))
+    if (element_found[i] && !(IS_CUSTOM_ELEMENT(i) ||
+                             IS_GROUP_ELEMENT(i) ||
+                             IS_EMPTY_ELEMENT(i)))
       (*elements)[(*num_elements)++] = i;
 
-  // add all elements used in current level (custom/group elements)
+  // add all elements used in current level (custom/group/empty elements)
   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
-    if (element_found[i] && (IS_CUSTOM_ELEMENT(i) || IS_GROUP_ELEMENT(i)))
+    if (element_found[i] && (IS_CUSTOM_ELEMENT(i) ||
+                            IS_GROUP_ELEMENT(i) ||
+                            IS_EMPTY_ELEMENT(i)))
       (*elements)[(*num_elements)++] = i;
 
   while (*num_elements % 4)    // pad with empty elements, if needed
@@ -5737,10 +5956,10 @@ static void ReinitializeElementList(void)
       int element = (*editor_elements_info[i].element_list)[j];
 
       if (element >= NUM_FILE_ELEMENTS)
-       Error(ERR_WARN, "editor element %d is runtime element", element);
+       Warn("editor element %d is runtime element", element);
 
       if (strEqual(getElementInfoText(element), INFOTEXT_UNKNOWN_ELEMENT))
-       Error(ERR_WARN, "no element description text for element %d", element);
+       Warn("no element description text for element %d", element);
     }
   }
 
@@ -5750,15 +5969,15 @@ static void ReinitializeElementList(void)
   // determine size of element list
   for (i = 0; editor_elements_info[i].setup_value != NULL; i++)
   {
-    boolean found_inactive_cascade = FALSE;
-
     if (*editor_elements_info[i].setup_value)
     {
+      boolean found_inactive_cascade = FALSE;
+
       if (setup.editor.el_headlines)
       {
        // required for correct padding of palette headline buttons
        if (*editor_elements_info[i].headline_list_size > 0)
-         num_editor_elements += editor.palette.cols;
+         num_editor_elements += ED_ELEMENTLIST_COLS;
 
        for (j = 0; j < *editor_elements_info[i].headline_list_size; j++)
        {
@@ -5775,8 +5994,8 @@ static void ReinitializeElementList(void)
       // required for correct padding of palette element buttons
       int element_list_size = *editor_elements_info[i].element_list_size;
       int element_rows =
-       (element_list_size + editor.palette.cols - 1) / editor.palette.cols;
-      int element_buttons = editor.palette.cols * element_rows;
+       (element_list_size + ED_ELEMENTLIST_COLS - 1) / ED_ELEMENTLIST_COLS;
+      int element_buttons = ED_ELEMENTLIST_COLS * element_rows;
 
       num_editor_elements += element_buttons;
     }
@@ -5808,7 +6027,7 @@ static void ReinitializeElementList(void)
       {
        // required for correct padding of palette headline buttons
        int headline_size = (*editor_elements_info[i].headline_list_size > 0 ?
-                            editor.palette.cols : 0);
+                            ED_ELEMENTLIST_COLS : 0);
 
        for (j = 0; j < headline_size; j++)
        {
@@ -5830,8 +6049,8 @@ static void ReinitializeElementList(void)
       // required for correct padding of palette element buttons
       int element_list_size = *editor_elements_info[i].element_list_size;
       int element_rows =
-       (element_list_size + editor.palette.cols - 1) / editor.palette.cols;
-      int element_buttons = editor.palette.cols * element_rows;
+       (element_list_size + ED_ELEMENTLIST_COLS - 1) / ED_ELEMENTLIST_COLS;
+      int element_buttons = ED_ELEMENTLIST_COLS * element_rows;
 
       // copy all elements from element list
       for (j = 0; j < element_list_size; j++)
@@ -6206,7 +6425,7 @@ static void CreateControlButtons(void)
                      GDI_END);
 
     if (gi == NULL)
-      Error(ERR_EXIT, "cannot create gadget");
+      Fail("cannot create gadget");
 
     level_editor_gadget[id] = gi;
   }
@@ -6272,7 +6491,7 @@ static void CreateControlButtons(void)
                      GDI_END);
 
     if (gi == NULL)
-      Error(ERR_EXIT, "cannot create gadget");
+      Fail("cannot create gadget");
 
     level_editor_gadget[id] = gi;
   }
@@ -6325,7 +6544,7 @@ static void CreateControlButtons(void)
                      GDI_END);
 
     if (gi == NULL)
-      Error(ERR_EXIT, "cannot create gadget");
+      Fail("cannot create gadget");
 
     level_editor_gadget[id] = gi;
   }
@@ -6360,11 +6579,9 @@ static void CreateCounterButtons(void)
       int graphic;
       struct GraphicInfo *gd;
       int gd_x1, gd_x2, gd_y1, gd_y2;
-      unsigned int event_mask;
+      unsigned int event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
       char infotext[max_infotext_len + 1];
 
-      event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
-
       if (i == ED_COUNTER_ID_SELECT_LEVEL)
       {
        graphic = (j == 0 ?
@@ -6419,7 +6636,7 @@ static void CreateCounterButtons(void)
                        GDI_END);
 
       if (gi == NULL)
-       Error(ERR_EXIT, "cannot create gadget");
+       Fail("cannot create gadget");
 
       level_editor_gadget[id] = gi;
       right_gadget_border[id] =
@@ -6481,7 +6698,7 @@ static void CreateCounterButtons(void)
                          GDI_END);
 
        if (gi == NULL)
-         Error(ERR_EXIT, "cannot create gadget");
+         Fail("cannot create gadget");
 
        level_editor_gadget[id] = gi;
        right_gadget_border[id] =
@@ -6504,7 +6721,6 @@ static void CreateDrawingAreas(void)
   for (i = 0; i < ED_NUM_DRAWING_AREAS; i++)
   {
     struct GadgetInfo *gi;
-    unsigned int event_mask;
     int id = drawingarea_info[i].gadget_id;
     int x = SX + ED_AREA_SETTINGS_X(drawingarea_info[i]);
     int y = SY + ED_AREA_SETTINGS_Y(drawingarea_info[i]);
@@ -6512,8 +6728,7 @@ static void CreateDrawingAreas(void)
     int area_ysize = drawingarea_info[i].area_ysize;
     int item_size = (id == GADGET_ID_DRAWING_LEVEL ?
                     ed_tilesize : ED_DRAWINGAREA_TILE_SIZE);
-
-    event_mask =
+    unsigned int event_mask =
       GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
       GD_EVENT_OFF_BORDERS | GD_EVENT_PIXEL_PRECISE;
 
@@ -6539,7 +6754,7 @@ static void CreateDrawingAreas(void)
                      GDI_END);
 
     if (gi == NULL)
-      Error(ERR_EXIT, "cannot create gadget");
+      Fail("cannot create gadget");
 
     level_editor_gadget[id] = gi;
     right_gadget_border[id] =
@@ -6560,7 +6775,7 @@ static void CreateTextInputGadgets(void)
     int gd_x2 = gd->src_x + gd->active_xoffset;
     int gd_y2 = gd->src_y + gd->active_yoffset;
     struct GadgetInfo *gi;
-    unsigned int event_mask;
+    unsigned int event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
     char infotext[MAX_OUTPUT_LINESIZE + 1];
     int id = textinput_info[i].gadget_id;
     int x, y;
@@ -6587,8 +6802,6 @@ static void CreateTextInputGadgets(void)
       y = ED_SETTINGS_Y(textinput_info[i].y);
     }
 
-    event_mask = GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
-
     sprintf(infotext, "Enter %s", textinput_info[i].infotext);
     infotext[max_infotext_len] = '\0';
 
@@ -6612,7 +6825,7 @@ static void CreateTextInputGadgets(void)
                      GDI_END);
 
     if (gi == NULL)
-      Error(ERR_EXIT, "cannot create gadget");
+      Fail("cannot create gadget");
 
     level_editor_gadget[id] = gi;
   }
@@ -6631,14 +6844,12 @@ static void CreateTextAreaGadgets(void)
     int gd_x2 = gd->src_x + gd->active_xoffset;
     int gd_y2 = gd->src_y + gd->active_yoffset;
     struct GadgetInfo *gi;
-    unsigned int event_mask;
+    unsigned int event_mask = GD_EVENT_TEXT_LEAVING;
     char infotext[MAX_OUTPUT_LINESIZE + 1];
     int id = textarea_info[i].gadget_id;
     int area_xsize = textarea_info[i].xsize;
     int area_ysize = textarea_info[i].ysize;
 
-    event_mask = GD_EVENT_TEXT_LEAVING;
-
     sprintf(infotext, "Enter %s", textarea_info[i].infotext);
     infotext[max_infotext_len] = '\0';
 
@@ -6661,7 +6872,7 @@ static void CreateTextAreaGadgets(void)
                      GDI_END);
 
     if (gi == NULL)
-      Error(ERR_EXIT, "cannot create gadget");
+      Fail("cannot create gadget");
 
     level_editor_gadget[id] = gi;
   }
@@ -6682,11 +6893,12 @@ static void CreateSelectboxGadgets(void)
     int gd_y2 = gd->src_y + gd->active_yoffset;
     int selectbox_button_xsize = gd2->width;
     struct GadgetInfo *gi;
-    unsigned int event_mask;
     char infotext[MAX_OUTPUT_LINESIZE + 1];
     int id = selectbox_info[i].gadget_id;
     int x = SX + ED_SETTINGS_X(selectbox_info[i].x);
     int y = SY + ED_SETTINGS_Y(selectbox_info[i].y);
+    unsigned int event_mask =
+      GD_EVENT_RELEASED | GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
 
     if (selectbox_info[i].size == -1)  // dynamically determine size
     {
@@ -6702,9 +6914,6 @@ static void CreateSelectboxGadgets(void)
       selectbox_info[i].size++;                // add one character empty space
     }
 
-    event_mask = GD_EVENT_RELEASED |
-      GD_EVENT_TEXT_RETURN | GD_EVENT_TEXT_LEAVING;
-
     // determine horizontal position to the right of specified gadget
     if (selectbox_info[i].gadget_id_align != GADGET_ID_NONE)
       x = (right_gadget_border[selectbox_info[i].gadget_id_align] +
@@ -6740,7 +6949,7 @@ static void CreateSelectboxGadgets(void)
                      GDI_END);
 
     if (gi == NULL)
-      Error(ERR_EXIT, "cannot create gadget");
+      Fail("cannot create gadget");
 
     level_editor_gadget[id] = gi;
     right_gadget_border[id] =
@@ -6757,7 +6966,7 @@ static void CreateTextbuttonGadgets(void)
   {
     int id = textbutton_info[i].gadget_id;
     int is_tab_button =
-      ((id >= GADGET_ID_LEVELINFO_LEVEL && id <= GADGET_ID_LEVELINFO_EDITOR) ||
+      ((id >= GADGET_ID_LEVELCONFIG_LEVEL && id <= GADGET_ID_LEVELCONFIG_EDITOR) ||
        (id >= GADGET_ID_PROPERTIES_INFO && id <= GADGET_ID_PROPERTIES_CHANGE));
     int graphic =
       (is_tab_button ? IMG_EDITOR_TABBUTTON : IMG_EDITOR_TEXTBUTTON);
@@ -6773,7 +6982,7 @@ static void CreateTextbuttonGadgets(void)
     int border_xsize = gd->border_size + gd->draw_xoffset;
     int border_ysize = gd->border_size;
     struct GadgetInfo *gi;
-    unsigned int event_mask;
+    unsigned int event_mask = GD_EVENT_RELEASED;
     char infotext[MAX_OUTPUT_LINESIZE + 1];
     int x = SX + ED_SETTINGS_X(textbutton_info[i].x);
     int y = SY + ED_SETTINGS_Y(textbutton_info[i].y);
@@ -6781,8 +6990,6 @@ static void CreateTextbuttonGadgets(void)
     if (textbutton_info[i].size == -1) // dynamically determine size
       textbutton_info[i].size = strlen(textbutton_info[i].text);
 
-    event_mask = GD_EVENT_RELEASED;
-
     sprintf(infotext, "%s", textbutton_info[i].infotext);
     infotext[max_infotext_len] = '\0';
 
@@ -6824,7 +7031,7 @@ static void CreateTextbuttonGadgets(void)
                      GDI_END);
 
     if (gi == NULL)
-      Error(ERR_EXIT, "cannot create gadget");
+      Fail("cannot create gadget");
 
     level_editor_gadget[id] = gi;
     right_gadget_border[id] =
@@ -6835,7 +7042,6 @@ static void CreateTextbuttonGadgets(void)
 static void CreateGraphicbuttonGadgets(void)
 {
   struct GadgetInfo *gi;
-  unsigned int event_mask;
   int i;
 
   // create buttons for scrolling of drawing area and element list
@@ -6850,8 +7056,7 @@ static void CreateGraphicbuttonGadgets(void)
     int gd_y1 = gd->src_y;
     int gd_x2 = gd->src_x + gd->pressed_xoffset;
     int gd_y2 = gd->src_y + gd->pressed_yoffset;
-
-    event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
+    unsigned int event_mask = GD_EVENT_RELEASED;
 
     // determine horizontal position to the right of specified gadget
     if (graphicbutton_info[i].gadget_id_align != GADGET_ID_NONE)
@@ -6880,7 +7085,7 @@ static void CreateGraphicbuttonGadgets(void)
                      GDI_END);
 
     if (gi == NULL)
-      Error(ERR_EXIT, "cannot create gadget");
+      Fail("cannot create gadget");
 
     level_editor_gadget[id] = gi;
     right_gadget_border[id] =
@@ -6943,7 +7148,7 @@ static void CreateScrollbarGadgets(void)
     int gd_y2 = gd->src_y + gd->pressed_yoffset;
     struct GadgetInfo *gi;
     int items_max, items_visible, item_position;
-    unsigned int event_mask;
+    unsigned int event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
 
     if (i == ED_SCROLLBAR_ID_LIST_VERTICAL)
     {
@@ -6967,8 +7172,6 @@ static void CreateScrollbarGadgets(void)
       }
     }
 
-    event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
-
     gi = CreateGadget(GDI_CUSTOM_ID, id,
                      GDI_CUSTOM_TYPE_ID, i,
                      GDI_IMAGE_ID, graphic,
@@ -6995,7 +7198,7 @@ static void CreateScrollbarGadgets(void)
                      GDI_END);
 
     if (gi == NULL)
-      Error(ERR_EXIT, "cannot create gadget");
+      Fail("cannot create gadget");
 
     level_editor_gadget[id] = gi;
   }
@@ -7004,11 +7207,8 @@ static void CreateScrollbarGadgets(void)
 static void CreateCheckbuttonGadgets(void)
 {
   struct GadgetInfo *gi;
-  unsigned int event_mask;
   int i;
 
-  event_mask = GD_EVENT_PRESSED;
-
   for (i = 0; i < ED_NUM_CHECKBUTTONS; i++)
   {
     int id = checkbutton_info[i].gadget_id;
@@ -7025,6 +7225,7 @@ static void CreateCheckbuttonGadgets(void)
     int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
     int x = SX + ED_SETTINGS_X(checkbutton_info[i].x);
     int y = SY + ED_SETTINGS_Y(checkbutton_info[i].y);
+    unsigned int event_mask = GD_EVENT_PRESSED;
 
     // determine horizontal position to the right of specified gadget
     if (checkbutton_info[i].gadget_id_align != GADGET_ID_NONE)
@@ -7055,7 +7256,7 @@ static void CreateCheckbuttonGadgets(void)
                      GDI_END);
 
     if (gi == NULL)
-      Error(ERR_EXIT, "cannot create gadget");
+      Fail("cannot create gadget");
 
     level_editor_gadget[id] = gi;
     right_gadget_border[id] =
@@ -7076,16 +7277,14 @@ static void CreateRadiobuttonGadgets(void)
   int gd_x2a = gd->src_x + gd->active_xoffset + gd->pressed_xoffset;
   int gd_y2a = gd->src_y + gd->active_yoffset + gd->pressed_yoffset;
   struct GadgetInfo *gi;
-  unsigned int event_mask;
   int i;
 
-  event_mask = GD_EVENT_PRESSED;
-
   for (i = 0; i < ED_NUM_RADIOBUTTONS; i++)
   {
     int id = radiobutton_info[i].gadget_id;
     int x = SX + ED_SETTINGS_X(radiobutton_info[i].x);
     int y = SY + ED_SETTINGS_Y(radiobutton_info[i].y);
+    unsigned int event_mask = GD_EVENT_PRESSED;
 
     int checked =
       (*radiobutton_info[i].value == radiobutton_info[i].checked_value);
@@ -7120,7 +7319,7 @@ static void CreateRadiobuttonGadgets(void)
                      GDI_END);
 
     if (gi == NULL)
-      Error(ERR_EXIT, "cannot create gadget");
+      Fail("cannot create gadget");
 
     level_editor_gadget[id] = gi;
     right_gadget_border[id] =
@@ -7139,18 +7338,23 @@ void CreateLevelEditorGadgets(void)
 
   num_editor_gadgets = NUM_EDITOR_GADGETS;
 
-  // printf("::: allocating %d gadgets ...\n", num_editor_gadgets);
+  // Debug("editor", "allocating %d gadgets ...\n", num_editor_gadgets);
 
   level_editor_gadget =
     checked_calloc(num_editor_gadgets * sizeof(struct GadgetInfo *));
   right_gadget_border =
     checked_calloc(num_editor_gadgets * sizeof(int));
 
-  editor_el_empty = checked_calloc(ED_NUM_ELEMENTLIST_BUTTONS * sizeof(int));
+  // set number of empty (padding) element buttons to maximum number of buttons
+  num_editor_el_empty = ED_NUM_ELEMENTLIST_BUTTONS;
+
+  editor_el_empty = checked_calloc(num_editor_el_empty * sizeof(int));
   editor_el_empty_ptr = editor_el_empty;
 
   use_permanent_palette = !editor.palette.show_as_separate_screen;
 
+  InitGadgetScreenBorders(-1, INFOTEXT_YPOS);
+
   ReinitializeElementList();
 
   CreateControlButtons();
@@ -7174,7 +7378,7 @@ void FreeLevelEditorGadgets(void)
 {
   int i;
 
-  // printf("::: freeing %d gadgets ...\n", num_editor_gadgets);
+  // Debug("editor", "freeing %d gadgets ...\n", num_editor_gadgets);
 
   for (i = 0; i < num_editor_gadgets; i++)
   {
@@ -7288,8 +7492,10 @@ static void MapDrawingArea(int id)
   int xoffset_below = getTextWidth(drawingarea_info[id].text_below, font_nr);
   int x_left  = gi->x - xoffset_left;
   int x_right = gi->x + gi->width + ED_DRAWINGAREA_TEXT_DISTANCE;
+  int x_above = gi->x - ED_DRAWINGAREA_BORDER_SIZE;
   int x_below = gi->x + (gi->width - xoffset_below) / 2;
   int y_side  = gi->y + (gi->height - font_height) / 2;
+  int y_above = gi->y - font_height - ED_DRAWINGAREA_TEXT_DISTANCE;
   int y_below = gi->y + gi->height + ED_DRAWINGAREA_TEXT_DISTANCE;
 
   if (drawingarea_info[id].text_left)
@@ -7298,6 +7504,9 @@ static void MapDrawingArea(int id)
   if (drawingarea_info[id].text_right)
     DrawText(x_right, y_side, drawingarea_info[id].text_right, font_nr);
 
+  if (drawingarea_info[id].text_above)
+    DrawText(x_above, y_above, drawingarea_info[id].text_above, font_nr);
+
   if (drawingarea_info[id].text_below)
     DrawText(x_below, y_below, drawingarea_info[id].text_below, font_nr);
 
@@ -7338,9 +7547,13 @@ static void MapTextAreaGadget(int id)
   int yoffset_above = font_height + ED_GADGET_LINE_DISTANCE;
   int x_above = ED_SETTINGS_X(textarea_info[id].x);
   int y_above = ED_SETTINGS_Y(textarea_info[id].y) - yoffset_above;
+  char *text_above = textarea_info[id].text_above;
+
+  if (gi->textarea.cropped && textarea_info[id].text_above_cropped)
+    text_above = textarea_info[id].text_above_cropped;
 
-  if (textarea_info[id].text_above)
-    DrawTextS(x_above, y_above, font_nr, textarea_info[id].text_above);
+  if (text_above)
+    DrawTextS(x_above, y_above, font_nr, text_above);
 
   ModifyGadget(gi, GDI_TEXT_VALUE, textarea_info[id].value, GDI_END);
 
@@ -7469,7 +7682,7 @@ static void MapCheckbuttonGadget(int id)
 
   // set position for gadgets with dynamically determined position
   if (checkbutton_info[id].x != -1)    // do not change dynamic positions
-    ModifyGadget(gi, GDI_X, SX + ED_SETTINGS_X(checkbutton_info[id].x),GDI_END);
+    ModifyGadget(gi, GDI_X, SX + ED_SETTINGS_X(checkbutton_info[id].x), GDI_END);
   ModifyGadget(gi, GDI_Y, SY + ED_SETTINGS_Y(checkbutton_info[id].y), GDI_END);
 
   x_left = gi->x - xoffset_left;
@@ -7552,6 +7765,14 @@ static void MapLevelEditorToolboxCustomGadgets(void)
   MapOrUnmapLevelEditorToolboxCustomGadgets(TRUE);
 }
 
+static void MapLevelEditorToolboxCustomGadgetsIfNeeded(void)
+{
+  if (IS_CUSTOM_ELEMENT(properties_element) ||
+      IS_GROUP_ELEMENT(properties_element) ||
+      IS_EMPTY_ELEMENT(properties_element))
+    MapLevelEditorToolboxCustomGadgets();
+}
+
 static void UnmapLevelEditorToolboxCustomGadgets(void)
 {
   MapOrUnmapLevelEditorToolboxCustomGadgets(FALSE);
@@ -7640,8 +7861,8 @@ static void DrawEditModeWindowExt(boolean remap_toolbox_gadgets)
     RedrawDrawingElements();
   }
 
-  if (edit_mode == ED_MODE_INFO)
-    DrawLevelInfoWindow();
+  if (edit_mode == ED_MODE_LEVELCONFIG)
+    DrawLevelConfigWindow();
   else if (edit_mode == ED_MODE_PROPERTIES)
     DrawPropertiesWindow();
   else if (edit_mode == ED_MODE_PALETTE)
@@ -7674,7 +7895,7 @@ static boolean LevelChanged(void)
 
   for (y = 0; y < lev_fieldy; y++) 
     for (x = 0; x < lev_fieldx; x++)
-      if (Feld[x][y] != level.field[x][y])
+      if (Tile[x][y] != level.field[x][y])
        field_changed = TRUE;
 
   return (level.changed || field_changed);
@@ -7702,7 +7923,7 @@ static boolean PrepareSavingIntoPersonalLevelSet(void)
     return TRUE;
   }
 
-  if (!Request("This level is read only! "
+  if (!Request("This level is read-only! "
               "Save into personal level set?", REQ_ASK))
     return FALSE;
 
@@ -7710,6 +7931,17 @@ static boolean PrepareSavingIntoPersonalLevelSet(void)
   leveldir_current =
     getTreeInfoFromIdentifier(leveldir_first, getLoginName());
 
+  // this may happen if "setup.internal.create_user_levelset" is FALSE
+  // or if file "levelinfo.conf" is missing in personal user level set
+  if (leveldir_current == NULL)
+  {
+    Request("Cannot find personal level set?!", REQ_CONFIRM);
+
+    leveldir_current = leveldir_former;
+
+    return FALSE;
+  }
+
   // find unused level number
   for (new_level_nr = leveldir_current->first_level; ; new_level_nr++)
   {
@@ -7730,7 +7962,7 @@ static boolean PrepareSavingIntoPersonalLevelSet(void)
   return TRUE;
 }
 
-static void ModifyLevelInfoForSavingIntoPersonalLevelSet(char *former_name)
+static void ModifyLevelConfigForSavingIntoPersonalLevelSet(char *former_name)
 {
   static char *filename_levelinfo = NULL, *mod_name = NULL;
   FILE *file;
@@ -7928,8 +8160,8 @@ static void replace_custom_element_in_playfield(int element_from,
 
   for (x = 0; x < lev_fieldx; x++)
     for (y = 0; y < lev_fieldy; y++)
-      if (Feld[x][y] == element_from)
-       Feld[x][y] = element_to;
+      if (Tile[x][y] == element_from)
+       Tile[x][y] = element_to;
 }
 
 static boolean CopyCustomElement(int element_old, int element_new,
@@ -7963,6 +8195,12 @@ static boolean CopyCustomElement(int element_old, int element_new,
 
     return FALSE;
   }
+  else if (IS_EMPTY_ELEMENT(element_old) && !IS_EMPTY_ELEMENT(element_new))
+  {
+    Request("Please choose empty element!", REQ_CONFIRM);
+
+    return FALSE;
+  }
   else
   {
     level.changed = TRUE;
@@ -8105,7 +8343,8 @@ static void CopyCustomElementPropertiesToEditor(int element)
 
   // set "change by direct action" selectbox help value
   custom_element_change.direct_action =
-    (HAS_CHANGE_EVENT(element, CE_TOUCHED_BY_PLAYER) ? CE_TOUCHED_BY_PLAYER :
+    (HAS_CHANGE_EVENT(element, CE_NEXT_TO_PLAYER) ? CE_NEXT_TO_PLAYER :
+     HAS_CHANGE_EVENT(element, CE_TOUCHED_BY_PLAYER) ? CE_TOUCHED_BY_PLAYER :
      HAS_CHANGE_EVENT(element, CE_PRESSED_BY_PLAYER) ? CE_PRESSED_BY_PLAYER :
      HAS_CHANGE_EVENT(element, CE_SWITCHED_BY_PLAYER) ? CE_SWITCHED_BY_PLAYER :
      HAS_CHANGE_EVENT(element, CE_SNAPPED_BY_PLAYER) ? CE_SNAPPED_BY_PLAYER :
@@ -8123,11 +8362,14 @@ static void CopyCustomElementPropertiesToEditor(int element)
      HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES) ? CE_SCORE_CHANGES :
      HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO) ? CE_VALUE_GETS_ZERO :
      HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO) ? CE_SCORE_GETS_ZERO :
+     HAS_CHANGE_EVENT(element, CE_CLICKED_BY_MOUSE) ? CE_CLICKED_BY_MOUSE :
+     HAS_CHANGE_EVENT(element, CE_PRESSED_BY_MOUSE) ? CE_PRESSED_BY_MOUSE :
      custom_element_change.direct_action);
 
   // set "change by other element action" selectbox help value
   custom_element_change.other_action =
-    (HAS_CHANGE_EVENT(element, CE_PLAYER_TOUCHES_X) ? CE_PLAYER_TOUCHES_X :
+    (HAS_CHANGE_EVENT(element, CE_PLAYER_NEXT_TO_X) ? CE_PLAYER_NEXT_TO_X :
+     HAS_CHANGE_EVENT(element, CE_PLAYER_TOUCHES_X) ? CE_PLAYER_TOUCHES_X :
      HAS_CHANGE_EVENT(element, CE_PLAYER_PRESSES_X) ? CE_PLAYER_PRESSES_X :
      HAS_CHANGE_EVENT(element, CE_PLAYER_SWITCHES_X) ? CE_PLAYER_SWITCHES_X :
      HAS_CHANGE_EVENT(element, CE_PLAYER_SNAPS_X) ? CE_PLAYER_SNAPS_X :
@@ -8137,6 +8379,7 @@ static void CopyCustomElementPropertiesToEditor(int element)
      HAS_CHANGE_EVENT(element, CE_PLAYER_DIGS_X) ? CE_PLAYER_DIGS_X :
      HAS_CHANGE_EVENT(element, CE_PLAYER_COLLECTS_X) ? CE_PLAYER_COLLECTS_X :
      HAS_CHANGE_EVENT(element, CE_PLAYER_DROPS_X) ? CE_PLAYER_DROPS_X :
+     HAS_CHANGE_EVENT(element, CE_NEXT_TO_X) ? CE_NEXT_TO_X :
      HAS_CHANGE_EVENT(element, CE_TOUCHING_X) ? CE_TOUCHING_X :
      HAS_CHANGE_EVENT(element, CE_HITTING_X) ? CE_HITTING_X :
      HAS_CHANGE_EVENT(element, CE_DIGGING_X) ? CE_DIGGING_X :
@@ -8150,6 +8393,8 @@ static void CopyCustomElementPropertiesToEditor(int element)
      HAS_CHANGE_EVENT(element, CE_SCORE_CHANGES_OF_X) ? CE_SCORE_CHANGES_OF_X :
      HAS_CHANGE_EVENT(element, CE_VALUE_GETS_ZERO_OF_X) ? CE_VALUE_GETS_ZERO_OF_X :
      HAS_CHANGE_EVENT(element, CE_SCORE_GETS_ZERO_OF_X) ? CE_SCORE_GETS_ZERO_OF_X :
+     HAS_CHANGE_EVENT(element, CE_MOUSE_CLICKED_ON_X) ? CE_MOUSE_CLICKED_ON_X :
+     HAS_CHANGE_EVENT(element, CE_MOUSE_PRESSED_ON_X) ? CE_MOUSE_PRESSED_ON_X :
      custom_element_change.other_action);
 }
 
@@ -8159,9 +8404,14 @@ static void CopyGroupElementPropertiesToEditor(int element)
   custom_element = element_info[element];      // needed for description
 }
 
+static void CopyEmptyElementPropertiesToEditor(int element)
+{
+  custom_element = element_info[element];
+}
+
 static void CopyClassicElementPropertiesToEditor(int element)
 {
-  if (ELEM_IS_PLAYER(element) || COULD_MOVE_INTO_ACID(element))
+  if (IS_PLAYER_ELEMENT(element) || COULD_MOVE_INTO_ACID(element))
     custom_element_properties[EP_CAN_MOVE_INTO_ACID] =
       getMoveIntoAcidProperty(&level, element);
 
@@ -8176,6 +8426,8 @@ static void CopyElementPropertiesToEditor(int element)
     CopyCustomElementPropertiesToEditor(element);
   else if (IS_GROUP_ELEMENT(element))
     CopyGroupElementPropertiesToEditor(element);
+  else if (IS_EMPTY_ELEMENT(element))
+    CopyEmptyElementPropertiesToEditor(element);
   else
     CopyClassicElementPropertiesToEditor(element);
 }
@@ -8263,6 +8515,7 @@ static void CopyCustomElementPropertiesToGame(int element)
   // ---------- element settings: advanced (custom elements) ------------------
 
   // set player change event from checkbox and selectbox
+  custom_element_change_events[CE_NEXT_TO_PLAYER] = FALSE;
   custom_element_change_events[CE_TOUCHED_BY_PLAYER] = FALSE;
   custom_element_change_events[CE_PRESSED_BY_PLAYER] = FALSE;
   custom_element_change_events[CE_SWITCHED_BY_PLAYER] = FALSE;
@@ -8281,10 +8534,13 @@ static void CopyCustomElementPropertiesToGame(int element)
   custom_element_change_events[CE_SCORE_CHANGES] = FALSE;
   custom_element_change_events[CE_VALUE_GETS_ZERO] = FALSE;
   custom_element_change_events[CE_SCORE_GETS_ZERO] = FALSE;
+  custom_element_change_events[CE_CLICKED_BY_MOUSE] = FALSE;
+  custom_element_change_events[CE_PRESSED_BY_MOUSE] = FALSE;
   custom_element_change_events[custom_element_change.direct_action] =
     custom_element_change_events[CE_BY_DIRECT_ACTION];
 
   // set other element action change event from checkbox and selectbox
+  custom_element_change_events[CE_PLAYER_NEXT_TO_X] = FALSE;
   custom_element_change_events[CE_PLAYER_TOUCHES_X] = FALSE;
   custom_element_change_events[CE_PLAYER_PRESSES_X] = FALSE;
   custom_element_change_events[CE_PLAYER_SWITCHES_X] = FALSE;
@@ -8295,6 +8551,7 @@ static void CopyCustomElementPropertiesToGame(int element)
   custom_element_change_events[CE_PLAYER_DIGS_X] = FALSE;
   custom_element_change_events[CE_PLAYER_COLLECTS_X] = FALSE;
   custom_element_change_events[CE_PLAYER_DROPS_X] = FALSE;
+  custom_element_change_events[CE_NEXT_TO_X] = FALSE;
   custom_element_change_events[CE_TOUCHING_X] = FALSE;
   custom_element_change_events[CE_HITTING_X] = FALSE;
   custom_element_change_events[CE_DIGGING_X] = FALSE;
@@ -8308,6 +8565,8 @@ static void CopyCustomElementPropertiesToGame(int element)
   custom_element_change_events[CE_SCORE_CHANGES_OF_X] = FALSE;
   custom_element_change_events[CE_VALUE_GETS_ZERO_OF_X] = FALSE;
   custom_element_change_events[CE_SCORE_GETS_ZERO_OF_X] = FALSE;
+  custom_element_change_events[CE_MOUSE_CLICKED_ON_X] = FALSE;
+  custom_element_change_events[CE_MOUSE_PRESSED_ON_X] = FALSE;
   custom_element_change_events[custom_element_change.other_action] =
     custom_element_change_events[CE_BY_OTHER_ACTION];
 
@@ -8320,6 +8579,9 @@ static void CopyCustomElementPropertiesToGame(int element)
   // copy change events also to special level editor variable
   custom_element = element_info[element];
   custom_element_change = *element_info[element].change;
+
+  // needed here to restore runtime value "element_info[element].gfx_element"
+  InitElementPropertiesGfxElement();
 }
 
 static void CopyGroupElementPropertiesToGame(int element)
@@ -8333,11 +8595,29 @@ static void CopyGroupElementPropertiesToGame(int element)
 
   element_info[element] = custom_element;
   *element_info[element].group = group_element_info;
+
+  // needed here to restore runtime value "element_info[element].gfx_element"
+  InitElementPropertiesGfxElement();
+}
+
+static void CopyEmptyElementPropertiesToGame(int element)
+{
+  // mark that this empty element has been modified
+  custom_element.modified_settings = TRUE;
+  level.changed = TRUE;
+
+  if (level.use_custom_template)
+    AskToCopyAndModifyLevelTemplate();
+
+  element_info[element] = custom_element;
+
+  // needed here to restore runtime value "element_info[element].gfx_element"
+  InitElementPropertiesGfxElement();
 }
 
 static void CopyClassicElementPropertiesToGame(int element)
 {
-  if (ELEM_IS_PLAYER(element) || COULD_MOVE_INTO_ACID(element))
+  if (IS_PLAYER_ELEMENT(element) || COULD_MOVE_INTO_ACID(element))
     setMoveIntoAcidProperty(&level, element,
                            custom_element_properties[EP_CAN_MOVE_INTO_ACID]);
 
@@ -8352,6 +8632,8 @@ static void CopyElementPropertiesToGame(int element)
     CopyCustomElementPropertiesToGame(element);
   else if (IS_GROUP_ELEMENT(element))
     CopyGroupElementPropertiesToGame(element);
+  else if (IS_EMPTY_ELEMENT(element))
+    CopyEmptyElementPropertiesToGame(element);
   else
     CopyClassicElementPropertiesToGame(element);
 }
@@ -8363,8 +8645,7 @@ static void CheckElementDescriptions(void)
 
   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
     if (getElementDescriptionFilename(i) == NULL && !IS_OBSOLETE(i))
-      Error(ERR_WARN, "no element description file for element '%s'",
-           EL_NAME(i));
+      Warn("no element description file for element '%s'", EL_NAME(i));
 }
 #endif
 
@@ -8397,6 +8678,9 @@ static void InitZoomLevelSettings(int zoom_tilesize)
     ed_tilesize = setup.auto_setup.editor_zoom_tilesize;
     ed_tilesize_default = DEFAULT_EDITOR_TILESIZE;
 
+    // make sure that tile size is always a power of 2
+    ed_tilesize = (1 << log_2(ed_tilesize));
+
     if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
     {
       ed_tilesize = DEFAULT_EDITOR_TILESIZE_MM;
@@ -8498,33 +8782,44 @@ static boolean useEditorDoorAnimation(void)
   return (door_1_viewport_unchanged && door_1_contains_toolbox);
 }
 
+static void DrawEditorDoorBackground(int graphic, int x, int y,
+                                    int width, int height)
+{
+  struct GraphicInfo *g = &graphic_info[graphic];
+
+  if (g->bitmap != NULL)
+    BlitBitmap(g->bitmap, drawto, g->src_x, g->src_y,
+              MIN(width, g->width), MIN(height, g->height), x, y);
+  else
+    ClearRectangle(drawto, x, y, width, height);
+}
+
 static void DrawEditorDoorContent(void)
 {
   // needed for gadgets drawn on background (like palette scrollbar)
   SetDoorBackgroundImage(IMG_UNDEFINED);
 
   // copy default editor door content to main double buffer
-  BlitBitmap(graphic_info[IMG_BACKGROUND_PALETTE].bitmap, drawto,
-            graphic_info[IMG_BACKGROUND_PALETTE].src_x,
-            graphic_info[IMG_BACKGROUND_PALETTE].src_y,
-            MIN(DXSIZE, graphic_info[IMG_BACKGROUND_PALETTE].width),
-            MIN(DYSIZE, graphic_info[IMG_BACKGROUND_PALETTE].height),
-            DX, DY);
+  DrawEditorDoorBackground(IMG_BACKGROUND_PALETTE, DX, DY, DXSIZE, DYSIZE);
 
   // draw bigger door
   DrawSpecialEditorDoor();
 
   // draw new control window
-  BlitBitmap(graphic_info[IMG_BACKGROUND_TOOLBOX].bitmap, drawto,
-            graphic_info[IMG_BACKGROUND_TOOLBOX].src_x,
-            graphic_info[IMG_BACKGROUND_TOOLBOX].src_y,
-            MIN(EXSIZE, graphic_info[IMG_BACKGROUND_TOOLBOX].width),
-            MIN(EYSIZE, graphic_info[IMG_BACKGROUND_TOOLBOX].height),
-            EX, EY);
+  DrawEditorDoorBackground(IMG_BACKGROUND_TOOLBOX, EX, EY, EXSIZE, EYSIZE);
 
   // draw all toolbox gadgets to editor doors
   MapControlButtons();
 
+  // when returning from test game to properties page, redraw toolbox gadgets
+  if (edit_mode == ED_MODE_PROPERTIES)
+  {
+    UnmapLevelEditorToolboxDrawingGadgets();
+    UnmapLevelEditorToolboxCustomGadgets();
+
+    MapLevelEditorToolboxCustomGadgetsIfNeeded();
+  }
+
   // draw all palette gadgets to editor doors
   ModifyEditorElementList();
   RedrawDrawingElements();
@@ -8539,7 +8834,7 @@ void DrawLevelEd(void)
 
   FadeSoundsAndMusic();
 
-  if (CheckIfGlobalBorderOrPlayfieldViewportHasChanged())
+  if (CheckFadeAll())
     fade_mask = REDRAW_ALL;
 
   FadeOut(fade_mask);
@@ -8559,15 +8854,15 @@ void DrawLevelEd(void)
 
   if (level_editor_test_game)
   {
-    CopyPlayfield(level.field, Feld);
-    CopyPlayfield(FieldBackup, level.field);
+    CopyPlayfield(level.field, Tile);
+    CopyPlayfield(TileBackup, level.field);
 
     level_editor_test_game = FALSE;
   }
   else
   {
     edit_mode = ED_MODE_DRAWING;
-    edit_mode_levelinfo = ED_MODE_LEVELINFO_LEVEL;
+    edit_mode_levelconfig = ED_MODE_LEVELCONFIG_LEVEL;
     edit_mode_properties = ED_MODE_PROPERTIES_INFO;
 
     ResetUndoBuffer();
@@ -8623,8 +8918,8 @@ static void AdjustDrawingAreaGadgets(void)
 
   if (suppressBorderElement())
   {
-    ed_xsize = max_ed_fieldx;
-    ed_ysize = max_ed_fieldy;
+    ed_xsize = lev_fieldx;
+    ed_ysize = lev_fieldy;
   }
 
   // check if we need any scrollbars
@@ -8950,7 +9245,7 @@ static int getTabulatorBarHeight(void)
 
 static Pixel getTabulatorBarColor(void)
 {
-  struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELINFO_LEVEL];
+  struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELCONFIG_LEVEL];
   struct GadgetDesign *gd = &gd_gi1->alt_design[GD_BUTTON_UNPRESSED];
   int gd_x = gd->x + gd_gi1->border.width / 2;
   int gd_y = gd->y + gd_gi1->height - 1;
@@ -8958,19 +9253,19 @@ static Pixel getTabulatorBarColor(void)
   return GetPixel(gd->bitmap, gd_x, gd_y);
 }
 
-static void DrawLevelInfoTabulatorGadgets(void)
+static void DrawLevelConfigTabulatorGadgets(void)
 {
-  struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELINFO_LEVEL];
+  struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_LEVELCONFIG_LEVEL];
   Pixel tab_color = getTabulatorBarColor();
-  int id_first = ED_TAB_BUTTON_ID_LEVELINFO_FIRST;
-  int id_last  = ED_TAB_BUTTON_ID_LEVELINFO_LAST;
+  int id_first = ED_TAB_BUTTON_ID_LEVELCONFIG_FIRST;
+  int id_last  = ED_TAB_BUTTON_ID_LEVELCONFIG_LAST;
   int i;
 
   for (i = id_first; i <= id_last; i++)
   {
     int gadget_id = textbutton_info[i].gadget_id;
     struct GadgetInfo *gi = level_editor_gadget[gadget_id];
-    boolean active = (i != edit_mode_levelinfo);
+    boolean active = (i != edit_mode_levelconfig);
 
     // draw background line below tabulator button
     ClearRectangleOnBackground(drawto, gi->x, gi->y + gi->height, gi->width, 1);
@@ -9003,7 +9298,7 @@ static void DrawPropertiesTabulatorGadgets(void)
   int i;
 
   // draw two config tabulators for player elements
-  if (ELEM_IS_PLAYER(properties_element))
+  if (IS_PLAYER_ELEMENT(properties_element))
     id_last = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG_2;
 
   // draw two config and one "change" tabulator for custom elements
@@ -9018,7 +9313,7 @@ static void DrawPropertiesTabulatorGadgets(void)
 
     // use "config 1" and "config 2" instead of "config" for players and CEs
     if (i == ED_TEXTBUTTON_ID_PROPERTIES_CONFIG &&
-       (ELEM_IS_PLAYER(properties_element) ||
+       (IS_PLAYER_ELEMENT(properties_element) ||
         IS_CUSTOM_ELEMENT(properties_element)))
       continue;
 
@@ -9059,7 +9354,7 @@ static int PrintElementDescriptionFromFile(char *filename, int font_nr,
                      TRUE, FALSE, FALSE);
 }
 
-static void DrawLevelInfoLevel(void)
+static void DrawLevelConfigLevel(void)
 {
   int i;
 
@@ -9088,7 +9383,7 @@ static char *getLevelSubdirFromSaveMode(int save_mode)
   return leveldir_current->subdir;
 }
 
-static void DrawLevelInfoLevelSet_DirectoryInfo(void)
+static void DrawLevelConfigLevelSet_DirectoryInfo(void)
 {
   char *directory_text = "Level set directory:";
   char *directory_name = getLevelSubdirFromSaveMode(levelset_save_mode);
@@ -9103,7 +9398,7 @@ static void DrawLevelInfoLevelSet_DirectoryInfo(void)
   PrintInfoText(directory_name, font2_nr, x, y);
 }
 
-static void DrawLevelInfoLevelSet(void)
+static void DrawLevelConfigLevelSet(void)
 {
   boolean artwork_exists = checkIfCustomArtworkExistsForCurrentLevelSet();
   boolean template_exists = fileExists(getLocalLevelTemplateFilename());
@@ -9136,10 +9431,10 @@ static void DrawLevelInfoLevelSet(void)
   MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_LEVELSET);
 
   // draw info text
-  DrawLevelInfoLevelSet_DirectoryInfo();
+  DrawLevelConfigLevelSet_DirectoryInfo();
 }
 
-static void DrawLevelInfoEditor(void)
+static void DrawLevelConfigEditor(void)
 {
   int i;
 
@@ -9162,7 +9457,7 @@ static void DrawLevelInfoEditor(void)
   MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_2);
 }
 
-static void DrawLevelInfoWindow(void)
+static void DrawLevelConfigWindow(void)
 {
   char *text = "Global Settings";
   int font_nr = FONT_TITLE_1;
@@ -9181,14 +9476,14 @@ static void DrawLevelInfoWindow(void)
 
   DrawText(sx, sy, text, font_nr);
 
-  DrawLevelInfoTabulatorGadgets();
+  DrawLevelConfigTabulatorGadgets();
 
-  if (edit_mode_levelinfo == ED_MODE_LEVELINFO_LEVEL)
-    DrawLevelInfoLevel();
-  else if (edit_mode_levelinfo == ED_MODE_LEVELINFO_LEVELSET)
-    DrawLevelInfoLevelSet();
-  else if (edit_mode_levelinfo == ED_MODE_LEVELINFO_EDITOR)
-    DrawLevelInfoEditor();
+  if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_LEVEL)
+    DrawLevelConfigLevel();
+  else if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_LEVELSET)
+    DrawLevelConfigLevelSet();
+  else if (edit_mode_levelconfig == ED_MODE_LEVELCONFIG_EDITOR)
+    DrawLevelConfigEditor();
 }
 
 static void DrawCustomContentArea(void)
@@ -9303,7 +9598,7 @@ static void DrawMagicBallContentAreas(void)
   DrawText(x, y + 2 * tilesize, "active",    font_nr);
 }
 
-static void DrawAndroidElementArea(int element)
+static void DrawAndroidElementArea(void)
 {
   int id = ED_DRAWING_ID_ANDROID_CONTENT;
   int num_elements = level.num_android_clone_elements;
@@ -9331,7 +9626,7 @@ static void DrawAndroidElementArea(int element)
   MapDrawingArea(id);
 }
 
-static void DrawGroupElementArea(int element)
+static void DrawGroupElementArea(void)
 {
   int id = ED_DRAWING_ID_GROUP_CONTENT;
   int num_elements = group_element_info.num_elements;
@@ -9388,13 +9683,40 @@ static void DrawPlayerInitialInventoryArea(int element)
   MapDrawingArea(id);
 }
 
+static void DrawMMBallContentArea(void)
+{
+  int id = ED_DRAWING_ID_MM_BALL_CONTENT;
+  int num_elements = level.num_mm_ball_contents;
+  int border_size = ED_DRAWINGAREA_BORDER_SIZE;
+  int sx = SX + ED_AREA_SETTINGS_X(drawingarea_info[id]) - border_size;
+  int sy = SY + ED_AREA_SETTINGS_Y(drawingarea_info[id]) - border_size;
+  int xsize = MAX_MM_BALL_CONTENTS;
+  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 * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size,
+                ysize * ED_DRAWINGAREA_TILE_SIZE + 2 * border_size);
+
+  MapDrawingArea(id);
+}
+
 static void DrawEnvelopeTextArea(int envelope_nr)
 {
   int id = ED_TEXTAREA_ID_ENVELOPE_INFO;
   struct GadgetInfo *gi = level_editor_gadget[textarea_info[id].gadget_id];
 
   UnmapGadget(gi);
-  DrawBackground(gi->x, gi->y, gi->width, gi->height);
+
+  DrawBackground(gi->x, gi->y,
+                gi->textarea.crop_width, gi->textarea.crop_height);
 
   if (envelope_nr != -1)
     textarea_info[id].value = level.envelope[envelope_nr].text;
@@ -9468,13 +9790,16 @@ static void DrawPropertiesInfo(void)
     { -1,                      NULL                                    }
   };
   char *filename = getElementDescriptionFilename(properties_element);
-  char *percentage_text = "In this level: ";
+  char *num_elements_text = "In this level: ";
+  char *num_similar_text = "Similar tiles: ";
   char *properties_text = "Standard properties: ";
   char *description_text = "Description:";
   char *no_description_text = "No description available.";
   char *none_text = "None";
   float percentage;
-  int num_elements_in_level;
+  int num_elements_in_level = 0;
+  int num_similar_in_level = 0;
+  int num_hires_tiles_in_level = 0;
   int num_standard_properties = 0;
   int font1_nr = FONT_TEXT_1;
   int font2_nr = FONT_TEXT_2;
@@ -9483,7 +9808,8 @@ static void DrawPropertiesInfo(void)
   int font2_height = getFontHeight(font2_nr);
   int line1_height = font1_height + ED_GADGET_LINE_DISTANCE;
   int font2_yoffset = (font1_height - font2_height) / 2;
-  int percentage_text_len = strlen(percentage_text) * font1_width;
+  int num_elements_text_len = strlen(num_elements_text) * font1_width;
+  int num_similar_text_len = strlen(num_similar_text) * font1_width;
   int properties_text_len = strlen(properties_text) * font1_width;
   int xpos = ED_ELEMENT_SETTINGS_X(0);
   int ypos = ED_ELEMENT_SETTINGS_Y(0) + ED_GADGET_SMALL_DISTANCE;
@@ -9502,22 +9828,66 @@ static void DrawPropertiesInfo(void)
 
   // ----- print number of elements / percentage of this element in level
 
-  num_elements_in_level = 0;
-  for (y = 0; y < lev_fieldy; y++) 
+  for (y = 0; y < lev_fieldy; y++)
+  {
     for (x = 0; x < lev_fieldx; x++)
-      if (Feld[x][y] == properties_element)
+    {
+      if (Tile[x][y] == properties_element)
+      {
        num_elements_in_level++;
+      }
+      else if (IS_MM_WALL(Tile[x][y]) &&
+              map_mm_wall_element(Tile[x][y]) == properties_element)
+      {
+       num_hires_tiles_in_level += numHiresTiles(Tile[x][y]);
+      }
+    }
+  }
+
   percentage = num_elements_in_level * 100.0 / (lev_fieldx * lev_fieldy);
 
-  DrawTextS(xpos, ypos, font1_nr, percentage_text);
+  DrawTextS(xpos, ypos, font1_nr, num_elements_text);
 
-  if (num_elements_in_level > 0)
-    DrawTextF(xpos + percentage_text_len, ypos + font2_yoffset, font2_nr,
+  if (num_hires_tiles_in_level > 0)
+    DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
+             "%d wall tiles", num_hires_tiles_in_level);
+  else if (num_elements_in_level > 0)
+    DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
              "%d (%.2f %%)", num_elements_in_level, percentage);
   else
-    DrawTextF(xpos + percentage_text_len, ypos + font2_yoffset, font2_nr,
+    DrawTextF(xpos + num_elements_text_len, ypos + font2_yoffset, font2_nr,
              none_text);
 
+  // ----- print number of similar elements / percentage of them in level
+
+  for (y = 0; y < lev_fieldy; y++)
+  {
+    for (x = 0; x < lev_fieldx; x++)
+    {
+      if (strEqual(element_info[Tile[x][y]].class_name,
+                  element_info[properties_element].class_name))
+      {
+       num_similar_in_level++;
+      }
+    }
+  }
+
+  if (num_similar_in_level != num_elements_in_level)
+  {
+    ypos += 1 * MAX(font1_height, font2_height);
+
+    percentage = num_similar_in_level * 100.0 / (lev_fieldx * lev_fieldy);
+
+    DrawTextS(xpos, ypos, font1_nr, num_similar_text);
+
+    if (num_similar_in_level > 0)
+      DrawTextF(xpos + num_similar_text_len, ypos + font2_yoffset, font2_nr,
+               "%d (%.2f %%)", num_similar_in_level, percentage);
+    else
+      DrawTextF(xpos + num_similar_text_len, ypos + font2_yoffset, font2_nr,
+               none_text);
+  }
+
   ypos += 2 * MAX(font1_height, font2_height);
 
   // ----- print standard properties of this element
@@ -9566,6 +9936,7 @@ static void DrawPropertiesInfo(void)
 #define TEXT_DURATION          "Duration when activated"
 #define TEXT_DELAY_ON          "Delay before activating"
 #define TEXT_DELAY_OFF         "Delay before deactivating"
+#define TEXT_DELAY_CHANGING    "Delay before changing"
 #define TEXT_DELAY_EXPLODING   "Delay before exploding"
 #define TEXT_DELAY_MOVING      "Delay before moving"
 #define TEXT_BALL_DELAY                "Element generation delay"
@@ -9630,9 +10001,9 @@ static struct
   { EL_NUT,            &level.score[SC_NUT],           TEXT_CRACKING   },
   { EL_DYNAMITE,       &level.score[SC_DYNAMITE],      TEXT_COLLECTING },
   { EL_EM_DYNAMITE,    &level.score[SC_DYNAMITE],      TEXT_COLLECTING },
-  { EL_DYNABOMB_INCREASE_NUMBER,&level.score[SC_DYNAMITE],TEXT_COLLECTING },
-  { EL_DYNABOMB_INCREASE_SIZE, &level.score[SC_DYNAMITE],TEXT_COLLECTING },
-  { EL_DYNABOMB_INCREASE_POWER,        &level.score[SC_DYNAMITE],TEXT_COLLECTING },
+  { EL_DYNABOMB_INCREASE_NUMBER,&level.score[SC_DYNAMITE], TEXT_COLLECTING },
+  { EL_DYNABOMB_INCREASE_SIZE, &level.score[SC_DYNAMITE], TEXT_COLLECTING },
+  { EL_DYNABOMB_INCREASE_POWER,        &level.score[SC_DYNAMITE], TEXT_COLLECTING },
   { EL_SHIELD_NORMAL,  &level.score[SC_SHIELD],        TEXT_COLLECTING },
   { EL_SHIELD_DEADLY,  &level.score[SC_SHIELD],        TEXT_COLLECTING },
   { EL_EXTRA_TIME,     &level.extra_time_score,        TEXT_COLLECTING },
@@ -9691,11 +10062,13 @@ static struct
   { EL_EMC_LENSES,     &level.lenses_score,            TEXT_COLLECTING },
   { EL_EMC_MAGNIFIER,  &level.magnify_score,           TEXT_COLLECTING },
   { EL_SPRING,         &level.slurp_score,             TEXT_SLURPING   },
+  { EL_SPRING_LEFT,    &level.slurp_score,             TEXT_SLURPING   },
+  { EL_SPRING_RIGHT,   &level.slurp_score,             TEXT_SLURPING   },
   { EL_EMC_LENSES,     &level.lenses_time,             TEXT_DURATION   },
   { EL_EMC_MAGNIFIER,  &level.magnify_time,            TEXT_DURATION   },
   { EL_MM_FUSE_ACTIVE, &level.mm_time_fuse,            TEXT_DELAY_OFF  },
   { EL_MM_BOMB,                &level.mm_time_bomb,            TEXT_DELAY_EXPLODING },
-  { EL_MM_GRAY_BALL,   &level.mm_time_ball,            TEXT_DELAY_ON   },
+  { EL_MM_GRAY_BALL,   &level.mm_time_ball,            TEXT_DELAY_CHANGING },
   { EL_MM_STEEL_BLOCK, &level.mm_time_block,           TEXT_DELAY_MOVING },
   { EL_MM_WOODEN_BLOCK,        &level.mm_time_block,           TEXT_DELAY_MOVING },
 
@@ -9709,11 +10082,13 @@ static boolean checkPropertiesConfig(int element)
   if (IS_GEM(element) ||
       IS_CUSTOM_ELEMENT(element) ||
       IS_GROUP_ELEMENT(element) ||
+      IS_EMPTY_ELEMENT(element) ||
       IS_BALLOON_ELEMENT(element) ||
       IS_ENVELOPE(element) ||
+      IS_MM_ENVELOPE(element) ||
       IS_MM_MCDUFFIN(element) ||
       IS_DF_LASER(element) ||
-      ELEM_IS_PLAYER(element) ||
+      IS_PLAYER_ELEMENT(element) ||
       HAS_EDITOR_CONTENT(element) ||
       CAN_GROW(element) ||
       COULD_MOVE_INTO_ACID(element) ||
@@ -9743,12 +10118,45 @@ static void SetAutomaticNumberOfGemsNeeded(void)
   {
     for (y = 0; y < lev_fieldy; y++)
     {
-      int element = Feld[x][y];
+      int element = Tile[x][y];
 
-      if (IS_GEM(element) ||
-         element == EL_MM_KETTLE ||
-         element == EL_DF_CELL)
-       level.gems_needed++;
+      switch (element)
+      {
+       case EL_EMERALD:
+       case EL_EMERALD_YELLOW:
+       case EL_EMERALD_RED:
+       case EL_EMERALD_PURPLE:
+       case EL_BD_DIAMOND:
+       case EL_WALL_EMERALD:
+       case EL_WALL_EMERALD_YELLOW:
+       case EL_WALL_EMERALD_RED:
+       case EL_WALL_EMERALD_PURPLE:
+       case EL_WALL_BD_DIAMOND:
+       case EL_NUT:
+       case EL_SP_INFOTRON:
+       case EL_MM_KETTLE:
+       case EL_DF_CELL:
+         level.gems_needed++;
+         break;
+
+       case EL_DIAMOND:
+       case EL_WALL_DIAMOND:
+         level.gems_needed += 3;
+         break;
+
+       case EL_PEARL:
+       case EL_WALL_PEARL:
+         level.gems_needed += 5;
+         break;
+
+       case EL_CRYSTAL:
+       case EL_WALL_CRYSTAL:
+         level.gems_needed += 8;
+         break;
+
+       default:
+         break;
+      }
     }
   }
 
@@ -9831,13 +10239,22 @@ static void DrawPropertiesConfig(void)
       DrawMagicBallContentAreas();
 
       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_RANDOM_BALL_CONTENT);
-      MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_BALL_STATE);
+      MapCheckbuttonGadget(ED_CHECKBUTTON_ID_INITIAL_BALL_ACTIVE);
     }
     else if (properties_element == EL_EMC_ANDROID)
-      DrawAndroidElementArea(properties_element);
+      DrawAndroidElementArea();
+    else if (properties_element == EL_MM_GRAY_BALL)
+    {
+      MapCounterButtons(ED_COUNTER_ID_MM_BALL_CONTENT);
+      MapSelectboxGadget(ED_SELECTBOX_ID_MM_BALL_CHOICE_MODE);
+      MapCheckbuttonGadget(ED_CHECKBUTTON_ID_ROTATE_MM_BALL_CONTENT);
+      MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EXPLODE_MM_BALL);
+
+      DrawMMBallContentArea();
+    }
   }
 
-  if (ELEM_IS_PLAYER(properties_element))
+  if (IS_PLAYER_ELEMENT(properties_element))
   {
     int player_nr = GET_PLAYER_NR(properties_element);
 
@@ -9899,6 +10316,8 @@ static void DrawPropertiesConfig(void)
 
       // draw checkbutton gadgets
       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY);
+      MapCheckbuttonGadget(ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT);
+      MapCheckbuttonGadget(ED_CHECKBUTTON_ID_KEEP_WALKABLE_CE);
 
       // draw counter gadgets
       MapCounterButtons(ED_COUNTER_ID_INVENTORY_SIZE);
@@ -9915,7 +10334,7 @@ static void DrawPropertiesConfig(void)
     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_EXPLODES_BY_FIRE);
 
   if (COULD_MOVE_INTO_ACID(properties_element) &&
-      !ELEM_IS_PLAYER(properties_element) &&
+      !IS_PLAYER_ELEMENT(properties_element) &&
       (!IS_CUSTOM_ELEMENT(properties_element) ||
        edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_2))
   {
@@ -9923,7 +10342,7 @@ static void DrawPropertiesConfig(void)
     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].x =
       ED_ELEMENT_SETTINGS_XPOS(IS_CUSTOM_ELEMENT(properties_element) ? 1 : 0);
     checkbutton_info[ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID].y =
-      ED_ELEMENT_SETTINGS_YPOS(IS_CUSTOM_ELEMENT(properties_element) ? 6 :
+      ED_ELEMENT_SETTINGS_YPOS(IS_CUSTOM_ELEMENT(properties_element) ? 7 :
                               IS_BALLOON_ELEMENT(properties_element) ||
                               HAS_EDITOR_CONTENT(properties_element) ? 1 : 0);
 
@@ -9933,7 +10352,9 @@ static void DrawPropertiesConfig(void)
   if (MAYBE_DONT_COLLIDE_WITH(properties_element))
     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH);
 
-  if (properties_element == EL_SPRING)
+  if (properties_element == EL_SPRING ||
+      properties_element == EL_SPRING_LEFT ||
+      properties_element == EL_SPRING_RIGHT)
     MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_SPRING_BUG);
 
   if (properties_element == EL_TIME_ORB_FULL)
@@ -9971,13 +10392,14 @@ static void DrawPropertiesConfig(void)
   if (IS_BALLOON_ELEMENT(properties_element))
     MapSelectboxGadget(ED_SELECTBOX_ID_WIND_DIRECTION);
 
-  if (IS_ENVELOPE(properties_element))
+  if (IS_ENVELOPE(properties_element) ||
+      IS_MM_ENVELOPE(properties_element))
   {
     int counter1_id = ED_COUNTER_ID_ENVELOPE_XSIZE;
     int counter2_id = ED_COUNTER_ID_ENVELOPE_YSIZE;
     int button1_id = ED_CHECKBUTTON_ID_ENVELOPE_AUTOWRAP;
     int button2_id = ED_CHECKBUTTON_ID_ENVELOPE_CENTERED;
-    int envelope_nr = properties_element - EL_ENVELOPE_1;
+    int envelope_nr = ENVELOPE_NR(properties_element);
 
     counterbutton_info[counter1_id].value = &level.envelope[envelope_nr].xsize;
     counterbutton_info[counter2_id].value = &level.envelope[envelope_nr].ysize;
@@ -10085,7 +10507,7 @@ static void DrawPropertiesConfig(void)
     MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
 
     // draw drawing area gadgets
-    DrawGroupElementArea(properties_element);
+    DrawGroupElementArea();
 
     // draw text input gadgets
     MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
@@ -10095,8 +10517,25 @@ static void DrawPropertiesConfig(void)
 
     draw_footer_line = TRUE;
   }
-
-  // draw little footer border line above CE/GE use/save template gadgets
+  else if (IS_EMPTY_ELEMENT(properties_element))
+  {
+    // draw stickybutton gadget
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
+
+    // draw checkbutton gadgets
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC);
+    MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE_1);
+
+    // draw textbutton gadgets
+    MapTextbuttonGadget(ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE_1);
+
+    // draw drawing area gadgets
+    MapDrawingArea(ED_DRAWING_ID_CUSTOM_GRAPHIC);
+
+    draw_footer_line = TRUE;
+  }
+
+  // draw little footer border line above CE/GE use/save template gadgets
   if (draw_footer_line)
   {
     struct GadgetInfo *gd_gi1 = level_editor_gadget[GADGET_ID_PROPERTIES_INFO];
@@ -10185,12 +10624,12 @@ static void DrawEditorElementName(int x, int y, int font_nr)
   int font_height = getFontHeight(font_nr);
   int max_text_width = SXSIZE - x - ED_ELEMENT_SETTINGS_X(0);
   int max_chars_per_line = max_text_width / font_width;
-  char buffer[max_chars_per_line + 1];
 
   if (strlen(element_name) <= max_chars_per_line)
     DrawTextS(x, y, font_nr, element_name);
   else
   {
+    char buffer[max_chars_per_line + 1];
     int next_pos = max_chars_per_line;
 
     strncpy(buffer, element_name, max_chars_per_line);
@@ -10251,12 +10690,12 @@ static void DrawPropertiesWindow(void)
     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_2;
 
   if (edit_mode_properties > ED_MODE_PROPERTIES_CONFIG &&
-      !ELEM_IS_PLAYER(properties_element) &&
+      !IS_PLAYER_ELEMENT(properties_element) &&
       !IS_CUSTOM_ELEMENT(properties_element))
     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG;
 
   if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG &&
-      (ELEM_IS_PLAYER(properties_element) ||
+      (IS_PLAYER_ELEMENT(properties_element) ||
        IS_CUSTOM_ELEMENT(properties_element)))
     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG_1;
 
@@ -10266,9 +10705,7 @@ static void DrawPropertiesWindow(void)
   UnmapLevelEditorToolboxDrawingGadgets();
   UnmapLevelEditorToolboxCustomGadgets();
 
-  if (IS_CUSTOM_ELEMENT(properties_element) ||
-      IS_GROUP_ELEMENT(properties_element))
-    MapLevelEditorToolboxCustomGadgets();
+  MapLevelEditorToolboxCustomGadgetsIfNeeded();
 
   SetMainBackgroundImage(IMG_BACKGROUND_EDITOR);
   ClearField();
@@ -10577,13 +11014,7 @@ static int getChipFromOpenDirectionNotEmpty(int direction, int element_old)
 
 static int getClosedTube(int x, int y)
 {
-  static int xy[4][2] =
-  {
-    { -1, 0 },
-    { +1, 0 },
-    { 0, -1 },
-    { 0, +1 }
-  };
+  struct XY *xy = xy_directions;
   int element_old = IntelliDrawBuffer[x][y];
   int direction_old = getOpenDirectionFromTube(element_old);
   int direction_new = MV_NONE;
@@ -10591,8 +11022,8 @@ static int getClosedTube(int x, int y)
 
   for (i = 0; i < NUM_DIRECTIONS; i++)
   {
-    int xx = x + xy[i][0];
-    int yy = y + xy[i][1];
+    int xx = x + xy[i].x;
+    int yy = y + xy[i].y;
     int dir = MV_DIR_FROM_BIT(i);
     int dir_opposite = MV_DIR_OPPOSITE(dir);
 
@@ -10607,13 +11038,7 @@ static int getClosedTube(int x, int y)
 
 static int getClosedBelt(int x, int y)
 {
-  static int xy[4][2] =
-  {
-    { -1, 0 },
-    { +1, 0 },
-    { 0, -1 },
-    { 0, +1 }
-  };
+  struct XY *xy = xy_directions;
   int element_old = IntelliDrawBuffer[x][y];
   int nr = getBeltNrFromBeltElement(element_old);
   int direction_old = getOpenDirectionFromBelt(element_old);
@@ -10622,8 +11047,8 @@ static int getClosedBelt(int x, int y)
 
   for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
   {
-    int xx = x + xy[i][0];
-    int yy = y + xy[i][1];
+    int xx = x + xy[i].x;
+    int yy = y + xy[i].y;
     int dir = MV_DIR_FROM_BIT(i);
     int dir_opposite = MV_DIR_OPPOSITE(dir);
 
@@ -10638,13 +11063,7 @@ static int getClosedBelt(int x, int y)
 
 static int getClosedPool(int x, int y)
 {
-  static int xy[4][2] =
-  {
-    { -1, 0 },
-    { +1, 0 },
-    { 0, -1 },
-    { 0, +1 }
-  };
+  struct XY *xy = xy_directions;
   int element_old = IntelliDrawBuffer[x][y];
   int direction_old = getOpenDirectionFromPool(element_old);
   int direction_new = MV_NONE;
@@ -10652,8 +11071,8 @@ static int getClosedPool(int x, int y)
 
   for (i = 0; i < NUM_DIRECTIONS; i++)
   {
-    int xx = x + xy[i][0];
-    int yy = y + xy[i][1];
+    int xx = x + xy[i].x;
+    int yy = y + xy[i].y;
     int dir = MV_DIR_FROM_BIT(i);
     int dir_opposite = MV_DIR_OPPOSITE(dir);
 
@@ -10669,13 +11088,7 @@ static int getClosedPool(int x, int y)
 
 static int getClosedPillar(int x, int y)
 {
-  static int xy[4][2] =
-  {
-    { -1, 0 },
-    { +1, 0 },
-    { 0, -1 },
-    { 0, +1 }
-  };
+  struct XY *xy = xy_directions;
   int element_old = IntelliDrawBuffer[x][y];
   int direction_old = getOpenDirectionFromPillar(element_old);
   int direction_new = MV_NONE;
@@ -10683,8 +11096,8 @@ static int getClosedPillar(int x, int y)
 
   for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
   {
-    int xx = x + xy[i][0];
-    int yy = y + xy[i][1];
+    int xx = x + xy[i].x;
+    int yy = y + xy[i].y;
     int dir = MV_DIR_FROM_BIT(i);
     int dir_opposite = MV_DIR_OPPOSITE(dir);
 
@@ -10699,13 +11112,7 @@ static int getClosedPillar(int x, int y)
 
 static int getClosedSteel2(int x, int y)
 {
-  static int xy[4][2] =
-  {
-    { -1, 0 },
-    { +1, 0 },
-    { 0, -1 },
-    { 0, +1 }
-  };
+  struct XY *xy = xy_directions;
   int element_old = IntelliDrawBuffer[x][y];
   int direction_old = getOpenDirectionFromSteel2(element_old);
   int direction_new = MV_NONE;
@@ -10713,8 +11120,8 @@ static int getClosedSteel2(int x, int y)
 
   for (i = 0; i < NUM_DIRECTIONS; i++)
   {
-    int xx = x + xy[i][0];
-    int yy = y + xy[i][1];
+    int xx = x + xy[i].x;
+    int yy = y + xy[i].y;
     int dir = MV_DIR_FROM_BIT(i);
     int dir_opposite = MV_DIR_OPPOSITE(dir);
 
@@ -10729,13 +11136,7 @@ static int getClosedSteel2(int x, int y)
 
 static int getClosedChip(int x, int y)
 {
-  static int xy[4][2] =
-  {
-    { -1, 0 },
-    { +1, 0 },
-    { 0, -1 },
-    { 0, +1 }
-  };
+  struct XY *xy = xy_directions;
   int element_old = IntelliDrawBuffer[x][y];
   int direction_old = getOpenDirectionFromChip(element_old);
   int direction_new = MV_NONE;
@@ -10743,8 +11144,8 @@ static int getClosedChip(int x, int y)
 
   for (i = 0; i < NUM_DIRECTIONS; i++)
   {
-    int xx = x + xy[i][0];
-    int yy = y + xy[i][1];
+    int xx = x + xy[i].x;
+    int yy = y + xy[i].y;
     int dir = MV_DIR_FROM_BIT(i);
     int dir_opposite = MV_DIR_OPPOSITE(dir);
 
@@ -10762,7 +11163,7 @@ static void SetElementSimpleExt(int x, int y, int dx, int dy, int element,
 {
   int sx = x - level_xpos;
   int sy = y - level_ypos;
-  int old_element = Feld[x][y];
+  int old_element = Tile[x][y];
   int new_element = element;
   unsigned int new_bitmask = (getDrawModeHiRes() ? (dx + 1) << (dy * 2) : 0x0f);
   boolean draw_masked = FALSE;
@@ -10788,7 +11189,7 @@ static void SetElementSimpleExt(int x, int y, int dx, int dy, int element,
   IntelliDrawBuffer[x][y] = element;
 
   if (change_level)
-    Feld[x][y] = element;
+    Tile[x][y] = element;
 
   if (IN_ED_FIELD(sx, sy))
   {
@@ -10824,19 +11225,12 @@ static void MergeAndCloseNeighbourElements(int x1, int y1, int *element1,
   SetElementSimple(x2, y2, *element2, change_level);
 }
 
-static void SetElementIntelliDraw(int x, int y, int new_element,
+static void SetElementIntelliDraw(int x, int y, int dx, int dy, int new_element,
                                  boolean change_level, int button)
 {
-  static int xy[4][2] =
-  {
-    { -1, 0 },
-    { +1, 0 },
-    { 0, -1 },
-    { 0, +1 }
-  };
+  struct XY *xy = xy_directions;
   static int last_x = -1;
   static int last_y = -1;
-  int old_element = IntelliDrawBuffer[x][y];
 
   if (new_element == EL_UNDEFINED)
   {
@@ -10846,6 +11240,8 @@ static void SetElementIntelliDraw(int x, int y, int new_element,
     return;
   }
 
+  int old_element = IntelliDrawBuffer[x][y];
+
   if (IS_TUBE(new_element))
   {
     int last_element_new = EL_UNDEFINED;
@@ -10858,8 +11254,8 @@ static void SetElementIntelliDraw(int x, int y, int new_element,
 
     for (i = 0; i < NUM_DIRECTIONS; i++)
     {
-      int xx = x + xy[i][0];
-      int yy = y + xy[i][1];
+      int xx = x + xy[i].x;
+      int yy = y + xy[i].y;
 
       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
          IS_TUBE(IntelliDrawBuffer[last_x][last_y]))
@@ -10896,8 +11292,8 @@ static void SetElementIntelliDraw(int x, int y, int new_element,
 
     for (i = MV_BIT_LEFT; i <= MV_BIT_RIGHT; i++)
     {
-      int xx = x + xy[i][0];
-      int yy = y + xy[i][1];
+      int xx = x + xy[i].x;
+      int yy = y + xy[i].y;
 
       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
          IS_BELT(IntelliDrawBuffer[last_x][last_y]))
@@ -10934,8 +11330,8 @@ static void SetElementIntelliDraw(int x, int y, int new_element,
 
     for (i = 0; i < NUM_DIRECTIONS; i++)
     {
-      int xx = x + xy[i][0];
-      int yy = y + xy[i][1];
+      int xx = x + xy[i].x;
+      int yy = y + xy[i].y;
 
       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
          IS_ACID_POOL_OR_ACID(IntelliDrawBuffer[last_x][last_y]))
@@ -10977,8 +11373,8 @@ static void SetElementIntelliDraw(int x, int y, int new_element,
 
     for (i = MV_BIT_UP; i <= MV_BIT_DOWN; i++)
     {
-      int xx = x + xy[i][0];
-      int yy = y + xy[i][1];
+      int xx = x + xy[i].x;
+      int yy = y + xy[i].y;
 
       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
          IS_EMC_PILLAR(IntelliDrawBuffer[last_x][last_y]))
@@ -11014,8 +11410,8 @@ static void SetElementIntelliDraw(int x, int y, int new_element,
 
     for (i = 0; i < NUM_DIRECTIONS; i++)
     {
-      int xx = x + xy[i][0];
-      int yy = y + xy[i][1];
+      int xx = x + xy[i].x;
+      int yy = y + xy[i].y;
 
       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
          IS_DC_STEELWALL_2(IntelliDrawBuffer[last_x][last_y]))
@@ -11049,8 +11445,8 @@ static void SetElementIntelliDraw(int x, int y, int new_element,
 
     for (i = 0; i < NUM_DIRECTIONS; i++)
     {
-      int xx = x + xy[i][0];
-      int yy = y + xy[i][1];
+      int xx = x + xy[i].x;
+      int yy = y + xy[i].y;
 
       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
          IS_SP_CHIP(IntelliDrawBuffer[last_x][last_y]))
@@ -11110,8 +11506,8 @@ static void SetElementIntelliDraw(int x, int y, int new_element,
 
     for (i = 0; i < NUM_DIRECTIONS; i++)
     {
-      int xx = x + xy[i][0];
-      int yy = y + xy[i][1];
+      int xx = x + xy[i].x;
+      int yy = y + xy[i].y;
 
       if (last_x == xx && last_y == yy && IN_LEV_FIELD(last_x, last_y) &&
          IS_IN_GROUP_EL(IntelliDrawBuffer[last_x][last_y], new_element))
@@ -11312,6 +11708,12 @@ static void SetElementIntelliDraw(int x, int y, int new_element,
        EL_DF_RECEIVER_DOWN,
        EL_DF_RECEIVER_LEFT
       },
+      {
+       EL_DF_SLOPE_1,
+       EL_DF_SLOPE_4,
+       EL_DF_SLOPE_3,
+       EL_DF_SLOPE_2
+      },
 
       {
        -1,
@@ -11528,6 +11930,24 @@ static void SetElementIntelliDraw(int x, int y, int new_element,
        EL_DF_MIRROR_ROTATING_3,
        EL_DF_MIRROR_ROTATING_2
       },
+      {
+       EL_DF_MIRROR_FIXED_1,
+       EL_DF_MIRROR_FIXED_16,
+       EL_DF_MIRROR_FIXED_15,
+       EL_DF_MIRROR_FIXED_14,
+       EL_DF_MIRROR_FIXED_13,
+       EL_DF_MIRROR_FIXED_12,
+       EL_DF_MIRROR_FIXED_11,
+       EL_DF_MIRROR_FIXED_10,
+       EL_DF_MIRROR_FIXED_9,
+       EL_DF_MIRROR_FIXED_8,
+       EL_DF_MIRROR_FIXED_7,
+       EL_DF_MIRROR_FIXED_6,
+       EL_DF_MIRROR_FIXED_5,
+       EL_DF_MIRROR_FIXED_4,
+       EL_DF_MIRROR_FIXED_3,
+       EL_DF_MIRROR_FIXED_2
+      },
 
       {
        -1,
@@ -11601,7 +12021,10 @@ static void SetElementIntelliDraw(int x, int y, int new_element,
     }
   }
 
-  SetElementSimple(x, y, new_element, change_level);
+  if (IS_MM_WALL_EDITOR(new_element))
+    SetElementSimpleExt(x, y, dx, dy, new_element, change_level);
+  else
+    SetElementSimple(x, y, new_element, change_level);
 
   last_x = x;
   last_y = y;
@@ -11613,18 +12036,36 @@ static void ResetIntelliDraw(void)
 
   for (x = 0; x < lev_fieldx; x++)
     for (y = 0; y < lev_fieldy; y++)
-      IntelliDrawBuffer[x][y] = Feld[x][y];
+      IntelliDrawBuffer[x][y] = Tile[x][y];
 
-  SetElementIntelliDraw(-1, -1, EL_UNDEFINED, FALSE, -1);
+  SetElementIntelliDraw(-1, -1, -1, -1, EL_UNDEFINED, FALSE, -1);
 }
 
 static boolean draw_mode_hires = FALSE;
 
+static boolean isHiresTileElement(int element)
+{
+  return (IS_MM_WALL(element)        || element == EL_EMPTY);
+}
+
+static boolean isHiresDrawElement(int element)
+{
+  return (IS_MM_WALL_EDITOR(element) || element == EL_EMPTY);
+}
+
+static int numHiresTiles(int element)
+{
+  if (IS_MM_WALL(element))
+    return get_number_of_bits(MM_WALL_BITS(element));
+
+  return 1;
+}
+
 static void SetDrawModeHiRes(int element)
 {
   draw_mode_hires =
     (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
-     (IS_MM_WALL_EDITOR(element) || element == EL_EMPTY));
+     isHiresDrawElement(element));
 }
 
 static boolean getDrawModeHiRes(void)
@@ -11646,9 +12087,9 @@ static void SetElementExt(int x, int y, int dx, int dy, int element,
                          boolean change_level, int button)
 {
   if (element < 0)
-    SetElementSimple(x, y, Feld[x][y], change_level);
-  else if (GetKeyModState() & KMOD_Shift && !IS_MM_WALL_EDITOR(element))
-    SetElementIntelliDraw(x, y, element, change_level, button);
+    SetElementSimple(x, y, Tile[x][y], change_level);
+  else if (GetKeyModState() & KMOD_Shift)
+    SetElementIntelliDraw(x, y, dx, dy, element, change_level, button);
   else
     SetElementSimpleExt(x, y, dx, dy, element, change_level);
 }
@@ -11690,7 +12131,7 @@ static int getLevelElementHiRes(int lx2, int ly2)
   int ly = ly2 / 2;
   int dx = lx2 % 2;
   int dy = ly2 % 2;
-  int element = Feld[lx][ly];
+  int element = Tile[lx][ly];
   unsigned int bitmask = (dx + 1) << (dy * 2);
 
   if (IS_MM_WALL(element))
@@ -11850,7 +12291,7 @@ static void DrawCircle(int from_x, int from_y, int to_x, int to_y,
   DrawArcExt(from_x, from_y, to_x2, to_y2, element, change_level);
   DrawArcExt(from_x, from_y, mirror_to_x2, to_y2, element, change_level);
   DrawArcExt(from_x, from_y, to_x2, mirror_to_y2, element, change_level);
-  DrawArcExt(from_x, from_y, mirror_to_x2, mirror_to_y2, element,change_level);
+  DrawArcExt(from_x, from_y, mirror_to_x2, mirror_to_y2, element, change_level);
 }
 #endif
 
@@ -11907,6 +12348,9 @@ static void SelectArea(int from_x, int from_y, int to_x, int to_y,
 #define CB_BRUSH_TO_CLIPBOARD          7
 #define CB_BRUSH_TO_CLIPBOARD_SMALL    8
 #define CB_UPDATE_BRUSH_POSITION       9
+#define CB_FLIP_BRUSH_X                        10
+#define CB_FLIP_BRUSH_Y                        11
+#define CB_FLIP_BRUSH_XY               12
 
 #define MAX_CB_PART_SIZE       10
 #define MAX_CB_LINE_SIZE       (MAX_LEV_FIELDX + 1)    // text plus newline
@@ -11915,6 +12359,185 @@ static void SelectArea(int from_x, int from_y, int to_x, int to_y,
                                 MAX_CB_NUM_LINES *     \
                                 MAX_CB_PART_SIZE)
 
+static int getFlippedTileExt(int map[], int element)
+{
+  int i;
+
+  for (i = 0; map[i] != -1; i++)
+    if (map[i] == element)
+      return map[i ^ 1];       // get flipped element by flipping LSB of index
+
+  return element;
+}
+
+static int getFlippedTileX(int element)
+{
+  int map[] =
+  {
+    EL_BD_BUTTERFLY_LEFT,              EL_BD_BUTTERFLY_RIGHT,
+    EL_BD_FIREFLY_LEFT,                        EL_BD_FIREFLY_RIGHT,
+    EL_BUG_LEFT,                       EL_BUG_RIGHT,
+    EL_SPACESHIP_LEFT,                 EL_SPACESHIP_RIGHT,
+    EL_PACMAN_LEFT,                    EL_PACMAN_RIGHT,
+    EL_ARROW_LEFT,                     EL_ARROW_RIGHT,
+    EL_MOLE_LEFT,                      EL_MOLE_RIGHT,
+    EL_BALLOON_SWITCH_LEFT,            EL_BALLOON_SWITCH_RIGHT,
+    EL_YAMYAM_LEFT,                    EL_YAMYAM_RIGHT,
+    EL_SP_PORT_LEFT,                   EL_SP_PORT_RIGHT,
+    EL_SP_GRAVITY_PORT_LEFT,           EL_SP_GRAVITY_PORT_RIGHT,
+    EL_SP_GRAVITY_ON_PORT_LEFT,                EL_SP_GRAVITY_ON_PORT_RIGHT,
+    EL_SP_GRAVITY_OFF_PORT_LEFT,       EL_SP_GRAVITY_OFF_PORT_RIGHT,
+    EL_CONVEYOR_BELT_1_LEFT,           EL_CONVEYOR_BELT_1_RIGHT,
+    EL_CONVEYOR_BELT_2_LEFT,           EL_CONVEYOR_BELT_2_RIGHT,
+    EL_CONVEYOR_BELT_3_LEFT,           EL_CONVEYOR_BELT_3_RIGHT,
+    EL_CONVEYOR_BELT_4_LEFT,           EL_CONVEYOR_BELT_4_RIGHT,
+    EL_SPRING_LEFT,                    EL_SPRING_RIGHT,
+    EL_SP_CHIP_LEFT,                   EL_SP_CHIP_RIGHT,
+    EL_TUBE_VERTICAL_LEFT,             EL_TUBE_VERTICAL_RIGHT,
+    EL_TUBE_LEFT_UP,                   EL_TUBE_RIGHT_UP,
+    EL_TUBE_LEFT_DOWN,                 EL_TUBE_RIGHT_DOWN,
+    EL_DC_STEELWALL_1_LEFT,            EL_DC_STEELWALL_1_RIGHT,
+    EL_DC_STEELWALL_1_TOPLEFT,         EL_DC_STEELWALL_1_TOPRIGHT,
+    EL_DC_STEELWALL_1_BOTTOMLEFT,      EL_DC_STEELWALL_1_BOTTOMRIGHT,
+    EL_DC_STEELWALL_1_TOPLEFT_2,       EL_DC_STEELWALL_1_TOPRIGHT_2,
+    EL_DC_STEELWALL_1_BOTTOMLEFT_2,    EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
+    EL_DC_STEELWALL_2_LEFT,            EL_DC_STEELWALL_2_RIGHT,
+    EL_ACID_POOL_TOPLEFT,              EL_ACID_POOL_TOPRIGHT,
+    EL_ACID_POOL_BOTTOMLEFT,           EL_ACID_POOL_BOTTOMRIGHT,
+
+    -1
+  };
+
+  return getFlippedTileExt(map, element);
+}
+
+static int getFlippedTileY(int element)
+{
+  int map[] =
+  {
+    EL_BD_BUTTERFLY_UP,                        EL_BD_BUTTERFLY_DOWN,
+    EL_BD_FIREFLY_UP,                  EL_BD_FIREFLY_DOWN,
+    EL_BUG_UP,                         EL_BUG_DOWN,
+    EL_SPACESHIP_UP,                   EL_SPACESHIP_DOWN,
+    EL_PACMAN_UP,                      EL_PACMAN_DOWN,
+    EL_ARROW_UP,                       EL_ARROW_DOWN,
+    EL_MOLE_UP,                                EL_MOLE_DOWN,
+    EL_BALLOON_SWITCH_UP,              EL_BALLOON_SWITCH_DOWN,
+    EL_YAMYAM_UP,                      EL_YAMYAM_DOWN,
+    EL_SP_PORT_UP,                     EL_SP_PORT_DOWN,
+    EL_SP_GRAVITY_PORT_UP,             EL_SP_GRAVITY_PORT_DOWN,
+    EL_SP_GRAVITY_ON_PORT_UP,          EL_SP_GRAVITY_ON_PORT_DOWN,
+    EL_SP_GRAVITY_OFF_PORT_UP,         EL_SP_GRAVITY_OFF_PORT_DOWN,
+    EL_SP_CHIP_TOP,                    EL_SP_CHIP_BOTTOM,
+    EL_TUBE_HORIZONTAL_UP,             EL_TUBE_HORIZONTAL_DOWN,
+    EL_TUBE_LEFT_UP,                   EL_TUBE_LEFT_DOWN,
+    EL_TUBE_RIGHT_UP,                  EL_TUBE_RIGHT_DOWN,
+    EL_DC_STEELWALL_1_TOP,             EL_DC_STEELWALL_1_BOTTOM,
+    EL_DC_STEELWALL_1_TOPLEFT,         EL_DC_STEELWALL_1_BOTTOMLEFT,
+    EL_DC_STEELWALL_1_TOPRIGHT,                EL_DC_STEELWALL_1_BOTTOMRIGHT,
+    EL_DC_STEELWALL_1_TOPLEFT_2,       EL_DC_STEELWALL_1_BOTTOMLEFT_2,
+    EL_DC_STEELWALL_1_TOPRIGHT_2,      EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
+    EL_DC_STEELWALL_2_TOP,             EL_DC_STEELWALL_2_BOTTOM,
+    EL_EMC_WALL_1,                     EL_EMC_WALL_3,
+
+    -1
+  };
+
+  return getFlippedTileExt(map, element);
+}
+
+static int getFlippedTileXY(int element)
+{
+  int map[] =
+  {
+    EL_BD_BUTTERFLY_LEFT,              EL_BD_BUTTERFLY_UP,
+    EL_BD_BUTTERFLY_RIGHT,             EL_BD_BUTTERFLY_DOWN,
+    EL_BD_FIREFLY_LEFT,                        EL_BD_FIREFLY_UP,
+    EL_BD_FIREFLY_RIGHT,               EL_BD_FIREFLY_DOWN,
+    EL_BUG_LEFT,                       EL_BUG_UP,
+    EL_BUG_RIGHT,                      EL_BUG_DOWN,
+    EL_SPACESHIP_LEFT,                 EL_SPACESHIP_UP,
+    EL_SPACESHIP_RIGHT,                        EL_SPACESHIP_DOWN,
+    EL_PACMAN_LEFT,                    EL_PACMAN_UP,
+    EL_PACMAN_RIGHT,                   EL_PACMAN_DOWN,
+    EL_ARROW_LEFT,                     EL_ARROW_UP,
+    EL_ARROW_RIGHT,                    EL_ARROW_DOWN,
+    EL_MOLE_LEFT,                      EL_MOLE_UP,
+    EL_MOLE_RIGHT,                     EL_MOLE_DOWN,
+    EL_BALLOON_SWITCH_LEFT,            EL_BALLOON_SWITCH_UP,
+    EL_BALLOON_SWITCH_RIGHT,           EL_BALLOON_SWITCH_DOWN,
+    EL_YAMYAM_LEFT,                    EL_YAMYAM_UP,
+    EL_YAMYAM_RIGHT,                   EL_YAMYAM_DOWN,
+    EL_SP_PORT_LEFT,                   EL_SP_PORT_UP,
+    EL_SP_PORT_RIGHT,                  EL_SP_PORT_DOWN,
+    EL_SP_GRAVITY_PORT_LEFT,           EL_SP_GRAVITY_PORT_UP,
+    EL_SP_GRAVITY_PORT_RIGHT,          EL_SP_GRAVITY_PORT_DOWN,
+    EL_SP_GRAVITY_ON_PORT_LEFT,                EL_SP_GRAVITY_ON_PORT_UP,
+    EL_SP_GRAVITY_ON_PORT_RIGHT,       EL_SP_GRAVITY_ON_PORT_DOWN,
+    EL_SP_GRAVITY_OFF_PORT_LEFT,       EL_SP_GRAVITY_OFF_PORT_UP,
+    EL_SP_GRAVITY_OFF_PORT_RIGHT,      EL_SP_GRAVITY_OFF_PORT_DOWN,
+    EL_SP_CHIP_LEFT,                   EL_SP_CHIP_TOP,
+    EL_SP_CHIP_RIGHT,                  EL_SP_CHIP_BOTTOM,
+    EL_TUBE_VERTICAL,                  EL_TUBE_HORIZONTAL,
+    EL_TUBE_VERTICAL_LEFT,             EL_TUBE_HORIZONTAL_UP,
+    EL_TUBE_VERTICAL_RIGHT,            EL_TUBE_HORIZONTAL_DOWN,
+    EL_TUBE_LEFT_DOWN,                 EL_TUBE_RIGHT_UP,
+    EL_DC_STEELWALL_1_LEFT,            EL_DC_STEELWALL_1_TOP,
+    EL_DC_STEELWALL_1_RIGHT,           EL_DC_STEELWALL_1_BOTTOM,
+    EL_DC_STEELWALL_1_HORIZONTAL,      EL_DC_STEELWALL_1_VERTICAL,
+    EL_DC_STEELWALL_1_TOPRIGHT,                EL_DC_STEELWALL_1_BOTTOMLEFT,
+    EL_DC_STEELWALL_1_TOPRIGHT_2,      EL_DC_STEELWALL_1_BOTTOMLEFT_2,
+    EL_DC_STEELWALL_2_LEFT,            EL_DC_STEELWALL_2_TOP,
+    EL_DC_STEELWALL_2_RIGHT,           EL_DC_STEELWALL_2_BOTTOM,
+    EL_DC_STEELWALL_2_HORIZONTAL,      EL_DC_STEELWALL_2_VERTICAL,
+    EL_EXPANDABLE_WALL_HORIZONTAL,     EL_EXPANDABLE_WALL_VERTICAL,
+    EL_EXPANDABLE_STEELWALL_HORIZONTAL,        EL_EXPANDABLE_STEELWALL_VERTICAL,
+
+    -1
+  };
+
+  return getFlippedTileExt(map, element);
+}
+
+static int getFlippedTile(int element, int mode)
+{
+  if (IS_MM_ELEMENT(element))
+  {
+    // get MM game element
+    element = map_element_RND_to_MM(element);
+
+    // get flipped game element
+    element = (mode == CB_FLIP_BRUSH_X  ? getFlippedTileX_MM(element) :
+              mode == CB_FLIP_BRUSH_Y  ? getFlippedTileY_MM(element) :
+              mode == CB_FLIP_BRUSH_XY ? getFlippedTileXY_MM(element) :
+              element);
+
+    // get RND game element again
+    element = map_element_MM_to_RND(element);
+  }
+  else
+  {
+    // get flipped game element
+    element = (mode == CB_FLIP_BRUSH_X  ? getFlippedTileX(element) :
+              mode == CB_FLIP_BRUSH_Y  ? getFlippedTileY(element) :
+              mode == CB_FLIP_BRUSH_XY ? getFlippedTileXY(element) :
+              element);
+  }
+
+  return element;
+}
+
+static void SwapFlippedTiles(short *tile1, short *tile2, int mode)
+{
+  // flip tiles
+  short tile1_flipped = getFlippedTile(*tile1, mode);
+  short tile2_flipped = getFlippedTile(*tile2, mode);
+
+  // swap tiles
+  *tile1 = tile2_flipped;
+  *tile2 = tile1_flipped;
+}
+
 static void DrawBrushElement(int sx, int sy, int element, boolean change_level)
 {
   DrawLineElement(sx, sy, element, change_level);
@@ -11942,27 +12565,28 @@ static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
     char text[MAX_CB_TEXT_SIZE + 1] = "";
     int width  = (draw_with_brush ? brush_width  : lev_fieldx);
     int height = (draw_with_brush ? brush_height : lev_fieldy);
+    char *format = "%s%03d";
+
+    for (y = 0; y < height; y++)
+      for (x = 0; x < width; x++)
+       if ((draw_with_brush ? brush_buffer[x][y] : Tile[x][y]) > 999)
+         format = "%s%04d";
 
     for (y = 0; y < height; y++)
     {
       for (x = 0; x < width; x++)
       {
-       int element = (draw_with_brush ? brush_buffer[x][y] : Feld[x][y]);
-       int element_mapped = element;
+       int element = (draw_with_brush ? brush_buffer[x][y] : Tile[x][y]);
        char *prefix = (mode == CB_DUMP_BRUSH ||
                        mode == CB_BRUSH_TO_CLIPBOARD ? "`" : "¸");
 
-       if (IS_CUSTOM_ELEMENT(element))
-         element_mapped = EL_CUSTOM_START;
-       else if (IS_GROUP_ELEMENT(element))
-         element_mapped = EL_GROUP_START;
-       else if (element >= NUM_FILE_ELEMENTS)
-         element_mapped = EL_UNKNOWN;
+       if (element >= NUM_FILE_ELEMENTS)
+         element = EL_UNKNOWN;
 
        // copy brush to level sketch text buffer for the R'n'D forum:
-       // - large tiles: `xxx (0x60 ASCII)
-       // - small tiles: Â¸xxx (0xb8 ISO-8859-1, 0xc2b8 UTF-8)
-       snprintf(part, MAX_CB_PART_SIZE + 1, "%s%03d", prefix, element_mapped);
+       // - large tiles: `xxx or `xxxx (0x60 ASCII)
+       // - small tiles: Â¸xxx or Â¸xxxx (0xb8 ISO-8859-1, 0xc2b8 UTF-8)
+       snprintf(part, MAX_CB_PART_SIZE + 1, format, prefix, element);
        strcat(text, part);
       }
 
@@ -11973,7 +12597,7 @@ static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
        mode == CB_BRUSH_TO_CLIPBOARD_SMALL)
       SDL_SetClipboardText(text);
     else
-      printf("%s", text);
+      Print("%s", text);       // print brush data to console and log file
 
     return;
   }
@@ -12009,11 +12633,13 @@ static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
 
     char *clipboard_text = SDL_GetClipboardText();
     char *ptr = clipboard_text;
+    boolean allow_new_row = FALSE;
     boolean stop = FALSE;
 
     while (*ptr && !stop)
     {
       boolean prefix_found = FALSE;
+      boolean start_new_row = FALSE;
 
       // level sketch element number prefixes (may be multi-byte characters)
       char *prefix_list[] = { "`", "¸" };
@@ -12042,19 +12668,10 @@ static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
        }
       }
 
-      // continue with next character if prefix not found
-      if (!prefix_found)
-      {
-       ptr++;          // !!! FIX THIS for real UTF-8 handling !!!
-
-       continue;
-      }
-
-      // continue with next character if prefix not found
-      if (strlen(ptr) < 3)
-       break;
-
-      if (ptr[0] >= '0' && ptr[0] <= '9' &&
+      // check if prefix found and followed by (at least) three digits
+      if (prefix_found &&
+         strlen(ptr) >= 3 &&
+         ptr[0] >= '0' && ptr[0] <= '9' &&
          ptr[1] >= '0' && ptr[1] <= '9' &&
          ptr[2] >= '0' && ptr[2] <= '9')
       {
@@ -12064,6 +12681,16 @@ static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
 
        ptr += 3;
 
+       // level sketch element number might consist of four digits
+       if (ptr[0] >= '0' && ptr[0] <= '9')
+       {
+         element = element * 10 + (ptr[0] - '0');
+         ptr++;
+       }
+
+       // remap some (historic, now obsolete) elements
+       element = getMappedElement(element);
+
        if (element >= NUM_FILE_ELEMENTS)
          element = EL_UNKNOWN;
 
@@ -12074,14 +12701,28 @@ static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
 
        x++;
 
-       if (x >= MAX_LEV_FIELDX || *ptr == '\n')
-       {
-         x = 0;
-         y++;
+       if (x >= MAX_LEV_FIELDX)
+         start_new_row = TRUE;
 
-         if (y >= MAX_LEV_FIELDY)
-           stop = TRUE;
-       }
+       allow_new_row = TRUE;
+      }
+      else
+      {
+       if ((*ptr == '\n' || *ptr == '\r') && allow_new_row)
+         start_new_row = TRUE;
+
+       ptr++;          // !!! FIX THIS for real UTF-8 handling !!!
+      }
+
+      if (start_new_row)
+      {
+       x = 0;
+       y++;
+
+       if (y >= MAX_LEV_FIELDY)
+         stop = TRUE;
+
+       allow_new_row = FALSE;
       }
     }
 
@@ -12120,11 +12761,41 @@ static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
 
       for (x = 0; x < MAX_LEV_FIELDX; x++)
        for (y = 0; y < MAX_LEV_FIELDY; y++)
-         Feld[x][y] = brush_buffer[x][y];
+         Tile[x][y] = brush_buffer[x][y];
 
       lev_fieldx = level.fieldx = brush_width;
       lev_fieldy = level.fieldy = brush_height;
 
+      boolean use_em_engine = TRUE;
+      boolean use_sp_engine = TRUE;
+      boolean use_mm_engine = TRUE;
+
+      for (x = 0; x < MAX_LEV_FIELDX; x++)
+      {
+       for (y = 0; y < MAX_LEV_FIELDY; y++)
+       {
+         int element = Tile[x][y];
+
+         if (!IS_EM_ELEMENT(element) && !IS_PLAYER_ELEMENT(element))
+           use_em_engine = FALSE;
+
+         if (!IS_SP_ELEMENT(element))
+           use_sp_engine = FALSE;
+
+         if (!IS_MM_ELEMENT(element) && element != EL_EMPTY)
+           use_mm_engine = FALSE;
+       }
+      }
+
+      level.game_engine_type = (use_em_engine ? GAME_ENGINE_TYPE_EM :
+                               use_sp_engine ? GAME_ENGINE_TYPE_SP :
+                               use_mm_engine ? GAME_ENGINE_TYPE_MM :
+                               GAME_ENGINE_TYPE_RND);
+
+      // update element selection list
+      ReinitializeElementList();
+      ModifyEditorElementList();
+
       SetBorderElement();
 
       DrawEditModeWindow();
@@ -12157,7 +12828,7 @@ static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
     {
       for (x = 0; x < brush_width; x++)
       {
-       brush_buffer[x][y] = Feld[from_lx + x][from_ly + y];
+       brush_buffer[x][y] = Tile[from_lx + x][from_ly + y];
 
        if (button != 1)
          DrawBrushElement(from_x + x, from_y + y, new_element, TRUE);
@@ -12227,6 +12898,37 @@ static void CopyBrushExt(int from_x, int from_y, int to_x, int to_y,
 
     delete_old_brush = TRUE;
   }
+  else if (mode == CB_FLIP_BRUSH_X)
+  {
+    for (y = 0; y < brush_height; y++)
+      for (x = 0; x < (brush_width + 1) / 2; x++)
+       SwapFlippedTiles(&brush_buffer[x][y],
+                        &brush_buffer[brush_width - x - 1][y], mode);
+
+    CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
+  }
+  else if (mode == CB_FLIP_BRUSH_Y)
+  {
+    for (y = 0; y < (brush_height + 1) / 2; y++)
+      for (x = 0; x < brush_width; x++)
+       SwapFlippedTiles(&brush_buffer[x][y],
+                        &brush_buffer[x][brush_height - y - 1], mode);
+
+    CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
+  }
+  else if (mode == CB_FLIP_BRUSH_XY)
+  {
+    CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
+
+    for (y = 0; y < MAX(brush_width, brush_height); y++)
+      for (x = 0; x <= y; x++)
+       SwapFlippedTiles(&brush_buffer[x][y],
+                        &brush_buffer[y][x], mode);
+
+    swap_numbers(&brush_width, &brush_height);
+
+    CopyBrushExt(last_cursor_x, last_cursor_y, 0, 0, 0, CB_BRUSH_TO_CURSOR);
+  }
 
   if (mode == CB_UPDATE_BRUSH_POSITION)
   {
@@ -12261,6 +12963,22 @@ static void DeleteBrushFromCursor(void)
   CopyBrushExt(0, 0, 0, 0, 0, CB_DELETE_OLD_CURSOR);
 }
 
+static void FlipBrushX(void)
+{
+  CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_X);
+}
+
+static void FlipBrushY(void)
+{
+  CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_Y);
+}
+
+static void RotateBrush(void)
+{
+  CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_XY);
+  CopyBrushExt(0, 0, 0, 0, 0, CB_FLIP_BRUSH_X);
+}
+
 void DumpBrush(void)
 {
   CopyBrushExt(0, 0, 0, 0, 0, CB_DUMP_BRUSH);
@@ -12286,9 +13004,19 @@ void CopyBrushToClipboard_Small(void)
   CopyBrushExt(0, 0, 0, 0, 0, CB_BRUSH_TO_CLIPBOARD_SMALL);
 }
 
+void UndoLevelEditorOperation(void)
+{
+  ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], -1);
+}
+
+void RedoLevelEditorOperation(void)
+{
+  ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], 3);
+}
+
 static void FloodFill(int from_x, int from_y, int fill_element)
 {
-  FloodFillLevel(from_x, from_y, fill_element, Feld, lev_fieldx, lev_fieldy);
+  FloodFillLevel(from_x, from_y, fill_element, Tile, lev_fieldx, lev_fieldy);
 }
 
 static void FloodFillWall_MM(int from_sx2, int from_sy2, int fill_element)
@@ -12297,20 +13025,20 @@ static void FloodFillWall_MM(int from_sx2, int from_sy2, int fill_element)
   int from_y = from_sy2 + 2 * level_ypos;
   int max_fillx = lev_fieldx * 2;
   int max_filly = lev_fieldy * 2;
-  short FillFeld[max_fillx][max_filly];
+  short Fill[max_fillx][max_filly];
   int x, y;
 
   for (x = 0; x < max_fillx; x++)
     for (y = 0; y < max_filly; y++)
-      FillFeld[x][y] = getLevelElementHiRes(x, y);
+      Fill[x][y] = getLevelElementHiRes(x, y);
 
   FloodFillLevelExt(from_x, from_y, fill_element, max_fillx, max_filly,
-                   FillFeld, max_fillx, max_filly);
+                   Fill, max_fillx, max_filly);
 
   for (x = 0; x < max_fillx; x++)
     for (y = 0; y < max_filly; y++)
-      if (FillFeld[x][y] == fill_element)
-       SetLevelElementHiRes(x, y, FillFeld[x][y]);
+      if (Fill[x][y] == fill_element)
+       SetLevelElementHiRes(x, y, Fill[x][y]);
 }
 
 // values for DrawLevelText() modes
@@ -12328,7 +13056,7 @@ static int DrawLevelText(int sx, int sy, char letter, int mode)
   static int start_sx;
   static int last_sx, last_sy;
   static boolean typing = FALSE;
-  int letter_element = EL_CHAR_ASCII0 + letter;
+  int letter_element;
   int lx = 0, ly = 0;
 
   // map lower case letters to upper case and convert special characters
@@ -12374,8 +13102,10 @@ static int DrawLevelText(int sx, int sy, char letter, int mode)
       break;
 
     case TEXT_SETCURSOR:
-      DrawEditorElement(last_sx, last_sy, Feld[lx][ly]);
+      DrawEditorElement(last_sx, last_sy, Tile[lx][ly]);
       DrawAreaBorder(sx, sy, sx, sy);
+      StartTextInput(SX + sx * ed_tilesize, SY + sy * ed_tilesize,
+                    ed_tilesize, ed_tilesize);
       last_sx = sx;
       last_sy = sy;
       break;
@@ -12387,8 +13117,8 @@ static int DrawLevelText(int sx, int sy, char letter, int mode)
            new_element1 <= EL_STEEL_CHAR_END)
          letter_element = letter_element - EL_CHAR_START + EL_STEEL_CHAR_START;
 
-       delete_buffer[sx - start_sx] = Feld[lx][ly];
-       Feld[lx][ly] = letter_element;
+       delete_buffer[sx - start_sx] = Tile[lx][ly];
+       Tile[lx][ly] = letter_element;
 
        if (sx + 1 < ed_fieldx && lx + 1 < lev_fieldx)
          DrawLevelText(sx + 1, sy, 0, TEXT_SETCURSOR);
@@ -12404,8 +13134,8 @@ static int DrawLevelText(int sx, int sy, char letter, int mode)
     case TEXT_BACKSPACE:
       if (sx > start_sx)
       {
-       Feld[lx - 1][ly] = delete_buffer[sx - start_sx - 1];
-       DrawEditorElement(sx - 1, sy, Feld[lx - 1][ly]);
+       Tile[lx - 1][ly] = delete_buffer[sx - start_sx - 1];
+       DrawEditorElement(sx - 1, sy, Tile[lx - 1][ly]);
        DrawLevelText(sx - 1, sy, 0, TEXT_SETCURSOR);
       }
       break;
@@ -12419,7 +13149,8 @@ static int DrawLevelText(int sx, int sy, char letter, int mode)
 
     case TEXT_END:
       CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
-      DrawEditorElement(sx, sy, Feld[lx][ly]);
+      DrawEditorElement(sx, sy, Tile[lx][ly]);
+      StopTextInput();
       typing = FALSE;
       break;
 
@@ -12440,7 +13171,7 @@ static void SetTextCursor(int unused_sx, int unused_sy, int sx, int sy,
   int ly = sy + level_ypos;
 
   if (element == -1)
-    DrawEditorElement(sx, sy, Feld[lx][ly]);
+    DrawEditorElement(sx, sy, Tile[lx][ly]);
   else
     DrawAreaBorder(sx, sy, sx, sy);
 }
@@ -12494,7 +13225,7 @@ static void CopyLevelToUndoBuffer(int mode)
 
   for (x = 0; x < lev_fieldx; x++)
     for (y = 0; y < lev_fieldy; y++)
-      UndoBuffer[undo_buffer_position][x][y] = Feld[x][y];
+      UndoBuffer[undo_buffer_position][x][y] = Tile[x][y];
 
   // check if drawing operation forces change of border style
   CheckLevelBorderElement(TRUE);
@@ -12516,8 +13247,8 @@ static void RandomPlacement(int new_element)
   {
     free_position[x][y] =
       (random_placement_background_restricted ?
-       Feld[x][y] == random_placement_background_element :
-       Feld[x][y] != new_element);
+       Tile[x][y] == random_placement_background_element :
+       Tile[x][y] != new_element);
 
     if (free_position[x][y])
       num_free_positions++;
@@ -12565,17 +13296,98 @@ static void WrapLevel(int dx, int dy)
 
   for (x = 0; x < lev_fieldx; x++)
     for (y = 0; y < lev_fieldy; y++)
-      FieldBackup[x][y] = Feld[x][y];
+      TileBackup[x][y] = Tile[x][y];
 
   for (x = 0; x < lev_fieldx; x++)
     for (y = 0; y < lev_fieldy; y++)
-      Feld[x][y] =
-       FieldBackup[(x + wrap_dx) % lev_fieldx][(y + wrap_dy) % lev_fieldy];
+      Tile[x][y] =
+       TileBackup[(x + wrap_dx) % lev_fieldx][(y + wrap_dy) % lev_fieldy];
 
   DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
   CopyLevelToUndoBuffer(UNDO_ACCUMULATE);
 }
 
+static void DrawAreaElementHighlight(boolean highlighted,
+                                    boolean highlighted_similar)
+{
+  DrawEditorLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
+
+  if (!highlighted)
+    return;
+
+  int x, y;
+
+  for (x = 0; x < ed_fieldx; x++)
+  {
+    for (y = 0; y < ed_fieldy; y++)
+    {
+      boolean highlight = FALSE;
+      int lx = x + level_xpos;
+      int ly = y + level_ypos;
+
+      if (!IN_LEV_FIELD(lx, ly))
+       continue;
+
+      // check if element is the same
+      if (Tile[lx][ly] == new_element1)
+       highlight = TRUE;
+
+      // check if element is similar
+      if (highlighted_similar &&
+         strEqual(element_info[Tile[lx][ly]].class_name,
+                  element_info[new_element1].class_name))
+       highlight = TRUE;
+
+      // check if element is matching MM style wall
+      if (IS_MM_WALL(Tile[lx][ly]) &&
+         map_mm_wall_element(Tile[lx][ly]) == new_element1)
+       highlight = TRUE;
+
+      if (!highlight)
+       continue;
+
+      if (IS_MM_WALL(Tile[lx][ly]) && !highlighted_similar)
+      {
+       int i;
+
+       for (i = 0; i < 4; i++)
+       {
+         if (!(MM_WALL_BITS(Tile[lx][ly]) & (1 << i)))
+           continue;
+
+         int xx = x * 2 + (i % 2);
+         int yy = y * 2 + (i / 2);
+         int sx = SX + xx * ed_tilesize / 2;
+         int sy = SY + yy * ed_tilesize / 2;
+         int from_sx = sx;
+         int from_sy = sy;
+         int to_sx = sx + ed_tilesize / 2 - 1;
+         int to_sy = sy + ed_tilesize / 2 - 1;
+
+         DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx,   from_sy);
+         DrawSimpleWhiteLine(drawto, to_sx,   from_sy, to_sx,   to_sy);
+         DrawSimpleWhiteLine(drawto, to_sx,   to_sy,   from_sx, to_sy);
+         DrawSimpleWhiteLine(drawto, from_sx, to_sy,   from_sx, from_sy);
+       }
+      }
+      else
+      {
+       int sx = SX + x * ed_tilesize;
+       int sy = SY + y * ed_tilesize;
+       int from_sx = sx;
+       int from_sy = sy;
+       int to_sx = sx + ed_tilesize - 1;
+       int to_sy = sy + ed_tilesize - 1;
+
+       DrawSimpleWhiteLine(drawto, from_sx, from_sy, to_sx,   from_sy);
+       DrawSimpleWhiteLine(drawto, to_sx,   from_sy, to_sx,   to_sy);
+       DrawSimpleWhiteLine(drawto, to_sx,   to_sy,   from_sx, to_sy);
+       DrawSimpleWhiteLine(drawto, from_sx, to_sy,   from_sx, from_sy);
+      }
+    }
+  }
+}
+
 static void CopyLevelTemplateToUserLevelSet(char *levelset_subdir)
 {
   char *template_filename_old = getLocalLevelTemplateFilename();
@@ -12591,8 +13403,10 @@ static void CopyLevelTemplateToUserLevelSet(char *levelset_subdir)
 static void HandleDrawingAreas(struct GadgetInfo *gi)
 {
   static boolean started_inside_drawing_area = FALSE;
-  static int last_sx = -1, last_sy = -1;
-  static int last_sx2 = -1, last_sy2 = -1;
+  static int last_sx = -1;
+  static int last_sy = -1;
+  static int last_sx2 = -1;
+  static int last_sy2 = -1;
   int id = gi->custom_id;
   int type_id = gi->custom_type_id;
   boolean button_press_event;
@@ -12612,8 +13426,6 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
   int dx = sx2 % 2;
   int dy = sy2 % 2;
   int lx = 0, ly = 0;
-  int min_lx = 0, min_ly = 0;
-  int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
   int x, y;
 
   button_press_event = (gi->event.type == GD_EVENT_PRESSED);
@@ -12625,6 +13437,9 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
 
   if (draw_level)
   {
+    int min_lx = 0, min_ly = 0;
+    int max_lx = lev_fieldx - 1, max_ly = lev_fieldy - 1;
+
     // get positions inside level field
     lx = sx + level_xpos;
     ly = sy + level_ypos;
@@ -12653,18 +13468,15 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
     sy2 = sy * 2 + dy;
   }
 
-  if (button_release_event)
-  {
-    last_sx = -1;
-    last_sy = -1;
-    last_sx2 = -1;
-    last_sy2 = -1;
-  }
-  else if (!button_press_event)
+  if (!button_press_event && !button_release_event)
   {
+    int old_element = (IN_LEV_FIELD(lx, ly) ? Tile[lx][ly] : EL_UNDEFINED);
+    boolean hires_drawing = (level.game_engine_type == GAME_ENGINE_TYPE_MM &&
+                            isHiresTileElement(old_element) &&
+                            isHiresDrawElement(new_element));
+
     // prevent handling events for every pixel position when moving mouse
-    if ((sx == last_sx && sy == last_sy &&
-        !IS_MM_WALL_EDITOR(new_element) && new_element != EL_EMPTY) ||
+    if ((sx == last_sx && sy == last_sy && !hires_drawing) ||
        (sx2 == last_sx2 && sy2 == last_sy2))
       return;
   }
@@ -12683,9 +13495,6 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
   if (!IS_VALID_BUTTON(button))
     return;
 
-  if (!button && !button_release_event)
-    return;
-
   // handle info callback for each invocation of action callback
   gi->callback_info(gi);
 
@@ -12721,10 +13530,9 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
          if (edit_mode == ED_MODE_DRAWING && draw_with_brush &&
              !inside_drawing_area)
            DeleteBrushFromCursor();
-       }
 
-       if (!button || button_release_event)
          break;
+       }
 
        if (draw_with_brush)
        {
@@ -12734,13 +13542,44 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
        {
          SetDrawModeHiRes(new_element);
 
-         if (new_element == EL_PLAYER_1)
+         if (IS_PLAYER_ELEMENT(new_element) || IS_MM_MCDUFFIN(new_element))
          {
            // remove player at old position
            for (y = 0; y < lev_fieldy; y++)
+           {
              for (x = 0; x < lev_fieldx; x++)
-               if (Feld[x][y] == EL_PLAYER_1)
+             {
+               int old_element = Tile[x][y];
+
+               if (IS_PLAYER_ELEMENT(old_element) &&
+                   IS_PLAYER_ELEMENT(new_element))
+               {
+                 int replaced_with_element =
+                   (old_element == EL_SOKOBAN_FIELD_PLAYER &&
+                    new_element == EL_PLAYER_1 ? EL_SOKOBAN_FIELD_EMPTY :
+
+                    old_element == EL_SOKOBAN_FIELD_PLAYER &&
+                    new_element == old_element ? EL_SOKOBAN_FIELD_EMPTY :
+
+                    new_element == EL_SOKOBAN_FIELD_PLAYER &&
+                    old_element == EL_PLAYER_1 ? EL_EMPTY :
+
+                    new_element >= EL_PLAYER_1 &&
+                    new_element <= EL_PLAYER_4 &&
+                    new_element == old_element ? EL_EMPTY :
+
+                    old_element);
+
+                 SetElement(x, y, replaced_with_element);
+               }
+               else if (IS_MM_MCDUFFIN(old_element) &&
+                        IS_MM_MCDUFFIN(new_element))
+               {
+                 // remove McDuffin at old position
                  SetElement(x, y, EL_EMPTY);
+               }
+             }
+           }
          }
 
          SetElementButton(lx, ly, dx, dy, new_element, button);
@@ -12785,22 +13624,19 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
        if (button_release_event)
          CopyLevelToUndoBuffer(UNDO_IMMEDIATE);
 
-       if (button)
-       {
-         SetDrawModeHiRes(new_element);
+       SetDrawModeHiRes(new_element);
 
-         if (getDrawModeHiRes())
-         {
-           sx = sx2;
-           sy = sy2;
-         }
+       if (getDrawModeHiRes())
+       {
+         sx = sx2;
+         sy = sy2;
+       }
 
-         if (!button_press_event)
-           DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
+       if (!button_press_event)
+         DrawLine(last_sx, last_sy, sx, sy, new_element, TRUE);
 
-         last_sx = sx;
-         last_sy = sy;
-       }
+       last_sx = sx;
+       last_sy = sy;
       }
       break;
 
@@ -12876,7 +13712,7 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
       break;
 
     case GADGET_ID_FLOOD_FILL:
-      if (button_press_event && Feld[lx][ly] != new_element)
+      if (button_press_event && Tile[lx][ly] != new_element)
       {
        if (IS_MM_WALL_EDITOR(new_element))
          FloodFillWall_MM(sx2, sy2, new_element);
@@ -12893,7 +13729,7 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
        ClickOnGadget(level_editor_gadget[last_drawing_function],
                      MB_LEFTBUTTON);
       else if (draw_level)
-       PickDrawingElement(button, Feld[lx][ly]);
+       PickDrawingElement(button, Tile[lx][ly]);
       else
       {
        int pos = sx * drawingarea_info[type_id].area_ysize + sy;
@@ -12983,11 +13819,11 @@ static void HandleCounterButtons(struct GadgetInfo *gi)
       break;
 
     case ED_COUNTER_ID_ANDROID_CONTENT:
-      DrawAndroidElementArea(properties_element);
+      DrawAndroidElementArea();
       break;
 
     case ED_COUNTER_ID_GROUP_CONTENT:
-      DrawGroupElementArea(properties_element);
+      DrawGroupElementArea();
       CopyGroupElementPropertiesToGame(properties_element);
       break;
 
@@ -12995,6 +13831,10 @@ static void HandleCounterButtons(struct GadgetInfo *gi)
       DrawPlayerInitialInventoryArea(properties_element);
       break;
 
+    case ED_COUNTER_ID_MM_BALL_CONTENT:
+      DrawMMBallContentArea();
+      break;
+
     case ED_COUNTER_ID_ENVELOPE_XSIZE:
     case ED_COUNTER_ID_ENVELOPE_YSIZE:
       DrawEnvelopeTextArea(-1);
@@ -13072,7 +13912,7 @@ static void HandleSelectboxGadgets(struct GadgetInfo *gi)
 
   if (type_id == ED_SELECTBOX_ID_LEVELSET_SAVE_MODE)
   {
-    DrawLevelInfoWindow();
+    DrawLevelConfigWindow();
   }
   else if (type_id == ED_SELECTBOX_ID_SELECT_CHANGE_PAGE)
   {
@@ -13117,12 +13957,12 @@ static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
   int type_id = gi->custom_type_id;
   int i;
 
-  if (type_id >= ED_TAB_BUTTON_ID_LEVELINFO_FIRST &&
-      type_id <= ED_TAB_BUTTON_ID_LEVELINFO_LAST)
+  if (type_id >= ED_TAB_BUTTON_ID_LEVELCONFIG_FIRST &&
+      type_id <= ED_TAB_BUTTON_ID_LEVELCONFIG_LAST)
   {
-    edit_mode_levelinfo = gi->custom_type_id;
+    edit_mode_levelconfig = gi->custom_type_id;
 
-    DrawLevelInfoWindow();
+    DrawLevelConfigWindow();
   }
   else if (type_id >= ED_TAB_BUTTON_ID_PROPERTIES_FIRST &&
           type_id <= ED_TAB_BUTTON_ID_PROPERTIES_LAST)
@@ -13137,10 +13977,10 @@ static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
     boolean new_template = !fileExists(getLocalLevelTemplateFilename());
 
     // backup original "level.field" (needed to track playfield changes)
-    CopyPlayfield(level.field, FieldBackup);
+    CopyPlayfield(level.field, TileBackup);
 
     // "SaveLevelTemplate()" uses "level.field", so copy editor playfield
-    CopyPlayfield(Feld, level.field);
+    CopyPlayfield(Tile, level.field);
 
     if (new_template ||
        Request("Save this template and kill the old?", REQ_ASK))
@@ -13150,7 +13990,7 @@ static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
       Request("Template saved!", REQ_CONFIRM);
 
     // restore original "level.field" (needed to track playfield changes)
-    CopyPlayfield(FieldBackup, level.field);
+    CopyPlayfield(TileBackup, level.field);
   }
   else if (type_id == ED_TEXTBUTTON_ID_SAVE_LEVELSET)
   {
@@ -13159,7 +13999,7 @@ static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
     if (levelset_save_mode == LEVELSET_SAVE_MODE_UPDATE &&
        leveldir_current->readonly)
     {
-      Request("This level set is read only!", REQ_CONFIRM);
+      Request("This level set is read-only!", REQ_CONFIRM);
 
       return;
     }
@@ -13350,9 +14190,11 @@ static void HandleCheckbuttons(struct GadgetInfo *gi)
     boolean template_related_changes_found = FALSE;
     int i;
 
-    // check if any custom or group elements have been changed
+    // check if any custom, group or empty elements have been changed
     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
-      if ((IS_CUSTOM_ELEMENT(i) || IS_GROUP_ELEMENT(i)) &&
+      if ((IS_CUSTOM_ELEMENT(i) ||
+          IS_GROUP_ELEMENT(i) ||
+          IS_EMPTY_ELEMENT(i)) &&
          element_info[i].modified_settings)
        template_related_changes_found = TRUE;
 
@@ -13620,7 +14462,7 @@ static void HandleControlButtons(struct GadgetInfo *gi)
       }
       else
       {
-       ChangeEditModeWindow(last_edit_mode);
+       ChangeEditModeWindow(ED_MODE_DRAWING);
 
        ClickOnGadget(level_editor_gadget[last_level_drawing_function],
                      MB_LEFTBUTTON);
@@ -13682,6 +14524,10 @@ static void HandleControlButtons(struct GadgetInfo *gi)
                     button == 2 ? ed_tilesize_default :
                     button == 3 ? ed_tilesize / 2 : ed_tilesize);
 
+      // when using touch device, cycle through all zoom tilesizes
+      if (runtime.uses_touch_device && ed_tilesize > TILESIZE)
+       ed_tilesize = MICRO_TILESIZE;
+
       // limit zoom level by upper and lower bound
       ed_tilesize = MIN(MAX(MICRO_TILESIZE, ed_tilesize), TILESIZE);
 
@@ -13716,7 +14562,9 @@ static void HandleControlButtons(struct GadgetInfo *gi)
       break;
 
     case GADGET_ID_UNDO:
-      if (button == 1 && GetKeyModState() & (KMOD_Shift|KMOD_Control))
+      if (button < 0)  // keep button value (even if modifier keys are pressed)
+       button = -button;
+      else if (button == 1 && GetKeyModState() & (KMOD_Shift | KMOD_Control))
        button = 3;
 
       if (button == 1 && undo_buffer_steps == 0)
@@ -13761,7 +14609,7 @@ static void HandleControlButtons(struct GadgetInfo *gi)
 
       for (x = 0; x < lev_fieldx; x++)
        for (y = 0; y < lev_fieldy; y++)
-         Feld[x][y] = UndoBuffer[undo_buffer_position][x][y];
+         Tile[x][y] = UndoBuffer[undo_buffer_position][x][y];
 
       // check if undo operation forces change of border style
       CheckLevelBorderElement(FALSE);
@@ -13770,16 +14618,16 @@ static void HandleControlButtons(struct GadgetInfo *gi)
 
       break;
 
-    case GADGET_ID_INFO:
-      if (edit_mode != ED_MODE_INFO)
+    case GADGET_ID_CONF:
+      if (edit_mode != ED_MODE_LEVELCONFIG)
       {
        last_edit_mode = edit_mode;
 
-       ChangeEditModeWindow(ED_MODE_INFO);
+       ChangeEditModeWindow(ED_MODE_LEVELCONFIG);
       }
       else
       {
-       ChangeEditModeWindow(last_edit_mode);
+       ChangeEditModeWindow(ED_MODE_DRAWING);
       }
       break;
 
@@ -13789,7 +14637,7 @@ static void HandleControlButtons(struct GadgetInfo *gi)
 
       for (x = 0; x < MAX_LEV_FIELDX; x++)
        for (y = 0; y < MAX_LEV_FIELDY; y++)
-         Feld[x][y] = (button == 1 ? EL_EMPTY : new_element);
+         Tile[x][y] = (button == 1 ? EL_EMPTY : new_element);
 
       CopyLevelToUndoBuffer(GADGET_ID_CLEAR);
 
@@ -13816,11 +14664,11 @@ static void HandleControlButtons(struct GadgetInfo *gi)
          Request("Save this level and kill the old?", REQ_ASK))
       {
        if (leveldir_former->readonly)
-         ModifyLevelInfoForSavingIntoPersonalLevelSet(leveldir_former->name);
+         ModifyLevelConfigForSavingIntoPersonalLevelSet(leveldir_former->name);
 
        SetAutomaticNumberOfGemsNeeded();
 
-       CopyPlayfield(Feld, level.field);
+       CopyPlayfield(Tile, level.field);
        SaveLevel(level_nr);
 
        level.changed = FALSE;
@@ -13851,8 +14699,8 @@ static void HandleControlButtons(struct GadgetInfo *gi)
       if (LevelChanged())
        level.game_version = GAME_VERSION_ACTUAL;
 
-      CopyPlayfield(level.field, FieldBackup);
-      CopyPlayfield(Feld, level.field);
+      CopyPlayfield(level.field, TileBackup);
+      CopyPlayfield(Tile, level.field);
 
       CopyNativeLevel_RND_to_Native(&level);
 
@@ -13881,7 +14729,8 @@ static void HandleControlButtons(struct GadgetInfo *gi)
          id <= GADGET_ID_ELEMENTLIST_LAST)
       {
        int element_position = id - GADGET_ID_ELEMENTLIST_FIRST;
-       int new_element = editor_elements[element_position + element_shift];
+
+       new_element = editor_elements[element_position + element_shift];
 
        if (IS_EDITOR_CASCADE(new_element))
        {
@@ -13952,13 +14801,13 @@ static void HandleControlButtons(struct GadgetInfo *gi)
       }
 #ifdef DEBUG
       else if (gi->event.type == GD_EVENT_PRESSED)
-       printf("default: HandleControlButtons: GD_EVENT_PRESSED(%d)\n", id);
+       Debug("editor", "default: HandleControlButtons: GD_EVENT_PRESSED(%d)", id);
       else if (gi->event.type == GD_EVENT_RELEASED)
-       printf("default: HandleControlButtons: GD_EVENT_RELEASED(%d)\n", id);
+       Debug("editor", "default: HandleControlButtons: GD_EVENT_RELEASED(%d)", id);
       else if (gi->event.type == GD_EVENT_MOVING)
-       printf("default: HandleControlButtons: GD_EVENT_MOVING(%d)\n", id);
+       Debug("editor", "default: HandleControlButtons: GD_EVENT_MOVING(%d)", id);
       else
-       printf("default: HandleControlButtons: ? (id == %d)\n", id);
+       Debug("editor", "default: HandleControlButtons: ? (id == %d)", id);
 #endif
       break;
   }
@@ -13967,7 +14816,6 @@ static void HandleControlButtons(struct GadgetInfo *gi)
 void HandleLevelEditorKeyInput(Key key)
 {
   char letter = getCharFromKey(key);
-  int button = MB_LEFTBUTTON;
 
   if (drawing_function == GADGET_ID_TEXT &&
       DrawLevelText(0, 0, 0, TEXT_QUERY_TYPING) == TRUE)
@@ -13980,165 +14828,164 @@ void HandleLevelEditorKeyInput(Key key)
       DrawLevelText(0, 0, 0, TEXT_NEWLINE);
     else if (key == KSYM_Escape)
       DrawLevelText(0, 0, 0, TEXT_END);
+
+    return;
   }
-  else if (button_status == MB_RELEASED)
+
+  int id = GADGET_ID_NONE;
+  int new_element_shift = element_shift;
+  int step = ED_ELEMENTLIST_BUTTONS_VERT - 1;
+  int button = MB_LEFTBUTTON;
+  int i;
+
+  switch (key)
   {
-    int id = GADGET_ID_NONE;
-    int new_element_shift = element_shift;
-    int step = ED_ELEMENTLIST_BUTTONS_VERT - 1;
-    int i;
+    case KSYM_Left:
+      id = GADGET_ID_SCROLL_LEFT;
+      break;
+    case KSYM_Right:
+      id = GADGET_ID_SCROLL_RIGHT;
+      break;
+    case KSYM_Up:
+      id = GADGET_ID_SCROLL_UP;
+      break;
+    case KSYM_Down:
+      id = GADGET_ID_SCROLL_DOWN;
+      break;
 
-    switch (key)
-    {
-      case KSYM_Left:
-       id = GADGET_ID_SCROLL_LEFT;
-       break;
-      case KSYM_Right:
-       id = GADGET_ID_SCROLL_RIGHT;
-       break;
-      case KSYM_Up:
-       id = GADGET_ID_SCROLL_UP;
-       break;
-      case KSYM_Down:
-       id = GADGET_ID_SCROLL_DOWN;
-       break;
+    case KSYM_Page_Up:
+    case KSYM_Page_Down:
+      step *= (key == KSYM_Page_Up ? -1 : +1);
+      element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
 
-      case KSYM_Page_Up:
-      case KSYM_Page_Down:
-       step *= (key == KSYM_Page_Up ? -1 : +1);
-        element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
+      if (element_shift < 0)
+       element_shift = 0;
+      if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
+       element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
 
-        if (element_shift < 0)
-          element_shift = 0;
-        if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
-          element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
+      ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
+                  GDI_SCROLLBAR_ITEM_POSITION,
+                  element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
 
-        ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
-                     GDI_SCROLLBAR_ITEM_POSITION,
-                     element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
+      ModifyEditorElementList();
 
-       ModifyEditorElementList();
+      break;
 
-       break;
+    case KSYM_Home:
+    case KSYM_End:
+      element_shift = (key == KSYM_Home ? 0 :
+                      num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS);
 
-      case KSYM_Home:
-      case KSYM_End:
-       element_shift = (key == KSYM_Home ? 0 :
-                        num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS);
+      ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
+                  GDI_SCROLLBAR_ITEM_POSITION,
+                  element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
 
-       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
-                    GDI_SCROLLBAR_ITEM_POSITION,
-                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
+      ModifyEditorElementList();
 
-       ModifyEditorElementList();
+      break;
 
-       break;
+    case KSYM_Insert:
+    case KSYM_Delete:
 
-      case KSYM_Insert:
-      case KSYM_Delete:
+      // this is needed to prevent interference with running "True X-Mouse"
+      if (GetKeyModStateFromEvents() & KMOD_Control)
+       break;
 
-       // this is needed to prevent interference with running "True X-Mouse"
-       if (GetKeyModStateFromEvents() & KMOD_Control)
+      // check for last or next editor cascade block in element list
+      for (i = 0; i < num_editor_elements; i++)
+      {
+       if ((key == KSYM_Insert && i == element_shift) ||
+           (key == KSYM_Delete && new_element_shift > element_shift))
          break;
 
-       // check for last or next editor cascade block in element list
-       for (i = 0; i < num_editor_elements; i++)
-       {
-         if ((key == KSYM_Insert && i == element_shift) ||
-             (key == KSYM_Delete && new_element_shift > element_shift))
-           break;
+       // jump to next cascade block (or to start of element list)
+       if (i == 0 || IS_EDITOR_CASCADE(editor_elements[i]))
+         new_element_shift = i;
+      }
 
-         // jump to next cascade block (or to start of element list)
-         if (i == 0 || IS_EDITOR_CASCADE(editor_elements[i]))
-           new_element_shift = i;
-       }
+      if (i < num_editor_elements)
+       element_shift = new_element_shift;
 
-       if (i < num_editor_elements)
-         element_shift = new_element_shift;
+      if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
+       element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
 
-       if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
-         element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
+      ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
+                  GDI_SCROLLBAR_ITEM_POSITION,
+                  element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
 
-       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
-                    GDI_SCROLLBAR_ITEM_POSITION,
-                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
+      ModifyEditorElementList();
 
-       ModifyEditorElementList();
+      break;
 
-       break;
+    case KSYM_Escape:
+      if (edit_mode == ED_MODE_DRAWING)
+       RequestExitLevelEditor(setup.ask_on_escape_editor, TRUE);
+      else if (edit_mode == ED_MODE_LEVELCONFIG)
+       HandleControlButtons(level_editor_gadget[GADGET_ID_CONF]);
+      else if (edit_mode == ED_MODE_PROPERTIES)
+       HandleControlButtons(level_editor_gadget[GADGET_ID_PROPERTIES]);
+      else if (edit_mode == ED_MODE_PALETTE)
+       HandleControlButtons(level_editor_gadget[GADGET_ID_PALETTE]);
+      else             // should never happen
+       ChangeEditModeWindow(ED_MODE_DRAWING);
 
-      case KSYM_Escape:
-        if (edit_mode == ED_MODE_DRAWING)
-       {
-         RequestExitLevelEditor(setup.ask_on_escape_editor, TRUE);
-       }
-        else if (edit_mode == ED_MODE_INFO)
-       {
-         HandleControlButtons(level_editor_gadget[GADGET_ID_INFO]);
-       }
-        else if (edit_mode == ED_MODE_PROPERTIES)
-       {
-         HandleControlButtons(level_editor_gadget[GADGET_ID_PROPERTIES]);
-       }
-        else if (edit_mode == ED_MODE_PALETTE)
-       {
-         HandleControlButtons(level_editor_gadget[GADGET_ID_PALETTE]);
-       }
-       else            // should never happen
-       {
-         ChangeEditModeWindow(ED_MODE_DRAWING);
-       }
+      break;
 
-        break;
+    default:
+      break;
+  }
 
-      default:
-       break;
-    }
+  if (id != GADGET_ID_NONE)
+    ClickOnGadget(level_editor_gadget[id], button);
+  else if (letter == '1' || letter == '?')
+    ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_LEFT], button);
+  else if (letter == '2')
+    ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_MIDDLE], button);
+  else if (letter == '3')
+    ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_RIGHT], button);
+  else if (letter == '.')
+    ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], button);
+  else if (letter == 'U')
+    ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], 3);
+  else if (letter == '-' || key == KSYM_KP_Subtract)
+    ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 3);
+  else if (letter == '0' || key == KSYM_KP_0)
+    ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 2);
+  else if (letter == '+' || key == KSYM_KP_Add ||
+          letter == '=')       // ("Shift-=" is "+" on US keyboards)
+    ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 1);
+  else if (key == KSYM_Return ||
+          key == KSYM_space ||
+          key == setup.shortcut.toggle_pause)
+    ClickOnGadget(level_editor_gadget[GADGET_ID_TEST], button);
+  else
+    for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
+      if (letter && letter == controlbutton_info[i].shortcut)
+       if (!anyTextGadgetActive())
+         ClickOnGadget(level_editor_gadget[i], button);
 
-    if (id != GADGET_ID_NONE)
-      ClickOnGadget(level_editor_gadget[id], button);
-    else if (letter == '1' || letter == '?')
-      ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_LEFT], button);
-    else if (letter == '2')
-      ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_MIDDLE], button);
-    else if (letter == '3')
-      ClickOnGadget(level_editor_gadget[GADGET_ID_ELEMENT_RIGHT], button);
-    else if (letter == '.')
-      ClickOnGadget(level_editor_gadget[GADGET_ID_SINGLE_ITEMS], button);
-    else if (letter == 'U')
-      ClickOnGadget(level_editor_gadget[GADGET_ID_UNDO], 3);
-    else if (letter == '-' || key == KSYM_KP_Subtract)
-      ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 3);
-    else if (letter == '0' || key == KSYM_KP_0)
-      ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 2);
-    else if (letter == '+' || key == KSYM_KP_Add ||
-            letter == '=')     // ("Shift-=" is "+" on US keyboards)
-      ClickOnGadget(level_editor_gadget[GADGET_ID_ZOOM], 1);
-    else if (key == KSYM_Return ||
-            key == KSYM_space ||
-            key == setup.shortcut.toggle_pause)
-      ClickOnGadget(level_editor_gadget[GADGET_ID_TEST], button);
-    else
-      for (i = 0; i < ED_NUM_CTRL_BUTTONS; i++)
-       if (letter && letter == controlbutton_info[i].shortcut)
-         if (!anyTextGadgetActive())
-           ClickOnGadget(level_editor_gadget[i], button);
+  if (draw_with_brush)
+  {
+    if (letter == 'x')
+      FlipBrushX();
+    else if (letter == 'y')
+      FlipBrushY();
+    else if (letter == 'z')
+      RotateBrush();
   }
 }
 
-void HandleLevelEditorIdle(void)
+static void HandleLevelEditorIdle_Properties(void)
 {
   int element_border = graphic_info[IMG_EDITOR_ELEMENT_BORDER].border_size;
   int x = editor.settings.element_graphic.x + element_border;
   int y = editor.settings.element_graphic.y + element_border;
-  static unsigned int action_delay = 0;
-  unsigned int action_delay_value = GameFrameDelay;
+  static DelayCounter action_delay = { 0 };
   int i;
 
-  if (edit_mode != ED_MODE_PROPERTIES)
-    return;
+  action_delay.value = GameFrameDelay;
 
-  if (!DelayReached(&action_delay, action_delay_value))
+  if (!DelayReached(&action_delay))
     return;
 
   for (i = 0; i < ED_NUM_SELECTBOX; i++)
@@ -14156,6 +15003,33 @@ void HandleLevelEditorIdle(void)
   FrameCounter++;      // increase animation frame counter
 }
 
+static void HandleLevelEditorIdle_Drawing(void)
+{
+  static boolean last_highlighted = FALSE;
+  static boolean last_highlighted_similar = FALSE;
+  boolean highlighted = (GetKeyModState() & KMOD_Alt);
+  boolean highlighted_similar = (GetKeyModState() & KMOD_Shift);
+
+  if (highlighted != last_highlighted ||
+      (highlighted && highlighted_similar != last_highlighted_similar))
+  {
+    DrawAreaElementHighlight(highlighted, highlighted_similar);
+
+    redraw_mask |= REDRAW_FIELD;
+  }
+
+  last_highlighted = highlighted;
+  last_highlighted_similar = highlighted_similar;
+}
+
+void HandleLevelEditorIdle(void)
+{
+  if (edit_mode == ED_MODE_PROPERTIES)
+    HandleLevelEditorIdle_Properties();
+  else if (edit_mode == ED_MODE_DRAWING)
+    HandleLevelEditorIdle_Drawing();
+}
+
 static void ClearEditorGadgetInfoText(void)
 {
   DrawBackground(INFOTEXT_XPOS, INFOTEXT_YPOS, INFOTEXT_XSIZE, INFOTEXT_YSIZE);
@@ -14164,7 +15038,6 @@ static void ClearEditorGadgetInfoText(void)
 void PrintEditorGadgetInfoText(struct GadgetInfo *gi)
 {
   char infotext[MAX_OUTPUT_LINESIZE + 1];
-  char shortcut[MAX_OUTPUT_LINESIZE + 1];
   int max_infotext_len = getMaxInfoTextLength();
 
   if (gi == NULL || strlen(gi->info_text) == 0)
@@ -14179,6 +15052,8 @@ void PrintEditorGadgetInfoText(struct GadgetInfo *gi)
 
     if (key)
     {
+      char shortcut[MAX_OUTPUT_LINESIZE + 1];
+
       if (gi->custom_id == GADGET_ID_SINGLE_ITEMS)
        sprintf(shortcut, " ('.' or '%c')", key);
       else if (gi->custom_id == GADGET_ID_PICK_ELEMENT)
@@ -14222,7 +15097,6 @@ void HandleEditorGadgetInfoText(void *ptr)
 
 static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
 {
-  static int start_lx, start_ly;
   int id = gi->custom_id;
   int type_id = gi->custom_type_id;
   int sx = gi->event.x;
@@ -14235,7 +15109,6 @@ static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
   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
 
@@ -14272,10 +15145,14 @@ static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
       sy = ly - level_ypos;
     }
 
-    if (IN_ED_FIELD(sx,sy) && IN_LEV_FIELD(lx, ly))
+    if (IN_ED_FIELD(sx, sy) && IN_LEV_FIELD(lx, ly))
     {
       if (button_status)       // if (gi->state == GD_BUTTON_PRESSED)
       {
+       static int start_lx = 0;
+       static int start_ly = 0;
+       char *text;
+
        if (gi->event.type == GD_EVENT_PRESSED)
        {
          start_lx = lx;
@@ -14327,7 +15204,7 @@ static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
                  ABS(lx - start_lx) + 1, ABS(ly - start_ly) + 1);
       }
       else if (actual_drawing_function == GADGET_ID_PICK_ELEMENT)
-       strncpy(infotext, getElementInfoText(Feld[lx][ly]), max_infotext_len);
+       strncpy(infotext, getElementInfoText(Tile[lx][ly]), max_infotext_len);
       else
        sprintf(infotext, "Level position: %d, %d", lx, ly);
     }
@@ -14406,7 +15283,7 @@ void RequestExitLevelEditor(boolean ask_if_level_has_changed,
        vp_door_2->height == VYSIZE)
       CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
     else
-      SetDoorState(DOOR_CLOSE_2);
+      SetDoorState(DOOR_CLOSE_ALL);
 
     BackToFront();