rnd-20131212-1-src
[rocksndiamonds.git] / src / init.c
index 0ef4dc379c009b2a7d13122b488306f1faf12399..aa30167af3c2eb52e07aa3426de1ff5fc9d34703 100644 (file)
 #include "conf_fnt.c"  /* include auto-generated data structure definitions */
 #include "conf_g2s.c"  /* include auto-generated data structure definitions */
 #include "conf_g2m.c"  /* include auto-generated data structure definitions */
+#include "conf_act.c"  /* include auto-generated data structure definitions */
 
 
 #define CONFIG_TOKEN_FONT_INITIAL              "font.initial"
+#define CONFIG_TOKEN_GLOBAL_BUSY               "global.busy"
 
 
 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
+static struct GraphicInfo    anim_initial;
 
 static int copy_properties[][5] =
 {
@@ -82,6 +85,82 @@ static int copy_properties[][5] =
   }
 };
 
+
+void DrawInitAnim()
+{
+  struct GraphicInfo *graphic_info_last = graphic_info;
+  int graphic = 0;
+  static unsigned int action_delay = 0;
+  unsigned int action_delay_value = GameFrameDelay;
+  int sync_frame = FrameCounter;
+  int x, y;
+
+  if (game_status != GAME_MODE_LOADING)
+    return;
+
+  if (anim_initial.bitmap == NULL || window == NULL)
+    return;
+
+  if (!DelayReached(&action_delay, action_delay_value))
+    return;
+
+#if 0
+  {
+    static unsigned int last_counter = -1;
+    unsigned int current_counter = Counter();
+    unsigned int delay = current_counter - last_counter;
+
+    if (last_counter != -1 && delay > action_delay_value + 5)
+      printf("::: DrawInitAnim: DELAY TOO LONG: %ld\n", delay);
+
+    last_counter = current_counter;
+  }
+#endif
+
+  x = ALIGNED_TEXT_XPOS(&init_last.busy);
+  y = ALIGNED_TEXT_YPOS(&init_last.busy);
+
+  graphic_info = &anim_initial;                /* graphic == 0 => anim_initial */
+
+#if 0
+  {
+    static boolean done = FALSE;
+
+    // if (!done)
+      printf("::: %d, %d, %d, %d => %d, %d [%d, %d] [%d, %d]\n",
+            init.busy.x, init.busy.y,
+            init.busy.align, init.busy.valign,
+            x, y,
+            graphic_info[graphic].width,
+            graphic_info[graphic].height,
+            sync_frame, anim_initial.anim_delay);
+
+    done = TRUE;
+  }
+#endif
+
+  if (sync_frame % anim_initial.anim_delay == 0)
+  {
+#if 1
+    Bitmap *src_bitmap;
+    int src_x, src_y;
+    int width = graphic_info[graphic].width;
+    int height = graphic_info[graphic].height;
+    int frame = getGraphicAnimationFrame(graphic, sync_frame);
+
+    getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
+    BlitBitmap(src_bitmap, window, src_x, src_y, width, height, x, y);
+#else
+    /* !!! this can only draw TILEX/TILEY size animations !!! */
+    DrawGraphicAnimationExt(window, x, y, graphic, sync_frame, NO_MASKING);
+#endif
+  }
+
+  graphic_info = graphic_info_last;
+
+  FrameCounter++;
+}
+
 void FreeGadgets()
 {
   FreeLevelEditorGadgets();
@@ -104,11 +183,19 @@ void InitGadgets()
   CreateToolButtons();
   CreateScreenGadgets();
 
+  InitGadgetsSoundCallback(PlaySoundActivating, PlaySoundSelecting);
+
   gadgets_initialized = TRUE;
 }
 
 inline void InitElementSmallImagesScaledUp(int graphic)
 {
+#if 0
+  struct FileInfo *fi = getImageListEntryFromImageID(graphic);
+
+  printf("::: '%s' -> '%s'\n", fi->token, fi->filename);
+#endif
+
   CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
 }
 
@@ -161,16 +248,37 @@ void SetBitmaps_EM(Bitmap **em_bitmap)
 }
 #endif
 
+#if 0
+/* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
+void SetBitmaps_SP(Bitmap **sp_bitmap)
+{
+  *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
+}
+#endif
+
 static int getFontBitmapID(int font_nr)
 {
   int special = -1;
 
-  if (game_status >= GAME_MODE_MAIN && game_status <= GAME_MODE_PSEUDO_PREVIEW)
+  /* (special case: do not use special font for GAME_MODE_LOADING) */
+  if (game_status >= GAME_MODE_TITLE_INITIAL &&
+      game_status <= GAME_MODE_PSEUDO_PREVIEW)
     special = game_status;
   else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
     special = GFX_SPECIAL_ARG_MAIN;
+#if 0
   else if (game_status == GAME_MODE_PLAYING)
     special = GFX_SPECIAL_ARG_DOOR;
+#endif
+
+#if 0
+  if (special != -1)
+  {
+    printf("%s%s\n",
+          font_info[font_nr].token_name,
+          special_suffix_info[special].suffix);
+  }
+#endif
 
   if (special != -1)
     return font_info[font_nr].special_bitmap_id[special];
@@ -178,6 +286,26 @@ static int getFontBitmapID(int font_nr)
     return font_nr;
 }
 
+static int getFontFromToken(char *token)
+{
+#if 1
+  char *value = getHashEntry(font_token_hash, token);
+
+  if (value != NULL)
+    return atoi(value);
+#else
+  int i;
+
+  /* !!! OPTIMIZE THIS BY USING HASH !!! */
+  for (i = 0; i < NUM_FONTS; i++)
+    if (strEqual(token, font_info[i].token_name))
+      return i;
+#endif
+
+  /* if font not found, use reliable default value */
+  return FONT_INITIAL_1;
+}
+
 void InitFontGraphicInfo()
 {
   static struct FontBitmapInfo *font_bitmap_info = NULL;
@@ -188,7 +316,8 @@ void InitFontGraphicInfo()
 
   if (graphic_info == NULL)            /* still at startup phase */
   {
-    InitFontInfo(font_initial, NUM_INITIAL_FONTS, getFontBitmapID);
+    InitFontInfo(font_initial, NUM_INITIAL_FONTS,
+                getFontBitmapID, getFontFromToken);
 
     return;
   }
@@ -230,18 +359,21 @@ void InitFontGraphicInfo()
     int graphic      = font_to_graphic[i].graphic;
     int base_graphic = font2baseimg(font_nr);
 
-    if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
+    if (IS_SPECIAL_GFX_ARG(special))
     {
       boolean base_redefined =
        getImageListEntryFromImageID(base_graphic)->redefined;
       boolean special_redefined =
        getImageListEntryFromImageID(graphic)->redefined;
+      boolean special_cloned = (graphic_info[graphic].clone_from != -1);
 
       /* if the base font ("font.title_1", for example) has been redefined,
         but not the special font ("font.title_1.LEVELS", for example), do not
         use an existing (in this case considered obsolete) special font
         anymore, but use the automatically determined default font */
-      if (base_redefined && !special_redefined)
+      /* special case: cloned special fonts must be explicitly redefined,
+        but are not automatically redefined by redefining base font */
+      if (base_redefined && !special_redefined && !special_cloned)
        continue;
 
       font_info[font_nr].special_graphic[special] = graphic;
@@ -260,7 +392,7 @@ void InitFontGraphicInfo()
     if (font_nr < 0)
       continue;
 
-    if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
+    if (IS_SPECIAL_GFX_ARG(special))
     {
       font_info[font_nr].special_graphic[special] = graphic;
       font_info[font_nr].special_bitmap_id[special] = num_font_bitmaps;
@@ -268,6 +400,45 @@ void InitFontGraphicInfo()
     }
   }
 
+  /* correct special font/graphic mapping for cloned fonts for downwards
+     compatibility of PREVIEW fonts -- this is only needed for implicit
+     redefinition of special font by redefined base font, and only if other
+     fonts are cloned from this special font (like in the "Zelda" level set) */
+  for (i = 0; font_to_graphic[i].font_nr > -1; i++)
+  {
+    int font_nr = font_to_graphic[i].font_nr;
+    int special = font_to_graphic[i].special;
+    int graphic = font_to_graphic[i].graphic;
+
+    if (IS_SPECIAL_GFX_ARG(special))
+    {
+      boolean special_redefined =
+       getImageListEntryFromImageID(graphic)->redefined;
+      boolean special_cloned = (graphic_info[graphic].clone_from != -1);
+
+      if (special_cloned && !special_redefined)
+      {
+       int j;
+
+       for (j = 0; font_to_graphic[j].font_nr > -1; j++)
+       {
+         int font_nr2 = font_to_graphic[j].font_nr;
+         int special2 = font_to_graphic[j].special;
+         int graphic2 = font_to_graphic[j].graphic;
+
+         if (IS_SPECIAL_GFX_ARG(special2) &&
+             graphic2 == graphic_info[graphic].clone_from)
+         {
+           font_info[font_nr].special_graphic[special] =
+             font_info[font_nr2].special_graphic[special2];
+           font_info[font_nr].special_bitmap_id[special] =
+             font_info[font_nr2].special_bitmap_id[special2];
+         }
+       }
+      }
+    }
+  }
+
   /* reset non-redefined ".active" font graphics if normal font is redefined */
   /* (this different treatment is needed because normal and active fonts are
      independently defined ("active" is not a property of font definitions!) */
@@ -365,7 +536,8 @@ void InitFontGraphicInfo()
     }
   }
 
-  InitFontInfo(font_bitmap_info, num_font_bitmaps, getFontBitmapID);
+  InitFontInfo(font_bitmap_info, num_font_bitmaps,
+              getFontBitmapID, getFontFromToken);
 }
 
 void InitElementGraphicInfo()
@@ -393,6 +565,8 @@ void InitElementGraphicInfo()
     }
   }
 
+  UPDATE_BUSY_STATE();
+
   /* initialize normal element/graphic mapping from static configuration */
   for (i = 0; element_to_graphic[i].element > -1; i++)
   {
@@ -451,6 +625,16 @@ void InitElementGraphicInfo()
     int graphic   = property_mapping[i].artwork_index;
     boolean crumbled = FALSE;
 
+#if 0
+    if ((element == EL_EM_DYNAMITE ||
+        element == EL_EM_DYNAMITE_ACTIVE) &&
+       action == ACTION_ACTIVE &&
+       (special == GFX_SPECIAL_ARG_EDITOR ||
+        special == GFX_SPECIAL_ARG_PANEL))
+      printf("::: DYNAMIC: %d, %d, %d -> %d\n",
+            element, action, special, graphic);
+#endif
+
     if (special == GFX_SPECIAL_ARG_CRUMBLED)
     {
       special = -1;
@@ -567,6 +751,8 @@ void InitElementGraphicInfo()
     }
   }
 
+  UPDATE_BUSY_STATE();
+
   /* adjust graphics with 2nd tile for movement according to direction
      (do this before correcting '-1' values to minimize calculations) */
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
@@ -607,8 +793,8 @@ void InitElementGraphicInfo()
          if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
          {
            /* get current (wrong) backside tile coordinates */
-           getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
-                               TRUE);
+           getFixedGraphicSourceExt(graphic, 0, &dummy,
+                                    &src_x_back, &src_y_back, TRUE);
 
            /* set frontside tile coordinates to backside tile coordinates */
            g->src_x = src_x_back;
@@ -626,6 +812,8 @@ void InitElementGraphicInfo()
     }
   }
 
+  UPDATE_BUSY_STATE();
+
   /* now set all '-1' values to element specific default values */
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
@@ -777,6 +965,8 @@ void InitElementGraphicInfo()
     }
   }
 
+  UPDATE_BUSY_STATE();
+
 #if 0
   /* !!! THIS ALSO CLEARS SPECIAL FLAGS (AND IS NOT NEEDED ANYWAY) !!! */
   /* set animation mode to "none" for each graphic with only 1 frame */
@@ -813,7 +1003,7 @@ void InitElementGraphicInfo()
     for (i = 0; i < MAX_NUM_ELEMENTS; i++)
       if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
          i != EL_UNKNOWN)
-       Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
+       Error(ERR_INFO, "warning: no graphic for element '%s' (%d)",
              element_info[i].token_name, i);
   }
 #endif
@@ -844,6 +1034,15 @@ void InitElementSpecialGraphicInfo()
     boolean special_redefined =
       getImageListEntryFromImageID(graphic)->redefined;
 
