rnd-20030716-1-src
[rocksndiamonds.git] / src / editor.c
index dd757b0560755526e7be89a91d8c4904b0e49673..d780a053e1453e4d44e34935756d610fd4d41822 100644 (file)
 
 #define GADGET_ID_LEVEL_NAME           (GADGET_ID_TEXT_INPUT_FIRST + 0)
 #define GADGET_ID_LEVEL_AUTHOR         (GADGET_ID_TEXT_INPUT_FIRST + 1)
+#define GADGET_ID_ELEMENT_NAME         (GADGET_ID_TEXT_INPUT_FIRST + 2)
 
 /* selectbox identifiers */
-#define GADGET_ID_SELECTBOX_FIRST      (GADGET_ID_TEXT_INPUT_FIRST + 2)
+#define GADGET_ID_SELECTBOX_FIRST      (GADGET_ID_TEXT_INPUT_FIRST + 3)
 
 #define GADGET_ID_CUSTOM_WALK_TO_ACTION        (GADGET_ID_SELECTBOX_FIRST + 0)
 #define GADGET_ID_CUSTOM_CONSISTENCY   (GADGET_ID_SELECTBOX_FIRST + 1)
 #define GADGET_ID_CUSTOM_MOVE_DIRECTION        (GADGET_ID_SELECTBOX_FIRST + 4)
 #define GADGET_ID_CUSTOM_MOVE_STEPSIZE (GADGET_ID_SELECTBOX_FIRST + 5)
 #define GADGET_ID_CUSTOM_SMASH_TARGETS (GADGET_ID_SELECTBOX_FIRST + 6)
-#define GADGET_ID_CUSTOM_ACCESS_TYPE   (GADGET_ID_SELECTBOX_FIRST + 7)
-#define GADGET_ID_CUSTOM_ACCESS_LAYER  (GADGET_ID_SELECTBOX_FIRST + 8)
-#define GADGET_ID_CHANGE_TIME_UNITS    (GADGET_ID_SELECTBOX_FIRST + 9)
-#define GADGET_ID_CHANGE_PLAYER_ACTION (GADGET_ID_SELECTBOX_FIRST + 10)
-#define GADGET_ID_CHANGE_COLLIDE_ACTION        (GADGET_ID_SELECTBOX_FIRST + 11)
-#define GADGET_ID_CHANGE_OTHER_ACTION  (GADGET_ID_SELECTBOX_FIRST + 12)
-#define GADGET_ID_CHANGE_POWER         (GADGET_ID_SELECTBOX_FIRST + 13)
+#define GADGET_ID_CUSTOM_SLIPPERY_TYPE (GADGET_ID_SELECTBOX_FIRST + 7)
+#define GADGET_ID_CUSTOM_ACCESS_TYPE   (GADGET_ID_SELECTBOX_FIRST + 8)
+#define GADGET_ID_CUSTOM_ACCESS_LAYER  (GADGET_ID_SELECTBOX_FIRST + 9)
+#define GADGET_ID_CHANGE_TIME_UNITS    (GADGET_ID_SELECTBOX_FIRST + 10)
+#define GADGET_ID_CHANGE_PLAYER_ACTION (GADGET_ID_SELECTBOX_FIRST + 11)
+#define GADGET_ID_CHANGE_COLLIDE_ACTION        (GADGET_ID_SELECTBOX_FIRST + 12)
+#define GADGET_ID_CHANGE_OTHER_ACTION  (GADGET_ID_SELECTBOX_FIRST + 13)
+#define GADGET_ID_CHANGE_POWER         (GADGET_ID_SELECTBOX_FIRST + 14)
 
 /* textbutton identifiers */
-#define GADGET_ID_TEXTBUTTON_FIRST     (GADGET_ID_SELECTBOX_FIRST + 14)
+#define GADGET_ID_TEXTBUTTON_FIRST     (GADGET_ID_SELECTBOX_FIRST + 15)
 
 #define GADGET_ID_PROPERTIES_INFO      (GADGET_ID_TEXTBUTTON_FIRST + 0)
 #define GADGET_ID_PROPERTIES_CONFIG    (GADGET_ID_TEXTBUTTON_FIRST + 1)
 /* values for text input gadgets */
 #define ED_TEXTINPUT_ID_LEVEL_NAME     0
 #define ED_TEXTINPUT_ID_LEVEL_AUTHOR   1
+#define ED_TEXTINPUT_ID_ELEMENT_NAME   2
 
-#define ED_NUM_TEXTINPUT               2
+#define ED_NUM_TEXTINPUT               3
 
 #define ED_TEXTINPUT_ID_LEVEL_FIRST    ED_TEXTINPUT_ID_LEVEL_NAME
 #define ED_TEXTINPUT_ID_LEVEL_LAST     ED_TEXTINPUT_ID_LEVEL_AUTHOR
 
 /* values for selectbox gadgets */
-#define ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION  0
-#define ED_SELECTBOX_ID_CUSTOM_CONSISTENCY     1
-#define ED_SELECTBOX_ID_CUSTOM_DEADLINESS      2
+#define ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE     0
+#define ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER    1
+#define ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION  2
 #define ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN    3
 #define ED_SELECTBOX_ID_CUSTOM_MOVE_DIRECTION  4
 #define ED_SELECTBOX_ID_CUSTOM_MOVE_STEPSIZE   5
 #define ED_SELECTBOX_ID_CUSTOM_SMASH_TARGETS   6
