rnd-20030208-2-src
[rocksndiamonds.git] / src / editor.c
index c6b2632a6f90970a4af49d84e6caf8957a5ae98b..ed78feab149af7f69bbd7efbb7416d79d9ff8514 100644 (file)
 #define GADGET_ID_ELEM_CONTENT_6       56
 #define GADGET_ID_ELEM_CONTENT_7       57
 #define GADGET_ID_AMOEBA_CONTENT       58
+#define GADGET_ID_RANDOM_BACKGROUND    59
 
 /* text input identifiers */
-#define GADGET_ID_LEVEL_NAME           59
-#define GADGET_ID_LEVEL_AUTHOR         60
+#define GADGET_ID_LEVEL_NAME           60
+#define GADGET_ID_LEVEL_AUTHOR         61
 
 /* gadgets for scrolling of drawing area */
-#define GADGET_ID_SCROLL_UP            61
-#define GADGET_ID_SCROLL_DOWN          62
-#define GADGET_ID_SCROLL_LEFT          63
-#define GADGET_ID_SCROLL_RIGHT         64
-#define GADGET_ID_SCROLL_HORIZONTAL    65
-#define GADGET_ID_SCROLL_VERTICAL      66
+#define GADGET_ID_SCROLL_UP            62
+#define GADGET_ID_SCROLL_DOWN          63
+#define GADGET_ID_SCROLL_LEFT          64
+#define GADGET_ID_SCROLL_RIGHT         65
+#define GADGET_ID_SCROLL_HORIZONTAL    66
+#define GADGET_ID_SCROLL_VERTICAL      67
 
 /* gadgets for scrolling element list */
-#define GADGET_ID_SCROLL_LIST_UP       67
-#define GADGET_ID_SCROLL_LIST_DOWN     68
-#define GADGET_ID_SCROLL_LIST_VERTICAL 69
-
-/* buttons for level settings */
-#define GADGET_ID_RANDOM_PERCENTAGE    70
-#define GADGET_ID_RANDOM_QUANTITY      71
-#define GADGET_ID_RANDOM_RESTRICTED    72
-#define GADGET_ID_DOUBLE_SPEED         73
-#define GADGET_ID_GRAVITY              74
-#define GADGET_ID_STICK_ELEMENT                75
-#define GADGET_ID_EM_SLIPPERY_GEMS     76
-
-/* another drawing area for random placement */
-#define GADGET_ID_RANDOM_BACKGROUND    77
+#define GADGET_ID_SCROLL_LIST_UP       68
+#define GADGET_ID_SCROLL_LIST_DOWN     69
+#define GADGET_ID_SCROLL_LIST_VERTICAL 70
+
+/* buttons for level/element properties */
+#define GADGET_ID_RANDOM_PERCENTAGE    71
+#define GADGET_ID_RANDOM_QUANTITY      72
+#define GADGET_ID_RANDOM_RESTRICTED    73
+#define GADGET_ID_DOUBLE_SPEED         74
+#define GADGET_ID_GRAVITY              75
+#define GADGET_ID_STICK_ELEMENT                76
+#define GADGET_ID_EM_SLIPPERY_GEMS     77
+#define GADGET_ID_CUSTOM_INDESTRUCTIBLE        78
+#define GADGET_ID_CUSTOM_CAN_FALL      79
+#define GADGET_ID_CUSTOM_SLIPPERY      80
 
 /* gadgets for buttons in element list */
-#define GADGET_ID_ELEMENTLIST_FIRST    78
-#define GADGET_ID_ELEMENTLIST_LAST     (78 + ED_NUM_ELEMENTLIST_BUTTONS - 1)
+#define GADGET_ID_ELEMENTLIST_FIRST    81
+#define GADGET_ID_ELEMENTLIST_LAST     (81 + ED_NUM_ELEMENTLIST_BUTTONS - 1)
 
 #define NUM_EDITOR_GADGETS             (GADGET_ID_ELEMENTLIST_LAST + 1)
 
 #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_INDESTRUCTIBLE        5
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL      6
+#define ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY      7
 
-#define ED_NUM_CHECKBUTTONS                    5
+#define ED_NUM_CHECKBUTTONS                    8
 
 #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_INDESTRUCTIBLE