+#if 0
+    if ((element == EL_EM_DYNAMITE ||
+        element == EL_EM_DYNAMITE_ACTIVE) &&
+       (special == GFX_SPECIAL_ARG_EDITOR ||
+        special == GFX_SPECIAL_ARG_PANEL))
+      printf("::: SPECIAL STATIC: %d, %d -> %d\n",
+            element, special, graphic);
+#endif
+
     /* if the base graphic ("emerald", for example) has been redefined,
        but not the special graphic ("emerald.EDITOR", for example), do not
        use an existing (in this case considered obsolete) special graphic
@@ -857,14 +1056,58 @@ void InitElementSpecialGraphicInfo()
   /* initialize special element/graphic mapping from dynamic configuration */
   for (i = 0; i < num_property_mappings; i++)
   {
-    int element = property_mapping[i].base_index;
-    int special = property_mapping[i].ext3_index;
-    int graphic = property_mapping[i].artwork_index;
+    int element   = property_mapping[i].base_index;
+    int action    = property_mapping[i].ext1_index;
+    int direction = property_mapping[i].ext2_index;
+    int special   = property_mapping[i].ext3_index;
+    int graphic   = property_mapping[i].artwork_index;
+
+#if 0
+    if ((element == EL_EM_DYNAMITE ||
+        element == EL_EM_DYNAMITE_ACTIVE ||
+        element == EL_CONVEYOR_BELT_1_MIDDLE ||
+        element == EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE) &&
+       (special == GFX_SPECIAL_ARG_EDITOR ||
+        special == GFX_SPECIAL_ARG_PANEL))
+      printf("::: SPECIAL DYNAMIC: %d, %d -> %d [%d]\n",
+            element, special, graphic, property_mapping[i].ext1_index);
+#endif
+
+#if 0
+    if (element == EL_CONVEYOR_BELT_1_MIDDLE &&
+       action == ACTION_ACTIVE)
+    {
+      element = EL_CONVEYOR_BELT_1_MIDDLE_ACTIVE;
+      action = -1;
+    }
+#endif
+
+#if 0
+    if (element == EL_MAGIC_WALL &&
+       action == ACTION_ACTIVE)
+    {
+      element = EL_MAGIC_WALL_ACTIVE;
+      action = -1;
+    }
+#endif
+
+#if 1
+    /* for action ".active", replace element with active element, if exists */
+    if (action == ACTION_ACTIVE && element != ELEMENT_ACTIVE(element))
+    {
+      element = ELEMENT_ACTIVE(element);
+      action = -1;
+    }
+#endif
 
     if (element >= MAX_NUM_ELEMENTS)
       continue;
 
-    if (special >= 0 && special < NUM_SPECIAL_GFX_ARGS)
+    /* do not change special graphic if action or direction was specified */
+    if (action != -1 || direction != -1)
+      continue;
+
+    if (IS_SPECIAL_GFX_ARG(special))
       element_info[element].special_graphic[special] = graphic;
   }
 
@@ -878,34 +1121,23 @@ void InitElementSpecialGraphicInfo()
 
 static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
 {
-  int i;
-  int x = 0;
-
-  if (type != TYPE_TOKEN)
+  if (type != TYPE_ELEMENT && type != TYPE_GRAPHIC)
     return get_parameter_value(value_raw, suffix, type);
 
   if (strEqual(value_raw, ARG_UNDEFINED))
     return ARG_UNDEFINED_VALUE;
 
-  /* !!! OPTIMIZE THIS BY USING HASH !!! */
-  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
-    if (strEqual(element_info[i].token_name, value_raw))
-      return i;
-
-  /* !!! OPTIMIZE THIS BY USING HASH !!! */
-  for (i = 0; image_config[i].token != NULL; i++)
+  if (type == TYPE_ELEMENT)
   {
-    int len_config_value = strlen(image_config[i].value);
-
-    if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
-       !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
-       !strEqual(image_config[i].value, UNDEFINED_FILENAME))
-      continue;
+    char *value = getHashEntry(element_token_hash, value_raw);
 
-    if (strEqual(image_config[i].token, value_raw))
-      return x;
+    return (value != NULL ? atoi(value) : EL_UNDEFINED);
+  }
+  else if (type == TYPE_GRAPHIC)
+  {
+    char *value = getHashEntry(graphic_token_hash, value_raw);
 
-    x++;
+    return (value != NULL ? atoi(value) : IMG_UNDEFINED);
   }
 
   return -1;
@@ -927,85 +1159,111 @@ static int get_scaled_graphic_height(int graphic)
   return original_height * scale_up_factor;
 }
 
-static void set_graphic_parameters(int graphic)
+static void set_graphic_parameters_ext(int graphic, int *parameter,
+                                      Bitmap *src_bitmap)
 {
-  struct FileInfo *image = getImageListEntryFromImageID(graphic);
-  char **parameter_raw = image->parameter;
-  Bitmap *src_bitmap = getBitmapFromImageID(graphic);
-  int parameter[NUM_GFX_ARGS];
+  struct GraphicInfo *g = &graphic_info[graphic];
   int anim_frames_per_row = 1, anim_frames_per_col = 1;
   int anim_frames_per_line = 1;
-  int i;
-
-  /* if fallback to default artwork is done, also use the default parameters */
-  if (image->fallback_to_default)
-    parameter_raw = image->default_parameter;
-
-  /* get integer values from string parameters */
-  for (i = 0; i < NUM_GFX_ARGS; i++)
-    parameter[i] = get_graphic_parameter_value(parameter_raw[i],
-                                              image_config_suffix[i].token,
-                                              image_config_suffix[i].type);
-
-  graphic_info[graphic].bitmap = src_bitmap;
 
   /* always start with reliable default values */
-  graphic_info[graphic].src_image_width = 0;
-  graphic_info[graphic].src_image_height = 0;
-  graphic_info[graphic].src_x = 0;
-  graphic_info[graphic].src_y = 0;
-  graphic_info[graphic].width  = TILEX;        /* default for element graphics */
-  graphic_info[graphic].height = TILEY;        /* default for element graphics */
-  graphic_info[graphic].offset_x = 0;  /* one or both of these values ... */
-  graphic_info[graphic].offset_y = 0;  /* ... will be corrected later */
-  graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
-  graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
-  graphic_info[graphic].swap_double_tiles = -1;        /* auto-detect tile swapping */
-  graphic_info[graphic].crumbled_like = -1;    /* do not use clone element */
-  graphic_info[graphic].diggable_like = -1;    /* do not use clone element */
-  graphic_info[graphic].border_size = TILEX / 8;  /* "CRUMBLED" border size */
-  graphic_info[graphic].scale_up_factor = 1;   /* default: no scaling up */
-  graphic_info[graphic].clone_from = -1;       /* do not use clone graphic */
-  graphic_info[graphic].anim_delay_fixed = 0;
-  graphic_info[graphic].anim_delay_random = 0;
-  graphic_info[graphic].post_delay_fixed = 0;
-  graphic_info[graphic].post_delay_random = 0;
-  graphic_info[graphic].fade_delay = -1;
-  graphic_info[graphic].post_delay = -1;
-  graphic_info[graphic].auto_delay = -1;
+  g->src_image_width = 0;
+  g->src_image_height = 0;
+  g->src_x = 0;
+  g->src_y = 0;
+  g->width  = TILEX;                   /* default for element graphics */
+  g->height = TILEY;                   /* default for element graphics */
+  g->offset_x = 0;                     /* one or both of these values ... */
+  g->offset_y = 0;                     /* ... will be corrected later */
+  g->offset2_x = 0;                    /* one or both of these values ... */
+  g->offset2_y = 0;                    /* ... will be corrected later */
+  g->swap_double_tiles = -1;           /* auto-detect tile swapping */
+  g->crumbled_like = -1;               /* do not use clone element */
+  g->diggable_like = -1;               /* do not use clone element */
+  g->border_size = TILEX / 8;          /* "CRUMBLED" border size */
+  g->scale_up_factor = 1;              /* default: no scaling up */
+  g->clone_from = -1;                  /* do not use clone graphic */
+  g->anim_delay_fixed = 0;
+  g->anim_delay_random = 0;
+  g->post_delay_fixed = 0;
+  g->post_delay_random = 0;
+  g->fade_mode = FADE_MODE_DEFAULT;
+  g->fade_delay = -1;
+  g->post_delay = -1;
+  g->auto_delay = -1;
+  g->align = ALIGN_CENTER;             /* default for title screens */
+  g->valign = VALIGN_MIDDLE;           /* default for title screens */
+  g->sort_priority = 0;                        /* default for title screens */
+  g->class = 0;
+  g->style = STYLE_DEFAULT;
+
+  g->bitmap = src_bitmap;
 
 #if 1
-  if (graphic_info[graphic].use_image_size)
+  /* optional zoom factor for scaling up the image to a larger size */
+  if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
+    g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
+  if (g->scale_up_factor < 1)
+    g->scale_up_factor = 1;            /* no scaling */
+#endif
+
+#if 1
+  if (g->use_image_size)
   {
-    /* set default bitmap size (with scaling, but without small images) */
-    graphic_info[graphic].width  = get_scaled_graphic_width(graphic);
-    graphic_info[graphic].height = get_scaled_graphic_height(graphic);
+    /* set new default bitmap size (with scaling, but without small images) */
+    g->width  = get_scaled_graphic_width(graphic);
+    g->height = get_scaled_graphic_height(graphic);
   }
 #endif
 
   /* optional x and y tile position of animation frame sequence */
   if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
-    graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
+    g->src_x = parameter[GFX_ARG_XPOS] * TILEX;
   if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
-    graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
+    g->src_y = parameter[GFX_ARG_YPOS] * TILEY;
 
   /* optional x and y pixel position of animation frame sequence */
   if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
-    graphic_info[graphic].src_x = parameter[GFX_ARG_X];
+    g->src_x = parameter[GFX_ARG_X];
   if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
-    graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
+    g->src_y = parameter[GFX_ARG_Y];
 
   /* optional width and height of each animation frame */
   if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
-    graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
+    g->width = parameter[GFX_ARG_WIDTH];
   if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
-    graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
+    g->height = parameter[GFX_ARG_HEIGHT];
+
+  if (src_bitmap)
+  {
+    if (g->width <= 0)
+    {
+      Error(ERR_INFO_LINE, "-");
+      Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
+           g->width, getTokenFromImageID(graphic), TILEX);
+      Error(ERR_INFO_LINE, "-");
 
+      g->width = TILEX;                /* will be checked to be inside bitmap later */
+    }
+
+    if (g->height <= 0)
+    {
+      Error(ERR_INFO_LINE, "-");
+      Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
+           g->height, getTokenFromImageID(graphic), TILEY);
+      Error(ERR_INFO_LINE, "-");
+
+      g->height = TILEY;       /* will be checked to be inside bitmap later */
+    }
+  }
+
+#if 0
   /* optional zoom factor for scaling up the image to a larger size */
   if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