-#define ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE     7
-#define ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER    8
-#define ED_SELECTBOX_ID_CHANGE_TIME_UNITS      9
-#define ED_SELECTBOX_ID_CHANGE_PLAYER_ACTION   10
-#define ED_SELECTBOX_ID_CHANGE_COLLIDE_ACTION  11
-#define ED_SELECTBOX_ID_CHANGE_OTHER_ACTION    12
-#define ED_SELECTBOX_ID_CHANGE_POWER           13
+#define ED_SELECTBOX_ID_CUSTOM_SLIPPERY_TYPE   7
+#define ED_SELECTBOX_ID_CUSTOM_DEADLINESS      8
+#define ED_SELECTBOX_ID_CUSTOM_CONSISTENCY     9
+#define ED_SELECTBOX_ID_CHANGE_TIME_UNITS      10
+#define ED_SELECTBOX_ID_CHANGE_PLAYER_ACTION   11
+#define ED_SELECTBOX_ID_CHANGE_COLLIDE_ACTION  12
+#define ED_SELECTBOX_ID_CHANGE_OTHER_ACTION    13
+#define ED_SELECTBOX_ID_CHANGE_POWER           14
 
-#define ED_NUM_SELECTBOX                       14
+#define ED_NUM_SELECTBOX                       15
 
-#define ED_SELECTBOX_ID_CUSTOM_FIRST   ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION
-#define ED_SELECTBOX_ID_CUSTOM_LAST    ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER
+#define ED_SELECTBOX_ID_CUSTOM_FIRST   ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE
+#define ED_SELECTBOX_ID_CUSTOM_LAST    ED_SELECTBOX_ID_CUSTOM_CONSISTENCY
 
 #define ED_SELECTBOX_ID_CHANGE_FIRST   ED_SELECTBOX_ID_CHANGE_TIME_UNITS
 #define ED_SELECTBOX_ID_CHANGE_LAST    ED_SELECTBOX_ID_CHANGE_POWER
 #define ED_CHECKBUTTON_ID_RANDOM_RESTRICTED    2
 #define ED_CHECKBUTTON_ID_STICK_ELEMENT                3
 #define ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS     4
-#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_RESULT        5
-#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE  6
-#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH 7
-#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT        8
-#define ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT        9
-#define ED_CHECKBUTTON_ID_CUSTOM_DEADLY                10
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE      11
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL      12
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH     13
-#define ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY      14
-#define ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE    15
+#define ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE    5
+#define ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT        6
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE      7
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL      8
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH     9
+#define ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY      10
+#define ED_CHECKBUTTON_ID_CUSTOM_DEADLY                11
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_RESULT        12
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE  13
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH 14
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT        15
 #define ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC   16
-#define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE  17
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE    18
-#define ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT   19
-#define ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION 20
-#define ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE 21
-#define ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM    22
-#define ED_CHECKBUTTON_ID_CHANGE_DELAY         23
-#define ED_CHECKBUTTON_ID_CHANGE_BY_PLAYER     24
-#define ED_CHECKBUTTON_ID_CHANGE_BY_COLLISION  25
-#define ED_CHECKBUTTON_ID_CHANGE_BY_OTHER      26
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE    17
+#define ED_CHECKBUTTON_ID_CHANGE_DELAY         18
+#define ED_CHECKBUTTON_ID_CHANGE_BY_PLAYER     19
+#define ED_CHECKBUTTON_ID_CHANGE_BY_COLLISION  20
+#define ED_CHECKBUTTON_ID_CHANGE_BY_OTHER      21
+#define ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION 22
+#define ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT   23
+#define ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE 24
+#define ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM    25
+#define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE  26
 
 #define ED_NUM_CHECKBUTTONS                    27
 
 #define ED_CHECKBUTTON_ID_LEVEL_FIRST  ED_CHECKBUTTON_ID_DOUBLE_SPEED
 #define ED_CHECKBUTTON_ID_LEVEL_LAST   ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
 
-#define ED_CHECKBUTTON_ID_CUSTOM_FIRST ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_RESULT
-#define ED_CHECKBUTTON_ID_CUSTOM_LAST  ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE
+#define ED_CHECKBUTTON_ID_CUSTOM_FIRST ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE
+#define ED_CHECKBUTTON_ID_CUSTOM_LAST  ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT
 
 #define ED_CHECKBUTTON_ID_CHANGE_FIRST ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC
-#define ED_CHECKBUTTON_ID_CHANGE_LAST  ED_CHECKBUTTON_ID_CHANGE_BY_OTHER
+#define ED_CHECKBUTTON_ID_CHANGE_LAST  ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE
 
 /* values for radiobutton gadgets */
 #define ED_RADIOBUTTON_ID_PERCENTAGE   0
@@ -881,6 +885,13 @@ static struct
     MAX_LEVEL_AUTHOR_LEN,
     level.author,
     "Author"
+  },
+  {
+    5 * MINI_TILEX,                    5 * MINI_TILEY - ED_BORDER_SIZE,
+    GADGET_ID_ELEMENT_NAME,
+    MAX_ELEMENT_NAME_LEN - 2,          /* currently 2 chars less editable */
+    custom_element.description,
+    NULL
   }
 };
 
@@ -890,7 +901,6 @@ static struct ValueTextInfo options_access_type[] =
   { EP_PASSABLE,               "pass"                          },
   { -1,                                NULL                            }
 };
-static int value_access_type = 0;
 
 static struct ValueTextInfo options_access_layer[] =
 {
@@ -899,7 +909,6 @@ static struct ValueTextInfo options_access_layer[] =
   { EP_ACCESSIBLE_UNDER,       "under"                         },
   { -1,                                NULL                            }
 };
