rnd-20030719-4-src
[rocksndiamonds.git] / src / editor.c
index 969aad79e6f72a4688bcdea75d87b3e7bc96a212..860b4248dfce780207cc0c261e6e66fa99bd7e21 100644 (file)
 #define ED_AREA_ELEM_CONTENT_XPOS      ( 2 * MINI_TILEX)
 #define ED_AREA_ELEM_CONTENT_YPOS      (22 * MINI_TILEY)
 
+/* yamyam content */
+#define ED_AREA_YAMYAM_CONTENT_XPOS(n) (ED_AREA_ELEM_CONTENT_XPOS + \
+                                        5 * (n % 4) * MINI_TILEX)
+#define ED_AREA_YAMYAM_CONTENT_YPOS(n) (ED_AREA_ELEM_CONTENT_YPOS + \
+                                        6 * (n / 4) * MINI_TILEY)
+
 /* custom change target */
 #define ED_AREA_ELEM_CONTENT2_XPOS     (20 * MINI_TILEX)
 #define ED_AREA_ELEM_CONTENT2_YPOS     (ED_SETTINGS_YPOS(2) + \
 #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)
 #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
 #define ED_RADIOBUTTON_ID_LEVEL_FIRST  ED_RADIOBUTTON_ID_PERCENTAGE
 #define ED_RADIOBUTTON_ID_LEVEL_LAST   ED_RADIOBUTTON_ID_QUANTITY
 