+#define ED_CHECKBUTTON_ID_CUSTOM_LAST  ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY
+
 /* values for radiobutton gadgets */
 #define ED_RADIOBUTTON_ID_PERCENTAGE   0
 #define ED_RADIOBUTTON_ID_QUANTITY     1
@@ -424,6 +431,13 @@ static int random_placement_background_element = EL_SAND;
 static boolean random_placement_background_restricted = FALSE;
 static boolean stick_element_properties_window = FALSE;
 
+static struct
+{
+  boolean indestructible;
+  boolean can_fall;
+  boolean slippery;
+} custom_element_properties[NUM_CUSTOM_ELEMENTS];
+
 static struct
 {
   int x, y;
@@ -678,6 +692,24 @@ static struct
     GADGET_ID_EM_SLIPPERY_GEMS,
     &level.em_slippery_gems,
     "slip down from certain flat walls","use EM style slipping behaviour"
+  },
+  {
+    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS(4),
+    GADGET_ID_CUSTOM_INDESTRUCTIBLE,
+    &custom_element_properties[0].indestructible,
+    "indestructible",                  "element cannot be destroyed"
+  },
+  {
+    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS(5),
+    GADGET_ID_CUSTOM_CAN_FALL,
+    &custom_element_properties[0].can_fall,
+    "can fall",                                "element can fall down"
+  },
+  {
+    ED_SETTINGS_XPOS,                  ED_COUNTER_YPOS(6),
+    GADGET_ID_CUSTOM_SLIPPERY,
+    &custom_element_properties[0].slippery,
+    "slippery",                                "other elements can fall down from it"
   }
 };
 
@@ -1563,13 +1595,22 @@ static void ReinitializeElementListButtons()
 
 static char *getElementInfoText(int element)
 {
-  char *info_text = "unknown";
+  char *info_text = NULL;
+
+  if (element < NUM_FILE_ELEMENTS)
+  {
+    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;
+  }
+
+  if (info_text == NULL)
+  {
+    info_text = "unknown";
 
-  if (element < NUM_FILE_ELEMENTS &&
-      element_info[element].editor_description != NULL)
-    info_text = element_info[element].editor_description;
-  else
     Error(ERR_WARN, "no element description for element %d", element);
+  }
 
   return info_text;
 }