-static int value_access_layer = 0;
 
 static struct ValueTextInfo options_walk_to_action[] =
 {
@@ -908,7 +917,6 @@ static struct ValueTextInfo options_walk_to_action[] =
   { EP_PUSHABLE,               "pushable"                      },
   { -1,                                NULL                            }
 };
-static int value_walk_to_action = 0;
 
 static struct ValueTextInfo options_move_pattern[] =
 {
@@ -951,11 +959,22 @@ static struct ValueTextInfo options_move_stepsize[] =
 static struct ValueTextInfo options_smash_targets[] =
 {
   { EP_CAN_SMASH_PLAYER,       "player"                        },
+#if 0
   { EP_CAN_SMASH_ENEMIES,      "enemies"                       },
+#endif
   { EP_CAN_SMASH_EVERYTHING,   "everything"                    },
   { -1,                                NULL                            }
 };
-static int value_smash_targets = 0;
+
+static struct ValueTextInfo options_slippery_type[] =
+{
+  { SLIPPERY_ANY_RANDOM,       "random"                        },
+  { SLIPPERY_ANY_LEFT_RIGHT,   "left, right"                   },
+  { SLIPPERY_ANY_RIGHT_LEFT,   "right, left"                   },
+  { SLIPPERY_ONLY_LEFT,                "only left"                     },
+  { SLIPPERY_ONLY_RIGHT,       "only right"                    },
+  { -1,                                NULL                            }
+};
 
 static struct ValueTextInfo options_deadliness[] =
 {
@@ -964,7 +983,6 @@ static struct ValueTextInfo options_deadliness[] =
   { EP_DONT_TOUCH,             "touching"                      },
   { -1,                                NULL                            }
 };
-static int value_deadliness = 0;
 
 static struct ValueTextInfo options_consistency[] =
 {
@@ -972,7 +990,6 @@ static struct ValueTextInfo options_consistency[] =
   { EP_INDESTRUCTIBLE,         "indestructible"                },
   { -1,                                NULL                            }
 };
-static int value_consistency = 0;
 
 static struct ValueTextInfo options_time_units[] =
 {
@@ -988,7 +1005,6 @@ static struct ValueTextInfo options_change_player_action[] =
   { CE_PUSHED_BY_PLAYER,       "pushed"                        },
   { -1,                                NULL                            }
 };
-static int value_change_player_action = 0;
 
 static struct ValueTextInfo options_change_collide_action[] =
 {
@@ -997,7 +1013,6 @@ static struct ValueTextInfo options_change_collide_action[] =
   { CE_SMASHED,                        "when smashed"                  },
   { -1,                                NULL                            }
 };
-static int value_change_collide_action = 0;
 
 static struct ValueTextInfo options_change_other_action[] =
 {
@@ -1010,7 +1025,6 @@ static struct ValueTextInfo options_change_other_action[] =
   { CE_OTHER_GETS_COLLECTED,           "player collects"               },
   { -1,                                NULL                                    }
 };
-static int value_change_other_action = 0;
 
 static struct ValueTextInfo options_change_power[] =
 {
@@ -1037,7 +1051,7 @@ static struct
     GADGET_ID_CUSTOM_ACCESS_TYPE,
     -1,
     options_access_type,
-    &value_access_type,
+    &custom_element.access_type,
     "player can", NULL, "type of access to this field"
   },
   {
@@ -1045,7 +1059,7 @@ static struct
     GADGET_ID_CUSTOM_ACCESS_LAYER,
     -1,
     options_access_layer,
-    &value_access_layer,
+    &custom_element.access_layer,
     NULL, NULL, "layer of access for this field"
   },
   {
@@ -1053,7 +1067,7 @@ static struct
     GADGET_ID_CUSTOM_WALK_TO_ACTION,
     -1,
     options_walk_to_action,
-    &value_walk_to_action,
+    &custom_element.walk_to_action,
     NULL, NULL, "diggable/collectible/pushable"
   },
   {
@@ -1085,15 +1099,23 @@ static struct
     GADGET_ID_CUSTOM_SMASH_TARGETS,
     -1,
     options_smash_targets,
-    &value_smash_targets,
+    &custom_element.smash_targets,
     "can smash", NULL, "elements that can be smashed"
   },
+  {
+    ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(10),
+    GADGET_ID_CUSTOM_SLIPPERY_TYPE,
+    -1,
+    options_slippery_type,
+    &custom_element.slippery_type,
+    "slippery", NULL, "where other elements fall down"
+  },
   {
     ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(11),
     GADGET_ID_CUSTOM_DEADLINESS,
     -1,
     options_deadliness,
-    &value_deadliness,
+    &custom_element.deadliness,
     "deadly when", NULL, "deadliness of element"
   },
   {
@@ -1101,7 +1123,7 @@ static struct
     GADGET_ID_CUSTOM_CONSISTENCY,
     -1,
     options_consistency,
-    &value_consistency,
+    &custom_element.consistency,
     NULL, "explodes to:", "consistency/destructibility"
   },
 
@@ -1120,7 +1142,7 @@ static struct
     GADGET_ID_CHANGE_PLAYER_ACTION,
     -1,
     options_change_player_action,
-    &value_change_player_action,
+    &custom_element.change_player_action,
     NULL, "by player", "type of player contact"
   },
   {
@@ -1128,7 +1150,7 @@ static struct
     GADGET_ID_CHANGE_COLLIDE_ACTION,
     -1,
     options_change_collide_action,
-    &value_change_collide_action,
+    &custom_element.change_collide_action,
     NULL, NULL, "change after impact or smash"
   },
   {
@@ -1136,7 +1158,7 @@ static struct
     GADGET_ID_CHANGE_OTHER_ACTION,
     -1,
     options_change_other_action,
-    &value_change_other_action,
+    &custom_element.change_other_action,
     NULL, "element:", "type of other element action"
   },
   {
@@ -1287,10 +1309,6 @@ static struct
   }
 };
 