+/* values for drawing area gadgets */
+#define ED_DRAWING_ID_DRAWING_LEVEL            0
+#define ED_DRAWING_ID_ELEMENT_CONTENT_0                1
+#define ED_DRAWING_ID_ELEMENT_CONTENT_1                2
+#define ED_DRAWING_ID_ELEMENT_CONTENT_2                3
+#define ED_DRAWING_ID_ELEMENT_CONTENT_3                4
+#define ED_DRAWING_ID_ELEMENT_CONTENT_4                5
+#define ED_DRAWING_ID_ELEMENT_CONTENT_5                6
+#define ED_DRAWING_ID_ELEMENT_CONTENT_6                7
+#define ED_DRAWING_ID_ELEMENT_CONTENT_7                8
+#define ED_DRAWING_ID_AMOEBA_CONTENT           9
+#define ED_DRAWING_ID_CUSTOM_GRAPHIC           10
+#define ED_DRAWING_ID_CUSTOM_CONTENT           11
+#define ED_DRAWING_ID_CUSTOM_CHANGE_TARGET     12
+#define ED_DRAWING_ID_CUSTOM_CHANGE_CONTENT    13
+#define ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER    14
+#define ED_DRAWING_ID_RANDOM_BACKGROUND                15
+
+#define ED_NUM_DRAWING_AREAS                   16
+
 
 /*
   -----------------------------------------------------------------------------
@@ -957,11 +985,23 @@ 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 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[] =
 {
   { EP_DONT_RUN_INTO,          "running into"                  },
@@ -1088,6 +1128,14 @@ static struct
     &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,
@@ -1367,7 +1415,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),
@@ -1470,6 +1518,138 @@ static struct
   },
 };
 
+static struct
+{
+  int x, y;
+  int area_xsize, area_ysize;
+  int gadget_id;
+  char *text_left;
+} drawingarea_info[ED_NUM_DRAWING_AREAS] =
+{
+  /* ---------- level playfield content ------------------------------------ */
+
+  {
+    0, 0,
+    MAX_ED_FIELDX, MAX_ED_FIELDY,
+    GADGET_ID_DRAWING_LEVEL,
+    NULL
+  },
+
+  /* ---------- yam yam content -------------------------------------------- */
+
+  {
+    ED_AREA_YAMYAM_CONTENT_XPOS(0),    ED_AREA_YAMYAM_CONTENT_YPOS(0),
+    3, 3,
+    GADGET_ID_ELEMENT_CONTENT_0,
+    NULL
+  },
+  {
+    ED_AREA_YAMYAM_CONTENT_XPOS(1),    ED_AREA_YAMYAM_CONTENT_YPOS(1),
+    3, 3,
+    GADGET_ID_ELEMENT_CONTENT_1,
+    NULL
+  },
+  {
+    ED_AREA_YAMYAM_CONTENT_XPOS(2),    ED_AREA_YAMYAM_CONTENT_YPOS(2),
+    3, 3,
+    GADGET_ID_ELEMENT_CONTENT_2,
+    NULL
+  },
+  {
+    ED_AREA_YAMYAM_CONTENT_XPOS(3),    ED_AREA_YAMYAM_CONTENT_YPOS(3),
+    3, 3,
+    GADGET_ID_ELEMENT_CONTENT_3,
+    NULL
+  },
+  {
+    ED_AREA_YAMYAM_CONTENT_XPOS(4),    ED_AREA_YAMYAM_CONTENT_YPOS(4),
+    3, 3,
+    GADGET_ID_ELEMENT_CONTENT_4,
+    NULL
+  },
+  {
+    ED_AREA_YAMYAM_CONTENT_XPOS(5),    ED_AREA_YAMYAM_CONTENT_YPOS(5),
+    3, 3,
+    GADGET_ID_ELEMENT_CONTENT_5,
+    NULL
+  },
+  {
+    ED_AREA_YAMYAM_CONTENT_XPOS(6),    ED_AREA_YAMYAM_CONTENT_YPOS(6),
+    3, 3,
+    GADGET_ID_ELEMENT_CONTENT_6,
+    NULL
+  },
+  {
+    ED_AREA_YAMYAM_CONTENT_XPOS(7),    ED_AREA_YAMYAM_CONTENT_YPOS(7),
+    3, 3,
+    GADGET_ID_ELEMENT_CONTENT_7,
+    NULL
+  },
+
+  /* ---------- amoeba content --------------------------------------------- */
+
+  {
+    ED_AREA_ELEM_CONTENT_XPOS,         ED_AREA_ELEM_CONTENT_YPOS,
+    1, 1,
+    GADGET_ID_AMOEBA_CONTENT,
+    NULL
+  },
+
+  /* ---------- custom graphic --------------------------------------------- */
+
+  {
+    ED_AREA_ELEM_CONTENT3_XPOS,                ED_AREA_ELEM_CONTENT3_YPOS,
+    1, 1,
+    GADGET_ID_CUSTOM_GRAPHIC,
+    NULL
+  },
+
+  /* ---------- custom content (when exploding) ---------------------------- */
+
+  {
+    ED_AREA_ELEM_CONTENT4_XPOS,                ED_AREA_ELEM_CONTENT4_YPOS,
+    3, 3,
+    GADGET_ID_CUSTOM_CONTENT,
+    NULL
+  },
+
+  /* ---------- custom change target --------------------------------------- */
+
+  {
+    ED_AREA_ELEM_CONTENT2_XPOS,                ED_AREA_ELEM_CONTENT2_YPOS,
+    1, 1,
+    GADGET_ID_CUSTOM_CHANGE_TARGET,
+    NULL
+  },
+
+  /* ---------- custom change content (extended change target) ------------- */
+
+  {
+    ED_AREA_ELEM_CONTENT6_XPOS,                ED_AREA_ELEM_CONTENT6_YPOS,
+    3, 3,
+    GADGET_ID_CUSTOM_CHANGE_CONTENT,
+    NULL
+  },
+
+  /* ---------- custom change trigger (element causing change) ------------- */
+
+  {
+    ED_AREA_ELEM_CONTENT5_XPOS,                ED_AREA_ELEM_CONTENT5_YPOS,
+    1, 1,
+    GADGET_ID_CUSTOM_CHANGE_TRIGGER,
+    NULL
+  },
+
+  /* ---------- random background (for random painting) -------------------- */
+
+  {
+    ED_AREA_RANDOM_BACKGROUND_XPOS,    ED_AREA_RANDOM_BACKGROUND_YPOS,
+    1, 1,
+    GADGET_ID_RANDOM_BACKGROUND,
+    NULL
+  },
+};
+
 
 /*
   -----------------------------------------------------------------------------
@@ -1500,6 +1680,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();
@@ -2789,47 +2970,26 @@ static void CreateCounterButtons()
 
 static void CreateDrawingAreas()
 {
-  struct GadgetInfo *gi;
-  unsigned long event_mask;
-  int id;
   int i;
 
-  event_mask =
-    GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
-    GD_EVENT_OFF_BORDERS;
-
-  /* one for the level drawing area ... */
-  id = GADGET_ID_DRAWING_LEVEL;
-  gi = CreateGadget(GDI_CUSTOM_ID, id,
-                   GDI_X, SX,
-                   GDI_Y, SY,
-                   GDI_TYPE, GD_TYPE_DRAWING_AREA,
-                   GDI_AREA_SIZE, ed_fieldx, ed_fieldy,
-                   GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
-                   GDI_EVENT_MASK, event_mask,
-                   GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
-                   GDI_CALLBACK_ACTION, HandleDrawingAreas,
-                   GDI_END);
-
-  if (gi == NULL)
-    Error(ERR_EXIT, "cannot create gadget");
-
-  level_editor_gadget[id] = gi;
-
-  /* ... up to eight areas for element content ... */
-  for (i=0; i<MAX_ELEMENT_CONTENTS; i++)
+  for (i=0; i<ED_NUM_DRAWING_AREAS; i++)
   {
-    int gx = SX + ED_AREA_ELEM_CONTENT_XPOS + 5 * (i % 4) * MINI_TILEX;
-    int gy = SX + ED_AREA_ELEM_CONTENT_YPOS + 6 * (i / 4) * MINI_TILEY;
+    struct GadgetInfo *gi;
+    unsigned long event_mask;
+    int id = drawingarea_info[i].gadget_id;
+    int area_xsize = drawingarea_info[i].area_xsize;
+    int area_ysize = drawingarea_info[i].area_ysize;
+
+    event_mask =
+      GD_EVENT_PRESSED | GD_EVENT_RELEASED | GD_EVENT_MOVING |
+      GD_EVENT_OFF_BORDERS;
 
-    id = GADGET_ID_ELEMENT_CONTENT_0 + i;
     gi = CreateGadget(GDI_CUSTOM_ID, id,
                      GDI_CUSTOM_TYPE_ID, i,
-                     GDI_X, gx,
-                     GDI_Y, gy,
-                     GDI_WIDTH, 3 * MINI_TILEX,
-                     GDI_HEIGHT, 3 * MINI_TILEY,
+                     GDI_X, SX + drawingarea_info[i].x,
+                     GDI_Y, SY + drawingarea_info[i].y,
                      GDI_TYPE, GD_TYPE_DRAWING_AREA,
+                     GDI_AREA_SIZE, area_xsize, area_ysize,
                      GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
                      GDI_EVENT_MASK, event_mask,
                      GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
@@ -2841,141 +3001,6 @@ static void CreateDrawingAreas()
 
     level_editor_gadget[id] = gi;
   }
-
-  /* ... one for the amoeba content ... */
-  id = GADGET_ID_AMOEBA_CONTENT;
-  gi = CreateGadget(GDI_CUSTOM_ID, id,
-                   GDI_X, SX + ED_AREA_ELEM_CONTENT_XPOS,
-                   GDI_Y, SY + ED_AREA_ELEM_CONTENT_YPOS,
-                   GDI_WIDTH, MINI_TILEX,
-                   GDI_HEIGHT, MINI_TILEY,
-                   GDI_TYPE, GD_TYPE_DRAWING_AREA,
-                   GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
-                   GDI_EVENT_MASK, event_mask,
-                   GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
-                   GDI_CALLBACK_ACTION, HandleDrawingAreas,
-                   GDI_END);
-
-  if (gi == NULL)
-    Error(ERR_EXIT, "cannot create gadget");
-
-  level_editor_gadget[id] = gi;
-
-  /* ... one for each custom element optional graphic element ... */
-  id = GADGET_ID_CUSTOM_GRAPHIC;
-  gi = CreateGadget(GDI_CUSTOM_ID, id,
-                   GDI_X, SX + ED_AREA_ELEM_CONTENT3_XPOS,
-                   GDI_Y, SY + ED_AREA_ELEM_CONTENT3_YPOS,
-                   GDI_WIDTH, MINI_TILEX,
-                   GDI_HEIGHT, MINI_TILEY,
-                   GDI_TYPE, GD_TYPE_DRAWING_AREA,
-                   GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
-                   GDI_EVENT_MASK, event_mask,
-                   GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
-                   GDI_CALLBACK_ACTION, HandleDrawingAreas,
-                   GDI_END);
-
-  if (gi == NULL)
-    Error(ERR_EXIT, "cannot create gadget");
-
-  level_editor_gadget[id] = gi;
-
-  /* ... one area for custom element explosion content ... */
-  id = GADGET_ID_CUSTOM_CONTENT;
-  gi = CreateGadget(GDI_CUSTOM_ID, id,
-                   GDI_CUSTOM_TYPE_ID, i,
-                   GDI_X, SX + ED_AREA_ELEM_CONTENT4_XPOS,
-                   GDI_Y, SX + ED_AREA_ELEM_CONTENT4_YPOS,
-                   GDI_WIDTH, 3 * MINI_TILEX,
-                   GDI_HEIGHT, 3 * MINI_TILEY,
-                   GDI_TYPE, GD_TYPE_DRAWING_AREA,
-                   GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
-                   GDI_EVENT_MASK, event_mask,
-                   GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
-                   GDI_CALLBACK_ACTION, HandleDrawingAreas,
-                   GDI_END);
-
-  if (gi == NULL)
-    Error(ERR_EXIT, "cannot create gadget");
-
-  level_editor_gadget[id] = gi;
-
-  /* ... one for each custom element change target element ... */
-  id = GADGET_ID_CUSTOM_CHANGE_TARGET;
-  gi = CreateGadget(GDI_CUSTOM_ID, id,
-                   GDI_X, SX + ED_AREA_ELEM_CONTENT2_XPOS,
-                   GDI_Y, SY + ED_AREA_ELEM_CONTENT2_YPOS,
-                   GDI_WIDTH, MINI_TILEX,
-                   GDI_HEIGHT, MINI_TILEY,
-                   GDI_TYPE, GD_TYPE_DRAWING_AREA,
-                   GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
-                   GDI_EVENT_MASK, event_mask,
-                   GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
-                   GDI_CALLBACK_ACTION, HandleDrawingAreas,
-                   GDI_END);
-
-  if (gi == NULL)
-    Error(ERR_EXIT, "cannot create gadget");
-
-  level_editor_gadget[id] = gi;
-
-  /* ... one area for extended custom element change target content ... */
-  id = GADGET_ID_CUSTOM_CHANGE_CONTENT;
-  gi = CreateGadget(GDI_CUSTOM_ID, id,
-                   GDI_CUSTOM_TYPE_ID, i,
-                   GDI_X, SX + ED_AREA_ELEM_CONTENT6_XPOS,
-                   GDI_Y, SX + ED_AREA_ELEM_CONTENT6_YPOS,
-                   GDI_WIDTH, 3 * MINI_TILEX,
-                   GDI_HEIGHT, 3 * MINI_TILEY,
-                   GDI_TYPE, GD_TYPE_DRAWING_AREA,
-                   GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
-                   GDI_EVENT_MASK, event_mask,
-                   GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
-                   GDI_CALLBACK_ACTION, HandleDrawingAreas,
-                   GDI_END);
-
-  if (gi == NULL)
-    Error(ERR_EXIT, "cannot create gadget");
-
-  level_editor_gadget[id] = gi;
-
-  /* ... one for each custom element change trigger element ... */
-  id = GADGET_ID_CUSTOM_CHANGE_TRIGGER;
-  gi = CreateGadget(GDI_CUSTOM_ID, id,
-                   GDI_X, SX + ED_AREA_ELEM_CONTENT5_XPOS,
-                   GDI_Y, SY + ED_AREA_ELEM_CONTENT5_YPOS,
-                   GDI_WIDTH, MINI_TILEX,
-                   GDI_HEIGHT, MINI_TILEY,
-                   GDI_TYPE, GD_TYPE_DRAWING_AREA,
-                   GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
-                   GDI_EVENT_MASK, event_mask,
-                   GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
-                   GDI_CALLBACK_ACTION, HandleDrawingAreas,
-                   GDI_END);
-
-  if (gi == NULL)
-    Error(ERR_EXIT, "cannot create gadget");
-
-  level_editor_gadget[id] = gi;
-
-  /* ... and one for random placement background restrictions */
-  id = GADGET_ID_RANDOM_BACKGROUND;
-  gi = CreateGadget(GDI_CUSTOM_ID, id,
-                   GDI_X, SX + ED_AREA_RANDOM_BACKGROUND_XPOS,
-                   GDI_Y, SY + ED_AREA_RANDOM_BACKGROUND_YPOS,
-                   GDI_WIDTH, MINI_TILEX,
-                   GDI_HEIGHT, MINI_TILEY,
-                   GDI_TYPE, GD_TYPE_DRAWING_AREA,
-                   GDI_ITEM_SIZE, MINI_TILEX, MINI_TILEY,
-                   GDI_EVENT_MASK, event_mask,
-                   GDI_CALLBACK_INFO, HandleDrawingAreaInfo,
-                   GDI_CALLBACK_ACTION, HandleDrawingAreas,
-                   GDI_END);
-
-  if (gi == NULL)
-    Error(ERR_EXIT, "cannot create gadget");
-
-  level_editor_gadget[id] = gi;
 }
 
 static void CreateTextInputGadgets()