@@ -1606,7 +1647,7 @@ static void ScrollMiniLevel(int from_x, int from_y, int scroll)
 
 static void CreateControlButtons()
 {
-  Bitmap *gd_bitmap = new_graphic_info[IMG_MENU_DOOR].bitmap;
+  Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
   struct GadgetInfo *gi;
   unsigned long event_mask;
   int i;
@@ -1784,7 +1825,7 @@ static void CreateControlButtons()
     gd_x2 = DOOR_GFX_PAGEX6 + ED_ELEMENTLIST_XPOS;
     gd_y  = DOOR_GFX_PAGEY1 + ED_ELEMENTLIST_YPOS;
 
-    getMiniGraphicSource(el2img(element), &deco_bitmap, &deco_x, &deco_y);
+    getMiniGraphicSource(el2edimg(element), &deco_bitmap, &deco_x, &deco_y);
     deco_xpos = (ED_ELEMENTLIST_XSIZE - MINI_TILEX) / 2;
     deco_ypos = (ED_ELEMENTLIST_YSIZE - MINI_TILEY) / 2;
 
@@ -1827,7 +1868,7 @@ static void CreateCounterButtons()
 
     for (j=0; j<2; j++)
     {
-      Bitmap *gd_bitmap = new_graphic_info[IMG_MENU_DOOR].bitmap;
+      Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
       struct GadgetInfo *gi;
       int id = (j == 0 ?
                counterbutton_info[i].gadget_id_down :
@@ -2049,7 +2090,7 @@ static void CreateTextInputGadgets()
 
   for (i=0; i<ED_NUM_TEXTINPUT; i++)
   {
-    Bitmap *gd_bitmap = new_graphic_info[IMG_MENU_DOOR].bitmap;
+    Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
     int gd_x, gd_y;
     struct GadgetInfo *gi;
     unsigned long event_mask;
@@ -2096,7 +2137,7 @@ static void CreateScrollbarGadgets()
   for (i=0; i<ED_NUM_SCROLLBARS; i++)
   {
     int id = scrollbar_info[i].gadget_id;
-    Bitmap *gd_bitmap = new_graphic_info[IMG_MENU_DOOR].bitmap;
+    Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
     int gd_x1, gd_x2, gd_y1, gd_y2;
     struct GadgetInfo *gi;
     int items_max, items_visible, item_position;
@@ -2161,7 +2202,7 @@ static void CreateScrollbarGadgets()
 
 static void CreateCheckbuttonGadgets()
 {
-  Bitmap *gd_bitmap = new_graphic_info[IMG_MENU_DOOR].bitmap;
+  Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
   struct GadgetInfo *gi;
   unsigned long event_mask;
   int gd_x1, gd_x2, gd_x3, gd_x4, gd_y;
@@ -2411,6 +2452,63 @@ static boolean LevelContainsPlayer()
   return player_found;
 }
 
+static void CopyPlayfield(short src[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
+                         short dst[MAX_LEV_FIELDX][MAX_LEV_FIELDY])
+{
+  int x, y;
+
+  for(x=0; x<lev_fieldx; x++)
+    for(y=0; y<lev_fieldy; y++) 
+      dst[x][y] = src[x][y];
+}
+
+static void CopyCustomElementPropertiesToEditor()
+{
+  int i;
+
+  for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
+  {
+    int element = EL_CUSTOM_START + i;
+    int properties = Properties1[element];
+
+    custom_element_properties[i].indestructible =
+      ((properties & EP_BIT_MASSIVE) != 0 ? TRUE : FALSE);
+
+    custom_element_properties[i].can_fall =
+      ((properties & EP_BIT_CAN_FALL) != 0 ? TRUE : FALSE);
+
+    custom_element_properties[i].slippery =
+      ((properties & EP_BIT_SLIPPERY) != 0 ? TRUE : FALSE);
+  }
+}
+
+static void CopyCustomElementPropertiesToGame()
+{
+  int i;
+
+  for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
+  {
+    int element = EL_CUSTOM_START + i;
+
+    Properties1[element] = EP_BITMASK_DEFAULT;
+
+    if (custom_element_properties[i].indestructible)
+      Properties1[element] |= EP_BIT_MASSIVE;
+    else
+      Properties1[element] &= ~EP_BIT_MASSIVE;
+
+    if (custom_element_properties[i].can_fall)
+      Properties1[element] |= EP_BIT_CAN_FALL;
+    else
+      Properties1[element] &= ~EP_BIT_CAN_FALL;
+
+    if (custom_element_properties[i].slippery)
+      Properties1[element] |= EP_BIT_SLIPPERY;
+    else
+      Properties1[element] &= ~EP_BIT_SLIPPERY;
+  }
+}
+
 void DrawLevelEd()
 {
   CloseDoor(DOOR_CLOSE_ALL);
@@ -2418,15 +2516,8 @@ void DrawLevelEd()
 
   if (level_editor_test_game)
   {
-    int x, y;
-
-    for(x=0; x<lev_fieldx; x++)
-      for(y=0; y<lev_fieldy; y++)
-       Feld[x][y] = Ur[x][y];
-
-    for(x=0; x<lev_fieldx; x++)
-      for(y=0; y<lev_fieldy; y++)
-       Ur[x][y] = FieldBackup[x][y];
+    CopyPlayfield(Ur, Feld);
+    CopyPlayfield(FieldBackup, Ur);
 
     level_editor_test_game = FALSE;
   }
@@ -2440,25 +2531,25 @@ void DrawLevelEd()
   }
 
   /* copy default editor door content to main double buffer */
-  BlitBitmap(new_graphic_info[IMG_MENU_DOOR].bitmap, drawto,
+  BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
             DOOR_GFX_PAGEX6, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY);
 
   /* draw mouse button brush elements */
   DrawMiniGraphicExt(drawto,
                     DX + ED_WIN_MB_LEFT_XPOS, DY + ED_WIN_MB_LEFT_YPOS,
-                    el2img(new_element1));
+                    el2edimg(new_element1));
   DrawMiniGraphicExt(drawto,
                     DX + ED_WIN_MB_MIDDLE_XPOS, DY + ED_WIN_MB_MIDDLE_YPOS,
-                    el2img(new_element2));
+                    el2edimg(new_element2));
   DrawMiniGraphicExt(drawto,
                     DX + ED_WIN_MB_RIGHT_XPOS, DY + ED_WIN_MB_RIGHT_YPOS,
-                    el2img(new_element3));
+                    el2edimg(new_element3));
 
   /* draw bigger door */
   DrawSpecialEditorDoor();
 
   /* draw new control window */
-  BlitBitmap(new_graphic_info[IMG_MENU_DOOR].bitmap, drawto,
+  BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
             DOOR_GFX_PAGEX8, 236, EXSIZE, EYSIZE, EX, EY);
 
   redraw_mask |= REDRAW_ALL;
@@ -2628,21 +2719,21 @@ static void PickDrawingElement(int button, int element)
     new_element1 = element;
     DrawMiniGraphicExt(drawto,
                       DX + ED_WIN_MB_LEFT_XPOS, DY + ED_WIN_MB_LEFT_YPOS,
-                      el2img(new_element1));
+                      el2edimg(new_element1));
   }
   else if (button == 2)
   {
     new_element2 = element;
     DrawMiniGraphicExt(drawto,
                       DX + ED_WIN_MB_MIDDLE_XPOS, DY + ED_WIN_MB_MIDDLE_YPOS,
-                      el2img(new_element2));
+                      el2edimg(new_element2));
   }
   else
   {
     new_element3 = element;
     DrawMiniGraphicExt(drawto,
                       DX + ED_WIN_MB_RIGHT_XPOS, DY + ED_WIN_MB_RIGHT_YPOS,
-                      el2img(new_element3));
+                      el2edimg(new_element3));
   }
 
   redraw_mask |= REDRAW_DOOR_1;
