minor change of text in request dialogs
[rocksndiamonds.git] / src / editor.c
index 8338bbb37973bb5fa8cb3456982e1484c53d1455..226fd56da5b6498677dd2e128dd2dbc6878ec889 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
 // ============================================================================
@@ -559,6 +559,7 @@ 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,
@@ -642,12 +643,13 @@ 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_CONTINUOUS_SNAPPING,
   GADGET_ID_BLOCK_SNAP_FIELD,
   GADGET_ID_BLOCK_LAST_FIELD,
@@ -839,6 +841,7 @@ 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,
@@ -947,12 +950,13 @@ 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_CONTINUOUS_SNAPPING,
   ED_CHECKBUTTON_ID_BLOCK_SNAP_FIELD,
   ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD,
@@ -1408,7 +1412,7 @@ 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),
@@ -1731,6 +1735,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"              },
@@ -1965,6 +1977,10 @@ 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"              },
 
   { -1,                                NULL                            }
 };
@@ -1994,6 +2010,10 @@ 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"              },
 
   { -1,                                NULL                            }
 };
@@ -2084,10 +2104,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"                      },
@@ -2413,6 +2434,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,      },
@@ -2455,6 +2477,14 @@ static struct
     &level.use_step_counter,
     NULL, NULL, "(0 => no limit)",     "time or step limit"
   },
+  {
+    -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(11),
     GADGET_ID_GAME_ENGINE_TYPE,                GADGET_ID_NONE,
@@ -2665,7 +2695,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"
@@ -3060,8 +3090,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"
   },
@@ -3100,6 +3130,13 @@ 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(9),
     GADGET_ID_CONTINUOUS_SNAPPING,     GADGET_ID_NONE,
@@ -3462,7 +3499,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 ---------------------------------------
@@ -3473,7 +3510,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 -----------------------------------------------
@@ -3483,56 +3520,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 --------------------------------------------
@@ -3542,66 +3579,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 ------------------------------------------------
@@ -3611,7 +3648,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 -------------------------------------------
@@ -3621,7 +3658,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 ----------------------------------------
@@ -3631,7 +3668,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 --------------------------------------
@@ -3641,7 +3678,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 --------------------------------------
@@ -3651,7 +3688,7 @@ 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"
   },
 
   // ---------- element settings: configure 1 (custom elements) ---------------
@@ -3663,7 +3700,7 @@ static struct
     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"
+    NULL, NULL, NULL, NULL,            "custom graphic element"
   },
 
   // ---------- element settings: configure 2 (custom elements) ---------------
@@ -3675,7 +3712,7 @@ static struct
     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) ------------------
@@ -3685,14 +3722,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) ------------------
@@ -3704,7 +3741,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) ----------------
@@ -3714,7 +3751,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) ----------------
@@ -3724,7 +3761,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) ----------------
@@ -3734,7 +3771,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 -----------------------------------------
@@ -3744,7 +3781,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) -----------------------
@@ -3754,7 +3791,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"
   },
 };
 
@@ -3846,7 +3883,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;
@@ -4046,13 +4083,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,
@@ -5546,8 +5583,8 @@ 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 always be true
+       element_found[Tile[x][y]] = TRUE;
 
   *num_elements = 0;
 
@@ -5739,10 +5776,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);
     }
   }
 
@@ -6208,7 +6245,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;
   }
@@ -6274,7 +6311,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;
   }
@@ -6327,7 +6364,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;
   }
@@ -6421,7 +6458,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] =
@@ -6483,7 +6520,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] =
@@ -6541,7 +6578,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] =
@@ -6614,7 +6651,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;
   }
@@ -6663,7 +6700,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;
   }
@@ -6742,7 +6779,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] =
@@ -6826,7 +6863,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] =
@@ -6882,7 +6919,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] =
@@ -6997,7 +7034,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;
   }
@@ -7057,7 +7094,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] =
@@ -7122,7 +7159,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] =
@@ -7141,7 +7178,7 @@ 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 *));
@@ -7179,7 +7216,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++)
   {
@@ -7293,8 +7330,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)
@@ -7303,6 +7342,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);
 
@@ -7679,7 +7721,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);
@@ -7707,7 +7749,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;
 
@@ -7715,6 +7757,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++)
   {
@@ -7933,8 +7986,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,
@@ -8128,6 +8181,8 @@ 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
@@ -8155,6 +8210,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);
 }
 
@@ -8286,6 +8343,8 @@ 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];
 
@@ -8313,6 +8372,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];
 
@@ -8325,6 +8386,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)
@@ -8338,6 +8402,9 @@ 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 CopyClassicElementPropertiesToGame(int element)
@@ -8368,8 +8435,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
 