-    graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
-  if (graphic_info[graphic].scale_up_factor < 1)
-    graphic_info[graphic].scale_up_factor = 1;         /* no scaling */
+    g->scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
+  if (g->scale_up_factor < 1)
+    g->scale_up_factor = 1;            /* no scaling */
+#endif
 
   if (src_bitmap)
   {
@@ -1013,99 +1271,381 @@ static void set_graphic_parameters(int graphic)
     int src_image_width  = get_scaled_graphic_width(graphic);
     int src_image_height = get_scaled_graphic_height(graphic);
 
-    anim_frames_per_row = src_image_width  / graphic_info[graphic].width;
-    anim_frames_per_col = src_image_height / graphic_info[graphic].height;
+    if (src_image_width == 0 || src_image_height == 0)
+    {
+      /* only happens when loaded outside artwork system (like "global.busy") */
+      src_image_width  = src_bitmap->width;
+      src_image_height = src_bitmap->height;
+    }
 
-    graphic_info[graphic].src_image_width  = src_image_width;
-    graphic_info[graphic].src_image_height = src_image_height;
+    anim_frames_per_row = src_image_width  / g->width;
+    anim_frames_per_col = src_image_height / g->height;
+
+    g->src_image_width  = src_image_width;
+    g->src_image_height = src_image_height;
   }
 
   /* correct x or y offset dependent of vertical or horizontal frame order */
   if (parameter[GFX_ARG_VERTICAL])     /* frames are ordered vertically */
   {
-    graphic_info[graphic].offset_y =
-      (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
-       parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
+    g->offset_y = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
+                  parameter[GFX_ARG_OFFSET] : g->height);
     anim_frames_per_line = anim_frames_per_col;
   }
   else                                 /* frames are ordered horizontally */
   {
-    graphic_info[graphic].offset_x =
-      (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
-       parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
+    g->offset_x = (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
+                  parameter[GFX_ARG_OFFSET] : g->width);
     anim_frames_per_line = anim_frames_per_row;
   }
 
   /* optionally, the x and y offset of frames can be specified directly */
   if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
-    graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
+    g->offset_x = parameter[GFX_ARG_XOFFSET];
   if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
-    graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
+    g->offset_y = parameter[GFX_ARG_YOFFSET];
 
   /* optionally, moving animations may have separate start and end graphics */
-  graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
+  g->double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
 
   if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
     parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
 
   /* correct x or y offset2 dependent of vertical or horizontal frame order */
   if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
-    graphic_info[graphic].offset2_y =
-      (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
-       parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
+    g->offset2_y = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
+                   parameter[GFX_ARG_2ND_OFFSET] : g->height);
   else                                 /* frames are ordered horizontally */
-    graphic_info[graphic].offset2_x =
-      (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
-       parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
+    g->offset2_x = (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
+                   parameter[GFX_ARG_2ND_OFFSET] : g->width);
 
   /* optionally, the x and y offset of 2nd graphic can be specified directly */
   if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
-    graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
+    g->offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
   if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
-    graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
+    g->offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
 
   /* optionally, the second movement tile can be specified as start tile */
   if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
-    graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
+    g->swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
 
   /* automatically determine correct number of frames, if not defined */
   if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
-    graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
+    g->anim_frames = parameter[GFX_ARG_FRAMES];
   else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
-    graphic_info[graphic].anim_frames =        anim_frames_per_row;
+    g->anim_frames = anim_frames_per_row;
   else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
-    graphic_info[graphic].anim_frames =        anim_frames_per_col;
+    g->anim_frames = anim_frames_per_col;
   else
-    graphic_info[graphic].anim_frames = 1;
+    g->anim_frames = 1;
 
-  if (graphic_info[graphic].anim_frames == 0)  /* frames must be at least 1 */
-    graphic_info[graphic].anim_frames = 1;
+  if (g->anim_frames == 0)             /* frames must be at least 1 */
+    g->anim_frames = 1;
 
-  graphic_info[graphic].anim_frames_per_line =
+  g->anim_frames_per_line =
     (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
      parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
 
-  graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
-  if (graphic_info[graphic].anim_delay == 0)   /* delay must be at least 1 */
-    graphic_info[graphic].anim_delay = 1;
+  g->anim_delay = parameter[GFX_ARG_DELAY];
+  if (g->anim_delay == 0)              /* delay must be at least 1 */
+    g->anim_delay = 1;
 
-  graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
+  g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
 #if 0
-  if (graphic_info[graphic].anim_frames == 1)
-    graphic_info[graphic].anim_mode = ANIM_NONE;
+  if (g->anim_frames == 1)
+    g->anim_mode = ANIM_NONE;
 #endif
 
   /* automatically determine correct start frame, if not defined */
   if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
-    graphic_info[graphic].anim_start_frame = 0;
-  else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
-    graphic_info[graphic].anim_start_frame =
-      graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
+    g->anim_start_frame = 0;
+  else if (g->anim_mode & ANIM_REVERSE)
+    g->anim_start_frame = g->anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
   else
-    graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
+    g->anim_start_frame = parameter[GFX_ARG_START_FRAME];
 
   /* animation synchronized with global frame counter, not move position */
-  graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
+  g->anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
+
+  /* optional element for cloning crumble graphics */
+  if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
+    g->crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
+
+  /* optional element for cloning digging graphics */
+  if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
+    g->diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
+
+  /* optional border size for "crumbling" diggable graphics */
+  if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
+    g->border_size = parameter[GFX_ARG_BORDER_SIZE];
+
+  /* this is only used for player "boring" and "sleeping" actions */
+  if (parameter[GFX_ARG_ANIM_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
+    g->anim_delay_fixed = parameter[GFX_ARG_ANIM_DELAY_FIXED];
+  if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
+    g->anim_delay_random = parameter[GFX_ARG_ANIM_DELAY_RANDOM];
+  if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
+    g->post_delay_fixed = parameter[GFX_ARG_POST_DELAY_FIXED];
+  if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
+    g->post_delay_random = parameter[GFX_ARG_POST_DELAY_RANDOM];
+
+  /* this is only used for toon animations */
+  g->step_offset = parameter[GFX_ARG_STEP_OFFSET];
+  g->step_delay  = parameter[GFX_ARG_STEP_DELAY];
+
+  /* this is only used for drawing font characters */
+  g->draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
+  g->draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
+
+  /* this is only used for drawing envelope graphics */
+  g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
+
+  /* optional graphic for cloning all graphics settings */
+  if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
+    g->clone_from = parameter[GFX_ARG_CLONE_FROM];
+
+  /* optional settings for drawing title screens and title messages */
+  if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
+    g->fade_mode = parameter[GFX_ARG_FADE_MODE];
+  if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
+    g->fade_delay = parameter[GFX_ARG_FADE_DELAY];
+  if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
+    g->post_delay = parameter[GFX_ARG_POST_DELAY];
+  if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
+    g->auto_delay = parameter[GFX_ARG_AUTO_DELAY];
+  if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
+    g->align = parameter[GFX_ARG_ALIGN];
+  if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
+    g->valign = parameter[GFX_ARG_VALIGN];
+  if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
+    g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
+
+  if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
+    g->class = parameter[GFX_ARG_CLASS];
+  if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
+    g->style = parameter[GFX_ARG_STYLE];
+
+  /* this is only used for drawing menu buttons and text */
+  g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
+  g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
+  g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
+  g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
+}
+
+static void set_graphic_parameters(int graphic)
+{
+#if 1
+  struct FileInfo *image = getImageListEntryFromImageID(graphic);
+  char **parameter_raw = image->parameter;
+  Bitmap *src_bitmap = getBitmapFromImageID(graphic);
+  int parameter[NUM_GFX_ARGS];
+  int i;
+
+  /* if fallback to default artwork is done, also use the default parameters */
+  if (image->fallback_to_default)
+    parameter_raw = image->default_parameter;
+
+  /* get integer values from string parameters */
+  for (i = 0; i < NUM_GFX_ARGS; i++)
+    parameter[i] = get_graphic_parameter_value(parameter_raw[i],
+                                              image_config_suffix[i].token,
+                                              image_config_suffix[i].type);
+
+  set_graphic_parameters_ext(graphic, parameter, src_bitmap);
+
+#else
+
+  struct FileInfo *image = getImageListEntryFromImageID(graphic);
+  char **parameter_raw = image->parameter;
+  Bitmap *src_bitmap = getBitmapFromImageID(graphic);
+  int parameter[NUM_GFX_ARGS];
+  int anim_frames_per_row = 1, anim_frames_per_col = 1;
+  int anim_frames_per_line = 1;
+  int i;
+
+  /* if fallback to default artwork is done, also use the default parameters */
+  if (image->fallback_to_default)
+    parameter_raw = image->default_parameter;
+
+  /* get integer values from string parameters */
+  for (i = 0; i < NUM_GFX_ARGS; i++)
+    parameter[i] = get_graphic_parameter_value(parameter_raw[i],
+                                              image_config_suffix[i].token,
+                                              image_config_suffix[i].type);
+
+  graphic_info[graphic].bitmap = src_bitmap;
+
+  /* always start with reliable default values */
+  graphic_info[graphic].src_image_width = 0;
+  graphic_info[graphic].src_image_height = 0;
+  graphic_info[graphic].src_x = 0;
+  graphic_info[graphic].src_y = 0;
+  graphic_info[graphic].width  = TILEX;        /* default for element graphics */
+  graphic_info[graphic].height = TILEY;        /* default for element graphics */
+  graphic_info[graphic].offset_x = 0;  /* one or both of these values ... */
+  graphic_info[graphic].offset_y = 0;  /* ... will be corrected later */
+  graphic_info[graphic].offset2_x = 0; /* one or both of these values ... */
+  graphic_info[graphic].offset2_y = 0; /* ... will be corrected later */
+  graphic_info[graphic].swap_double_tiles = -1;        /* auto-detect tile swapping */
+  graphic_info[graphic].crumbled_like = -1;    /* do not use clone element */
+  graphic_info[graphic].diggable_like = -1;    /* do not use clone element */
+  graphic_info[graphic].border_size = TILEX / 8;  /* "CRUMBLED" border size */
+  graphic_info[graphic].scale_up_factor = 1;   /* default: no scaling up */
+  graphic_info[graphic].clone_from = -1;       /* do not use clone graphic */
+  graphic_info[graphic].anim_delay_fixed = 0;
+  graphic_info[graphic].anim_delay_random = 0;
+  graphic_info[graphic].post_delay_fixed = 0;
+  graphic_info[graphic].post_delay_random = 0;
+  graphic_info[graphic].fade_mode = FADE_MODE_DEFAULT;
+  graphic_info[graphic].fade_delay = -1;
+  graphic_info[graphic].post_delay = -1;
+  graphic_info[graphic].auto_delay = -1;
+  graphic_info[graphic].align = ALIGN_CENTER;  /* default for title screens */
+  graphic_info[graphic].valign = VALIGN_MIDDLE;        /* default for title screens */
+  graphic_info[graphic].sort_priority = 0;     /* default for title screens */
+
+#if 1
+  /* optional zoom factor for scaling up the image to a larger size */
+  if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
+  if (graphic_info[graphic].scale_up_factor < 1)
+    graphic_info[graphic].scale_up_factor = 1;         /* no scaling */
+#endif
+
+#if 1
+  if (graphic_info[graphic].use_image_size)
+  {
+    /* set new default bitmap size (with scaling, but without small images) */
+    graphic_info[graphic].width  = get_scaled_graphic_width(graphic);
+    graphic_info[graphic].height = get_scaled_graphic_height(graphic);
+  }
+#endif
+
+  /* optional x and y tile position of animation frame sequence */
+  if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].src_x = parameter[GFX_ARG_XPOS] * TILEX;
+  if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].src_y = parameter[GFX_ARG_YPOS] * TILEY;
+
+  /* optional x and y pixel position of animation frame sequence */
+  if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].src_x = parameter[GFX_ARG_X];
+  if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].src_y = parameter[GFX_ARG_Y];
+
+  /* optional width and height of each animation frame */
+  if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].width = parameter[GFX_ARG_WIDTH];
+  if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].height = parameter[GFX_ARG_HEIGHT];
+
+#if 0
+  /* optional zoom factor for scaling up the image to a larger size */
+  if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].scale_up_factor = parameter[GFX_ARG_SCALE_UP_FACTOR];
+  if (graphic_info[graphic].scale_up_factor < 1)
+    graphic_info[graphic].scale_up_factor = 1;         /* no scaling */
+#endif
+
+  if (src_bitmap)
+  {
+    /* get final bitmap size (with scaling, but without small images) */
+    int src_image_width  = get_scaled_graphic_width(graphic);
+    int src_image_height = get_scaled_graphic_height(graphic);
+
+    anim_frames_per_row = src_image_width  / graphic_info[graphic].width;
+    anim_frames_per_col = src_image_height / graphic_info[graphic].height;
+
+    graphic_info[graphic].src_image_width  = src_image_width;
+    graphic_info[graphic].src_image_height = src_image_height;
+  }
+
+  /* correct x or y offset dependent of vertical or horizontal frame order */
+  if (parameter[GFX_ARG_VERTICAL])     /* frames are ordered vertically */
+  {
+    graphic_info[graphic].offset_y =
+      (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
+       parameter[GFX_ARG_OFFSET] : graphic_info[graphic].height);
+    anim_frames_per_line = anim_frames_per_col;
+  }
+  else                                 /* frames are ordered horizontally */
+  {
+    graphic_info[graphic].offset_x =
+      (parameter[GFX_ARG_OFFSET] != ARG_UNDEFINED_VALUE ?
+       parameter[GFX_ARG_OFFSET] : graphic_info[graphic].width);
+    anim_frames_per_line = anim_frames_per_row;
+  }
+
+  /* optionally, the x and y offset of frames can be specified directly */
+  if (parameter[GFX_ARG_XOFFSET] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].offset_x = parameter[GFX_ARG_XOFFSET];
+  if (parameter[GFX_ARG_YOFFSET] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].offset_y = parameter[GFX_ARG_YOFFSET];
+
+  /* optionally, moving animations may have separate start and end graphics */
+  graphic_info[graphic].double_movement = parameter[GFX_ARG_2ND_MOVEMENT_TILE];
+
+  if (parameter[GFX_ARG_2ND_VERTICAL] == ARG_UNDEFINED_VALUE)
+    parameter[GFX_ARG_2ND_VERTICAL] = !parameter[GFX_ARG_VERTICAL];
+
+  /* correct x or y offset2 dependent of vertical or horizontal frame order */
+  if (parameter[GFX_ARG_2ND_VERTICAL]) /* frames are ordered vertically */
+    graphic_info[graphic].offset2_y =
+      (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
+       parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].height);
+  else                                 /* frames are ordered horizontally */
+    graphic_info[graphic].offset2_x =
+      (parameter[GFX_ARG_2ND_OFFSET] != ARG_UNDEFINED_VALUE ?
+       parameter[GFX_ARG_2ND_OFFSET] : graphic_info[graphic].width);
+
+  /* optionally, the x and y offset of 2nd graphic can be specified directly */
+  if (parameter[GFX_ARG_2ND_XOFFSET] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].offset2_x = parameter[GFX_ARG_2ND_XOFFSET];
+  if (parameter[GFX_ARG_2ND_YOFFSET] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].offset2_y = parameter[GFX_ARG_2ND_YOFFSET];
+
+  /* optionally, the second movement tile can be specified as start tile */
+  if (parameter[GFX_ARG_2ND_SWAP_TILES] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].swap_double_tiles= parameter[GFX_ARG_2ND_SWAP_TILES];
+
+  /* automatically determine correct number of frames, if not defined */
+  if (parameter[GFX_ARG_FRAMES] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].anim_frames = parameter[GFX_ARG_FRAMES];
+  else if (parameter[GFX_ARG_XPOS] == 0 && !parameter[GFX_ARG_VERTICAL])
+    graphic_info[graphic].anim_frames =        anim_frames_per_row;
+  else if (parameter[GFX_ARG_YPOS] == 0 && parameter[GFX_ARG_VERTICAL])
+    graphic_info[graphic].anim_frames =        anim_frames_per_col;
+  else
+    graphic_info[graphic].anim_frames = 1;
+
+  if (graphic_info[graphic].anim_frames == 0)  /* frames must be at least 1 */
+    graphic_info[graphic].anim_frames = 1;
+
+  graphic_info[graphic].anim_frames_per_line =
+    (parameter[GFX_ARG_FRAMES_PER_LINE] != ARG_UNDEFINED_VALUE ?
+     parameter[GFX_ARG_FRAMES_PER_LINE] : anim_frames_per_line);
+
+  graphic_info[graphic].anim_delay = parameter[GFX_ARG_DELAY];
+  if (graphic_info[graphic].anim_delay == 0)   /* delay must be at least 1 */
+    graphic_info[graphic].anim_delay = 1;
+
+  graphic_info[graphic].anim_mode = parameter[GFX_ARG_ANIM_MODE];
+#if 0
+  if (graphic_info[graphic].anim_frames == 1)
+    graphic_info[graphic].anim_mode = ANIM_NONE;
+#endif
+
+  /* automatically determine correct start frame, if not defined */
+  if (parameter[GFX_ARG_START_FRAME] == ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].anim_start_frame = 0;
+  else if (graphic_info[graphic].anim_mode & ANIM_REVERSE)
+    graphic_info[graphic].anim_start_frame =
+      graphic_info[graphic].anim_frames - parameter[GFX_ARG_START_FRAME] - 1;
+  else
+    graphic_info[graphic].anim_start_frame = parameter[GFX_ARG_START_FRAME];
+
+  /* animation synchronized with global frame counter, not move position */
+  graphic_info[graphic].anim_global_sync = parameter[GFX_ARG_GLOBAL_SYNC];
 
   /* optional element for cloning crumble graphics */
   if (parameter[GFX_ARG_CRUMBLED_LIKE] != ARG_UNDEFINED_VALUE)
@@ -1148,13 +1688,24 @@ static void set_graphic_parameters(int graphic)
   if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
     graphic_info[graphic].clone_from = parameter[GFX_ARG_CLONE_FROM];
 