-static boolean can_explode_by_fire = FALSE;
-static boolean can_explode_smashed = FALSE;
-static boolean can_explode_impact = FALSE;
-
 static struct
 {
   int x, y;
@@ -1371,7 +1389,7 @@ static struct
     ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(10),
     GADGET_ID_CUSTOM_SLIPPERY,
     &custom_element_properties[EP_SLIPPERY],
-    "slippery",                                "other elements can fall down from it"
+    NULL,                              "other elements can fall down from it"
   },
   {
     ED_SETTINGS_XPOS(0),               ED_SETTINGS_YPOS(11),
@@ -1388,19 +1406,19 @@ static struct
   {
     ED_SETTINGS_XPOS(1),               ED_SETTINGS_YPOS(13),
     GADGET_ID_CUSTOM_EXPLODE_FIRE,
-    &can_explode_by_fire,
+    &custom_element.can_explode_by_fire,
     "by fire",                         "element can explode by fire/explosion"
   },
   {
     ED_SETTINGS_XPOS(7),               ED_SETTINGS_YPOS(13),
     GADGET_ID_CUSTOM_EXPLODE_SMASH,
-    &can_explode_smashed,
+    &custom_element.can_explode_smashed,
     "smashed",                         "element can explode when smashed"
   },
   {
     ED_SETTINGS_XPOS(13),              ED_SETTINGS_YPOS(13),
     GADGET_ID_CUSTOM_EXPLODE_IMPACT,
-    &can_explode_impact,
+    &custom_element.can_explode_impact,
     "impact",                          "element can explode on impact"
   },
 
@@ -1504,6 +1522,7 @@ static void ModifyEditorCounter(int, int);
 static void ModifyEditorCounterLimits(int, int, int);
 static void ModifyEditorSelectbox(int, int);
 static void ModifyEditorElementList();
+static void RedrawDrawingElements();
 static void DrawDrawingWindow();
 static void DrawLevelInfoWindow();
 static void DrawPropertiesWindow();
@@ -2388,7 +2407,9 @@ static char *getElementInfoText(int element)
 
   if (element < NUM_FILE_ELEMENTS)
   {
-    if (element_info[element].custom_description != NULL)
+    if (strlen(element_info[element].description) > 0)
+      info_text = element_info[element].description;
+    else if (element_info[element].custom_description != NULL)
       info_text = element_info[element].custom_description;
     else if (element_info[element].editor_description != NULL)
       info_text = element_info[element].editor_description;
@@ -3435,9 +3456,12 @@ static void MapTextInputGadget(int id)
   int x = textinput_info[id].x + xoffset_above;
   int y = textinput_info[id].y + yoffset_above;
 
-  sprintf(infotext, "%s:", textinput_info[id].infotext);
-  infotext[max_infotext_len] = '\0';
-  DrawTextF(x, y, FONT_TEXT_1, infotext);
+  if (textinput_info[id].infotext)
+  {
+    sprintf(infotext, "%s:", textinput_info[id].infotext);
+    infotext[max_infotext_len] = '\0';
+    DrawTextF(x, y, FONT_TEXT_1, infotext);
+  }
 
   ModifyGadget(level_editor_gadget[textinput_info[id].gadget_id],
               GDI_TEXT_VALUE, textinput_info[id].value, GDI_END);
@@ -3569,6 +3593,9 @@ static void ResetUndoBuffer()
 
 static void DrawEditModeWindow()
 {
+  ModifyEditorElementList();
+  RedrawDrawingElements();
+
   if (edit_mode == ED_MODE_INFO)
     DrawLevelInfoWindow();
   else if (edit_mode == ED_MODE_PROPERTIES)
@@ -3584,7 +3611,7 @@ static boolean LevelChanged()
 
   for(y=0; y<lev_fieldy; y++) 
     for(x=0; x<lev_fieldx; x++)
-      if (Feld[x][y] != Ur[x][y])
+      if (Feld[x][y] != level.field[x][y])
        level_changed = TRUE;
 
   return level_changed;
@@ -3621,7 +3648,7 @@ static void CopyCustomElementPropertiesToEditor(int element)
   /* needed here to initialize combined element properties */
   InitElementPropertiesEngine(level.game_version);
 
-  custom_element = element_info[properties_element];
+  custom_element = element_info[element];
 
   for (i=0; i < NUM_ELEMENT_PROPERTIES; i++)
     custom_element_properties[i] = HAS_PROPERTY(element, i);
@@ -3632,88 +3659,88 @@ static void CopyCustomElementPropertiesToEditor(int element)
   /* ---------- element settings: configure (custom elements) ------------- */
 
   /* set accessible layer selectbox help value */
-  value_access_type =
+  custom_element.access_type =
     (IS_WALKABLE(element) ? EP_WALKABLE :
      IS_PASSABLE(element) ? EP_PASSABLE :
-     value_access_type);
-  value_access_layer =
+     custom_element.access_type);
+  custom_element.access_layer =
     (IS_ACCESSIBLE_OVER(element) ? EP_ACCESSIBLE_OVER :
      IS_ACCESSIBLE_INSIDE(element) ? EP_ACCESSIBLE_INSIDE :
      IS_ACCESSIBLE_UNDER(element) ? EP_ACCESSIBLE_UNDER :
-     value_access_layer);
+     custom_element.access_layer);
   custom_element_properties[EP_ACCESSIBLE] =
     (IS_ACCESSIBLE_OVER(element) ||
      IS_ACCESSIBLE_INSIDE(element) ||
      IS_ACCESSIBLE_UNDER(element));
 
   /* set walk-to-object action selectbox help value */
-  value_walk_to_action =
+  custom_element.walk_to_action =
     (IS_DIGGABLE(element) ? EP_DIGGABLE :
      IS_COLLECTIBLE(element) ? EP_COLLECTIBLE :
      IS_PUSHABLE(element) ? EP_PUSHABLE :
-     value_walk_to_action);
+     custom_element.walk_to_action);
   custom_element_properties[EP_WALK_TO_OBJECT] =
     (IS_DIGGABLE(element) ||
      IS_COLLECTIBLE(element) ||
      IS_PUSHABLE(element));
 
   /* set smash targets selectbox help value */