@@ -2650,46 +2741,49 @@ static void PickDrawingElement(int button, int element)
 
 static void DrawDrawingWindow()
 {
+  SetMainBackgroundImage(IMG_UNDEFINED);
   ClearWindow();
-
-#if 1
-  ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
-  redraw_mask |= REDRAW_FROM_BACKBUFFER;
-#endif
-
   UnmapLevelEditorWindowGadgets();
+
   AdjustDrawingAreaGadgets();
   AdjustLevelScrollPosition();
   AdjustEditorScrollbar(GADGET_ID_SCROLL_HORIZONTAL);
   AdjustEditorScrollbar(GADGET_ID_SCROLL_VERTICAL);
+
   DrawMiniLevel(ed_fieldx, ed_fieldy, level_xpos, level_ypos);
   MapMainDrawingArea();
 }
 
+static void DrawElementBorder(int dest_x, int dest_y, int width, int height)
+{
+  int border_graphic = IMG_SAND;
+  Bitmap *src_bitmap;
+  int src_x, src_y;
+  int num_mini_tilex = width / MINI_TILEX + 1;
+  int num_mini_tiley = width / MINI_TILEY + 1;
+  int x, y;
+
+  getMiniGraphicSource(border_graphic, &src_bitmap, &src_x, &src_y);
+
+  for (y=0; y < num_mini_tiley; y++)
+    for (x=0; x < num_mini_tilex; x++)
+      BlitBitmap(src_bitmap, drawto, src_x, src_y, MINI_TILEX, MINI_TILEY,
+                dest_x - MINI_TILEX / 2 + x * MINI_TILEX,
+                dest_y - MINI_TILEY / 2 + y * MINI_TILEY);
+
+  ClearRectangle(drawto, dest_x - 1, dest_y - 1, width + 2, height + 2);
+}
+
 static void DrawRandomPlacementBackgroundArea()
 {
   int area_x = ED_AREA_RANDOM_BACKGROUND_XPOS / MINI_TILEX;
   int area_y = ED_AREA_RANDOM_BACKGROUND_YPOS / MINI_TILEY;
   int area_sx = SX + ED_AREA_RANDOM_BACKGROUND_XPOS;
   int area_sy = SY + ED_AREA_RANDOM_BACKGROUND_YPOS;
-  int x, y;
 
   ElementContent[0][0][0] = random_placement_background_element;
 
-  /* draw decorative border for the object */
-  for (y=0; y<2; y++)
-    for (x=0; x<2; x++)
-      DrawMiniElement(area_x + x, area_y + y, EL_SAND);
-
-  ClearRectangle(drawto,
-                area_sx + MINI_TILEX/2 - 1, area_sy + MINI_TILEY/2 - 1,
-                MINI_TILEX + 2, MINI_TILEY + 2);
-
-  /* copy border to the right location */
-  BlitBitmap(drawto, drawto,
-            area_sx, area_sy, 3 * MINI_TILEX, 3 * MINI_TILEY,
-            area_sx - MINI_TILEX/2, area_sy - MINI_TILEY/2);
-
+  DrawElementBorder(area_sx, area_sy, MINI_TILEX, MINI_TILEY);
   DrawMiniElement(area_x, area_y, ElementContent[0][0][0]);
 
   MapDrawingArea(GADGET_ID_RANDOM_BACKGROUND);
@@ -2707,6 +2801,7 @@ static void DrawLevelInfoWindow()
   int font_color = FC_GREEN;
   int i, x, y;
 
+  SetMainBackgroundImage(IMG_BACKGROUND_EDITOR_SETTINGS_LEVEL);
   ClearWindow();
   UnmapLevelEditorWindowGadgets();
 
@@ -2794,29 +2889,15 @@ static void DrawAmoebaContentArea()
   int area_sx = SX + ED_AREA_ELEM_CONTENT_XPOS;
   int area_sy = SY + ED_AREA_ELEM_CONTENT_YPOS;
   int font_color = FC_GREEN;
-  int x, y;
 
   ElementContent[0][0][0] = level.amoeba_content;
 
-  /* draw decorative border for the object */
-  for (y=0; y<2; y++)
-    for (x=0; x<2; x++)
-      DrawMiniElement(area_x + x, area_y + y, EL_SAND);
-
-  ClearRectangle(drawto,
-                area_sx + MINI_TILEX/2 - 1, area_sy + MINI_TILEY/2 - 1,
-                MINI_TILEX + 2, MINI_TILEY + 2);
-
-  /* copy border to the right location */
-  BlitBitmap(drawto, drawto,
-            area_sx, area_sy, 3 * MINI_TILEX, 3 * MINI_TILEY,
-            area_sx - MINI_TILEX/2, area_sy - MINI_TILEY/2);
+  DrawElementBorder(area_sx, area_sy, MINI_TILEX, MINI_TILEY);
+  DrawMiniElement(area_x, area_y, ElementContent[0][0][0]);
 
   DrawText(area_sx + TILEX, area_sy + 1, "Content of amoeba",
           FS_SMALL, font_color);
 
-  DrawMiniElement(area_x, area_y, ElementContent[0][0][0]);
-
   MapDrawingArea(GADGET_ID_AMOEBA_CONTENT);
 }
 