-  /* optional settings for drawing title screens */
+  /* optional settings for drawing title screens and title messages */
+  if (parameter[GFX_ARG_FADE_MODE] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].fade_mode = parameter[GFX_ARG_FADE_MODE];
   if (parameter[GFX_ARG_FADE_DELAY] != ARG_UNDEFINED_VALUE)
     graphic_info[graphic].fade_delay = parameter[GFX_ARG_FADE_DELAY];
   if (parameter[GFX_ARG_POST_DELAY] != ARG_UNDEFINED_VALUE)
     graphic_info[graphic].post_delay = parameter[GFX_ARG_POST_DELAY];
   if (parameter[GFX_ARG_AUTO_DELAY] != ARG_UNDEFINED_VALUE)
     graphic_info[graphic].auto_delay = parameter[GFX_ARG_AUTO_DELAY];
+  if (parameter[GFX_ARG_ALIGN] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].align = parameter[GFX_ARG_ALIGN];
+  if (parameter[GFX_ARG_VALIGN] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].valign = parameter[GFX_ARG_VALIGN];
+  if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
+    graphic_info[graphic].sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
+#endif
+
+  UPDATE_BUSY_STATE();
 }
 
 static void set_cloned_graphic_parameters(int graphic)
@@ -1174,18 +1725,18 @@ static void set_cloned_graphic_parameters(int graphic)
 
   if (num_references_followed >= max_num_images)
   {
-    Error(ERR_RETURN_LINE, "-");
-    Error(ERR_RETURN, "warning: error found in config file:");
-    Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
-    Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(graphic));
-    Error(ERR_RETURN, "error: loop discovered when resolving cloned graphics");
-    Error(ERR_RETURN, "custom graphic rejected for this element/action");
+    Error(ERR_INFO_LINE, "-");
+    Error(ERR_INFO, "warning: error found in config file:");
+    Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
+    Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
+    Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
+    Error(ERR_INFO, "custom graphic rejected for this element/action");
 
     if (graphic == fallback_graphic)
       Error(ERR_EXIT, "fatal error: no fallback graphic available");
 
-    Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
-    Error(ERR_RETURN_LINE, "-");
+    Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
+    Error(ERR_INFO_LINE, "-");
 
     graphic_info[graphic] = graphic_info[fallback_graphic];
   }
@@ -1206,7 +1757,7 @@ static void InitGraphicInfo()
   static boolean clipmasks_initialized = FALSE;
   Pixmap src_pixmap;
   XGCValues clip_gc_values;
-  unsigned long clip_gc_valuemask;
+  unsigned int clip_gc_valuemask;
   GC copy_clipmask_gc = None;
 #endif
 
@@ -1222,9 +1773,11 @@ static void InitGraphicInfo()
     IMG_BACKGROUND_ENVELOPE_4,
 
     IMG_BACKGROUND,
+    IMG_BACKGROUND_TITLE_INITIAL,
     IMG_BACKGROUND_TITLE,
     IMG_BACKGROUND_MAIN,
     IMG_BACKGROUND_LEVELS,
+    IMG_BACKGROUND_LEVELNR,
     IMG_BACKGROUND_SCORES,
     IMG_BACKGROUND_EDITOR,
     IMG_BACKGROUND_INFO,
@@ -1235,6 +1788,8 @@ static void InitGraphicInfo()
     IMG_BACKGROUND_INFO_LEVELSET,
     IMG_BACKGROUND_SETUP,
     IMG_BACKGROUND_DOOR,
+    IMG_BACKGROUND_TAPE,
+    IMG_BACKGROUND_PANEL,
 
     IMG_TITLESCREEN_INITIAL_1,
     IMG_TITLESCREEN_INITIAL_2,
@@ -1313,7 +1868,7 @@ static void InitGraphicInfo()
     /* check if first animation frame is inside specified bitmap */
 
     first_frame = 0;
-    getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
+    getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
 
 #if 1
     /* this avoids calculating wrong start position for out-of-bounds frame */