-  value_smash_targets =
+  custom_element.smash_targets =
     (CAN_SMASH_EVERYTHING(element) ? EP_CAN_SMASH_EVERYTHING :
      CAN_SMASH_ENEMIES(element) ? EP_CAN_SMASH_ENEMIES :
      CAN_SMASH_PLAYER(element) ? EP_CAN_SMASH_PLAYER :
-     value_smash_targets);
+     custom_element.smash_targets);
   custom_element_properties[EP_CAN_SMASH] =
     (CAN_SMASH_EVERYTHING(element) ||
      CAN_SMASH_ENEMIES(element) ||
      CAN_SMASH_PLAYER(element));
 
   /* set deadliness selectbox help value */
-  value_deadliness =
+  custom_element.deadliness =
     (DONT_TOUCH(element) ? EP_DONT_TOUCH :
      DONT_COLLIDE_WITH(element) ? EP_DONT_COLLIDE_WITH :
      DONT_RUN_INTO(element) ? EP_DONT_RUN_INTO :
-     value_deadliness);
+     custom_element.deadliness);
   custom_element_properties[EP_DEADLY] =
     (DONT_TOUCH(element) ||
      DONT_COLLIDE_WITH(element) ||
      DONT_RUN_INTO(element));
 
   /* set consistency selectbox help value */
-  value_consistency =
+  custom_element.consistency =
     (IS_INDESTRUCTIBLE(element) ? EP_INDESTRUCTIBLE :
      CAN_EXPLODE(element) ? EP_CAN_EXPLODE :
-     value_consistency);
+     custom_element.consistency);
   custom_element_properties[EP_EXPLODE_RESULT] =
     (IS_INDESTRUCTIBLE(element) ||
      CAN_EXPLODE(element));
 
   /* special case: sub-settings dependent from main setting */
-  if (CAN_EXPLODE(element))
-  {
-    can_explode_by_fire = CAN_EXPLODE_BY_FIRE(element);
-    can_explode_smashed = CAN_EXPLODE_SMASHED(element);
-    can_explode_impact  = CAN_EXPLODE_IMPACT(element);
-  };
+  if (CAN_EXPLODE_BY_FIRE(element))
+    custom_element.can_explode_by_fire = TRUE;
+  if (CAN_EXPLODE_SMASHED(element))
+    custom_element.can_explode_smashed = TRUE;
+  if (CAN_EXPLODE_IMPACT(element))
+    custom_element.can_explode_impact  = TRUE;
 
   /* ---------- element settings: advanced (custom elements) --------------- */
 
   /* set change by player selectbox help value */
-  value_change_player_action =
+  custom_element.change_player_action =
     (HAS_CHANGE_EVENT(element, CE_PUSHED_BY_PLAYER) ? CE_PUSHED_BY_PLAYER :
      HAS_CHANGE_EVENT(element, CE_PRESSED_BY_PLAYER) ? CE_PRESSED_BY_PLAYER :
      HAS_CHANGE_EVENT(element, CE_TOUCHED_BY_PLAYER) ? CE_TOUCHED_BY_PLAYER :
-     value_change_player_action);
+     custom_element.change_player_action);
 
   /* set change by collision selectbox help value */
-  value_change_collide_action =
+  custom_element.change_collide_action =
     (HAS_CHANGE_EVENT(element, CE_SMASHED) ? CE_SMASHED :
      HAS_CHANGE_EVENT(element, CE_IMPACT) ? CE_IMPACT :
      HAS_CHANGE_EVENT(element, CE_COLLISION) ? CE_COLLISION :
-     value_change_collide_action);
+     custom_element.change_collide_action);
 
   /* set change by other element action selectbox help value */
-  value_change_other_action =
+  custom_element.change_other_action =
     (HAS_CHANGE_EVENT(element, CE_OTHER_GETS_COLLECTED) ? CE_OTHER_GETS_COLLECTED :
      HAS_CHANGE_EVENT(element, CE_OTHER_GETS_PUSHED) ? CE_OTHER_GETS_PUSHED :
      HAS_CHANGE_EVENT(element, CE_OTHER_GETS_PRESSED) ? CE_OTHER_GETS_PRESSED :
@@ -3721,14 +3748,31 @@ static void CopyCustomElementPropertiesToEditor(int element)
      HAS_CHANGE_EVENT(element, CE_OTHER_IS_EXPLODING) ? CE_OTHER_IS_EXPLODING :
      HAS_CHANGE_EVENT(element, CE_OTHER_IS_CHANGING) ? CE_OTHER_IS_CHANGING :
      HAS_CHANGE_EVENT(element, CE_OTHER_IS_TOUCHING) ? CE_OTHER_IS_TOUCHING :
-     value_change_other_action);
+     custom_element.change_other_action);
 }
 
 static void CopyCustomElementPropertiesToGame(int element)
 {
   int i;
+  int access_type_and_layer;
 
-  element_info[properties_element] = custom_element;
+  if (level.use_custom_template)
+  {
+    if (Request("Copy and modify level tem- plate ?", REQ_ASK))
+    {
+      level.use_custom_template = FALSE;
+      ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE],
+                  GDI_CHECKED, FALSE, GDI_END);
+    }
+    else
+    {
+      LoadLevelTemplate(-1);
+
+      DrawEditModeWindow();
+    }
+  }
+
+  element_info[element] = custom_element;
 
   /* ---------- element settings: configure (custom elements) ------------- */
 