@@ -2849,28 +2930,12 @@ static void DrawElementContentAreas()
   MapCounterButtons(counter_id);
 
   /* delete content areas in case of reducing number of them */
-  ClearRectangle(backbuffer,
-                SX, area_sy - MINI_TILEX,
-                SXSIZE, 12 * MINI_TILEY);
+  DrawBackground(SX, area_sy - MINI_TILEX, SXSIZE, 12 * MINI_TILEY);
 
-  /* draw some decorative border for the objects */
   for (i=0; i<level.num_yam_contents; i++)
-  {
-    for (y=0; y<4; y++)
-      for (x=0; x<4; x++)
-       DrawMiniElement(area_x + 5 * (i % 4) + x, area_y + 6 * (i / 4) + y,
-                       EL_SAND);
-
-    ClearRectangle(drawto,
-                  area_sx + 5 * (i % 4) * MINI_TILEX + MINI_TILEX/2 - 1,
-                  area_sy + 6 * (i / 4) * MINI_TILEY + MINI_TILEY/2 - 1,
-                  3 * MINI_TILEX + 2, 3 * MINI_TILEY + 2);
-  }
-
-  /* copy border to the right location */
-  BlitBitmap(drawto, drawto,
-            area_sx, area_sy, (5 * 4 + 1) * MINI_TILEX, 11 * MINI_TILEY,
-            area_sx - MINI_TILEX/2, area_sy - MINI_TILEY/2);
+    DrawElementBorder(area_sx + 5 * (i % 4) * MINI_TILEX,
+                     area_sy + 6 * (i / 4) * MINI_TILEY,
+                     3 * MINI_TILEX, 3 * MINI_TILEY);
 
   DrawText(area_sx + (5 * 4 - 1) * MINI_TILEX, area_sy + 0 * MINI_TILEY + 1,
           "Content", FS_SMALL, font_color);