@@ -1325,21 +1880,21 @@ static void InitGraphicInfo()
        src_x + width  > src_bitmap_width ||
        src_y + height > src_bitmap_height)
     {
-      Error(ERR_RETURN_LINE, "-");
-      Error(ERR_RETURN, "warning: error found in config file:");
-      Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
-      Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
-      Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
-      Error(ERR_RETURN,
+      Error(ERR_INFO_LINE, "-");
+      Error(ERR_INFO, "warning: error found in config file:");
+      Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
+      Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
+      Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
+      Error(ERR_INFO,
            "error: first animation frame out of bounds (%d, %d) [%d, %d]",
            src_x, src_y, src_bitmap_width, src_bitmap_height);
-      Error(ERR_RETURN, "custom graphic rejected for this element/action");
+      Error(ERR_INFO, "custom graphic rejected for this element/action");
 
       if (i == fallback_graphic)
        Error(ERR_EXIT, "fatal error: no fallback graphic available");
 
-      Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
-      Error(ERR_RETURN_LINE, "-");
+      Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
+      Error(ERR_INFO_LINE, "-");
 
       graphic_info[i] = graphic_info[fallback_graphic];
     }
@@ -1347,34 +1902,35 @@ static void InitGraphicInfo()
     /* check if last animation frame is inside specified bitmap */
 
     last_frame = graphic_info[i].anim_frames - 1;
-    getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
+    getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
 
     if (src_x < 0 || src_y < 0 ||
        src_x + width  > src_bitmap_width ||
        src_y + height > src_bitmap_height)
     {
-      Error(ERR_RETURN_LINE, "-");
-      Error(ERR_RETURN, "warning: error found in config file:");
-      Error(ERR_RETURN, "- config file: '%s'", getImageConfigFilename());
-      Error(ERR_RETURN, "- config token: '%s'", getTokenFromImageID(i));
-      Error(ERR_RETURN, "- image file: '%s'", src_bitmap->source_filename);
-      Error(ERR_RETURN,
+      Error(ERR_INFO_LINE, "-");
+      Error(ERR_INFO, "warning: error found in config file:");
+      Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
+      Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
+      Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
+      Error(ERR_INFO,
            "error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
            last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
-      Error(ERR_RETURN, "custom graphic rejected for this element/action");
+      Error(ERR_INFO, "::: %d, %d", width, height);
+      Error(ERR_INFO, "custom graphic rejected for this element/action");
 
       if (i == fallback_graphic)
        Error(ERR_EXIT, "fatal error: no fallback graphic available");
 
-      Error(ERR_RETURN, "fallback done to 'char_exclam' for this graphic");
-      Error(ERR_RETURN_LINE, "-");
+      Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
+      Error(ERR_INFO_LINE, "-");
 
       graphic_info[i] = graphic_info[fallback_graphic];
     }
 
 #if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
     /* currently we only need a tile clip mask from the first frame */
-    getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
+    getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
 
     if (copy_clipmask_gc == None)
     {
@@ -1408,6 +1964,60 @@ static void InitGraphicInfo()
 #endif
 }
 
+static void InitGraphicCompatibilityInfo()
+{
+  struct FileInfo *fi_global_door =
+    getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
+  int num_images = getImageListSize();
+  int i;
+
+  /* the following compatibility handling is needed for the following case:
+     versions up to 3.3.0.0 used one large bitmap "global.door" for various
+     graphics mainly used for door and panel graphics, like editor, tape and
+     in-game buttons with hard-coded bitmap positions and button sizes; as
+     these graphics now have individual definitions, redefining "global.door"
+     to change all these graphics at once like before does not work anymore
+     (because all those individual definitions still have their default values);
+     to solve this, remap all those individual definitions that are not
+     redefined to the new bitmap of "global.door" if it was redefined */
+
+  /* special compatibility handling if image "global.door" was redefined */
+  if (fi_global_door->redefined)
+  {
+    for (i = 0; i < num_images; i++)
+    {
+      struct FileInfo *fi = getImageListEntryFromImageID(i);
+
+      /* process only those images that still use the default settings */
+      if (!fi->redefined)
+      {
+       /* process all images which default to same image as "global.door" */
+       if (strEqual(fi->default_filename, fi_global_door->default_filename))
+       {
+         // printf("::: special treatment needed for token '%s'\n", fi->token);
+
+         graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
+       }
+      }
+    }
+  }
+
+#if 0
+  for (i = 0; i < num_images; i++)
+  {
+    struct FileInfo *fi = getImageListEntryFromImageID(i);
+
+    if (i == IMG_GLOBAL_DOOR)
+    {
+      printf("::: %s, %s, %d\n",
+            fi->default_filename,
+            fi->filename,
+            fi->redefined);
+    }
+  }
+#endif
+}
+
 static void InitElementSoundInfo()
 {
   struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
@@ -1571,7 +2181,7 @@ static void set_sound_parameters(int sound, char **parameter_raw)
   sound_info[sound].volume = parameter[SND_ARG_VOLUME];
 
   /* sound priority to give certain sounds a higher or lower priority */
-  sound_info[sound].volume = parameter[SND_ARG_VOLUME];
+  sound_info[sound].priority = parameter[SND_ARG_PRIORITY];
 }
 
 static void InitSoundInfo()
@@ -1784,21 +2394,39 @@ static void InitMusicInfo()
 
 static void ReinitializeGraphics()
 {
+  print_timestamp_init("ReinitializeGraphics");
+
   InitGraphicInfo();                   /* graphic properties mapping */
+  print_timestamp_time("InitGraphicInfo");
   InitElementGraphicInfo();            /* element game graphic mapping */
+  print_timestamp_time("InitElementGraphicInfo");
   InitElementSpecialGraphicInfo();     /* element special graphic mapping */
+  print_timestamp_time("InitElementSpecialGraphicInfo");
 
   InitElementSmallImages();            /* scale elements to all needed sizes */
+  print_timestamp_time("InitElementSmallImages");
   InitScaledImages();                  /* scale all other images, if needed */
+  print_timestamp_time("InitScaledImages");
   InitFontGraphicInfo();               /* initialize text drawing functions */
+  print_timestamp_time("InitFontGraphicInfo");
 
   InitGraphicInfo_EM();                        /* graphic mapping for EM engine */
+  print_timestamp_time("InitGraphicInfo_EM");
+
+  InitGraphicCompatibilityInfo();
+  print_timestamp_time("InitGraphicCompatibilityInfo");
 
   SetMainBackgroundImage(IMG_BACKGROUND);
+  print_timestamp_time("SetMainBackgroundImage");
   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
+  print_timestamp_time("SetDoorBackgroundImage");
 
   InitGadgets();
+  print_timestamp_time("InitGadgets");
   InitToons();
+  print_timestamp_time("InitToons");
+
+  print_timestamp_done("ReinitializeGraphics");
 }
 
 static void ReinitializeSounds()
@@ -1946,7 +2574,7 @@ boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
   return FALSE;
 }
 
-static void resolve_group_element(int group_element, int recursion_depth)
+static void ResolveGroupElementExt(int group_element, int recursion_depth)
 {
   static int group_nr;
   static struct ElementGroupInfo *group;
@@ -1970,10 +2598,13 @@ static void resolve_group_element(int group_element, int recursion_depth)
   if (recursion_depth == 0)                    /* initialization */
   {
     group = actual_group;
-    group_nr = group_element - EL_GROUP_START;
+    group_nr = GROUP_NR(group_element);
 
     group->num_elements_resolved = 0;
     group->choice_pos = 0;
+
+    for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+      element_info[i].in_group[group_nr] = FALSE;
   }
 
   for (i = 0; i < actual_group->num_elements; i++)
@@ -1984,7 +2615,7 @@ static void resolve_group_element(int group_element, int recursion_depth)
       break;
 
     if (IS_GROUP_ELEMENT(element))
-      resolve_group_element(element, recursion_depth + 1);
+      ResolveGroupElementExt(element, recursion_depth + 1);
     else
     {
       group->element_resolved[group->num_elements_resolved++] = element;
@@ -1993,8 +2624,15 @@ static void resolve_group_element(int group_element, int recursion_depth)
   }
 }
 
+void ResolveGroupElement(int group_element)
+{
+  ResolveGroupElementExt(group_element, 0);
+}
+
 void InitElementPropertiesStatic()
 {
+  static boolean clipboard_elements_initialized = FALSE;
+
   static int ep_diggable[] =
   {
     EL_SAND,
@@ -2010,6 +2648,7 @@ void InitElementPropertiesStatic()
     /* (if amoeba can grow into anything diggable, maybe keep these out) */
 #if 0
     EL_LANDMINE,
+    EL_DC_LANDMINE,
     EL_TRAP_ACTIVE,
     EL_SP_BUGGY_BASE_ACTIVE,
     EL_EMC_PLANT,
@@ -2047,7 +2686,7 @@ void InitElementPropertiesStatic()
     EL_SP_DISK_RED,
     EL_PEARL,
     EL_CRYSTAL,
-    EL_KEY_WHITE,
+    EL_DC_KEY_WHITE,
     EL_SHIELD_NORMAL,
     EL_SHIELD_DEADLY,
     EL_EXTRA_TIME,
@@ -2059,6 +2698,11 @@ void InitElementPropertiesStatic()
     EL_EMC_LENSES,
     EL_EMC_MAGNIFIER,
 
+#if 0
+    /* !!! handle separately !!! */
+    EL_DC_LANDMINE,    /* deadly when running into, but can be snapped */
+#endif
+
     -1
   };
 
@@ -2085,6 +2729,7 @@ void InitElementPropertiesStatic()
     /* !!! maybe this should better be handled by 'ep_diggable' !!! */
 #if 1
     EL_LANDMINE,
+    EL_DC_LANDMINE,
     EL_TRAP_ACTIVE,
     EL_SP_BUGGY_BASE_ACTIVE,
     EL_EMC_PLANT,
@@ -2163,13 +2808,48 @@ void InitElementPropertiesStatic()
     EL_SIGN_STOP,
     EL_SIGN_WHEELCHAIR,
     EL_SIGN_PARKING,
-    EL_SIGN_ONEWAY,
+    EL_SIGN_NO_ENTRY,
+    EL_SIGN_UNUSED_1,
+    EL_SIGN_GIVE_WAY,
+    EL_SIGN_ENTRY_FORBIDDEN,
+    EL_SIGN_EMERGENCY_EXIT,
+    EL_SIGN_YIN_YANG,
+    EL_SIGN_UNUSED_2,
+    EL_SIGN_SPERMS,
+    EL_SIGN_BULLET,
     EL_SIGN_HEART,
-    EL_SIGN_TRIANGLE,
-    EL_SIGN_ROUND,
-    EL_SIGN_EXIT,
-    EL_SIGN_YINYANG,
-    EL_SIGN_OTHER,
+    EL_SIGN_CROSS,
+    EL_SIGN_FRANKIE,
+    EL_STEEL_EXIT_CLOSED,
+    EL_STEEL_EXIT_OPEN,
+    EL_STEEL_EXIT_OPENING,
+    EL_STEEL_EXIT_CLOSING,
+    EL_EM_STEEL_EXIT_CLOSED,
+    EL_EM_STEEL_EXIT_OPEN,
+    EL_EM_STEEL_EXIT_OPENING,
+    EL_EM_STEEL_EXIT_CLOSING,
+    EL_DC_STEELWALL_1_LEFT,
+    EL_DC_STEELWALL_1_RIGHT,
+    EL_DC_STEELWALL_1_TOP,
+    EL_DC_STEELWALL_1_BOTTOM,
+    EL_DC_STEELWALL_1_HORIZONTAL,
+    EL_DC_STEELWALL_1_VERTICAL,
+    EL_DC_STEELWALL_1_TOPLEFT,
+    EL_DC_STEELWALL_1_TOPRIGHT,
+    EL_DC_STEELWALL_1_BOTTOMLEFT,
+    EL_DC_STEELWALL_1_BOTTOMRIGHT,
+    EL_DC_STEELWALL_1_TOPLEFT_2,
+    EL_DC_STEELWALL_1_TOPRIGHT_2,
+    EL_DC_STEELWALL_1_BOTTOMLEFT_2,
+    EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
+    EL_DC_STEELWALL_2_LEFT,
+    EL_DC_STEELWALL_2_RIGHT,
+    EL_DC_STEELWALL_2_TOP,
+    EL_DC_STEELWALL_2_BOTTOM,
+    EL_DC_STEELWALL_2_HORIZONTAL,
+    EL_DC_STEELWALL_2_VERTICAL,
+    EL_DC_STEELWALL_2_MIDDLE,
+    EL_DC_STEELWALL_2_SINGLE,
     EL_STEELWALL_SLIPPERY,
     EL_EMC_STEELWALL_1,
     EL_EMC_STEELWALL_2,
@@ -2212,21 +2892,25 @@ void InitElementPropertiesStatic()
     EL_EMC_GATE_6_GRAY_ACTIVE,
     EL_EMC_GATE_7_GRAY_ACTIVE,
     EL_EMC_GATE_8_GRAY_ACTIVE,
+    EL_DC_GATE_WHITE,
+    EL_DC_GATE_WHITE_GRAY,
+    EL_DC_GATE_WHITE_GRAY_ACTIVE,
+    EL_DC_GATE_FAKE_GRAY,
     EL_SWITCHGATE_OPEN,
     EL_SWITCHGATE_OPENING,
     EL_SWITCHGATE_CLOSED,
     EL_SWITCHGATE_CLOSING,
-#if 0
-    EL_SWITCHGATE_SWITCH_UP,
-    EL_SWITCHGATE_SWITCH_DOWN,
+#if 1
+    EL_DC_SWITCHGATE_SWITCH_UP,
+    EL_DC_SWITCHGATE_SWITCH_DOWN,
 #endif
     EL_TIMEGATE_OPEN,
     EL_TIMEGATE_OPENING,
     EL_TIMEGATE_CLOSED,
     EL_TIMEGATE_CLOSING,
-#if 0
-    EL_TIMEGATE_SWITCH,
-    EL_TIMEGATE_SWITCH_ACTIVE,
+#if 1
+    EL_DC_TIMEGATE_SWITCH,
+    EL_DC_TIMEGATE_SWITCH_ACTIVE,
 #endif
     EL_TUBE_ANY,
     EL_TUBE_VERTICAL,
@@ -2239,6 +2923,9 @@ void InitElementPropertiesStatic()
     EL_TUBE_LEFT_DOWN,
     EL_TUBE_RIGHT_UP,
     EL_TUBE_RIGHT_DOWN,
+    EL_EXPANDABLE_STEELWALL_HORIZONTAL,
+    EL_EXPANDABLE_STEELWALL_VERTICAL,
+    EL_EXPANDABLE_STEELWALL_ANY,
 
     -1
   };
@@ -2331,8 +3018,10 @@ void InitElementPropertiesStatic()
     EL_NUT,
     EL_AMOEBA_DROP,
     EL_QUICKSAND_FULL,
+    EL_QUICKSAND_FAST_FULL,
     EL_MAGIC_WALL_FULL,
     EL_BD_MAGIC_WALL_FULL,
+    EL_DC_MAGIC_WALL_FULL,
     EL_TIME_ORB_FULL,
     EL_TIME_ORB_EMPTY,
     EL_SP_ZONK,
@@ -2460,8 +3149,17 @@ void InitElementPropertiesStatic()
     EL_SP_EMPTY_SPACE,
     EL_SOKOBAN_FIELD_EMPTY,
     EL_EXIT_OPEN,
+    EL_EM_EXIT_OPEN,
+#if 1
+    EL_EM_EXIT_OPENING,
+#endif
     EL_SP_EXIT_OPEN,
     EL_SP_EXIT_OPENING,
+    EL_STEEL_EXIT_OPEN,
+    EL_EM_STEEL_EXIT_OPEN,
+#if 1
+    EL_EM_STEEL_EXIT_OPENING,
+#endif
     EL_GATE_1,
     EL_GATE_2,
     EL_GATE_3,
@@ -2529,6 +3227,9 @@ void InitElementPropertiesStatic()
     EL_EMC_GATE_6_GRAY_ACTIVE,
     EL_EMC_GATE_7_GRAY_ACTIVE,
     EL_EMC_GATE_8_GRAY_ACTIVE,
+    EL_DC_GATE_WHITE,
+    EL_DC_GATE_WHITE_GRAY,
+    EL_DC_GATE_WHITE_GRAY_ACTIVE,
     EL_SWITCHGATE_OPEN,
     EL_TIMEGATE_OPEN,
 
@@ -2641,6 +3342,9 @@ void InitElementPropertiesStatic()
     EL_EMC_GATE_6_GRAY_ACTIVE,
     EL_EMC_GATE_7_GRAY_ACTIVE,
     EL_EMC_GATE_8_GRAY_ACTIVE,
+    EL_DC_GATE_WHITE,
+    EL_DC_GATE_WHITE_GRAY,
+    EL_DC_GATE_WHITE_GRAY_ACTIVE,
     EL_SWITCHGATE_OPEN,
     EL_TIMEGATE_OPEN,
 
@@ -2770,6 +3474,22 @@ void InitElementPropertiesStatic()
     -1
   };
 
+  static int ep_can_pass_dc_magic_wall[] =
+  {
+    EL_ROCK,
+    EL_BD_ROCK,
+    EL_EMERALD,
+    EL_BD_DIAMOND,
+    EL_EMERALD_YELLOW,
+    EL_EMERALD_RED,
+    EL_EMERALD_PURPLE,
+    EL_DIAMOND,
+    EL_PEARL,
+    EL_CRYSTAL,
+
+    -1
+  };
+
   static int ep_switchable[] =
   {
     EL_ROBOT_WHEEL,
@@ -2788,9 +3508,12 @@ void InitElementPropertiesStatic()
     EL_CONVEYOR_BELT_4_SWITCH_RIGHT,
     EL_SWITCHGATE_SWITCH_UP,
     EL_SWITCHGATE_SWITCH_DOWN,
+    EL_DC_SWITCHGATE_SWITCH_UP,
+    EL_DC_SWITCHGATE_SWITCH_DOWN,
     EL_LIGHT_SWITCH,
     EL_LIGHT_SWITCH_ACTIVE,
     EL_TIMEGATE_SWITCH,
+    EL_DC_TIMEGATE_SWITCH,
     EL_BALLOON_SWITCH_LEFT,
     EL_BALLOON_SWITCH_RIGHT,
     EL_BALLOON_SWITCH_UP,
@@ -3126,8 +3849,12 @@ void InitElementPropertiesStatic()
     EL_INVISIBLE_WALL_ACTIVE,
     EL_SWITCHGATE_SWITCH_UP,
     EL_SWITCHGATE_SWITCH_DOWN,
+    EL_DC_SWITCHGATE_SWITCH_UP,
+    EL_DC_SWITCHGATE_SWITCH_DOWN,
     EL_TIMEGATE_SWITCH,
     EL_TIMEGATE_SWITCH_ACTIVE,
+    EL_DC_TIMEGATE_SWITCH,
+    EL_DC_TIMEGATE_SWITCH_ACTIVE,
     EL_EMC_WALL_1,
     EL_EMC_WALL_2,
     EL_EMC_WALL_3,
@@ -3182,13 +3909,42 @@ void InitElementPropertiesStatic()
     EL_SIGN_STOP,
     EL_SIGN_WHEELCHAIR,
     EL_SIGN_PARKING,
-    EL_SIGN_ONEWAY,
+    EL_SIGN_NO_ENTRY,
+    EL_SIGN_UNUSED_1,
+    EL_SIGN_GIVE_WAY,
+    EL_SIGN_ENTRY_FORBIDDEN,
+    EL_SIGN_EMERGENCY_EXIT,
+    EL_SIGN_YIN_YANG,
+    EL_SIGN_UNUSED_2,
+    EL_SIGN_SPERMS,
+    EL_SIGN_BULLET,
     EL_SIGN_HEART,
-    EL_SIGN_TRIANGLE,
-    EL_SIGN_ROUND,
-    EL_SIGN_EXIT,
-    EL_SIGN_YINYANG,
-    EL_SIGN_OTHER,
+    EL_SIGN_CROSS,
+    EL_SIGN_FRANKIE,
+    EL_STEEL_EXIT_CLOSED,
+    EL_STEEL_EXIT_OPEN,
+    EL_DC_STEELWALL_1_LEFT,
+    EL_DC_STEELWALL_1_RIGHT,
+    EL_DC_STEELWALL_1_TOP,
+    EL_DC_STEELWALL_1_BOTTOM,
+    EL_DC_STEELWALL_1_HORIZONTAL,
+    EL_DC_STEELWALL_1_VERTICAL,
+    EL_DC_STEELWALL_1_TOPLEFT,
+    EL_DC_STEELWALL_1_TOPRIGHT,
+    EL_DC_STEELWALL_1_BOTTOMLEFT,
+    EL_DC_STEELWALL_1_BOTTOMRIGHT,
+    EL_DC_STEELWALL_1_TOPLEFT_2,
+    EL_DC_STEELWALL_1_TOPRIGHT_2,
+    EL_DC_STEELWALL_1_BOTTOMLEFT_2,
+    EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
+    EL_DC_STEELWALL_2_LEFT,
+    EL_DC_STEELWALL_2_RIGHT,
+    EL_DC_STEELWALL_2_TOP,
+    EL_DC_STEELWALL_2_BOTTOM,
+    EL_DC_STEELWALL_2_HORIZONTAL,
+    EL_DC_STEELWALL_2_VERTICAL,
+    EL_DC_STEELWALL_2_MIDDLE,
+    EL_DC_STEELWALL_2_SINGLE,
     EL_STEELWALL_SLIPPERY,
     EL_EMC_STEELWALL_1,
     EL_EMC_STEELWALL_2,
@@ -3330,6 +4086,17 @@ void InitElementPropertiesStatic()
     -1
   };
 
+  static int ep_acid_pool[] =
+  {
+    EL_ACID_POOL_TOPLEFT,
+    EL_ACID_POOL_TOPRIGHT,
+    EL_ACID_POOL_BOTTOMLEFT,
+    EL_ACID_POOL_BOTTOM,
+    EL_ACID_POOL_BOTTOMRIGHT,
+
+    -1
+  };
+
   static int ep_keygate[] =
   {
     EL_GATE_1,
@@ -3368,6 +4135,9 @@ void InitElementPropertiesStatic()
     EL_EMC_GATE_6_GRAY_ACTIVE,
     EL_EMC_GATE_7_GRAY_ACTIVE,
     EL_EMC_GATE_8_GRAY_ACTIVE,
+    EL_DC_GATE_WHITE,
+    EL_DC_GATE_WHITE_GRAY,
+    EL_DC_GATE_WHITE_GRAY_ACTIVE,
 
     -1
   };
@@ -3401,6 +4171,7 @@ void InitElementPropertiesStatic()
     EL_PLAYER_2,
     EL_PLAYER_3,
     EL_PLAYER_4,
+    EL_SOKOBAN_FIELD_PLAYER,
     EL_SP_MURPHY,
     EL_YAMYAM,
     EL_YAMYAM_LEFT,
@@ -3460,6 +4231,7 @@ void InitElementPropertiesStatic()
     EL_STEELWALL,
     EL_AMOEBA_DEAD,
     EL_QUICKSAND_EMPTY,
+    EL_QUICKSAND_FAST_EMPTY,
     EL_STONEBLOCK,
     EL_ROBOT_WHEEL,
     EL_KEY_1,
@@ -3510,6 +4282,10 @@ void InitElementPropertiesStatic()
     EL_EMC_GATE_6_GRAY_ACTIVE,
     EL_EMC_GATE_7_GRAY_ACTIVE,
     EL_EMC_GATE_8_GRAY_ACTIVE,
+    EL_DC_GATE_WHITE,
+    EL_DC_GATE_WHITE_GRAY,
+    EL_DC_GATE_WHITE_GRAY_ACTIVE,
+    EL_DC_GATE_FAKE_GRAY,
     EL_DYNAMITE,
     EL_EM_DYNAMITE,
     EL_INVISIBLE_STEELWALL,
@@ -3540,6 +4316,8 @@ void InitElementPropertiesStatic()
     EL_MAGIC_WALL_DEAD,
     EL_BD_MAGIC_WALL,
     EL_BD_MAGIC_WALL_DEAD,
+    EL_DC_MAGIC_WALL,
+    EL_DC_MAGIC_WALL_DEAD,
     EL_AMOEBA_TO_DIAMOND,
     EL_BLOCKED,
     EL_SP_EMPTY,
@@ -3600,13 +4378,40 @@ void InitElementPropertiesStatic()
     EL_SIGN_STOP,
     EL_SIGN_WHEELCHAIR,
     EL_SIGN_PARKING,
-    EL_SIGN_ONEWAY,
+    EL_SIGN_NO_ENTRY,
+    EL_SIGN_UNUSED_1,
+    EL_SIGN_GIVE_WAY,
+    EL_SIGN_ENTRY_FORBIDDEN,
+    EL_SIGN_EMERGENCY_EXIT,
+    EL_SIGN_YIN_YANG,
+    EL_SIGN_UNUSED_2,
+    EL_SIGN_SPERMS,
+    EL_SIGN_BULLET,
     EL_SIGN_HEART,
-    EL_SIGN_TRIANGLE,
-    EL_SIGN_ROUND,
-    EL_SIGN_EXIT,
-    EL_SIGN_YINYANG,
-    EL_SIGN_OTHER,
+    EL_SIGN_CROSS,
+    EL_SIGN_FRANKIE,
+    EL_DC_STEELWALL_1_LEFT,
+    EL_DC_STEELWALL_1_RIGHT,
+    EL_DC_STEELWALL_1_TOP,
+    EL_DC_STEELWALL_1_BOTTOM,
+    EL_DC_STEELWALL_1_HORIZONTAL,
+    EL_DC_STEELWALL_1_VERTICAL,
+    EL_DC_STEELWALL_1_TOPLEFT,
+    EL_DC_STEELWALL_1_TOPRIGHT,
+    EL_DC_STEELWALL_1_BOTTOMLEFT,
+    EL_DC_STEELWALL_1_BOTTOMRIGHT,
+    EL_DC_STEELWALL_1_TOPLEFT_2,
+    EL_DC_STEELWALL_1_TOPRIGHT_2,
+    EL_DC_STEELWALL_1_BOTTOMLEFT_2,
+    EL_DC_STEELWALL_1_BOTTOMRIGHT_2,
+    EL_DC_STEELWALL_2_LEFT,
+    EL_DC_STEELWALL_2_RIGHT,
+    EL_DC_STEELWALL_2_TOP,
+    EL_DC_STEELWALL_2_BOTTOM,
+    EL_DC_STEELWALL_2_HORIZONTAL,
+    EL_DC_STEELWALL_2_VERTICAL,
+    EL_DC_STEELWALL_2_MIDDLE,
+    EL_DC_STEELWALL_2_SINGLE,
     EL_STEELWALL_SLIPPERY,
     EL_EMC_STEELWALL_1,
     EL_EMC_STEELWALL_2,
@@ -3645,6 +4450,7 @@ void InitElementPropertiesStatic()
   {
     EL_SAND,
     EL_LANDMINE,
+    EL_DC_LANDMINE,
     EL_TRAP,
     EL_TRAP_ACTIVE,
 
@@ -3662,6 +4468,7 @@ void InitElementPropertiesStatic()
     EL_INTERNAL_CASCADE_DC_ACTIVE,
     EL_INTERNAL_CASCADE_DX_ACTIVE,
     EL_INTERNAL_CASCADE_CHARS_ACTIVE,
+    EL_INTERNAL_CASCADE_STEEL_CHARS_ACTIVE,
     EL_INTERNAL_CASCADE_CE_ACTIVE,
     EL_INTERNAL_CASCADE_GE_ACTIVE,
     EL_INTERNAL_CASCADE_REF_ACTIVE,
@@ -3682,6 +4489,7 @@ void InitElementPropertiesStatic()
     EL_INTERNAL_CASCADE_DC,
     EL_INTERNAL_CASCADE_DX,
     EL_INTERNAL_CASCADE_CHARS,
+    EL_INTERNAL_CASCADE_STEEL_CHARS,
     EL_INTERNAL_CASCADE_CE,
     EL_INTERNAL_CASCADE_GE,
     EL_INTERNAL_CASCADE_REF,
@@ -3743,6 +4551,7 @@ void InitElementPropertiesStatic()
 
     { ep_player,                       EP_PLAYER                       },
     { ep_can_pass_magic_wall,          EP_CAN_PASS_MAGIC_WALL          },
+    { ep_can_pass_dc_magic_wall,       EP_CAN_PASS_DC_MAGIC_WALL       },
     { ep_switchable,                   EP_SWITCHABLE                   },
     { ep_bd_element,                   EP_BD_ELEMENT                   },
     { ep_sp_element,                   EP_SP_ELEMENT                   },
@@ -3758,6 +4567,7 @@ void InitElementPropertiesStatic()
     { ep_belt_active,                  EP_BELT_ACTIVE                  },
     { ep_belt_switch,                  EP_BELT_SWITCH                  },
     { ep_tube,                         EP_TUBE                         },
+    { ep_acid_pool,                    EP_ACID_POOL                    },
     { ep_keygate,                      EP_KEYGATE                      },
     { ep_amoeboid,                     EP_AMOEBOID                     },
     { ep_amoebalive,                   EP_AMOEBALIVE                   },
@@ -3782,9 +4592,12 @@ void InitElementPropertiesStatic()
   int i, j, k;
 
   /* always start with reliable default values (element has no properties) */
+  /* (but never initialize clipboard elements after the very first time) */
+  /* (to be able to use clipboard elements between several levels) */
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
-    for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
-      SET_PROPERTY(i, j, FALSE);
+    if (!IS_CLIPBOARD_ELEMENT(i) || !clipboard_elements_initialized)
+      for (j = 0; j < NUM_ELEMENT_PROPERTIES; j++)
+       SET_PROPERTY(i, j, FALSE);
 
   /* set all base element properties from above array definitions */
   for (i = 0; element_properties[i].elements != NULL; i++)
@@ -3798,6 +4611,12 @@ void InitElementPropertiesStatic()
       if (HAS_PROPERTY(copy_properties[j][0], i))
        for (k = 1; k <= 4; k++)
          SET_PROPERTY(copy_properties[j][k], i, TRUE);
+
+  /* set static element properties that are not listed in array definitions */
+  for (i = EL_STEEL_CHAR_START; i <= EL_STEEL_CHAR_END; i++)
+    SET_PROPERTY(i, EP_INDESTRUCTIBLE, TRUE);
+
+  clipboard_elements_initialized = TRUE;
 }
 
 void InitElementPropertiesEngine(int engine_version)
@@ -3839,20 +4658,22 @@ void InitElementPropertiesEngine(int engine_version)
      property (which means that conditional property changes must be set to
      a reliable default value before) */
 
-  /* ---------- recursively resolve group elements ------------------------- */
-
-  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
-    for (j = 0; j < NUM_GROUP_ELEMENTS; j++)
-      element_info[i].in_group[j] = FALSE;
-
+  /* resolve group elements */
   for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
-    resolve_group_element(EL_GROUP_START + i, 0);
+    ResolveGroupElement(EL_GROUP_START + i);
 
   /* set all special, combined or engine dependent element properties */
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
+    /* do not change (already initialized) clipboard elements here */
+    if (IS_CLIPBOARD_ELEMENT(i))
+      continue;
+
     /* ---------- INACTIVE ------------------------------------------------- */
-    SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
+    SET_PROPERTY(i, EP_INACTIVE, ((i >= EL_CHAR_START &&
+                                  i <= EL_CHAR_END) ||
+                                 (i >= EL_STEEL_CHAR_START &&
+                                  i <= EL_STEEL_CHAR_END)));
 
     /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
     SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
@@ -3906,7 +4727,6 @@ void InitElementPropertiesEngine(int engine_version)
                                             !IS_COLLECTIBLE(i)));
 
     /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