@@ -3739,30 +3783,31 @@ static void CopyCustomElementPropertiesToGame(int element)
   custom_element_properties[EP_PASSABLE_OVER] = FALSE;
   custom_element_properties[EP_PASSABLE_INSIDE] = FALSE;
   custom_element_properties[EP_PASSABLE_UNDER] = FALSE;
-  custom_element_properties[((value_access_type == EP_WALKABLE ?
-                             EP_WALKABLE_OVER : EP_PASSABLE_OVER) +
-                            (value_access_layer - EP_ACCESSIBLE_OVER))] =
+  access_type_and_layer = ((custom_element.access_type == EP_WALKABLE ?
+                           EP_WALKABLE_OVER : EP_PASSABLE_OVER) +
+                          (custom_element.access_layer - EP_ACCESSIBLE_OVER));
+  custom_element_properties[access_type_and_layer] =
     custom_element_properties[EP_ACCESSIBLE];
 
   /* set walk-to-object property from checkbox and selectbox */
   custom_element_properties[EP_DIGGABLE] = FALSE;
   custom_element_properties[EP_COLLECTIBLE] = FALSE;
   custom_element_properties[EP_PUSHABLE] = FALSE;
-  custom_element_properties[value_walk_to_action] =
+  custom_element_properties[custom_element.walk_to_action] =
     custom_element_properties[EP_WALK_TO_OBJECT];
 
   /* set smash property from checkbox and selectbox */
   custom_element_properties[EP_CAN_SMASH_PLAYER] = FALSE;
   custom_element_properties[EP_CAN_SMASH_ENEMIES] = FALSE;
   custom_element_properties[EP_CAN_SMASH_EVERYTHING] = FALSE;
-  custom_element_properties[value_smash_targets] =
+  custom_element_properties[custom_element.smash_targets] =
     custom_element_properties[EP_CAN_SMASH];
 
   /* set deadliness property from checkbox and selectbox */
   custom_element_properties[EP_DONT_RUN_INTO] = FALSE;
   custom_element_properties[EP_DONT_COLLIDE_WITH] = FALSE;
   custom_element_properties[EP_DONT_TOUCH] = FALSE;
-  custom_element_properties[value_deadliness] =
+  custom_element_properties[custom_element.deadliness] =
     custom_element_properties[EP_DEADLY];
 
   /* set consistency property from checkbox and selectbox */
@@ -3771,15 +3816,18 @@ static void CopyCustomElementPropertiesToGame(int element)
   custom_element_properties[EP_CAN_EXPLODE_BY_FIRE] = FALSE;
   custom_element_properties[EP_CAN_EXPLODE_SMASHED] = FALSE;
   custom_element_properties[EP_CAN_EXPLODE_IMPACT] = FALSE;
-  custom_element_properties[value_consistency] =
+  custom_element_properties[custom_element.consistency] =
     custom_element_properties[EP_EXPLODE_RESULT];
 
   /* special case: sub-settings dependent from main setting */
   if (custom_element_properties[EP_CAN_EXPLODE])
   {
-    custom_element_properties[EP_CAN_EXPLODE_BY_FIRE] = can_explode_by_fire;
-    custom_element_properties[EP_CAN_EXPLODE_SMASHED] = can_explode_smashed;
-    custom_element_properties[EP_CAN_EXPLODE_IMPACT]  = can_explode_impact;
+    custom_element_properties[EP_CAN_EXPLODE_BY_FIRE] =
+      custom_element.can_explode_by_fire;
+    custom_element_properties[EP_CAN_EXPLODE_SMASHED] =
+      custom_element.can_explode_smashed;
+    custom_element_properties[EP_CAN_EXPLODE_IMPACT] =
+      custom_element.can_explode_impact;
   }
 
   /* ---------- element settings: advanced (custom elements) --------------- */
@@ -3788,14 +3836,14 @@ static void CopyCustomElementPropertiesToGame(int element)
   custom_element_change_events[CE_TOUCHED_BY_PLAYER] = FALSE;
   custom_element_change_events[CE_PRESSED_BY_PLAYER] = FALSE;
   custom_element_change_events[CE_PUSHED_BY_PLAYER] = FALSE;
-  custom_element_change_events[value_change_player_action] =
+  custom_element_change_events[custom_element.change_player_action] =
     custom_element_change_events[CE_BY_PLAYER];
 
   /* set collision change event from checkbox and selectbox */
   custom_element_change_events[CE_COLLISION] = FALSE;
   custom_element_change_events[CE_IMPACT] = FALSE;
   custom_element_change_events[CE_SMASHED] = FALSE;
-  custom_element_change_events[value_change_collide_action] =
+  custom_element_change_events[custom_element.change_collide_action] =
     custom_element_change_events[CE_BY_COLLISION];
 
   /* set other element action change event from checkbox and selectbox */