@@ -2895,43 +2960,6 @@ static void DrawElementContentAreas()
     MapDrawingArea(GADGET_ID_ELEM_CONTENT_0 + i);
 }
 
-#if 0
-static void DrawPropertiesElement(int xstart, int ystart, int element)
-{
-  int x, y;
-
-  /* draw some decorative border for the object */
-  for (y=0; y<3; y++)
-    for (x=0; x<3; x++)
-      DrawMiniElement(xstart + x , ystart + y, EL_SAND);
-
-  ClearRectangle(drawto,
-                SX + xstart * MINI_TILEX + MINI_TILEX/2 - 1,
-                SY + ystart * MINI_TILEY + MINI_TILEY/2 - 1,
-                TILEX + 2, TILEY + 2);
-
-  /* copy border to the right location */
-  BlitBitmap(drawto, drawto,
-            SX + xstart * MINI_TILEX,
-            SY + ystart * MINI_TILEY,
-            2 * TILEX, 2 * TILEY,
-            SX + xstart * MINI_TILEX - MINI_TILEX/2,
-            SY + ystart * MINI_TILEY - MINI_TILEY/2);
-
-  DrawGraphicAnimation(xstart / 2, ystart / 2, el2img(element));
-
-  /* copy the whole stuff to the definitive location */
-  BlitBitmap(drawto, drawto,
-            SX + xstart * MINI_TILEX - MINI_TILEX/2,
-            SY + ystart * MINI_TILEY - MINI_TILEY,
-            2 * TILEX, 2 * TILEY,
-            SX + xstart * MINI_TILEX - MINI_TILEX/2,
-            SY + ystart * MINI_TILEY - MINI_TILEY/2);
-
-  FrameCounter++;      /* increase animation frame counter */
-}
-#endif
-
 #define TEXT_COLLECTING                "Score for collecting"
 #define TEXT_SMASHING          "Score for smashing"
 #define TEXT_CRACKING          "Score for cracking"
@@ -2988,7 +3016,7 @@ static void DrawPropertiesWindow()
     { EL_PACMAN_LEFT,  &level.score[SC_PACMAN],        TEXT_SMASHING },
     { EL_PACMAN_DOWN,  &level.score[SC_PACMAN],        TEXT_SMASHING },
     { EL_NUT,          &level.score[SC_KOKOSNUSS],     TEXT_CRACKING },