@@ -8402,6 +8468,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;
@@ -8503,29 +8572,31 @@ 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();
@@ -8544,7 +8615,7 @@ void DrawLevelEd(void)
 
   FadeSoundsAndMusic();
 
-  if (CheckIfGlobalBorderOrPlayfieldViewportHasChanged())
+  if (CheckFadeAll())
     fade_mask = REDRAW_ALL;
 
   FadeOut(fade_mask);
@@ -8564,8 +8635,8 @@ 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;
   }
@@ -9510,7 +9581,7 @@ static void DrawPropertiesInfo(void)
   num_elements_in_level = 0;
   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++;
   percentage = num_elements_in_level * 100.0 / (lev_fieldx * lev_fieldy);
 
@@ -9696,6 +9767,8 @@ 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  },
@@ -9748,12 +9821,45 @@ static void SetAutomaticNumberOfGemsNeeded(void)
   {
     for (y = 0; y < lev_fieldy; y++)
     {
-      int element = Feld[x][y];
+      int element = Tile[x][y];
+
+      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;
 
-      if (IS_GEM(element) ||
-         element == EL_MM_KETTLE ||
-         element == EL_DF_CELL)
-       level.gems_needed++;
+       case EL_CRYSTAL:
+       case EL_WALL_CRYSTAL:
+         level.gems_needed += 8;
+         break;
+
+       default:
+         break;
+      }
     }
   }
 
@@ -9836,7 +9942,7 @@ 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);
@@ -9904,6 +10010,7 @@ static void DrawPropertiesConfig(void)
 
       // draw checkbutton gadgets
       MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_INITIAL_INVENTORY);
+      MapCheckbuttonGadget(ED_CHECKBUTTON_ID_FINISH_DIG_COLLECT);
 
       // draw counter gadgets
       MapCounterButtons(ED_COUNTER_ID_INVENTORY_SIZE);
@@ -9938,7 +10045,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)
@@ -10767,7 +10876,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;
@@ -10793,7 +10902,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))
   {
@@ -10841,7 +10950,6 @@ static void SetElementIntelliDraw(int x, int y, int new_element,
   };
   static int last_x = -1;
   static int last_y = -1;
-  int old_element = IntelliDrawBuffer[x][y];
 
   if (new_element == EL_UNDEFINED)
   {
@@ -10851,6 +10959,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;
@@ -11618,18 +11728,28 @@ 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);
 }
 
 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 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)
@@ -11651,7 +11771,7 @@ 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);
+    SetElementSimple(x, y, Tile[x][y], change_level);
   else if (GetKeyModState() & KMOD_Shift && !IS_MM_WALL_EDITOR(element))
     SetElementIntelliDraw(x, y, element, change_level, button);
   else
@@ -11695,7 +11815,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))
@@ -11947,27 +12067,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);
       }
 
@@ -11978,7 +12099,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;
   }
@@ -12014,11 +12135,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[] = { "`", "¸" };
@@ -12047,19 +12170,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')
       {
@@ -12069,6 +12183,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;
 
@@ -12079,14 +12203,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;
       }
     }
 
@@ -12125,11 +12263,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) && !ELEM_IS_PLAYER(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();
@@ -12162,7 +12330,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);
@@ -12291,9 +12459,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)
@@ -12302,20 +12480,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
@@ -12379,7 +12557,7 @@ 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);
@@ -12394,8 +12572,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);
@@ -12411,8 +12589,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;
@@ -12426,7 +12604,7 @@ 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;
@@ -12448,7 +12626,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);
 }
@@ -12502,7 +12680,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);
@@ -12524,8 +12702,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++;
@@ -12573,17 +12751,54 @@ 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)
+{
+  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++)
+    {
+      int lx = x + level_xpos;
+      int ly = y + level_ypos;
+
+      if (!IN_LEV_FIELD(lx, ly))
+       continue;
+
+      if (Tile[lx][ly] != new_element1)
+       continue;
+
+      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();
@@ -12670,9 +12885,13 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
   }
   else if (!button_press_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;
   }
@@ -12742,13 +12961,37 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
        {
          SetDrawModeHiRes(new_element);
 
-         if (new_element == EL_PLAYER_1)
+         if (ELEM_IS_PLAYER(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)
-                 SetElement(x, y, EL_EMPTY);
+             {
+               int old_element = Tile[x][y];
+
+               if (ELEM_IS_PLAYER(old_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);
+               }
+             }
+           }
          }
 
          SetElementButton(lx, ly, dx, dy, new_element, button);
@@ -12884,7 +13127,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);
@@ -12901,7 +13144,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;
@@ -13145,10 +13388,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))
@@ -13158,7 +13401,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)
   {
@@ -13167,7 +13410,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;
     }
@@ -13628,7 +13871,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);
@@ -13690,6 +13933,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);
 