-
     if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
       SET_PROPERTY(i, EP_DRAGONFIRE_PROOF, TRUE);
     else
@@ -4029,12 +4849,24 @@ void InitElementPropertiesEngine(int engine_version)
   {
     static int ep_em_slippery_wall[] =
     {
-      EL_STEELWALL,
       EL_WALL,
+      EL_STEELWALL,
       EL_EXPANDABLE_WALL,
       EL_EXPANDABLE_WALL_HORIZONTAL,
       EL_EXPANDABLE_WALL_VERTICAL,
       EL_EXPANDABLE_WALL_ANY,
+      EL_EXPANDABLE_STEELWALL_HORIZONTAL,
+      EL_EXPANDABLE_STEELWALL_VERTICAL,
+      EL_EXPANDABLE_STEELWALL_ANY,
+      EL_EXPANDABLE_STEELWALL_GROWING,
+      -1
+    };
+
+    static int ep_em_explodes_by_fire[] =
+    {
+      EL_EM_DYNAMITE,
+      EL_EM_DYNAMITE_ACTIVE,
+      EL_MOLE,
       -1
     };
 
@@ -4047,6 +4879,11 @@ void InitElementPropertiesEngine(int engine_version)
     SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
                 (level.em_slippery_gems &&
                  engine_version > VERSION_IDENT(2,0,1,0)));
+
+    /* special EM style explosion behaviour regarding chain reactions */
+    for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
+      SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
+                  level.em_explodes_by_fire);
   }
 
   /* this is needed because some graphics depend on element properties */
@@ -4073,27 +4910,124 @@ void InitElementPropertiesAfterLoading(int engine_version)
   }
 }
 
+void InitElementPropertiesGfxElement()
+{
+  int i;
+
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+  {
+    struct ElementInfo *ei = &element_info[i];
+
+    ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
+  }
+}
+
 static void InitGlobal()
 {
+  int graphic;
   int i;
 
-  for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
+  for (i = 0; i < MAX_NUM_ELEMENTS + 1; i++)
+  {
+    /* check if element_name_info entry defined for each element in "main.h" */
+    if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
+      Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
+
+    element_info[i].token_name = element_name_info[i].token_name;
+    element_info[i].class_name = element_name_info[i].class_name;
+    element_info[i].editor_description= element_name_info[i].editor_description;
+
+#if 0
+    printf("%04d: %s\n", i, element_name_info[i].token_name);
+#endif
+  }
+
+  /* create hash from image config list */
+  image_config_hash = newSetupFileHash();
+  for (i = 0; image_config[i].token != NULL; i++)
+    setHashEntry(image_config_hash,
+                image_config[i].token,
+                image_config[i].value);
+
+  /* create hash from element token list */
+  element_token_hash = newSetupFileHash();
+  for (i = 0; element_name_info[i].token_name != NULL; i++)
+    setHashEntry(element_token_hash,
+                element_name_info[i].token_name,
+                int2str(i, 0));
+
+  /* create hash from graphic token list */
+  graphic_token_hash = newSetupFileHash();
+  for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
+    if (strSuffix(image_config[i].value, ".png") ||
+       strSuffix(image_config[i].value, ".pcx") ||
+       strSuffix(image_config[i].value, ".wav") ||
+       strEqual(image_config[i].value, UNDEFINED_FILENAME))
+      setHashEntry(graphic_token_hash,
+                  image_config[i].token,
+                  int2str(graphic++, 0));
+
+  /* create hash from font token list */
+  font_token_hash = newSetupFileHash();
+  for (i = 0; font_info[i].token_name != NULL; i++)
+    setHashEntry(font_token_hash,
+                font_info[i].token_name,
+                int2str(i, 0));
+
+  /* always start with reliable default values (all elements) */
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+    ActiveElement[i] = i;
+
+  /* now add all entries that have an active state (active elements) */
+  for (i = 0; element_with_active_state[i].element != -1; i++)
+  {
+    int element = element_with_active_state[i].element;
+    int element_active = element_with_active_state[i].element_active;
+
+    ActiveElement[element] = element_active;
+  }
+
+  /* always start with reliable default values (all buttons) */
+  for (i = 0; i < NUM_IMAGE_FILES; i++)
+    ActiveButton[i] = i;
+
+  /* now add all entries that have an active state (active buttons) */
+  for (i = 0; button_with_active_state[i].button != -1; i++)
+  {
+    int button = button_with_active_state[i].button;
+    int button_active = button_with_active_state[i].button_active;
+
+    ActiveButton[button] = button_active;
+  }
+
+  /* always start with reliable default values (all fonts) */
+  for (i = 0; i < NUM_FONTS; i++)
+    ActiveFont[i] = i;
+
+  /* now add all entries that have an active state (active fonts) */
+  for (i = 0; font_with_active_state[i].font_nr != -1; i++)
   {
-    /* check if element_name_info entry defined for each element in "main.h" */
-    if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
-      Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
+    int font = font_with_active_state[i].font_nr;
+    int font_active = font_with_active_state[i].font_nr_active;
 
-    element_info[i].token_name = element_name_info[i].token_name;
-    element_info[i].class_name = element_name_info[i].class_name;
-    element_info[i].editor_description=element_name_info[i].editor_description;
+    ActiveFont[font] = font_active;
   }
 
   global.autoplay_leveldir = NULL;
   global.convert_leveldir = NULL;
+  global.create_images_dir = NULL;
 
   global.frames_per_second = 0;
   global.fps_slowdown = FALSE;
   global.fps_slowdown_factor = 1;
+
+  global.border_status = GAME_MODE_MAIN;
+#if 0
+  global.fading_status = GAME_MODE_MAIN;
+  global.fading_type = TYPE_ENTER_MENU;
+#endif
+
+  global.use_envelope_request = FALSE; /* !!! MOVE TO ARTWORK CONFIG !!! */
 }
 
 void Execute_Command(char *command)