-    { EL_DYNAMITE      ,&level.score[SC_DYNAMIT],      TEXT_COLLECTING },
+    { EL_DYNAMITE,     &level.score[SC_DYNAMIT],       TEXT_COLLECTING },
     { EL_KEY1,         &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
     { EL_KEY2,         &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
     { EL_KEY3,         &level.score[SC_SCHLUESSEL],    TEXT_COLLECTING },
@@ -3006,54 +3034,23 @@ static void DrawPropertiesWindow()
     { -1, NULL, NULL }
   };
 
+  SetMainBackgroundImage(IMG_BACKGROUND_EDITOR_SETTINGS_ELEMENT);
   ClearWindow();
   UnmapLevelEditorWindowGadgets();
 
   DrawText(SX + ED_SETTINGS2_XPOS, SY + ED_SETTINGS_YPOS,
           "Element Settings", FS_BIG, FC_YELLOW);
 
-#if 1
-  /* draw some decorative border for the object */
-  for (y=0; y<3; y++)
-    for (x=0; x<3; x++)
-      DrawMiniElement(xstart + x , ystart + y, EL_SAND);
-
-  ClearRectangle(drawto,
-                SX + xstart * MINI_TILEX + MINI_TILEX/2 - 1,
-                SY + ystart * MINI_TILEY + MINI_TILEY/2 - 1,
-                TILEX + 2, TILEY + 2);
-
-  /* copy border to the right location */
-  BlitBitmap(drawto, drawto,
-            SX + xstart * MINI_TILEX,
-            SY + ystart * MINI_TILEY,
-            2 * TILEX, 2 * TILEY,
-            SX + xstart * MINI_TILEX - MINI_TILEX/2,
-            SY + ystart * MINI_TILEY - MINI_TILEY/2);
-
-#if 0
-  DrawGraphic(xstart / 2, ystart / 2, el2img(properties_element), 0);
-#else
-  DrawGraphicAnimation(xstart / 2, ystart / 2, el2img(properties_element));
-#endif
-
-  /* copy the whole stuff to the definitive location */
-  BlitBitmap(drawto, drawto,
-            SX + xstart * MINI_TILEX - MINI_TILEX/2,
-            SY + ystart * MINI_TILEY - MINI_TILEY,
-            2 * TILEX, 2 * TILEY,
-            SX + xstart * MINI_TILEX - MINI_TILEX/2,
-            SY + ystart * MINI_TILEY - MINI_TILEY/2);
+  DrawElementBorder(SX + xstart * MINI_TILEX,
+                   SY + ystart * MINI_TILEY + MINI_TILEY / 2,
+                   TILEX, TILEY);
+  DrawGraphicAnimationExt(drawto,
+                         SX + xstart * MINI_TILEX,
+                         SY + ystart * MINI_TILEY + MINI_TILEY / 2,
+                         el2edimg(properties_element), -1, NO_MASKING);
 
   FrameCounter = 0;    /* restart animation frame counter */
 
-#else
-
-  FrameCounter = 0;    /* restart animation frame counter */
-  DrawPropertiesElement(xstart, ystart, properties_element);
-
-#endif
-
   DrawTextF((xstart + 3) * MINI_TILEX, (ystart + 1) * MINI_TILEY,
            font_color, getElementInfoText(properties_element));
 
@@ -3115,6 +3112,49 @@ static void DrawPropertiesWindow()
                 GDI_CHECKED, *checkbutton_info[i].value, GDI_END);
     MapCheckbuttonGadget(i);
   }
+
+  if (IS_CUSTOM_ELEMENT(properties_element))
+  {
+    int nr = properties_element - EL_CUSTOM_START;
+
+    CopyCustomElementPropertiesToEditor();
+
+    /* draw checkbutton gadget */
+    i = ED_CHECKBUTTON_ID_CUSTOM_INDESTRUCTIBLE;
+    x = checkbutton_info[i].x + xoffset_right2;
+    y = checkbutton_info[i].y + yoffset_right2;
+
+    checkbutton_info[i].value = &custom_element_properties[nr].indestructible;
+
+    DrawTextF(x, y, font_color, checkbutton_info[i].text);
+    ModifyGadget(level_editor_gadget[checkbutton_info[i].gadget_id],
+                GDI_CHECKED, *checkbutton_info[i].value, GDI_END);
+    MapCheckbuttonGadget(i);
+
+    /* draw checkbutton gadget */
+    i = ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL;
+    x = checkbutton_info[i].x + xoffset_right2;
+    y = checkbutton_info[i].y + yoffset_right2;
+
+    checkbutton_info[i].value = &custom_element_properties[nr].can_fall;
+
+    DrawTextF(x, y, font_color, checkbutton_info[i].text);
+    ModifyGadget(level_editor_gadget[checkbutton_info[i].gadget_id],
+                GDI_CHECKED, *checkbutton_info[i].value, GDI_END);
+    MapCheckbuttonGadget(i);
+
+    /* draw checkbutton gadget */
+    i = ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY;
+    x = checkbutton_info[i].x + xoffset_right2;
+    y = checkbutton_info[i].y + yoffset_right2;
+
+    checkbutton_info[i].value = &custom_element_properties[nr].slippery;
+
+    DrawTextF(x, y, font_color, checkbutton_info[i].text);
+    ModifyGadget(level_editor_gadget[checkbutton_info[i].gadget_id],
+                GDI_CHECKED, *checkbutton_info[i].value, GDI_END);
+    MapCheckbuttonGadget(i);
+  }
 }
 
 static void DrawLineElement(int sx, int sy, int element, boolean change_level)
@@ -3837,11 +3877,11 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
        DrawMiniGraphicExt(drawto,
                           gi->x + sx * MINI_TILEX,
                           gi->y + sy * MINI_TILEY,
-                          el2img(new_element));
+                          el2edimg(new_element));
        DrawMiniGraphicExt(window,
                           gi->x + sx * MINI_TILEX,
                           gi->y + sy * MINI_TILEY,
-                          el2img(new_element));
+                          el2edimg(new_element));
 
        if (id == GADGET_ID_AMOEBA_CONTENT)
          level.amoeba_content = new_element;