@@ -3806,7 +3854,7 @@ static void CopyCustomElementPropertiesToGame(int element)
   custom_element_change_events[CE_OTHER_GETS_PRESSED] = FALSE;
   custom_element_change_events[CE_OTHER_GETS_PUSHED] = FALSE;
   custom_element_change_events[CE_OTHER_GETS_COLLECTED] = FALSE;
-  custom_element_change_events[value_change_other_action] =
+  custom_element_change_events[custom_element.change_other_action] =
     custom_element_change_events[CE_BY_OTHER];
 
   for (i=0; i < NUM_ELEMENT_PROPERTIES; i++)
@@ -3816,7 +3864,7 @@ static void CopyCustomElementPropertiesToGame(int element)
     SET_CHANGE_EVENT(element, i, custom_element_change_events[i]);
 
   /* copy change events also to special level editor variable */
-  custom_element = element_info[properties_element];
+  custom_element = element_info[element];
 }
 
 void DrawLevelEd()
@@ -3826,8 +3874,8 @@ void DrawLevelEd()
 
   if (level_editor_test_game)
   {
-    CopyPlayfield(Ur, Feld);
-    CopyPlayfield(FieldBackup, Ur);
+    CopyPlayfield(level.field, Feld);
+    CopyPlayfield(FieldBackup, level.field);
 
     level_editor_test_game = FALSE;
   }
@@ -3846,16 +3894,10 @@ void DrawLevelEd()
   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
             DOOR_GFX_PAGEX6, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY);
 
+#if 0
   /* draw mouse button brush elements */
-  DrawMiniGraphicExt(drawto,
-                    DX + ED_WIN_MB_LEFT_XPOS, DY + ED_WIN_MB_LEFT_YPOS,
-                    el2edimg(new_element1));
-  DrawMiniGraphicExt(drawto,
-                    DX + ED_WIN_MB_MIDDLE_XPOS, DY + ED_WIN_MB_MIDDLE_YPOS,
-                    el2edimg(new_element2));
-  DrawMiniGraphicExt(drawto,
-                    DX + ED_WIN_MB_RIGHT_XPOS, DY + ED_WIN_MB_RIGHT_YPOS,
-                    el2edimg(new_element3));
+  RedrawDrawingElements();
+#endif
 
   /* draw bigger door */
   DrawSpecialEditorDoor();
@@ -3867,17 +3909,19 @@ void DrawLevelEd()
   redraw_mask |= REDRAW_ALL;
 
   ReinitializeElementListButtons();    /* only needed after setup changes */
+#if 0
   ModifyEditorElementList();           /* may be needed for custom elements */
+#endif
 
   UnmapTapeButtons();
   MapControlButtons();
 
+  DrawEditModeWindow();
+
   /* copy actual editor door content to door double buffer for OpenDoor() */
   BlitBitmap(drawto, bitmap_db_door,
             DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
 
-  DrawEditModeWindow();
-
   OpenDoor(DOOR_OPEN_1);
 }
 
@@ -4528,19 +4572,9 @@ static void DrawPropertiesTabulatorGadgets()
   int gd_y = gd->y + gd_gi->height - 1;
   Pixel tab_color = GetPixel(gd->bitmap, gd_x, gd_y);
   int id_first = ED_TEXTBUTTON_ID_PROPERTIES_INFO;
-#if 1
   int id_last  = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG;
-#else
-  int id_last  = ED_TEXTBUTTON_ID_PROPERTIES_INFO;
-#endif
   int i;
 
-#if 0
-  /* draw additional "configure" tabulator for configurable elements */
-  if (checkPropertiesConfig())
-    id_last = ED_TEXTBUTTON_ID_PROPERTIES_CONFIG;
-#endif
-
   /* draw additional "advanced" tabulator for custom elements */
   if (IS_CUSTOM_ELEMENT(properties_element))
     id_last = ED_TEXTBUTTON_ID_PROPERTIES_ADVANCED;
@@ -4829,6 +4863,9 @@ static void DrawPropertiesConfig()
 
     /* draw drawing area gadgets */
     DrawCustomContentArea();
+
+    /* draw text input gadgets */
+    MapTextInputGadget(ED_TEXTINPUT_ID_ELEMENT_NAME);
   }
 }
 
@@ -4928,12 +4965,6 @@ static void DrawPropertiesWindow()
       !IS_CUSTOM_ELEMENT(properties_element))
     edit_mode_properties = ED_MODE_PROPERTIES_CONFIG;
 
-#if 0
-  if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG &&
-      !checkPropertiesConfig())
-    edit_mode_properties = ED_MODE_PROPERTIES_INFO;
-#endif
-
   if (IS_CUSTOM_ELEMENT(properties_element))
     CopyCustomElementPropertiesToEditor(properties_element);
 
@@ -4968,6 +4999,16 @@ static void DrawPropertiesWindow()
     DrawPropertiesAdvanced();
 }
 