@@ -3455,7 +3480,8 @@ static void MapSelectboxGadget(int id)
   int x = selectbox_info[id].x + xoffset_left;
   int y = selectbox_info[id].y + yoffset_left;
 
-  DrawTextF(x, y, FONT_TEXT_1, selectbox_info[id].text_left);
+  if (selectbox_info[id].text_left)
+    DrawTextF(x, y, FONT_TEXT_1, selectbox_info[id].text_left);
 
   if (selectbox_info[id].text_right)
   {
@@ -3486,7 +3512,9 @@ static void MapRadiobuttonGadget(int id)
   boolean checked =
     (*radiobutton_info[id].value == radiobutton_info[id].checked_value);
 
-  DrawTextF(x, y, FONT_TEXT_1, radiobutton_info[id].text_right);
+  if (radiobutton_info[id].text_right)
+    DrawTextF(x, y, FONT_TEXT_1, radiobutton_info[id].text_right);
+
   ModifyGadget(level_editor_gadget[radiobutton_info[id].gadget_id],
               GDI_CHECKED, checked, GDI_END);
 
@@ -3500,7 +3528,9 @@ static void MapCheckbuttonGadget(int id)
   int x = checkbutton_info[id].x + xoffset_right;
   int y = checkbutton_info[id].y + yoffset_right;
 
-  DrawTextF(x, y, FONT_TEXT_1, checkbutton_info[id].text_right);
+  if (checkbutton_info[id].text_right)
+    DrawTextF(x, y, FONT_TEXT_1, checkbutton_info[id].text_right);
+
   ModifyGadget(level_editor_gadget[checkbutton_info[id].gadget_id],
               GDI_CHECKED, *checkbutton_info[id].value,
               GDI_Y, SY + checkbutton_info[id].y, GDI_END);
@@ -3570,6 +3600,9 @@ static void ResetUndoBuffer()
 
 static void DrawEditModeWindow()
 {
+  ModifyEditorElementList();
+  RedrawDrawingElements();
+
   if (edit_mode == ED_MODE_INFO)
     DrawLevelInfoWindow();
   else if (edit_mode == ED_MODE_PROPERTIES)
@@ -3585,7 +3618,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;
@@ -3622,7 +3655,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);
@@ -3730,7 +3763,23 @@ 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) ------------- */
 
@@ -3822,7 +3871,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()
@@ -3832,8 +3881,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;
   }
@@ -3852,16 +3901,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();
@@ -3873,17 +3916,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);
 }
 
@@ -4961,6 +5006,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;
@@ -5695,34 +5750,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);
 
-         DrawPropertiesAdvancedDrawingAreas();
+         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;
@@ -5949,13 +6006,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)
@@ -5973,15 +6043,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();
   }
 }
 
@@ -6229,12 +6315,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;
 
@@ -6246,8 +6338,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();