@@ -4026,7 +4066,13 @@ static void HandleRadiobuttons(struct GadgetInfo *gi)
 
 static void HandleCheckbuttons(struct GadgetInfo *gi)
 {
-  *checkbutton_info[gi->custom_type_id].value ^= TRUE;
+  int type_id = gi->custom_type_id;
+
+  *checkbutton_info[type_id].value ^= TRUE;
+
+  if (type_id >= ED_CHECKBUTTON_ID_CUSTOM_FIRST &&
+      type_id <= ED_CHECKBUTTON_ID_CUSTOM_LAST)
+    CopyCustomElementPropertiesToGame();
 }
 
 static void HandleControlButtons(struct GadgetInfo *gi)
@@ -4163,7 +4209,7 @@ static void HandleControlButtons(struct GadgetInfo *gi)
        int element = editor_elements[element_shift + i];
 
        UnmapGadget(gi);
-       getMiniGraphicSource(el2img(element), &gd->bitmap, &gd->x, &gd->y);
+       getMiniGraphicSource(el2edimg(element), &gd->bitmap, &gd->x, &gd->y);
        ModifyGadget(gi, GDI_INFO_TEXT, getElementInfoText(element), GDI_END);
        MapGadget(gi);
       }
@@ -4270,9 +4316,8 @@ static void HandleControlButtons(struct GadgetInfo *gi)
       {
        if (Request("Save this level and kill the old ?", REQ_ASK))
        {
-         for(x=0; x<lev_fieldx; x++)
-           for(y=0; y<lev_fieldy; y++) 
-             Ur[x][y] = Feld[x][y];
+         CopyPlayfield(Feld, Ur);
+
          SaveLevel(level_nr);
        }
       }
@@ -4286,13 +4331,8 @@ static void HandleControlButtons(struct GadgetInfo *gi)
        if (LevelChanged())
          level.game_version = GAME_VERSION_ACTUAL;
 
-       for(x=0; x<lev_fieldx; x++)
-         for(y=0; y<lev_fieldy; y++)
-           FieldBackup[x][y] = Ur[x][y];
-
-       for(x=0; x<lev_fieldx; x++)
-         for(y=0; y<lev_fieldy; y++)
-           Ur[x][y] = Feld[x][y];
+       CopyPlayfield(Ur, FieldBackup);
+       CopyPlayfield(Feld, Ur);
 
        UnmapLevelEditorGadgets();
        UndrawSpecialEditorDoor();
@@ -4436,15 +4476,12 @@ void HandleLevelEditorIdle()
   if (!DelayReached(&action_delay, action_delay_value))
     return;
 
-  FY += MINI_TILEY / 2;
-#if 1
-  DrawGraphicAnimation(xpos, ypos, el2img(properties_element));
-#else
-  DrawGraphicAnimation(xpos, ypos, el_dir_act2img(properties_element,
-                                                 MV_NO_MOVING,
-                                                 ...));
-#endif
-  FY -= MINI_TILEY / 2;
+  DrawGraphicAnimationExt(drawto,
+                         SX + xpos * TILEX,
+                         SY + ypos * TILEY + MINI_TILEY / 2,
+                         el2edimg(properties_element), -1, NO_MASKING);
+
+  MarkTileDirty(xpos, ypos);
   MarkTileDirty(xpos, ypos + 1);
 
   FrameCounter++;      /* increase animation frame counter */
@@ -4452,9 +4489,7 @@ void HandleLevelEditorIdle()
 
 void ClearEditorGadgetInfoText()
 {
-  ClearRectangle(drawto,
-                INFOTEXT_XPOS, INFOTEXT_YPOS, INFOTEXT_XSIZE, INFOTEXT_YSIZE);
-  redraw_mask |= REDRAW_FIELD;
+  DrawBackground(INFOTEXT_XPOS, INFOTEXT_YPOS, INFOTEXT_XSIZE, INFOTEXT_YSIZE);
 }
 
 void HandleEditorGadgetInfoText(void *ptr)