@@ -4191,7 +5125,7 @@ void Execute_Command(char *command)
 
     exit(0);
   }
-  else if (strncmp(command, "dump level ", 11) == 0)
+  else if (strPrefix(command, "dump level "))
   {
     char *filename = &command[11];
 
@@ -4203,7 +5137,7 @@ void Execute_Command(char *command)
 
     exit(0);
   }
-  else if (strncmp(command, "dump tape ", 10) == 0)
+  else if (strPrefix(command, "dump tape "))
   {
     char *filename = &command[10];
 
@@ -4215,7 +5149,7 @@ void Execute_Command(char *command)
 
     exit(0);
   }
-  else if (strncmp(command, "autoplay ", 9) == 0)
+  else if (strPrefix(command, "autoplay "))
   {
     char *str_ptr = getStringCopy(&command[9]);        /* read command parameters */
 
@@ -4251,9 +5185,9 @@ void Execute_Command(char *command)
        str_ptr++;
     }
   }
-  else if (strncmp(command, "convert ", 8) == 0)
+  else if (strPrefix(command, "convert "))
   {
-    char *str_copy = getStringCopy(&command[8]);
+    char *str_copy = getStringCopy(strchr(command, ' ') + 1);
     char *str_ptr = strchr(str_copy, ' ');
 
     global.convert_leveldir = str_copy;
@@ -4265,9 +5199,22 @@ void Execute_Command(char *command)
       global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
     }
   }
+  else if (strPrefix(command, "create images "))
+  {
+#if defined(TARGET_SDL)
+    global.create_images_dir = getStringCopy(&command[14]);
+
+    if (access(global.create_images_dir, W_OK) != 0)
+      Error(ERR_EXIT, "image target directory '%s' not found or not writable",
+           global.create_images_dir);
+#else
+    Error(ERR_EXIT, "command only available for SDL target");
+#endif
+  }
 
 #if DEBUG
 #if defined(TARGET_SDL)
+#if !defined(TARGET_SDL2)
   else if (strEqual(command, "SDL_ListModes"))
   {
     SDL_Rect **modes;
@@ -4302,6 +5249,7 @@ void Execute_Command(char *command)
     exit(0);
   }
 #endif
+#endif
 #endif
 
   else
@@ -4492,12 +5440,38 @@ static void InitArtworkConfig()
 static void InitMixer()
 {
   OpenAudio();
+
   StartMixer();
 }
 
+void InitGfxBuffers()
+{
+  ReCreateBitmap(&bitmap_db_store, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
+  ReCreateBitmap(&bitmap_db_cross, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
+  ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE, DEFAULT_DEPTH);
+  ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE, DEFAULT_DEPTH);
+  ReCreateBitmap(&bitmap_db_door, 3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
+  ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
+
+  /* initialize screen properties */
+  InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
+                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
+                  bitmap_db_field);
+  InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
+  InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
+  InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
+  InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
+  InitGfxClipRegion(FALSE, -1, -1, -1, -1);
+
+  InitGfxBuffers_EM();
+  InitGfxBuffers_SP();
+}
+
 void InitGfx()
 {
+  struct GraphicInfo *graphic_info_last = graphic_info;
   char *filename_font_initial = NULL;
+  char *filename_anim_initial = NULL;
   Bitmap *bitmap_font_initial = NULL;
   int font_height;
   int i, j;
@@ -4524,7 +5498,7 @@ void InitGfx()
          font_initial[j].src_y = atoi(image_config[i].value);
        else if (strEqual(&image_config[i].token[len_font_token], ".width"))
          font_initial[j].width = atoi(image_config[i].value);
-       else if (strEqual(&image_config[i].token[len_font_token],".height"))
+       else if (strEqual(&image_config[i].token[len_font_token], ".height"))
          font_initial[j].height = atoi(image_config[i].value);
       }
     }
@@ -4539,11 +5513,16 @@ void InitGfx()
   if (filename_font_initial == NULL)   /* should not happen */
     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
 
+#if 1
+  InitGfxBuffers();
+#else
   /* create additional image buffers for double-buffering and cross-fading */
+  bitmap_db_store = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
   bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
   bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
   bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
   bitmap_db_door  = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
+  bitmap_db_toons = CreateBitmap(FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
 
   /* initialize screen properties */
   InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
@@ -4551,7 +5530,11 @@ void InitGfx()
                   bitmap_db_field);
   InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
   InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
+  InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
   InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
+#endif
+
+  InitGfxCustomArtworkInfo();
 
   bitmap_font_initial = LoadCustomImage(filename_font_initial);
 
@@ -4562,11 +5545,112 @@ void InitGfx()
 
   font_height = getFontHeight(FC_RED);
 
+#if 1
+  DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
+#else
   DrawInitText(getProgramInitString(), 20, FC_YELLOW);
+#endif
   DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
   DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
 
-  DrawInitText("Loading graphics:", 120, FC_GREEN);
+  DrawInitText("Loading graphics", 120, FC_GREEN);
+
+#if 1
+#if 1
+  /* initialize busy animation with default values */
+  int parameter[NUM_GFX_ARGS];
+  for (i = 0; i < NUM_GFX_ARGS; i++)
+    parameter[i] = get_graphic_parameter_value(image_config_suffix[i].value,
+                                               image_config_suffix[i].token,
+                                               image_config_suffix[i].type);
+#if 0
+  for (i = 0; i < NUM_GFX_ARGS; i++)
+    printf("::: '%s' => %d\n", image_config_suffix[i].token, parameter[i]);
+#endif
+#endif
+
+  /* determine settings for busy animation (when displaying startup messages) */
+  for (i = 0; image_config[i].token != NULL; i++)
+  {
+    char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
+    int len_anim_token = strlen(anim_token);
+
+    if (strEqual(image_config[i].token, anim_token))
+      filename_anim_initial = image_config[i].value;
+    else if (strlen(image_config[i].token) > len_anim_token &&
+            strncmp(image_config[i].token, anim_token, len_anim_token) == 0)
+    {
+#if 1
+      for (j = 0; image_config_suffix[j].token != NULL; j++)
+      {
+       if (strEqual(&image_config[i].token[len_anim_token],
+                    image_config_suffix[j].token))
+         parameter[j] =
+           get_graphic_parameter_value(image_config[i].value,
+                                       image_config_suffix[j].token,
+                                       image_config_suffix[j].type);
+      }
+#else
+      if (strEqual(&image_config[i].token[len_anim_token], ".x"))
+       anim_initial.src_x = atoi(image_config[i].value);
+      else if (strEqual(&image_config[i].token[len_anim_token], ".y"))
+       anim_initial.src_y = atoi(image_config[i].value);
+      else if (strEqual(&image_config[i].token[len_anim_token], ".width"))
+       anim_initial.width = atoi(image_config[i].value);
+      else if (strEqual(&image_config[i].token[len_anim_token], ".height"))
+       anim_initial.height = atoi(image_config[i].value);
+      else if (strEqual(&image_config[i].token[len_anim_token], ".frames"))
+       anim_initial.anim_frames = atoi(image_config[i].value);
+      else if (strEqual(&image_config[i].token[len_anim_token],
+                       ".frames_per_line"))
+       anim_initial.anim_frames_per_line = atoi(image_config[i].value);
+      else if (strEqual(&image_config[i].token[len_anim_token], ".delay"))
+       anim_initial.anim_delay = atoi(image_config[i].value);
+#endif
+    }
+  }
+
+#if defined(CREATE_SPECIAL_EDITION_RND_JUE)
+  filename_anim_initial = "loading.pcx";
+
+  parameter[GFX_ARG_X] = 0;
+  parameter[GFX_ARG_Y] = 0;
+  parameter[GFX_ARG_WIDTH] = 128;
+  parameter[GFX_ARG_HEIGHT] = 40;
+  parameter[GFX_ARG_FRAMES] = 32;
+  parameter[GFX_ARG_DELAY] = 4;
+  parameter[GFX_ARG_FRAMES_PER_LINE] = ARG_UNDEFINED_VALUE;
+#endif
+
+  if (filename_anim_initial == NULL)   /* should not happen */
+    Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
+
+  anim_initial.bitmap = LoadCustomImage(filename_anim_initial);
+
+  graphic_info = &anim_initial;                /* graphic == 0 => anim_initial */
+
+  set_graphic_parameters_ext(0, parameter, anim_initial.bitmap);
+
+#if 0
+  printf("::: INIT_GFX: anim_frames_per_line == %d [%d / %d] [%d, %d]\n",
+        graphic_info[0].anim_frames_per_line,
+        get_scaled_graphic_width(0),
+        graphic_info[0].width,
+        getOriginalImageWidthFromImageID(0),
+        graphic_info[0].scale_up_factor);
+#endif
+
+  graphic_info = graphic_info_last;
+
+  init.busy.width  = anim_initial.width;
+  init.busy.height = anim_initial.height;
+
+  InitMenuDesignSettings_Static();
+  InitGfxDrawBusyAnimFunction(DrawInitAnim);
+
+  /* use copy of busy animation to prevent change while reloading artwork */
+  init_last = init;
+#endif
 }
 
 void RedrawBackground()
@@ -4581,14 +5665,17 @@ void InitGfxBackground()
 {
   int x, y;
 
-  drawto = backbuffer;
   fieldbuffer = bitmap_db_field;
   SetDrawtoField(DRAW_BACKBUFFER);
 
+#if 1
+  ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
+#else
   RedrawBackground();
 
   ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
   ClearRectangle(bitmap_db_door, 0, 0, 3 * DXSIZE, DYSIZE + VYSIZE);
+#endif
 
   for (x = 0; x < MAX_BUF_XSIZE; x++)
     for (y = 0; y < MAX_BUF_YSIZE; y++)
@@ -4604,15 +5691,39 @@ static void InitLevelInfo()
   LoadLevelSetup_SeriesInfo();                 /* last played level info */
 }
 