@@ -13724,7 +13971,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)
@@ -13769,7 +14018,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);
@@ -13787,7 +14036,7 @@ static void HandleControlButtons(struct GadgetInfo *gi)
       }
       else
       {
-       ChangeEditModeWindow(last_edit_mode);
+       ChangeEditModeWindow(ED_MODE_DRAWING);
       }
       break;
 
@@ -13797,7 +14046,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);
 
@@ -13828,7 +14077,7 @@ static void HandleControlButtons(struct GadgetInfo *gi)
 
        SetAutomaticNumberOfGemsNeeded();
 
-       CopyPlayfield(Feld, level.field);
+       CopyPlayfield(Tile, level.field);
        SaveLevel(level_nr);
 
        level.changed = FALSE;
@@ -13859,8 +14108,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);
 
@@ -13960,13 +14209,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;
   }
@@ -13975,7 +14224,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)
@@ -13988,153 +14236,144 @@ 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 i;
 
-    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;
+  int id = GADGET_ID_NONE;
+  int new_element_shift = element_shift;
+  int step = ED_ELEMENTLIST_BUTTONS_VERT - 1;
+  int button = MB_LEFTBUTTON;
+  int i;
 
-      case KSYM_Page_Up:
-      case KSYM_Page_Down:
-       step *= (key == KSYM_Page_Up ? -1 : +1);
-        element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
+  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;
 
-        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;
+    case KSYM_Page_Up:
+    case KSYM_Page_Down:
+      step *= (key == KSYM_Page_Up ? -1 : +1);
+      element_shift += step * ED_ELEMENTLIST_BUTTONS_HORIZ;
 
-        ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
-                     GDI_SCROLLBAR_ITEM_POSITION,
-                     element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
+      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;
 
-       ModifyEditorElementList();
+      ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
+                  GDI_SCROLLBAR_ITEM_POSITION,
+                  element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
 
-       break;
+      ModifyEditorElementList();
 
-      case KSYM_Home:
-      case KSYM_End:
-       element_shift = (key == KSYM_Home ? 0 :
-                        num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS);
+      break;
 
-       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
-                    GDI_SCROLLBAR_ITEM_POSITION,
-                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
+    case KSYM_Home:
+    case KSYM_End:
+      element_shift = (key == KSYM_Home ? 0 :
+                      num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS);
 
-       ModifyEditorElementList();
+      ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
+                  GDI_SCROLLBAR_ITEM_POSITION,
+                  element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
 
-       break;
+      ModifyEditorElementList();
 
-      case KSYM_Insert:
-      case KSYM_Delete:
+      break;
 
-       // this is needed to prevent interference with running "True X-Mouse"
-       if (GetKeyModStateFromEvents() & KMOD_Control)
-         break;
+    case KSYM_Insert:
+    case KSYM_Delete:
 
-       // 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;
+      // this is needed to prevent interference with running "True X-Mouse"
+      if (GetKeyModStateFromEvents() & KMOD_Control)
+       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;
-       }
+      // 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;
 
-       if (i < num_editor_elements)
-         element_shift = new_element_shift;
+       // 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 (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
-         element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
+      if (i < num_editor_elements)
+       element_shift = new_element_shift;
 
-       ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
-                    GDI_SCROLLBAR_ITEM_POSITION,
-                    element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
+      if (element_shift > num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS)
+       element_shift = num_editor_elements - ED_NUM_ELEMENTLIST_BUTTONS;
 
-       ModifyEditorElementList();
+      ModifyGadget(level_editor_gadget[GADGET_ID_SCROLL_LIST_VERTICAL],
+                  GDI_SCROLLBAR_ITEM_POSITION,
+                  element_shift / ED_ELEMENTLIST_BUTTONS_HORIZ, GDI_END);
 
-       break;
+      ModifyEditorElementList();
 
-      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;
+    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);
 
-      default:
-       break;
-    }
+      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);
+    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);
 }
 
-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;
@@ -14143,9 +14382,6 @@ void HandleLevelEditorIdle(void)
   unsigned int action_delay_value = GameFrameDelay;
   int i;
 
-  if (edit_mode != ED_MODE_PROPERTIES)
-    return;
-
   if (!DelayReached(&action_delay, action_delay_value))
     return;
 
@@ -14164,6 +14400,29 @@ void HandleLevelEditorIdle(void)
   FrameCounter++;      // increase animation frame counter
 }
 
+static void HandleLevelEditorIdle_Drawing(void)
+{
+  static boolean last_highlighted = FALSE;
+  boolean highlighted = (GetKeyModState() & KMOD_Alt);
+
+  if (highlighted != last_highlighted)
+  {
+    DrawAreaElementHighlight(highlighted);
+
+    last_highlighted = highlighted;
+
+    redraw_mask |= REDRAW_FIELD;
+  }
+}
+
+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);
@@ -14335,7 +14594,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);
     }