+static void UpdateCustomElementGraphicGadgets()
+{
+  ModifyEditorElementList();
+  RedrawDrawingElements();
+
+  if (edit_mode == ED_MODE_PROPERTIES &&
+      edit_mode_properties == ED_MODE_PROPERTIES_ADVANCED)
+    DrawPropertiesAdvancedDrawingAreas();
+}
+
 static void DrawLineElement(int sx, int sy, int element, boolean change_level)
 {
   int lx = sx + level_xpos;
@@ -5702,32 +5743,36 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
        {
          new_element = GFX_ELEMENT(new_element);
          custom_element.gfx_element = new_element;
-         element_info[properties_element] = custom_element;
 
-         ModifyEditorElementList();
-         RedrawDrawingElements();
+         CopyCustomElementPropertiesToGame(properties_element);
+
+         UpdateCustomElementGraphicGadgets();
 
          FrameCounter = 0;     /* restart animation frame counter */
        }
        else if (id == GADGET_ID_CUSTOM_CONTENT)
        {
          custom_element.content[sx][sy] = new_element;
-         element_info[properties_element] = custom_element;
+
+         CopyCustomElementPropertiesToGame(properties_element);
        }
        else if (id == GADGET_ID_CUSTOM_CHANGE_TARGET)
        {
          custom_element.change.target_element = new_element;
-         element_info[properties_element] = custom_element;
+
+         CopyCustomElementPropertiesToGame(properties_element);
        }
        else if (id == GADGET_ID_CUSTOM_CHANGE_CONTENT)
        {
          custom_element.change.content[sx][sy] = new_element;
-         element_info[properties_element] = custom_element;
+
+         CopyCustomElementPropertiesToGame(properties_element);
        }
        else if (id == GADGET_ID_CUSTOM_CHANGE_TRIGGER)
        {
          custom_element.change.trigger_element = new_element;
-         element_info[properties_element] = custom_element;
+
+         CopyCustomElementPropertiesToGame(properties_element);
        }
        else if (id == GADGET_ID_RANDOM_BACKGROUND)
          random_placement_background_element = new_element;
@@ -5926,7 +5971,16 @@ static void HandleCounterButtons(struct GadgetInfo *gi)
 
 static void HandleTextInputGadgets(struct GadgetInfo *gi)
 {
-  strcpy(textinput_info[gi->custom_type_id].value, gi->text.value);
+  int type_id = gi->custom_type_id;
+
+  strcpy(textinput_info[type_id].value, gi->text.value);
+
+  if (type_id == ED_TEXTINPUT_ID_ELEMENT_NAME)
+  {
+    CopyCustomElementPropertiesToGame(properties_element);
+
+    ModifyEditorElementList(); /* update changed button info text */
+  }
 }
 
 static void HandleSelectboxGadgets(struct GadgetInfo *gi)
@@ -5945,13 +5999,26 @@ static void HandleSelectboxGadgets(struct GadgetInfo *gi)
 
 static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
 {
-  if (gi->custom_type_id >= ED_TEXTBUTTON_ID_PROPERTIES_INFO &&
-      gi->custom_type_id <= ED_TEXTBUTTON_ID_PROPERTIES_ADVANCED)
+  int type_id = gi->custom_type_id;
+
+  if (type_id >= ED_TEXTBUTTON_ID_PROPERTIES_INFO &&
+      type_id <= ED_TEXTBUTTON_ID_PROPERTIES_ADVANCED)
   {
     edit_mode_properties = gi->custom_type_id;
 
     DrawPropertiesWindow();
   }
+  else if (type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE)
+  {
+    boolean new_template = (!LevelFileExists(-1));
+
+    if (new_template ||
+       Request("Save this tem- plate and kill the old ?", REQ_ASK))
+      SaveLevelTemplate();
+
+    if (new_template)
+      Request("Tem- plate saved !", REQ_CONFIRM);
+  }
 }
 
 static void HandleRadiobuttons(struct GadgetInfo *gi)
@@ -5969,15 +6036,31 @@ static void HandleCheckbuttons(struct GadgetInfo *gi)
   if ((type_id >= ED_CHECKBUTTON_ID_CUSTOM_FIRST &&
        type_id <= ED_CHECKBUTTON_ID_CUSTOM_LAST) ||
       (type_id >= ED_CHECKBUTTON_ID_CHANGE_FIRST &&
-       type_id <= ED_CHECKBUTTON_ID_CHANGE_LAST))
+       type_id <= ED_CHECKBUTTON_ID_CHANGE_LAST &&
+       type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE))
+  {
     CopyCustomElementPropertiesToGame(properties_element);
+  }
 
   if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC)
   {
-    ModifyEditorElementList();
-    RedrawDrawingElements();
+    UpdateCustomElementGraphicGadgets();
+  }
+  else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE)
+  {
+    if (level.use_custom_template && !LevelFileExists(-1))
+    {
+      Request("No level tem- plate found !", REQ_CONFIRM);
 
-    DrawPropertiesAdvancedDrawingAreas();
+      level.use_custom_template = FALSE;
+      ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END);
+
+      return;
+    }
+
+    LoadLevelTemplate(level.use_custom_template ? -1 : level_nr);
+
+    DrawEditModeWindow();
   }
 }
 
@@ -6225,12 +6308,18 @@ static void HandleControlButtons(struct GadgetInfo *gi)
        Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
       else
       {
-       if (Request("Save this level and kill the old ?", REQ_ASK))
+       boolean new_level = (!LevelFileExists(level_nr));
+
+       if (new_level ||
+           Request("Save this level and kill the old ?", REQ_ASK))
        {
-         CopyPlayfield(Feld, Ur);
+         CopyPlayfield(Feld, level.field);
 
          SaveLevel(level_nr);
        }
+
+       if (new_level)
+         Request("Level saved !", REQ_CONFIRM);
       }
       break;
 
@@ -6242,8 +6331,8 @@ static void HandleControlButtons(struct GadgetInfo *gi)
        if (LevelChanged())
          level.game_version = GAME_VERSION_ACTUAL;
 
-       CopyPlayfield(Ur, FieldBackup);
-       CopyPlayfield(Feld, Ur);
+       CopyPlayfield(level.field, FieldBackup);
+       CopyPlayfield(Feld, level.field);
 
        UnmapLevelEditorGadgets();
        UndrawSpecialEditorDoor();