-void InitLevelArtworkInfo()
+static void InitLevelArtworkInfo()
 {
   LoadLevelArtworkInfo();
 }
 
 static void InitImages()
 {
+  print_timestamp_init("InitImages");
+
+#if 0
+  printf("::: leveldir_current->identifier == '%s'\n",
+        leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
+  printf("::: leveldir_current->graphics_path == '%s'\n",
+        leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
+  printf("::: leveldir_current->graphics_set == '%s'\n",
+        leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
+  printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
+        leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
+#endif
+
   setLevelArtworkDir(artwork.gfx_first);
 
+#if 0
+  printf("::: leveldir_current->identifier == '%s'\n",
+        leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
+  printf("::: leveldir_current->graphics_path == '%s'\n",
+        leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
+  printf("::: leveldir_current->graphics_set == '%s'\n",
+        leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
+  printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
+        leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
+#endif
+
 #if 0
   printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
         leveldir_current->identifier,
@@ -4622,16 +5733,35 @@ static void InitImages()
         leveldir_current->graphics_path);
 #endif
 
+  UPDATE_BUSY_STATE();
+
   ReloadCustomImages();
+  print_timestamp_time("ReloadCustomImages");
+
+  UPDATE_BUSY_STATE();
 
   LoadCustomElementDescriptions();
-  LoadSpecialMenuDesignSettings();
+  print_timestamp_time("LoadCustomElementDescriptions");
+
+  UPDATE_BUSY_STATE();
+
+  LoadMenuDesignSettings();
+  print_timestamp_time("LoadMenuDesignSettings");
+
+  UPDATE_BUSY_STATE();
 
   ReinitializeGraphics();
+  print_timestamp_time("ReinitializeGraphics");
+
+  UPDATE_BUSY_STATE();
+
+  print_timestamp_done("InitImages");
 }
 
 static void InitSound(char *identifier)
 {
+  print_timestamp_init("InitSound");
+
   if (identifier == NULL)
     identifier = artwork.snd_current->identifier;
 
@@ -4639,11 +5769,18 @@ static void InitSound(char *identifier)
   setLevelArtworkDir(artwork.snd_first);
 
   InitReloadCustomSounds(identifier);
+  print_timestamp_time("InitReloadCustomSounds");
+
   ReinitializeSounds();
+  print_timestamp_time("ReinitializeSounds");
+
+  print_timestamp_done("InitSound");
 }
 
 static void InitMusic(char *identifier)
 {
+  print_timestamp_init("InitMusic");
+
   if (identifier == NULL)
     identifier = artwork.mus_current->identifier;
 
@@ -4651,7 +5788,12 @@ static void InitMusic(char *identifier)
   setLevelArtworkDir(artwork.mus_first);
 
   InitReloadCustomMusic(identifier);
+  print_timestamp_time("InitReloadCustomMusic");
+
   ReinitializeMusic();
+  print_timestamp_time("ReinitializeMusic");
+
+  print_timestamp_done("InitMusic");
 }
 
 void InitNetworkServer()
@@ -4677,6 +5819,124 @@ void InitNetworkServer()
 #endif
 }
 
+static boolean CheckArtworkConfigForCustomElements(char *filename)
+{
+  SetupFileHash *setup_file_hash;
+  boolean redefined_ce_found = FALSE;
+
+  /* !!! CACHE THIS BY USING HASH 'filename' => 'true/false' !!! */
+
+  if ((setup_file_hash = loadSetupFileHash(filename)) != NULL)
+  {
+    BEGIN_HASH_ITERATION(setup_file_hash, itr)
+    {
+      char *token = HASH_ITERATION_TOKEN(itr);
+
+      if (strPrefix(token, "custom_"))
+      {
+       redefined_ce_found = TRUE;
+
+       break;
+      }
+    }
+    END_HASH_ITERATION(setup_file_hash, itr)
+
+    freeSetupFileHash(setup_file_hash);
+  }
+
+  return redefined_ce_found;
+}
+
+static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
+{
+  char *filename_base, *filename_local;
+  boolean redefined_ce_found = FALSE;
+
+  setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
+
+#if 0
+  printf("::: leveldir_current->identifier == '%s'\n",
+        leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
+  printf("::: leveldir_current->graphics_path == '%s'\n",
+        leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
+  printf("::: leveldir_current->graphics_set == '%s'\n",
+        leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
+  printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
+        leveldir_current == NULL ? "[NULL]" :
+        LEVELDIR_ARTWORK_SET(leveldir_current, type));
+#endif
+
+  /* first look for special artwork configured in level series config */
+  filename_base = getCustomArtworkLevelConfigFilename(type);
+
+#if 0
+  printf("::: filename_base == '%s'\n", filename_base);
+#endif
+
+  if (fileExists(filename_base))
+    redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_base);
+
+  filename_local = getCustomArtworkConfigFilename(type);
+
+#if 0
+  printf("::: filename_local == '%s'\n", filename_local);
+#endif
+
+  if (filename_local != NULL && !strEqual(filename_base, filename_local))
+    redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
+
+#if 0
+  printf("::: redefined_ce_found == %d\n", redefined_ce_found);
+#endif
+
+  return redefined_ce_found;
+}
+
+static void InitOverrideArtwork()
+{
+  boolean redefined_ce_found = FALSE;
+
+  /* to check if this level set redefines any CEs, do not use overriding */
+  gfx.override_level_graphics = FALSE;
+  gfx.override_level_sounds   = FALSE;
+  gfx.override_level_music    = FALSE;
+
+  /* now check if this level set has definitions for custom elements */
+  if (setup.override_level_graphics == AUTO ||
+      setup.override_level_sounds   == AUTO ||
+      setup.override_level_music    == AUTO)
+    redefined_ce_found =
+      (CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_GRAPHICS) |
+       CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_SOUNDS) |
+       CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
+
+#if 0
+  printf("::: redefined_ce_found == %d\n", redefined_ce_found);
+#endif
+
+  if (redefined_ce_found)
+  {
+    /* this level set has CE definitions: change "AUTO" to "FALSE" */
+    gfx.override_level_graphics = (setup.override_level_graphics == TRUE);
+    gfx.override_level_sounds   = (setup.override_level_sounds   == TRUE);
+    gfx.override_level_music    = (setup.override_level_music    == TRUE);
+  }
+  else
+  {
+    /* this level set has no CE definitions: change "AUTO" to "TRUE" */
+    gfx.override_level_graphics = (setup.override_level_graphics != FALSE);
+    gfx.override_level_sounds   = (setup.override_level_sounds   != FALSE);
+    gfx.override_level_music    = (setup.override_level_music    != FALSE);
+  }
+
+#if 0
+  printf("::: => %d, %d, %d\n",
+        gfx.override_level_graphics,
+        gfx.override_level_sounds,
+        gfx.override_level_music);
+#endif
+}
+
 static char *getNewArtworkIdentifier(int type)
 {
   static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
@@ -4684,7 +5944,11 @@ static char *getNewArtworkIdentifier(int type)
   static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
   static boolean initialized[3] = { FALSE, FALSE, FALSE };
   TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type);
+#if 1
+  boolean setup_override_artwork = GFX_OVERRIDE_ARTWORK(type);
+#else
   boolean setup_override_artwork = SETUP_OVERRIDE_ARTWORK(setup, type);
+#endif
   char *setup_artwork_set = SETUP_ARTWORK_SET(setup, type);
   char *leveldir_identifier = leveldir_current->identifier;
 #if 1
@@ -4792,13 +6056,16 @@ static char *getNewArtworkIdentifier(int type)
 
 void ReloadCustomArtwork(int force_reload)
 {
+  int last_game_status = game_status;  /* save current game status */
   char *gfx_new_identifier;
   char *snd_new_identifier;
   char *mus_new_identifier;
   boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
   boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
   boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
-  boolean redraw_screen = FALSE;
+  boolean reload_needed;
+
+  InitOverrideArtwork();
 
   force_reload_gfx |= AdjustGraphicsForEMC();
 
@@ -4806,6 +6073,34 @@ void ReloadCustomArtwork(int force_reload)
   snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
   mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
 
+  reload_needed = (gfx_new_identifier != NULL || force_reload_gfx ||
+                  snd_new_identifier != NULL || force_reload_snd ||
+                  mus_new_identifier != NULL || force_reload_mus);
+
+  if (!reload_needed)
+    return;
+
+  print_timestamp_init("ReloadCustomArtwork");
+
+  game_status = GAME_MODE_LOADING;
+
+  FadeOut(REDRAW_ALL);
+
+#if 1
+  ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
+#else
+  ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
+#endif
+  print_timestamp_time("ClearRectangle");
+
+#if 0
+  printf("::: fading in ... %d\n", fading.fade_mode);
+#endif
+  FadeIn(REDRAW_ALL);
+#if 0
+  printf("::: done\n");
+#endif
+
   if (gfx_new_identifier != NULL || force_reload_gfx)
   {
 #if 0
@@ -4816,39 +6111,64 @@ void ReloadCustomArtwork(int force_reload)
           leveldir_current->graphics_set);
 #endif
 
-    ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
-
     InitImages();
-
-    redraw_screen = TRUE;
+    print_timestamp_time("InitImages");
   }
 
   if (snd_new_identifier != NULL || force_reload_snd)
   {
-    ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
-
     InitSound(snd_new_identifier);
-
-    redraw_screen = TRUE;
+    print_timestamp_time("InitSound");
   }
 
   if (mus_new_identifier != NULL || force_reload_mus)
   {
-    ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
-
     InitMusic(mus_new_identifier);
-
-    redraw_screen = TRUE;
+    print_timestamp_time("InitMusic");
   }
 
-  if (redraw_screen)
-  {
-    RedrawBackground();
+  game_status = last_game_status;      /* restore current game status */
 
-    /* force redraw of (open or closed) door graphics */
-    SetDoorState(DOOR_OPEN_ALL);
-    CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
-  }
+  init_last = init;                    /* switch to new busy animation */
+
+#if 0
+  printf("::: ----------------DELAY 1 ...\n");
+  Delay(3000);
+#endif
+
+#if 0
+  printf("::: FadeOut @ ReloadCustomArtwork ...\n");
+#endif
+  FadeOut(REDRAW_ALL);
+#if 0
+  printf("::: FadeOut @ ReloadCustomArtwork done\n");
+#endif
+
+  RedrawBackground();
+
+  /* force redraw of (open or closed) door graphics */
+  SetDoorState(DOOR_OPEN_ALL);
+  CloseDoor(DOOR_CLOSE_ALL | DOOR_NO_DELAY);
+
+#if 1
+#if 1
+#if 1
+  FadeSetEnterScreen();
+  FadeSkipNextFadeOut();
+  // FadeSetDisabled();
+#else
+  FadeSkipNext();
+#endif
+#else
+  fading = fading_none;
+#endif
+#endif
+
+#if 0
+  redraw_mask = REDRAW_ALL;
+#endif
+
+  print_timestamp_done("ReloadCustomArtwork");
 }
 
 void KeyboardAutoRepeatOffUnlessAutoplay()
@@ -4857,6 +6177,63 @@ void KeyboardAutoRepeatOffUnlessAutoplay()
     KeyboardAutoRepeatOff();
 }
 
+void DisplayExitMessage(char *format, va_list ap)
+{
+  // check if draw buffer and fonts for exit message are already available
+  if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
+    return;
+
+  int font_1 = FC_RED;
+  int font_2 = FC_YELLOW;
+  int font_3 = FC_BLUE;
+  int font_width = getFontWidth(font_2);
+  int font_height = getFontHeight(font_2);
+  int sx = SX;
+  int sy = SY;
+  int sxsize = WIN_XSIZE - 2 * sx;
+  int sysize = WIN_YSIZE - 2 * sy;
+  int line_length = sxsize / font_width;
+  int max_lines = sysize / font_height;
+  int num_lines_printed;
+
+  gfx.sx = sx;
+  gfx.sy = sy;
+  gfx.sxsize = sxsize;
+  gfx.sysize = sysize;
+
+  sy = 20;
+
+  ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
+
+  DrawTextSCentered(sy, font_1, "Fatal error:");
+  sy += 3 * font_height;;
+
+  num_lines_printed =
+    DrawTextBufferVA(sx, sy, format, ap, font_2,
+                    line_length, line_length, max_lines,
+                    0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
+  sy += (num_lines_printed + 3) * font_height;
+
+  DrawTextSCentered(sy, font_1, "For details, see the following error file:");
+  sy += 3 * font_height;
+
+  num_lines_printed =
+    DrawTextBuffer(sx, sy, program.error_filename, font_2,
+                  line_length, line_length, max_lines,
+                  0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
+
+  DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
+
+  redraw_mask = REDRAW_ALL;
+
+  BackToFront();
+
+  /* deactivate toons on error message screen */
+  setup.toons = FALSE;
+
+  WaitForEventToContinue();
+}
+
 
 /* ========================================================================= */
 /* OpenAll()                                                                 */
@@ -4864,8 +6241,18 @@ void KeyboardAutoRepeatOffUnlessAutoplay()
 
 void OpenAll()
 {
+  print_timestamp_init("OpenAll");
+
+  game_status = GAME_MODE_LOADING;
+
+#if 1
+  InitCounter();
+#endif
+
   InitGlobal();                        /* initialize some global variables */
 
+  print_timestamp_time("[init global stuff]");
+
   if (options.execute_command)
     Execute_Command(options.execute_command);
 
@@ -4882,36 +6269,64 @@ void OpenAll()
 
   InitSetup();
 
+  print_timestamp_time("[init setup/config stuff (1)]");
+
   InitGameInfo();
+  print_timestamp_time("[init setup/config stuff (2)]");
   InitPlayerInfo();
+  print_timestamp_time("[init setup/config stuff (3)]");
   InitArtworkInfo();           /* needed before loading gfx, sound & music */
+  print_timestamp_time("[init setup/config stuff (4)]");
   InitArtworkConfig();         /* needed before forking sound child process */
+  print_timestamp_time("[init setup/config stuff (5)]");
   InitMixer();
+  print_timestamp_time("[init setup/config stuff (6)]");
 
+#if 0
   InitCounter();
+#endif
 
   InitRND(NEW_RANDOMIZE);
   InitSimpleRandom(NEW_RANDOMIZE);
 
   InitJoysticks();
 
+  print_timestamp_time("[init setup/config stuff]");
+
   InitVideoDisplay();
-  InitVideoBuffer(&backbuffer, &window, WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH,
-                 setup.fullscreen);
+  InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
+
+  InitEventFilter(FilterEvents);
 
-  InitEventFilter(FilterMouseMotionEvents);
+  print_timestamp_time("[init video stuff]");
 
   InitElementPropertiesStatic();
   InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
+  InitElementPropertiesGfxElement();
+
+  print_timestamp_time("[init element properties stuff]");
 
   InitGfx();
 
+  print_timestamp_time("InitGfx");
+
   InitLevelInfo();
+  print_timestamp_time("InitLevelInfo");
+
   InitLevelArtworkInfo();
+  print_timestamp_time("InitLevelArtworkInfo");
+
+  InitOverrideArtwork();       /* needs to know current level directory */
+  print_timestamp_time("InitOverrideArtwork");
 
   InitImages();                        /* needs to know current level directory */
+  print_timestamp_time("InitImages");
+
   InitSound(NULL);             /* needs to know current level directory */
+  print_timestamp_time("InitSound");
+
   InitMusic(NULL);             /* needs to know current level directory */
+  print_timestamp_time("InitMusic");
 
   InitGfxBackground();
 
@@ -4919,6 +6334,10 @@ void OpenAll()
   em_open_all();
 #endif
 
+#if 1
+  sp_open_all();
+#endif
+
   if (global.autoplay_leveldir)
   {
     AutoPlayTape();
@@ -4929,9 +6348,27 @@ void OpenAll()
     ConvertLevels();
     return;
   }
+  else if (global.create_images_dir)
+  {
+    CreateLevelSketchImages();
+    return;
+  }
 
   game_status = GAME_MODE_MAIN;
 
+#if 1
+  FadeSetEnterScreen();
+  if (!(fading.fade_mode & FADE_TYPE_TRANSFORM))
+    FadeSkipNextFadeOut();
+  // FadeSetDisabled();
+#else
+  fading = fading_none;
+#endif
+
+  print_timestamp_time("[post-artwork]");
+
+  print_timestamp_done("OpenAll");
+
   DrawMainMenu();
 
   InitNetworkServer();
@@ -4948,18 +6385,35 @@ void CloseAllAndExit(int exit_value)
   em_close_all();
 #endif
 
+#if 1
+  sp_close_all();
+#endif
+
   FreeAllImages();
 
 #if defined(TARGET_SDL)
+#if defined(TARGET_SDL2)
+  // !!! TODO !!!
+  // set a flag to tell the network server thread to quit and wait for it
+  // using SDL_WaitThread()
+#else
   if (network_server)  /* terminate network server */
     SDL_KillThread(server_thread);
+#endif
 #endif
 
   CloseVideoDisplay();
   ClosePlatformDependentStuff();
 
   if (exit_value != 0)
-    NotifyUserAboutErrorFile();
+  {
+    /* fall back to default level set (current set may have caused an error) */
+    SaveLevelSetup_LastSeries_Deactivate();
+
+    /* tell user where to find error log file which may contain more details */
+    // (error notification now directly displayed on screen inside R'n'D
+    // NotifyUserAboutErrorFile();     /* currently only works for Windows */
+  }
 
   exit(exit_value);
 }