added using '.draw_masked' for global animation and toon graphics
[rocksndiamonds.git] / src / init.c
index 5f18d26f118565519fd1f06f8c0eb2fc84b1226c..d5a66835964e794a78a17a3c219207deb1b6aea1 100644 (file)
@@ -1,15 +1,13 @@
-/***********************************************************
-* Rocks'n'Diamonds -- McDuffin Strikes Back!               *
-*----------------------------------------------------------*
-* (c) 1995-2006 Artsoft Entertainment                      *
-*               Holger Schemel                             *
-*               Detmolder Strasse 189                      *
-*               33604 Bielefeld                            *
-*               Germany                                    *
-*               e-mail: info@artsoft.org                   *
-*----------------------------------------------------------*
-* init.c                                                   *
-***********************************************************/
+// ============================================================================
+// Rocks'n'Diamonds - McDuffin Strikes Back!
+// ----------------------------------------------------------------------------
+// (c) 1995-2014 by Artsoft Entertainment
+//                         Holger Schemel
+//                 info@artsoft.org
+//                 http://www.artsoft.org/
+// ----------------------------------------------------------------------------
+// init.c
+// ============================================================================
 
 #include "libgame/libgame.h"
 
@@ -23,7 +21,7 @@
 #include "files.h"
 #include "network.h"
 #include "netserv.h"
-#include "cartoons.h"
+#include "anim.h"
 #include "config.h"
 
 #include "conf_e2g.c"  /* include auto-generated data structure definitions */
@@ -86,6 +84,10 @@ static int copy_properties[][5] =
 };
 
 
+/* forward declaration for internal use */
+static int get_graphic_parameter_value(char *, char *, int);
+
+
 void DrawInitAnim()
 {
   struct GraphicInfo *graphic_info_last = graphic_info;
@@ -104,44 +106,18 @@ void DrawInitAnim()
   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
+  if (init_last.busy.x == -1)
+    init_last.busy.x = WIN_XSIZE / 2;
+  if (init_last.busy.y == -1)
+    init_last.busy.y = WIN_YSIZE / 2;
 
   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;
@@ -150,10 +126,6 @@ void DrawInitAnim()
 
     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;
@@ -188,21 +160,32 @@ void InitGadgets()
   gadgets_initialized = TRUE;
 }
 
-inline void InitElementSmallImagesScaledUp(int graphic)
+inline static void InitElementSmallImagesScaledUp(int graphic)
 {
-#if 0
-  struct FileInfo *fi = getImageListEntryFromImageID(graphic);
-
-  printf("::: '%s' -> '%s'\n", fi->token, fi->filename);
-#endif
+  struct GraphicInfo *g = &graphic_info[graphic];
 
-  CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
+  // create small and game tile sized bitmaps (and scale up, if needed)
+  CreateImageWithSmallImages(graphic, g->scale_up_factor, g->tile_size);
 }
 
 void InitElementSmallImages()
 {
+  print_timestamp_init("InitElementSmallImages");
+
   static int special_graphics[] =
   {
+    IMG_FLAMES_1_LEFT,
+    IMG_FLAMES_2_LEFT,
+    IMG_FLAMES_3_LEFT,
+    IMG_FLAMES_1_RIGHT,
+    IMG_FLAMES_2_RIGHT,
+    IMG_FLAMES_3_RIGHT,
+    IMG_FLAMES_1_UP,
+    IMG_FLAMES_2_UP,
+    IMG_FLAMES_3_UP,
+    IMG_FLAMES_1_DOWN,
+    IMG_FLAMES_2_DOWN,
+    IMG_FLAMES_3_DOWN,
     IMG_EDITOR_ELEMENT_BORDER,
     IMG_EDITOR_ELEMENT_BORDER_INPUT,
     IMG_EDITOR_CASCADE_LIST,
@@ -213,30 +196,93 @@ void InitElementSmallImages()
   int num_property_mappings = getImageListPropertyMappingSize();
   int i;
 
-  /* initialize normal images from static configuration */
+  print_timestamp_time("getImageListPropertyMapping/Size");
+
+  print_timestamp_init("InitElementSmallImagesScaledUp (1)");
+  /* initialize normal element images from static configuration */
   for (i = 0; element_to_graphic[i].element > -1; i++)
     InitElementSmallImagesScaledUp(element_to_graphic[i].graphic);
+  print_timestamp_done("InitElementSmallImagesScaledUp (1)");
 
-  /* initialize special images from static configuration */
+  /* initialize special element images from static configuration */
   for (i = 0; element_to_special_graphic[i].element > -1; i++)
     InitElementSmallImagesScaledUp(element_to_special_graphic[i].graphic);
+  print_timestamp_time("InitElementSmallImagesScaledUp (2)");
 
-  /* initialize images from dynamic configuration (may be elements or other) */
+  /* initialize element images from dynamic configuration */
   for (i = 0; i < num_property_mappings; i++)
-    InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
+    if (property_mapping[i].base_index < MAX_NUM_ELEMENTS)
+      InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
+  print_timestamp_time("InitElementSmallImagesScaledUp (3)");
 
-  /* initialize special images from above list (non-element images) */
+  /* initialize special non-element images from above list */
   for (i = 0; special_graphics[i] > -1; i++)
     InitElementSmallImagesScaledUp(special_graphics[i]);
+  print_timestamp_time("InitElementSmallImagesScaledUp (4)");
+
+  print_timestamp_done("InitElementSmallImages");
+}
+
+inline static void InitScaledImagesScaledUp(int graphic)
+{
+  struct GraphicInfo *g = &graphic_info[graphic];
+
+  ScaleImage(graphic, g->scale_up_factor);
 }
 
 void InitScaledImages()
 {
+  struct PropertyMapping *property_mapping = getImageListPropertyMapping();
+  int num_property_mappings = getImageListPropertyMappingSize();
   int i;
 
   /* scale normal images from static configuration, if not already scaled */
   for (i = 0; i < NUM_IMAGE_FILES; i++)
-    ScaleImage(i, graphic_info[i].scale_up_factor);
+    InitScaledImagesScaledUp(i);
+
+  /* scale images from dynamic configuration, if not already scaled */
+  for (i = 0; i < num_property_mappings; i++)
+    InitScaledImagesScaledUp(property_mapping[i].artwork_index);
+}
+
+void InitBitmapPointers()
+{
+  int num_images = getImageListSize();
+  int i;
+
+  // standard size bitmap may have changed -- update default bitmap pointer
+  for (i = 0; i < num_images; i++)
+    if (graphic_info[i].bitmaps)
+      graphic_info[i].bitmap = graphic_info[i].bitmaps[IMG_BITMAP_STANDARD];
+}
+
+void InitImageTextures()
+{
+  int i, j, k;
+
+  FreeAllImageTextures();
+
+  for (i = IMG_GLOBAL_BORDER_FIRST; i <= IMG_GLOBAL_BORDER_LAST; i++)
+    CreateImageTextures(i);
+
+  for (i = 0; i < MAX_NUM_TOONS; i++)
+    CreateImageTextures(IMG_TOON_1 + i);
+
+  for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
+  {
+    for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
+    {
+      for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
+      {
+       int graphic = global_anim_info[i].graphic[j][k];
+
+       if (graphic == IMG_UNDEFINED)
+         continue;
+
+       CreateImageTextures(graphic);
+      }
+    }
+  }
 }
 
 #if 1
@@ -266,19 +312,6 @@ static int getFontBitmapID(int font_nr)
     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];
@@ -288,19 +321,10 @@ static int getFontBitmapID(int 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;
@@ -540,6 +564,176 @@ void InitFontGraphicInfo()
               getFontBitmapID, getFontFromToken);
 }
 
+void InitGlobalAnimGraphicInfo()
+{
+  struct PropertyMapping *property_mapping = getImageListPropertyMapping();
+  int num_property_mappings = getImageListPropertyMappingSize();
+  int i, j, k;
+
+  if (graphic_info == NULL)            /* still at startup phase */
+    return;
+
+  /* always start with reliable default values (no global animations) */
+  for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
+    for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
+      for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
+       global_anim_info[i].graphic[j][k] = IMG_UNDEFINED;
+
+  /* initialize global animation definitions from static configuration */
+  for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
+  {
+    int j = GLOBAL_ANIM_ID_PART_BASE;
+    int k = GFX_SPECIAL_ARG_DEFAULT;
+
+    global_anim_info[i].graphic[j][k] = IMG_GFX_GLOBAL_ANIM_1 + i;
+  }
+
+  /* initialize global animation definitions from dynamic configuration */
+  for (i = 0; i < num_property_mappings; i++)
+  {
+    int anim_nr = property_mapping[i].base_index - MAX_NUM_ELEMENTS - NUM_FONTS;
+    int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
+    int special = property_mapping[i].ext3_index;
+    int graphic = property_mapping[i].artwork_index;
+
+    if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
+      continue;
+
+    /* set animation part to base part, if not specified */
+    if (!IS_GLOBAL_ANIM_PART(part_nr))
+      part_nr = GLOBAL_ANIM_ID_PART_BASE;
+
+    /* set animation screen to default, if not specified */
+    if (!IS_SPECIAL_GFX_ARG(special))
+      special = GFX_SPECIAL_ARG_DEFAULT;
+
+    global_anim_info[anim_nr].graphic[part_nr][special] = graphic;
+
+    /* fix default value for ".draw_masked" (for backward compatibility) */
+    struct GraphicInfo *g = &graphic_info[graphic];
+    struct FileInfo *image = getImageListEntryFromImageID(graphic);
+    char **parameter_raw = image->parameter;
+    int p = GFX_ARG_DRAW_MASKED;
+    int draw_masked = get_graphic_parameter_value(parameter_raw[p],
+                                                 image_config_suffix[p].token,
+                                                 image_config_suffix[p].type);
+
+    /* if ".draw_masked" parameter is undefined, use default value "TRUE" */
+    if (draw_masked == ARG_UNDEFINED_VALUE)
+      g->draw_masked = TRUE;
+  }
+
+#if 0
+  printf("::: InitGlobalAnimGraphicInfo\n");
+
+  for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
+    for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
+      for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
+       if (global_anim_info[i].graphic[j][k] != IMG_UNDEFINED &&
+           graphic_info[global_anim_info[i].graphic[j][k]].bitmap != NULL)
+         printf("::: - anim %d, part %d, mode %d => %d\n",
+                i, j, k, global_anim_info[i].graphic[j][k]);
+#endif
+}
+
+void InitGlobalAnimSoundInfo()
+{
+  struct PropertyMapping *property_mapping = getSoundListPropertyMapping();
+  int num_property_mappings = getSoundListPropertyMappingSize();
+  int i, j, k;
+
+  /* always start with reliable default values (no global animation sounds) */
+  for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
+    for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
+      for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
+       global_anim_info[i].sound[j][k] = SND_UNDEFINED;
+
+  /* initialize global animation sound definitions from dynamic configuration */
+  for (i = 0; i < num_property_mappings; i++)
+  {
+    int anim_nr = property_mapping[i].base_index - 2 * MAX_NUM_ELEMENTS;
+    int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
+    int special = property_mapping[i].ext3_index;
+    int sound   = property_mapping[i].artwork_index;
+
+    // sound uses control definition; map it to position of graphic (artwork)
+    anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
+
+    if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
+      continue;
+
+    /* set animation part to base part, if not specified */
+    if (!IS_GLOBAL_ANIM_PART(part_nr))
+      part_nr = GLOBAL_ANIM_ID_PART_BASE;
+
+    /* set animation screen to default, if not specified */
+    if (!IS_SPECIAL_GFX_ARG(special))
+      special = GFX_SPECIAL_ARG_DEFAULT;
+
+    global_anim_info[anim_nr].sound[part_nr][special] = sound;
+  }
+
+#if 0
+  printf("::: InitGlobalAnimSoundInfo\n");
+
+  for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
+    for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
+      for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
+       if (global_anim_info[i].sound[j][k] != SND_UNDEFINED)
+         printf("::: - anim %d, part %d, mode %d => %d\n",
+                i, j, k, global_anim_info[i].sound[j][k]);
+#endif
+}
+
+void InitGlobalAnimMusicInfo()
+{
+  struct PropertyMapping *property_mapping = getMusicListPropertyMapping();
+  int num_property_mappings = getMusicListPropertyMappingSize();
+  int i, j, k;
+
+  /* always start with reliable default values (no global animation music) */
+  for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
+    for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
+      for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
+       global_anim_info[i].music[j][k] = MUS_UNDEFINED;
+
+  /* initialize global animation music definitions from dynamic configuration */
+  for (i = 0; i < num_property_mappings; i++)
+  {
+    int anim_nr = property_mapping[i].base_index - NUM_MUSIC_PREFIXES;
+    int part_nr = property_mapping[i].ext1_index - ACTION_PART_1;
+    int special = property_mapping[i].ext2_index;
+    int music   = property_mapping[i].artwork_index;
+
+    // music uses control definition; map it to position of graphic (artwork)
+    anim_nr -= GLOBAL_ANIM_ID_CONTROL_FIRST;
+
+    if (anim_nr < 0 || anim_nr >= NUM_GLOBAL_ANIM_TOKENS)
+      continue;
+
+    /* set animation part to base part, if not specified */
+    if (!IS_GLOBAL_ANIM_PART(part_nr))
+      part_nr = GLOBAL_ANIM_ID_PART_BASE;
+
+    /* set animation screen to default, if not specified */
+    if (!IS_SPECIAL_GFX_ARG(special))
+      special = GFX_SPECIAL_ARG_DEFAULT;
+
+    global_anim_info[anim_nr].music[part_nr][special] = music;
+  }
+
+#if 0
+  printf("::: InitGlobalAnimMusicInfo\n");
+
+  for (i = 0; i < NUM_GLOBAL_ANIMS; i++)
+    for (j = 0; j < NUM_GLOBAL_ANIM_PARTS_ALL; j++)
+      for (k = 0; k < NUM_SPECIAL_GFX_ARGS; k++)
+       if (global_anim_info[i].music[j][k] != MUS_UNDEFINED)
+         printf("::: - anim %d, part %d, mode %d => %d\n",
+                i, j, k, global_anim_info[i].music[j][k]);
+#endif
+}
+
 void InitElementGraphicInfo()
 {
   struct PropertyMapping *property_mapping = getImageListPropertyMapping();
@@ -625,16 +819,6 @@ 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;
@@ -707,12 +891,9 @@ void InitElementGraphicInfo()
     }
   }
 
-#if 1
   /* set hardcoded definitions for some runtime elements without graphic */
   element_info[EL_AMOEBA_TO_DIAMOND].graphic[ACTION_DEFAULT] = IMG_AMOEBA_DEAD;
-#endif
 
-#if 1
   /* set hardcoded definitions for some internal elements without graphic */
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
@@ -721,7 +902,6 @@ void InitElementGraphicInfo()
     else if (IS_EDITOR_CASCADE_ACTIVE(i))
       element_info[i].graphic[ACTION_DEFAULT] = IMG_EDITOR_CASCADE_LIST_ACTIVE;
   }
-#endif
 
   /* now set all undefined/invalid graphics to -1 to set to default after it */
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
@@ -787,14 +967,12 @@ void InitElementGraphicInfo()
              (move_dir == MV_BIT_UP    && !front_is_left_or_upper) ||
              (move_dir == MV_BIT_RIGHT &&  front_is_left_or_upper) ||
              (move_dir == MV_BIT_DOWN  &&  front_is_left_or_upper)));
-         Bitmap *dummy;
 
          /* swap frontside and backside graphic tile coordinates, if needed */
          if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
          {
            /* get current (wrong) backside tile coordinates */
-           getFixedGraphicSourceExt(graphic, 0, &dummy,
-                                    &src_x_back, &src_y_back, TRUE);
+           getGraphicSourceXY(graphic, 0, &src_x_back, &src_y_back, TRUE);
 
            /* set frontside tile coordinates to backside tile coordinates */
            g->src_x = src_x_back;
@@ -824,14 +1002,9 @@ void InitElementGraphicInfo()
 
     if (default_graphic == -1)
       default_graphic = IMG_UNKNOWN;
-#if 1
+
     if (default_crumbled == -1)
       default_crumbled = default_graphic;
-#else
-    /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
-    if (default_crumbled == -1)
-      default_crumbled = IMG_EMPTY;
-#endif
 
     for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
     {
@@ -842,14 +1015,9 @@ void InitElementGraphicInfo()
 
       if (default_direction_graphic[dir] == -1)
        default_direction_graphic[dir] = default_graphic;
-#if 1
+
       if (default_direction_crumbled[dir] == -1)
        default_direction_crumbled[dir] = default_direction_graphic[dir];
-#else
-      /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
-      if (default_direction_crumbled[dir] == -1)
-       default_direction_crumbled[dir] = default_crumbled;
-#endif
     }
 
     for (act = 0; act < NUM_ACTIONS; act++)
@@ -885,7 +1053,6 @@ void InitElementGraphicInfo()
       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
        default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
 
-#if 1
       /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
       /* !!! make this better !!! */
       if (i == EL_EMPTY_SPACE)
@@ -893,18 +1060,12 @@ void InitElementGraphicInfo()
        default_action_graphic = element_info[EL_DEFAULT].graphic[act];
        default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
       }
-#endif
 
       if (default_action_graphic == -1)
        default_action_graphic = default_graphic;
-#if 1
+
       if (default_action_crumbled == -1)
        default_action_crumbled = default_action_graphic;
-#else
-      /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
-      if (default_action_crumbled == -1)
-       default_action_crumbled = default_crumbled;
-#endif
 
       for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
       {
@@ -926,20 +1087,9 @@ void InitElementGraphicInfo()
          element_info[i].direction_graphic[act][dir] =
            default_action_direction_graphic;
 
-#if 1
        if (default_action_direction_crumbled == -1)
          default_action_direction_crumbled =
            element_info[i].direction_graphic[act][dir];
-#else
-       if (default_action_direction_crumbled == -1)
-         default_action_direction_crumbled =
-           (act_remove ? default_remove_graphic :
-            act_turning ?
-            element_info[i].direction_crumbled[ACTION_TURNING][dir] :
-            default_action_crumbled != default_crumbled ?
-            default_action_crumbled :
-            default_direction_crumbled[dir]);
-#endif
 
        if (element_info[i].direction_crumbled[act][dir] == -1)
          element_info[i].direction_crumbled[act][dir] =
@@ -952,62 +1102,13 @@ void InitElementGraphicInfo()
          (act_remove ? default_remove_graphic :
           act_turning ? element_info[i].graphic[ACTION_TURNING] :
           default_action_graphic);
-#if 1
+
       if (element_info[i].crumbled[act] == -1)
        element_info[i].crumbled[act] = element_info[i].graphic[act];
-#else
-      if (element_info[i].crumbled[act] == -1)
-       element_info[i].crumbled[act] =
-         (act_remove ? default_remove_graphic :
-          act_turning ? element_info[i].crumbled[ACTION_TURNING] :
-          default_action_crumbled);
-#endif
     }
   }
 
   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 */
-  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
-  {
-    for (act = 0; act < NUM_ACTIONS; act++)
-    {
-      int graphic = element_info[i].graphic[act];
-      int crumbled = element_info[i].crumbled[act];
-
-      if (graphic_info[graphic].anim_frames == 1)
-       graphic_info[graphic].anim_mode = ANIM_NONE;
-      if (graphic_info[crumbled].anim_frames == 1)
-       graphic_info[crumbled].anim_mode = ANIM_NONE;
-
-      for (dir = 0; dir < NUM_DIRECTIONS_FULL; dir++)
-      {
-       graphic = element_info[i].direction_graphic[act][dir];
-       crumbled = element_info[i].direction_crumbled[act][dir];
-
-       if (graphic_info[graphic].anim_frames == 1)
-         graphic_info[graphic].anim_mode = ANIM_NONE;
-       if (graphic_info[crumbled].anim_frames == 1)
-         graphic_info[crumbled].anim_mode = ANIM_NONE;
-      }
-    }
-  }
-#endif
-
-#if 0
-#if DEBUG
-  if (options.verbose)
-  {
-    for (i = 0; i < MAX_NUM_ELEMENTS; i++)
-      if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
-         i != EL_UNKNOWN)
-       Error(ERR_INFO, "warning: no graphic for element '%s' (%d)",
-             element_info[i].token_name, i);
-  }
-#endif
-#endif
 }
 
 void InitElementSpecialGraphicInfo()
@@ -1034,15 +1135,6 @@ 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
@@ -1062,43 +1154,12 @@ void InitElementSpecialGraphicInfo()
     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;
@@ -1131,13 +1192,36 @@ static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
   {
     char *value = getHashEntry(element_token_hash, value_raw);
 
+    if (value == NULL)
+    {
+      Error(ERR_INFO_LINE, "-");
+      Error(ERR_INFO, "warning: error found in config file:");
+      Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
+      Error(ERR_INFO, "error: invalid element token '%s'", value_raw);
+      Error(ERR_INFO, "custom graphic rejected for this element/action");
+      Error(ERR_INFO, "fallback done to undefined element for this graphic");
+      Error(ERR_INFO_LINE, "-");
+    }
+
     return (value != NULL ? atoi(value) : EL_UNDEFINED);
   }
   else if (type == TYPE_GRAPHIC)
   {
     char *value = getHashEntry(graphic_token_hash, value_raw);
+    int fallback_graphic = IMG_CHAR_EXCLAM;
 
-    return (value != NULL ? atoi(value) : IMG_UNDEFINED);
+    if (value == NULL)
+    {
+      Error(ERR_INFO_LINE, "-");
+      Error(ERR_INFO, "warning: error found in config file:");
+      Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
+      Error(ERR_INFO, "error: invalid graphic token '%s'", value_raw);
+      Error(ERR_INFO, "custom graphic rejected for this element/action");
+      Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
+      Error(ERR_INFO_LINE, "-");
+    }
+
+    return (value != NULL ? atoi(value) : fallback_graphic);
   }
 
   return -1;
@@ -1160,9 +1244,10 @@ static int get_scaled_graphic_height(int graphic)
 }
 
 static void set_graphic_parameters_ext(int graphic, int *parameter,
-                                      Bitmap *src_bitmap)
+                                      Bitmap **src_bitmaps)
 {
   struct GraphicInfo *g = &graphic_info[graphic];
+  Bitmap *src_bitmap = (src_bitmaps ? src_bitmaps[IMG_BITMAP_STANDARD] : NULL);
   int anim_frames_per_row = 1, anim_frames_per_col = 1;
   int anim_frames_per_line = 1;
 
@@ -1182,11 +1267,18 @@ static void set_graphic_parameters_ext(int graphic, int *parameter,
   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->tile_size = TILESIZE;             /* default: standard tile size */
   g->clone_from = -1;                  /* do not use clone graphic */
+  g->init_delay_fixed = 0;
+  g->init_delay_random = 0;
   g->anim_delay_fixed = 0;
   g->anim_delay_random = 0;
   g->post_delay_fixed = 0;
   g->post_delay_random = 0;
+  g->init_event = ANIM_EVENT_DEFAULT;
+  g->anim_event = ANIM_EVENT_DEFAULT;
+  g->draw_masked = FALSE;
+  g->draw_order = 0;
   g->fade_mode = FADE_MODE_DEFAULT;
   g->fade_delay = -1;
   g->post_delay = -1;
@@ -1197,30 +1289,49 @@ static void set_graphic_parameters_ext(int graphic, int *parameter,
   g->class = 0;
   g->style = STYLE_DEFAULT;
 
+  g->bitmaps = src_bitmaps;
   g->bitmap = src_bitmap;
 
-#if 1
   /* 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 */
+
+  /* optional tile size for using non-standard image size */
+  if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
+  {
+    g->tile_size = parameter[GFX_ARG_TILE_SIZE];
+
+#if 0
+    // CHECK: should tile sizes less than standard tile size be allowed?
+    if (g->tile_size < TILESIZE)
+      g->tile_size = TILESIZE;         /* standard tile size */
 #endif
 
-#if 1
+    // when setting tile size, also set width and height accordingly
+    g->width  = g->tile_size;
+    g->height = g->tile_size;
+  }
+
   if (g->use_image_size)
   {
     /* 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 width and height of each animation frame */
+  if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
+    g->width = parameter[GFX_ARG_WIDTH];
+  if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
+    g->height = parameter[GFX_ARG_HEIGHT];
 
   /* optional x and y tile position of animation frame sequence */
   if (parameter[GFX_ARG_XPOS] != ARG_UNDEFINED_VALUE)
-    g->src_x = parameter[GFX_ARG_XPOS] * TILEX;
+    g->src_x = parameter[GFX_ARG_XPOS] * g->width;
   if (parameter[GFX_ARG_YPOS] != ARG_UNDEFINED_VALUE)
-    g->src_y = parameter[GFX_ARG_YPOS] * TILEY;
+    g->src_y = parameter[GFX_ARG_YPOS] * g->height;
 
   /* optional x and y pixel position of animation frame sequence */
   if (parameter[GFX_ARG_X] != ARG_UNDEFINED_VALUE)
@@ -1228,12 +1339,6 @@ static void set_graphic_parameters_ext(int graphic, int *parameter,
   if (parameter[GFX_ARG_Y] != ARG_UNDEFINED_VALUE)
     g->src_y = parameter[GFX_ARG_Y];
 
-  /* optional width and height of each animation frame */
-  if (parameter[GFX_ARG_WIDTH] != ARG_UNDEFINED_VALUE)
-    g->width = parameter[GFX_ARG_WIDTH];
-  if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
-    g->height = parameter[GFX_ARG_HEIGHT];
-
   if (src_bitmap)
   {
     if (g->width <= 0)
@@ -1257,14 +1362,6 @@ static void set_graphic_parameters_ext(int graphic, int *parameter,
     }
   }
 
-#if 0
-  /* 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 (src_bitmap)
   {
     /* get final bitmap size (with scaling, but without small images) */
@@ -1278,8 +1375,16 @@ static void set_graphic_parameters_ext(int graphic, int *parameter,
       src_image_height = src_bitmap->height;
     }
 
-    anim_frames_per_row = src_image_width  / g->width;
-    anim_frames_per_col = src_image_height / g->height;
+    if (parameter[GFX_ARG_TILE_SIZE] != ARG_UNDEFINED_VALUE)
+    {
+      anim_frames_per_row = MAX(1, src_image_width  / g->tile_size);
+      anim_frames_per_col = MAX(1, src_image_height / g->tile_size);
+    }
+    else
+    {
+      anim_frames_per_row = MAX(1, src_image_width  / g->width);
+      anim_frames_per_col = MAX(1, src_image_height / g->height);
+    }
 
     g->src_image_width  = src_image_width;
     g->src_image_height = src_image_height;
@@ -1351,10 +1456,6 @@ static void set_graphic_parameters_ext(int graphic, int *parameter,
     g->anim_delay = 1;
 
   g->anim_mode = parameter[GFX_ARG_ANIM_MODE];
-#if 0
-  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)
@@ -1379,7 +1480,11 @@ static void set_graphic_parameters_ext(int graphic, int *parameter,
   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 */
+  /* used for global animations and player "boring" and "sleeping" actions */
+  if (parameter[GFX_ARG_INIT_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
+    g->init_delay_fixed = parameter[GFX_ARG_INIT_DELAY_FIXED];
+  if (parameter[GFX_ARG_INIT_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
+    g->init_delay_random = parameter[GFX_ARG_INIT_DELAY_RANDOM];
   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)
@@ -1389,16 +1494,38 @@ static void set_graphic_parameters_ext(int graphic, int *parameter,
   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];
+  /* used for global animations */
+  if (parameter[GFX_ARG_INIT_EVENT] != ARG_UNDEFINED_VALUE)
+    g->init_event = parameter[GFX_ARG_INIT_EVENT];
+  if (parameter[GFX_ARG_ANIM_EVENT] != ARG_UNDEFINED_VALUE)
+    g->anim_event = parameter[GFX_ARG_ANIM_EVENT];
+
+  /* used for toon animations and global animations */
+  g->step_offset  = parameter[GFX_ARG_STEP_OFFSET];
+  g->step_xoffset = parameter[GFX_ARG_STEP_XOFFSET];
+  g->step_yoffset = parameter[GFX_ARG_STEP_YOFFSET];
+  g->step_delay   = parameter[GFX_ARG_STEP_DELAY];
+  g->direction    = parameter[GFX_ARG_DIRECTION];
+  g->position     = parameter[GFX_ARG_POSITION];
+  g->x            = parameter[GFX_ARG_X];      // (may be uninitialized,
+  g->y            = parameter[GFX_ARG_Y];      // unlike src_x and src_y)
 
   /* 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];
+  /* use a different default value for global animations and toons */
+  if ((graphic >= IMG_GFX_GLOBAL_ANIM_1 && graphic <= IMG_GFX_GLOBAL_ANIM_8) ||
+      (graphic >= IMG_TOON_1            && graphic <= IMG_TOON_20))
+    g->draw_masked = TRUE;
+
+  /* this is used for drawing envelopes, global animations and toons */
+  if (parameter[GFX_ARG_DRAW_MASKED] != ARG_UNDEFINED_VALUE)
+    g->draw_masked = parameter[GFX_ARG_DRAW_MASKED];
+
+  /* used for toon animations and global animations */
+  if (parameter[GFX_ARG_DRAW_ORDER] != ARG_UNDEFINED_VALUE)
+    g->draw_order = parameter[GFX_ARG_DRAW_ORDER];
 
   /* optional graphic for cloning all graphics settings */
   if (parameter[GFX_ARG_CLONE_FROM] != ARG_UNDEFINED_VALUE)
@@ -1434,33 +1561,10 @@ static void set_graphic_parameters_ext(int graphic, int *parameter,
 
 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);
+  Bitmap **src_bitmaps = getBitmapsFromImageID(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 */
@@ -1473,237 +1577,7 @@ static void set_graphic_parameters(int graphic)
                                               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)
-    graphic_info[graphic].crumbled_like = parameter[GFX_ARG_CRUMBLED_LIKE];
-
-  /* optional element for cloning digging graphics */
-  if (parameter[GFX_ARG_DIGGABLE_LIKE] != ARG_UNDEFINED_VALUE)
-    graphic_info[graphic].diggable_like = parameter[GFX_ARG_DIGGABLE_LIKE];
-
-  /* optional border size for "crumbling" diggable graphics */
-  if (parameter[GFX_ARG_BORDER_SIZE] != ARG_UNDEFINED_VALUE)
-    graphic_info[graphic].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)
-    graphic_info[graphic].anim_delay_fixed =
-      parameter[GFX_ARG_ANIM_DELAY_FIXED];
-  if (parameter[GFX_ARG_ANIM_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
-    graphic_info[graphic].anim_delay_random =
-      parameter[GFX_ARG_ANIM_DELAY_RANDOM];
-  if (parameter[GFX_ARG_POST_DELAY_FIXED] != ARG_UNDEFINED_VALUE)
-    graphic_info[graphic].post_delay_fixed =
-      parameter[GFX_ARG_POST_DELAY_FIXED];
-  if (parameter[GFX_ARG_POST_DELAY_RANDOM] != ARG_UNDEFINED_VALUE)
-    graphic_info[graphic].post_delay_random =
-      parameter[GFX_ARG_POST_DELAY_RANDOM];
-
-  /* this is only used for toon animations */
-  graphic_info[graphic].step_offset = parameter[GFX_ARG_STEP_OFFSET];
-  graphic_info[graphic].step_delay  = parameter[GFX_ARG_STEP_DELAY];
-
-  /* this is only used for drawing font characters */
-  graphic_info[graphic].draw_xoffset = parameter[GFX_ARG_DRAW_XOFFSET];
-  graphic_info[graphic].draw_yoffset = parameter[GFX_ARG_DRAW_YOFFSET];
-
-  /* this is only used for drawing envelope graphics */
-  graphic_info[graphic].draw_masked = parameter[GFX_ARG_DRAW_MASKED];
-
-  /* optional graphic for cloning all graphics settings */
-  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 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
+  set_graphic_parameters_ext(graphic, parameter, src_bitmaps);
 
   UPDATE_BUSY_STATE();
 }
@@ -1733,7 +1607,7 @@ static void set_cloned_graphic_parameters(int graphic)
     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_EXIT, "no fallback graphic available");
 
     Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
     Error(ERR_INFO_LINE, "-");
@@ -1753,24 +1627,21 @@ static void InitGraphicInfo()
   int num_images = getImageListSize();
   int i;
 
-#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
-  static boolean clipmasks_initialized = FALSE;
-  Pixmap src_pixmap;
-  XGCValues clip_gc_values;
-  unsigned int clip_gc_valuemask;
-  GC copy_clipmask_gc = None;
-#endif
-
   /* use image size as default values for width and height for these images */
   static int full_size_graphics[] =
   {
     IMG_GLOBAL_BORDER,
+    IMG_GLOBAL_BORDER_MAIN,
+    IMG_GLOBAL_BORDER_SCORES,
+    IMG_GLOBAL_BORDER_EDITOR,
+    IMG_GLOBAL_BORDER_PLAYING,
     IMG_GLOBAL_DOOR,
 
     IMG_BACKGROUND_ENVELOPE_1,
     IMG_BACKGROUND_ENVELOPE_2,
     IMG_BACKGROUND_ENVELOPE_3,
     IMG_BACKGROUND_ENVELOPE_4,
+    IMG_BACKGROUND_REQUEST,
 
     IMG_BACKGROUND,
     IMG_BACKGROUND_TITLE_INITIAL,
@@ -1785,11 +1656,15 @@ static void InitGraphicInfo()
     IMG_BACKGROUND_INFO_MUSIC,
     IMG_BACKGROUND_INFO_CREDITS,
     IMG_BACKGROUND_INFO_PROGRAM,
+    IMG_BACKGROUND_INFO_VERSION,
     IMG_BACKGROUND_INFO_LEVELSET,
     IMG_BACKGROUND_SETUP,
+    IMG_BACKGROUND_PLAYING,
     IMG_BACKGROUND_DOOR,
     IMG_BACKGROUND_TAPE,
     IMG_BACKGROUND_PANEL,
+    IMG_BACKGROUND_PALETTE,
+    IMG_BACKGROUND_TOOLBOX,
 
     IMG_TITLESCREEN_INITIAL_1,
     IMG_TITLESCREEN_INITIAL_2,
@@ -1802,6 +1677,17 @@ static void InitGraphicInfo()
     IMG_TITLESCREEN_4,
     IMG_TITLESCREEN_5,
 
+    IMG_BACKGROUND_TITLEMESSAGE_INITIAL_1,
+    IMG_BACKGROUND_TITLEMESSAGE_INITIAL_2,
+    IMG_BACKGROUND_TITLEMESSAGE_INITIAL_3,
+    IMG_BACKGROUND_TITLEMESSAGE_INITIAL_4,
+    IMG_BACKGROUND_TITLEMESSAGE_INITIAL_5,
+    IMG_BACKGROUND_TITLEMESSAGE_1,
+    IMG_BACKGROUND_TITLEMESSAGE_2,
+    IMG_BACKGROUND_TITLEMESSAGE_3,
+    IMG_BACKGROUND_TITLEMESSAGE_4,
+    IMG_BACKGROUND_TITLEMESSAGE_5,
+
     -1
   };
 
@@ -1809,7 +1695,6 @@ static void InitGraphicInfo()
 
   graphic_info = checked_calloc(num_images * sizeof(struct GraphicInfo));
 
-#if 1
   /* initialize "use_image_size" flag with default value */
   for (i = 0; i < num_images; i++)
     graphic_info[i].use_image_size = FALSE;
@@ -1817,23 +1702,6 @@ static void InitGraphicInfo()
   /* initialize "use_image_size" flag from static configuration above */
   for (i = 0; full_size_graphics[i] != -1; i++)
     graphic_info[full_size_graphics[i]].use_image_size = TRUE;
-#endif
-
-#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
-  if (clipmasks_initialized)
-  {
-    for (i = 0; i < num_images; i++)
-    {
-      if (graphic_info[i].clip_mask)
-       XFreePixmap(display, graphic_info[i].clip_mask);
-      if (graphic_info[i].clip_gc)
-       XFreeGC(display, graphic_info[i].clip_gc);
-
-      graphic_info[i].clip_mask = None;
-      graphic_info[i].clip_gc = None;
-    }
-  }
-#endif
 
   /* first set all graphic paramaters ... */
   for (i = 0; i < num_images; i++)
@@ -1870,11 +1738,12 @@ static void InitGraphicInfo()
     first_frame = 0;
     getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
 
-#if 1
     /* this avoids calculating wrong start position for out-of-bounds frame */
     src_x = graphic_info[i].src_x;
     src_y = graphic_info[i].src_y;
-#endif
+
+    if (program.headless)
+      continue;
 
     if (src_x < 0 || src_y < 0 ||
        src_x + width  > src_bitmap_width ||
@@ -1885,13 +1754,14 @@ static void InitGraphicInfo()
       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, "- frame size: %d, %d", width, height);
       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_INFO, "custom graphic rejected for this element/action");
 
       if (i == fallback_graphic)
-       Error(ERR_EXIT, "fatal error: no fallback graphic available");
+       Error(ERR_EXIT, "no fallback graphic available");
 
       Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
       Error(ERR_INFO_LINE, "-");
@@ -1913,55 +1783,21 @@ static void InitGraphicInfo()
       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, "- frame size: %d, %d", width, height);
       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_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_EXIT, "no fallback graphic available");
 
       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 */
-    getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
-
-    if (copy_clipmask_gc == None)
-    {
-      clip_gc_values.graphics_exposures = False;
-      clip_gc_valuemask = GCGraphicsExposures;
-      copy_clipmask_gc = XCreateGC(display, src_bitmap->clip_mask,
-                                  clip_gc_valuemask, &clip_gc_values);
-    }
-
-    graphic_info[i].clip_mask =
-      XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
-
-    src_pixmap = src_bitmap->clip_mask;
-    XCopyArea(display, src_pixmap, graphic_info[i].clip_mask,
-             copy_clipmask_gc, src_x, src_y, TILEX, TILEY, 0, 0);
-
-    clip_gc_values.graphics_exposures = False;
-    clip_gc_values.clip_mask = graphic_info[i].clip_mask;
-    clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
-
-    graphic_info[i].clip_gc =
-      XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
-#endif
   }
-
-#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
-  if (copy_clipmask_gc)
-    XFreeGC(display, copy_clipmask_gc);
-
-  clipmasks_initialized = TRUE;
-#endif
 }
 
 static void InitGraphicCompatibilityInfo()
@@ -1996,26 +1832,14 @@ static void InitGraphicCompatibilityInfo()
        {
          // printf("::: special treatment needed for token '%s'\n", fi->token);
 
-         graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
+         graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
+         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
+  InitGraphicCompatibilityInfo_Doors();
 }
 
 static void InitElementSoundInfo()
@@ -2100,19 +1924,10 @@ static void InitElementSoundInfo()
       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].sound[act] != -1)
        default_action_sound = element_info[EL_SB_DEFAULT].sound[act];
 
-      /* !!! there's no such thing as a "default action sound" !!! */
-#if 0
-      /* look for element specific default sound (independent from action) */
-      if (element_info[i].sound[ACTION_DEFAULT] != -1)
-       default_action_sound = element_info[i].sound[ACTION_DEFAULT];
-#endif
-
-#if 1
       /* !!! needed because EL_EMPTY_SPACE treated as IS_SP_ELEMENT !!! */
       /* !!! make this better !!! */
       if (i == EL_EMPTY_SPACE)
        default_action_sound = element_info[EL_DEFAULT].sound[act];
-#endif
 
       /* no sound for this specific action -- use default action sound */
       if (element_info[i].sound[act] == -1)
@@ -2153,12 +1968,6 @@ static void InitGameModeSoundInfo()
   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
     if (menu.sound[i] == -1)
       menu.sound[i] = menu.sound[GAME_MODE_DEFAULT];
-
-#if 0
-  for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
-    if (menu.sound[i] != -1)
-      printf("::: menu.sound[%d] == %d\n", i, menu.sound[i]);
-#endif
 }
 
 static void set_sound_parameters(int sound, char **parameter_raw)
@@ -2206,11 +2015,7 @@ static void InitSoundInfo()
     int len_effect_text = strlen(sound->token);
 
     sound_effect_properties[i] = ACTION_OTHER;
-    sound_info[i].loop = FALSE;                /* default: play sound only once */
-
-#if 0
-    printf("::: sound %d: '%s'\n", i, sound->token);
-#endif
+    sound_info[i].loop = FALSE;                /* default: play sound only once */
 
     /* determine all loop sounds and identify certain sound classes */
 
@@ -2274,10 +2079,6 @@ static void InitGameModeMusicInfo()
     int gamemode = gamemode_to_music[i].gamemode;
     int music    = gamemode_to_music[i].music;
 
-#if 0
-    printf("::: gamemode == %d, music == %d\n", gamemode, music);
-#endif
-
     if (gamemode < 0)
       gamemode = GAME_MODE_DEFAULT;
 
@@ -2288,15 +2089,10 @@ static void InitGameModeMusicInfo()
   for (i = 0; i < num_property_mappings; i++)
   {
     int prefix   = property_mapping[i].base_index;
-    int gamemode = property_mapping[i].ext1_index;
-    int level    = property_mapping[i].ext2_index;
+    int gamemode = property_mapping[i].ext2_index;
+    int level    = property_mapping[i].ext3_index;
     int music    = property_mapping[i].artwork_index;
 
-#if 0
-    printf("::: prefix == %d, gamemode == %d, level == %d, music == %d\n",
-          prefix, gamemode, level, music);
-#endif
-
     if (prefix < 0 || prefix >= NUM_MUSIC_PREFIXES)
       continue;
 
@@ -2328,15 +2124,6 @@ static void InitGameModeMusicInfo()
   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
     if (menu.music[i] == -1)
       menu.music[i] = menu.music[GAME_MODE_DEFAULT];
-
-#if 0
-  for (i = 0; i < MAX_LEVELS; i++)
-    if (levelset.music[i] != -1)
-      printf("::: levelset.music[%d] == %d\n", i, levelset.music[i]);
-  for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
-    if (menu.music[i] != -1)
-      printf("::: menu.music[%d] == %d\n", i, menu.music[i]);
-#endif
 }
 
 static void set_music_parameters(int music, char **parameter_raw)
@@ -2396,6 +2183,8 @@ static void ReinitializeGraphics()
 {
   print_timestamp_init("ReinitializeGraphics");
 
+  InitGfxTileSizeInfo(game.tile_size, TILESIZE);
+
   InitGraphicInfo();                   /* graphic properties mapping */
   print_timestamp_time("InitGraphicInfo");
   InitElementGraphicInfo();            /* element game graphic mapping */
@@ -2407,8 +2196,15 @@ static void ReinitializeGraphics()
   print_timestamp_time("InitElementSmallImages");
   InitScaledImages();                  /* scale all other images, if needed */
   print_timestamp_time("InitScaledImages");
+  InitBitmapPointers();                        /* set standard size bitmap pointers */
+  print_timestamp_time("InitBitmapPointers");
   InitFontGraphicInfo();               /* initialize text drawing functions */
   print_timestamp_time("InitFontGraphicInfo");
+  InitGlobalAnimGraphicInfo();         /* initialize global animation config */
+  print_timestamp_time("InitGlobalAnimGraphicInfo");
+
+  InitImageTextures();                 /* create textures for certain images */
+  print_timestamp_time("InitImageTextures");
 
   InitGraphicInfo_EM();                        /* graphic mapping for EM engine */
   print_timestamp_time("InitGraphicInfo_EM");
@@ -2423,8 +2219,8 @@ static void ReinitializeGraphics()
 
   InitGadgets();
   print_timestamp_time("InitGadgets");
-  InitToons();
-  print_timestamp_time("InitToons");
+  InitDoors();
+  print_timestamp_time("InitDoors");
 
   print_timestamp_done("ReinitializeGraphics");
 }
@@ -2434,6 +2230,7 @@ static void ReinitializeSounds()
   InitSoundInfo();             /* sound properties mapping */
   InitElementSoundInfo();      /* element game sound mapping */
   InitGameModeSoundInfo();     /* game mode sound mapping */
+  InitGlobalAnimSoundInfo();   /* global animation sound settings */
 
   InitPlayLevelSound();                /* internal game sound settings */
 }
@@ -2442,6 +2239,7 @@ static void ReinitializeMusic()
 {
   InitMusicInfo();             /* music properties mapping */
   InitGameModeMusicInfo();     /* game mode music mapping */
+  InitGlobalAnimMusicInfo();   /* global animation music settings */
 }
 
 static int get_special_property_bit(int element, int property_bit_nr)
@@ -2900,18 +2698,14 @@ void InitElementPropertiesStatic()
     EL_SWITCHGATE_OPENING,
     EL_SWITCHGATE_CLOSED,
     EL_SWITCHGATE_CLOSING,
-#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 1
     EL_DC_TIMEGATE_SWITCH,
     EL_DC_TIMEGATE_SWITCH_ACTIVE,
-#endif
     EL_TUBE_ANY,
     EL_TUBE_VERTICAL,
     EL_TUBE_HORIZONTAL,
@@ -3150,16 +2944,12 @@ void InitElementPropertiesStatic()
     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,
@@ -4830,15 +4620,9 @@ void InitElementPropertiesEngine(int engine_version)
                                                  HAS_ACTION(i)));
 
     /* ---------- GFX_CRUMBLED --------------------------------------------- */
-#if 1
     SET_PROPERTY(i, EP_GFX_CRUMBLED,
                 element_info[i].crumbled[ACTION_DEFAULT] !=
                 element_info[i].graphic[ACTION_DEFAULT]);
-#else
-    /* !!! THIS LOOKS CRAPPY FOR SAND ETC. WITHOUT CRUMBLED GRAPHICS !!! */
-    SET_PROPERTY(i, EP_GFX_CRUMBLED,
-                element_info[i].crumbled[ACTION_DEFAULT] != IMG_EMPTY);
-#endif
 
     /* ---------- EDITOR_CASCADE ------------------------------------------- */
     SET_PROPERTY(i, EP_EDITOR_CASCADE, (IS_EDITOR_CASCADE_ACTIVE(i) ||
@@ -4936,10 +4720,6 @@ static void InitGlobal()
     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 */
@@ -4974,6 +4754,33 @@ static void InitGlobal()
                 font_info[i].token_name,
                 int2str(i, 0));
 
+  /* set default filenames for all cloned graphics in static configuration */
+  for (i = 0; image_config[i].token != NULL; i++)
+  {
+    if (strEqual(image_config[i].value, UNDEFINED_FILENAME))
+    {
+      char *token = image_config[i].token;
+      char *token_clone_from = getStringCat2(token, ".clone_from");
+      char *token_cloned = getHashEntry(image_config_hash, token_clone_from);
+
+      if (token_cloned != NULL)
+      {
+       char *value_cloned = getHashEntry(image_config_hash, token_cloned);
+
+       if (value_cloned != NULL)
+       {
+         /* set default filename in static configuration */
+         image_config[i].value = value_cloned;
+
+         /* set default filename in image config hash */
+         setHashEntry(image_config_hash, token, value_cloned);
+       }
+      }
+
+      free(token_clone_from);
+    }
+  }
+
   /* always start with reliable default values (all elements) */
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
     ActiveElement[i] = i;
@@ -5018,14 +4825,9 @@ static void InitGlobal()
   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.border_status = GAME_MODE_LOADING;
+  global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
 
   global.use_envelope_request = FALSE;
 }
@@ -5036,57 +4838,57 @@ void Execute_Command(char *command)
 
   if (strEqual(command, "print graphicsinfo.conf"))
   {
-    printf("# You can configure additional/alternative image files here.\n");
-    printf("# (The entries below are default and therefore commented out.)\n");
-    printf("\n");
-    printf("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
-    printf("\n");
-    printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
-    printf("\n");
+    Print("# You can configure additional/alternative image files here.\n");
+    Print("# (The entries below are default and therefore commented out.)\n");
+    Print("\n");
+    Print("%s\n", getFormattedSetupEntry("name", "Classic Graphics"));
+    Print("\n");
+    Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
+    Print("\n");
 
     for (i = 0; image_config[i].token != NULL; i++)
-      printf("# %s\n", getFormattedSetupEntry(image_config[i].token,
-                                             image_config[i].value));
+      Print("# %s\n", getFormattedSetupEntry(image_config[i].token,
+                                            image_config[i].value));
 
     exit(0);
   }
   else if (strEqual(command, "print soundsinfo.conf"))
   {
-    printf("# You can configure additional/alternative sound files here.\n");
-    printf("# (The entries below are default and therefore commented out.)\n");
-    printf("\n");
-    printf("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
-    printf("\n");
-    printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
-    printf("\n");
+    Print("# You can configure additional/alternative sound files here.\n");
+    Print("# (The entries below are default and therefore commented out.)\n");
+    Print("\n");
+    Print("%s\n", getFormattedSetupEntry("name", "Classic Sounds"));
+    Print("\n");
+    Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
+    Print("\n");
 
     for (i = 0; sound_config[i].token != NULL; i++)
-      printf("# %s\n", getFormattedSetupEntry(sound_config[i].token,
-                                             sound_config[i].value));
+      Print("# %s\n", getFormattedSetupEntry(sound_config[i].token,
+                                            sound_config[i].value));
 
     exit(0);
   }
   else if (strEqual(command, "print musicinfo.conf"))
   {
-    printf("# You can configure additional/alternative music files here.\n");
-    printf("# (The entries below are default and therefore commented out.)\n");
-    printf("\n");
-    printf("%s\n", getFormattedSetupEntry("name", "Classic Music"));
-    printf("\n");
-    printf("%s\n", getFormattedSetupEntry("sort_priority", "100"));
-    printf("\n");
+    Print("# You can configure additional/alternative music files here.\n");
+    Print("# (The entries below are default and therefore commented out.)\n");
+    Print("\n");
+    Print("%s\n", getFormattedSetupEntry("name", "Classic Music"));
+    Print("\n");
+    Print("%s\n", getFormattedSetupEntry("sort_priority", "100"));
+    Print("\n");
 
     for (i = 0; music_config[i].token != NULL; i++)
-      printf("# %s\n", getFormattedSetupEntry(music_config[i].token,
-                                             music_config[i].value));
+      Print("# %s\n", getFormattedSetupEntry(music_config[i].token,
+                                            music_config[i].value));
 
     exit(0);
   }
   else if (strEqual(command, "print editorsetup.conf"))
   {
-    printf("# You can configure your personal editor element list here.\n");
-    printf("# (The entries below are default and therefore commented out.)\n");
-    printf("\n");
+    Print("# You can configure your personal editor element list here.\n");
+    Print("# (The entries below are default and therefore commented out.)\n");
+    Print("\n");
 
     /* this is needed to be able to check element list for cascade elements */
     InitElementPropertiesStatic();
@@ -5098,30 +4900,30 @@ void Execute_Command(char *command)
   }
   else if (strEqual(command, "print helpanim.conf"))
   {
-    printf("# You can configure different element help animations here.\n");
-    printf("# (The entries below are default and therefore commented out.)\n");
-    printf("\n");
+    Print("# You can configure different element help animations here.\n");
+    Print("# (The entries below are default and therefore commented out.)\n");
+    Print("\n");
 
     for (i = 0; helpanim_config[i].token != NULL; i++)
     {
-      printf("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
-                                             helpanim_config[i].value));
+      Print("# %s\n", getFormattedSetupEntry(helpanim_config[i].token,
+                                            helpanim_config[i].value));
 
       if (strEqual(helpanim_config[i].token, "end"))
-       printf("#\n");
+       Print("#\n");
     }
 
     exit(0);
   }
   else if (strEqual(command, "print helptext.conf"))
   {
-    printf("# You can configure different element help text here.\n");
-    printf("# (The entries below are default and therefore commented out.)\n");
-    printf("\n");
+    Print("# You can configure different element help text here.\n");
+    Print("# (The entries below are default and therefore commented out.)\n");
+    Print("\n");
 
     for (i = 0; helptext_config[i].token != NULL; i++)
-      printf("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
-                                             helptext_config[i].value));
+      Print("# %s\n", getFormattedSetupEntry(helptext_config[i].token,
+                                            helptext_config[i].value));
 
     exit(0);
   }
@@ -5149,10 +4951,20 @@ void Execute_Command(char *command)
 
     exit(0);
   }
-  else if (strPrefix(command, "autoplay "))
+  else if (strPrefix(command, "autotest ") ||
+          strPrefix(command, "autoplay ") ||
+          strPrefix(command, "autoffwd ") ||
+          strPrefix(command, "autowarp "))
   {
     char *str_ptr = getStringCopy(&command[9]);        /* read command parameters */
 
+    global.autoplay_mode =
+      (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
+       strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
+       strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
+       strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
+       AUTOPLAY_MODE_NONE);
+
     while (*str_ptr != '\0')                   /* continue parsing string */
     {
       /* cut leading whitespace from string, replace it by string terminator */
@@ -5184,6 +4996,9 @@ void Execute_Command(char *command)
       while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
        str_ptr++;
     }
+
+    if (global.autoplay_mode == AUTOPLAY_MODE_TEST)
+      program.headless = TRUE;
   }
   else if (strPrefix(command, "convert "))
   {
@@ -5198,107 +5013,23 @@ void Execute_Command(char *command)
       *str_ptr++ = '\0';                       /* terminate leveldir string */
       global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
     }
+
+    program.headless = TRUE;
   }
   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_SDL2)
-  else if (strEqual(command, "SDL_ListModes"))
-  {
-    SDL_Init(SDL_INIT_VIDEO);
-
-    int num_displays = SDL_GetNumVideoDisplays();
-
-    // check if there are any displays available
-    if (num_displays < 0)
-    {
-      printf("No displays available: %s\n", SDL_GetError());
-
-      exit(-1);
-    }
-
-    for (i = 0; i < num_displays; i++)
-    {
-      int num_modes = SDL_GetNumDisplayModes(i);
-      int j;
-
-      printf("Available display modes for display %d:\n", i);
-
-      // check if there are any display modes available for this display
-      if (num_modes < 0)
-      {
-       printf("No display modes available for display %d: %s\n",
-              i, SDL_GetError());
-
-       exit(-1);
-      }
-
-      for (j = 0; j < num_modes; j++)
-      {
-       SDL_DisplayMode mode;
-
-       if (SDL_GetDisplayMode(i, j, &mode) < 0)
-       {
-         printf("Cannot get display mode %d for display %d: %s\n",
-                j, i, SDL_GetError());
-
-         exit(-1);
-       }
-
-       printf("- %d x %d\n", mode.w, mode.h);
-      }
-    }
-
-    exit(0);
   }
-#elif defined(TARGET_SDL)
-  else if (strEqual(command, "SDL_ListModes"))
+  else if (strPrefix(command, "create CE image "))
   {
-    SDL_Rect **modes;
-    int i;
-
-    SDL_Init(SDL_INIT_VIDEO);
-
-    /* get available fullscreen/hardware modes */
-    modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
-
-    /* check if there are any modes available */
-    if (modes == NULL)
-    {
-      printf("No modes available!\n");
-
-      exit(-1);
-    }
-
-    /* check if our resolution is restricted */
-    if (modes == (SDL_Rect **)-1)
-    {
-      printf("All resolutions available.\n");
-    }
-    else
-    {
-      printf("Available display modes:\n");
-
-      for (i = 0; modes[i]; i++)
-       printf("- %d x %d\n", modes[i]->w, modes[i]->h);
-    }
+    CreateCustomElementImages(&command[16]);
 
     exit(0);
   }
-#endif
-#endif
-
   else
   {
     Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
@@ -5359,33 +5090,15 @@ static char *get_level_id_suffix(int id_nr)
   return id_suffix;
 }
 
-#if 0
-static char *get_element_class_token(int element)
-{
-  char *element_class_name = element_info[element].class_name;
-  char *element_class_token = checked_malloc(strlen(element_class_name) + 3);
-
-  sprintf(element_class_token, "[%s]", element_class_name);
-
-  return element_class_token;
-}
-
-static char *get_action_class_token(int action)
-{
-  char *action_class_name = &element_action_info[action].suffix[1];
-  char *action_class_token = checked_malloc(strlen(action_class_name) + 3);
-
-  sprintf(action_class_token, "[%s]", action_class_name);
-
-  return action_class_token;
-}
-#endif
-
 static void InitArtworkConfig()
 {
-  static char *image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + 1];
-  static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS + 1];
-  static char *music_id_prefix[NUM_MUSIC_PREFIXES + 1];
+  static char *image_id_prefix[MAX_NUM_ELEMENTS +
+                              NUM_FONTS +
+                              NUM_GLOBAL_ANIM_TOKENS + 1];
+  static char *sound_id_prefix[2 * MAX_NUM_ELEMENTS +
+                              NUM_GLOBAL_ANIM_TOKENS + 1];
+  static char *music_id_prefix[NUM_MUSIC_PREFIXES +
+                              NUM_GLOBAL_ANIM_TOKENS + 1];
   static char *action_id_suffix[NUM_ACTIONS + 1];
   static char *direction_id_suffix[NUM_DIRECTIONS_FULL + 1];
   static char *special_id_suffix[NUM_SPECIAL_GFX_ARGS + 1];
@@ -5444,18 +5157,27 @@ static void InitArtworkConfig()
     image_id_prefix[i] = element_info[i].token_name;
   for (i = 0; i < NUM_FONTS; i++)
     image_id_prefix[MAX_NUM_ELEMENTS + i] = font_info[i].token_name;
-  image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS] = NULL;
+  for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
+    image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + i] =
+      global_anim_info[i].token_name;
+  image_id_prefix[MAX_NUM_ELEMENTS + NUM_FONTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
 
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
     sound_id_prefix[i] = element_info[i].token_name;
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
     sound_id_prefix[MAX_NUM_ELEMENTS + i] =
       get_string_in_brackets(element_info[i].class_name);
-  sound_id_prefix[2 * MAX_NUM_ELEMENTS] = NULL;
+  for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
+    sound_id_prefix[2 * MAX_NUM_ELEMENTS + i] =
+      global_anim_info[i].token_name;
+  sound_id_prefix[2 * MAX_NUM_ELEMENTS + NUM_GLOBAL_ANIM_TOKENS] = NULL;
 
   for (i = 0; i < NUM_MUSIC_PREFIXES; i++)
     music_id_prefix[i] = music_prefix_info[i].prefix;
-  music_id_prefix[NUM_MUSIC_PREFIXES] = NULL;
+  for (i = 0; i < NUM_GLOBAL_ANIM_TOKENS; i++)
+    music_id_prefix[NUM_MUSIC_PREFIXES + i] =
+      global_anim_info[i].token_name;
+  music_id_prefix[NUM_MUSIC_PREFIXES + NUM_GLOBAL_ANIM_TOKENS] = NULL;
 
   for (i = 0; i < NUM_ACTIONS; i++)
     action_id_suffix[i] = element_action_info[i].suffix;
@@ -5480,8 +5202,8 @@ static void InitArtworkConfig()
                sound_id_prefix, action_id_suffix, dummy,
                special_id_suffix, ignore_sound_tokens);
   InitMusicList(music_config, NUM_MUSIC_FILES, music_config_suffix,
-               music_id_prefix, special_id_suffix, level_id_suffix,
-               dummy, ignore_music_tokens);
+               music_id_prefix, action_id_suffix, special_id_suffix,
+               level_id_suffix, ignore_music_tokens);
 }
 
 static void InitMixer()
@@ -5493,13 +5215,25 @@ static void InitMixer()
 
 void InitGfxBuffers()
 {
+  static int win_xsize_last = -1;
+  static int win_ysize_last = -1;
+
   /* create additional image buffers for double-buffering and cross-fading */
-  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);
+
+  if (WIN_XSIZE != win_xsize_last || WIN_YSIZE != win_ysize_last)
+  {
+    /* used to temporarily store the backbuffer -- only re-create if changed */
+    ReCreateBitmap(&bitmap_db_store_1, WIN_XSIZE, WIN_YSIZE);
+    ReCreateBitmap(&bitmap_db_store_2, WIN_XSIZE, WIN_YSIZE);
+
+    win_xsize_last = WIN_XSIZE;
+    win_ysize_last = WIN_YSIZE;
+  }
+
+  ReCreateBitmap(&bitmap_db_field, FXSIZE, FYSIZE);
+  ReCreateBitmap(&bitmap_db_panel, DXSIZE, DYSIZE);
+  ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE);
+  ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE);
 
   /* initialize screen properties */
   InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
@@ -5512,6 +5246,9 @@ void InitGfxBuffers()
   InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
   InitGfxClipRegion(FALSE, -1, -1, -1, -1);
 
+  /* required if door size definitions have changed */
+  InitGraphicCompatibilityInfo_Doors();
+
   InitGfxBuffers_EM();
   InitGfxBuffers_SP();
 }
@@ -5564,6 +5301,7 @@ void InitGfx()
 
   InitGfxBuffers();
   InitGfxCustomArtworkInfo();
+  InitGfxOtherSettings();
 
   bitmap_font_initial = LoadCustomImage(filename_font_initial);
 
@@ -5574,101 +5312,95 @@ void InitGfx()
 
   font_height = getFontHeight(FC_RED);
 
-#if 1
-  DrawInitTextAlways(getWindowTitleString(), 20, FC_YELLOW);
-#else
-  DrawInitTextAlways(getProgramInitString(), 20, FC_YELLOW);
-#endif
-  DrawInitTextAlways(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
-  DrawInitTextAlways(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height,
-                    FC_RED);
+  DrawInitText(getProgramInitString(), 20, FC_YELLOW);
+  DrawInitText(setup.internal.program_copyright, 50, FC_RED);
+  DrawInitText(setup.internal.program_website, WIN_YSIZE - 20 - font_height,
+              FC_RED);
 
-  DrawInitTextAlways("Loading graphics", 120, FC_GREEN);
+  DrawInitText("Loading graphics", 120, FC_GREEN);
 
-#if 1
-#if 1
-  /* initialize busy animation with default values */
+  /* initialize settings for 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);
+
+  /* read settings for busy animation from default custom artwork config */
+  char *gfx_config_filename = getPath3(options.graphics_directory,
+                                      GFX_DEFAULT_SUBDIR,
+                                      GRAPHICSINFO_FILENAME);
+
+  if (fileExists(gfx_config_filename))
   {
-    char *anim_token = CONFIG_TOKEN_GLOBAL_BUSY;
-    int len_anim_token = strlen(anim_token);
+    SetupFileHash *setup_file_hash = loadSetupFileHash(gfx_config_filename);
 
-    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 (setup_file_hash)
     {
-#if 1
-      for (j = 0; image_config_suffix[j].token != NULL; j++)
+      char *filename = getHashEntry(setup_file_hash, anim_token);
+
+      if (filename)
       {
-       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);
+       filename_anim_initial = getStringCopy(filename);
+
+       for (j = 0; image_config_suffix[j].token != NULL; j++)
+       {
+         int type = image_config_suffix[j].type;
+         char *suffix = image_config_suffix[j].token;
+         char *token = getStringCat2(anim_token, suffix);
+         char *value = getHashEntry(setup_file_hash, token);
+
+         checked_free(token);
+
+         if (value)
+           parameter[j] = get_graphic_parameter_value(value, suffix, 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
+
+      freeSetupFileHash(setup_file_hash);
     }
   }
 
-#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)
+  {
+    /* read settings for busy animation from static default artwork config */
+    for (i = 0; image_config[i].token != NULL; i++)
+    {
+      if (strEqual(image_config[i].token, anim_token))
+       filename_anim_initial = getStringCopy(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)
+      {
+       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);
+       }
+      }
+    }
+  }
 
   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);
+  anim_initial.bitmaps =
+    checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
 
-  graphic_info = &anim_initial;                /* graphic == 0 => anim_initial */
+  anim_initial.bitmaps[IMG_BITMAP_STANDARD] =
+    LoadCustomImage(filename_anim_initial);
 
-  set_graphic_parameters_ext(0, parameter, anim_initial.bitmap);
+  checked_free(filename_anim_initial);
 
-#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 = &anim_initial;                /* graphic == 0 => anim_initial */
+
+  set_graphic_parameters_ext(0, parameter, anim_initial.bitmaps);
 
   graphic_info = graphic_info_last;
 
@@ -5676,41 +5408,26 @@ void InitGfx()
   init.busy.height = anim_initial.height;
 
   InitMenuDesignSettings_Static();
+
   InitGfxDrawBusyAnimFunction(DrawInitAnim);
+  InitGfxDrawGlobalAnimFunction(DrawGlobalAnimations);
+  InitGfxDrawGlobalBorderFunction(DrawMaskedBorderToTarget);
+
+  gfx.fade_border_source_status = global.border_status;
+  gfx.fade_border_target_status = global.border_status;
+  gfx.masked_border_bitmap_ptr = backbuffer;
 
   /* use copy of busy animation to prevent change while reloading artwork */
   init_last = init;
-#endif
-}
-
-void RedrawBackground()
-{
-  BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, backbuffer,
-            0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
-
-  redraw_mask = REDRAW_ALL;
 }
 
 void InitGfxBackground()
 {
-  int x, y;
-
   fieldbuffer = bitmap_db_field;
-  SetDrawtoField(DRAW_BACKBUFFER);
+  SetDrawtoField(DRAW_TO_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++)
-      redraw[x][y] = 0;
-  redraw_tiles = 0;
   redraw_mask = REDRAW_ALL;
 }
 
@@ -5719,6 +5436,15 @@ static void InitLevelInfo()
   LoadLevelInfo();                             /* global level info */
   LoadLevelSetup_LastSeries();                 /* last played series info */
   LoadLevelSetup_SeriesInfo();                 /* last played level info */
+
+  if (global.autoplay_leveldir &&
+      global.autoplay_mode != AUTOPLAY_MODE_TEST)
+  {
+    leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
+                                                 global.autoplay_leveldir);
+    if (leveldir_current == NULL)
+      leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
+  }
 }
 
 static void InitLevelArtworkInfo()
@@ -5783,6 +5509,9 @@ static void InitImages()
   ReinitializeGraphics();
   print_timestamp_time("ReinitializeGraphics");
 
+  LoadMenuDesignSettings_AfterGraphics();
+  print_timestamp_time("LoadMenuDesignSettings_AfterGraphics");
+
   UPDATE_BUSY_STATE();
 
   print_timestamp_done("InitImages");
@@ -5826,6 +5555,14 @@ static void InitMusic(char *identifier)
   print_timestamp_done("InitMusic");
 }
 
+static void InitArtworkDone()
+{
+  if (program.headless)
+    return;
+
+  InitGlobalAnimations();
+}
+
 void InitNetworkServer()
 {
 #if defined(NETWORK_AVALIABLE)
@@ -5974,19 +5711,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
   /* !!! setLevelArtworkDir() should be moved to an earlier stage !!! */
   char *leveldir_artwork_set = setLevelArtworkDir(artwork_first_node);
-#else
-  char *leveldir_artwork_set = LEVELDIR_ARTWORK_SET(leveldir_current, type);
-#endif
   boolean has_level_artwork_set = (leveldir_artwork_set != NULL);
   char *artwork_current_identifier;
   char *artwork_new_identifier = NULL; /* default: nothing has changed */
@@ -6016,16 +5745,6 @@ static char *getNewArtworkIdentifier(int type)
   /* 2nd step: check if it is really needed to reload artwork set
      ------------------------------------------------------------ */
 
-#if 0
-  if (type == ARTWORK_TYPE_GRAPHICS)
-    printf("::: 0: '%s' ['%s', '%s'] ['%s' ('%s')]\n",
-          artwork_new_identifier,
-          ARTWORK_CURRENT_IDENTIFIER(artwork, type),
-          artwork_current_identifier,
-          leveldir_current->graphics_set,
-          leveldir_current->identifier);
-#endif
-
   /* ---------- reload if level set and also artwork set has changed ------- */
   if (leveldir_current_identifier[type] != leveldir_identifier &&
       (last_has_level_artwork_set[type] || has_level_artwork_set))
@@ -6034,22 +5753,12 @@ static char *getNewArtworkIdentifier(int type)
   leveldir_current_identifier[type] = leveldir_identifier;
   last_has_level_artwork_set[type] = has_level_artwork_set;
 
-#if 0
-  if (type == ARTWORK_TYPE_GRAPHICS)
-    printf("::: 1: '%s'\n", artwork_new_identifier);
-#endif
-
   /* ---------- reload if "override artwork" setting has changed ----------- */
   if (last_override_level_artwork[type] != setup_override_artwork)
     artwork_new_identifier = artwork_current_identifier;
 
   last_override_level_artwork[type] = setup_override_artwork;
 
-#if 0
-  if (type == ARTWORK_TYPE_GRAPHICS)
-    printf("::: 2: '%s'\n", artwork_new_identifier);
-#endif
-
   /* ---------- reload if current artwork identifier has changed ----------- */
   if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
                artwork_current_identifier))
@@ -6057,30 +5766,12 @@ static char *getNewArtworkIdentifier(int type)
 
   *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
 
-#if 0
-  if (type == ARTWORK_TYPE_GRAPHICS)
-    printf("::: 3: '%s'\n", artwork_new_identifier);
-#endif
-
   /* ---------- do not reload directly after starting ---------------------- */
   if (!initialized[type])
     artwork_new_identifier = NULL;
 
   initialized[type] = TRUE;
 
-#if 0
-  if (type == ARTWORK_TYPE_GRAPHICS)
-    printf("::: 4: '%s'\n", artwork_new_identifier);
-#endif
-
-#if 0
-  if (type == ARTWORK_TYPE_GRAPHICS)
-    printf("CHECKING OLD/NEW GFX:\n- OLD: %s\n- NEW: %s ['%s', '%s'] ['%s']\n",
-          artwork.gfx_current_identifier, artwork_current_identifier,
-          artwork.gfx_current->identifier, leveldir_current->graphics_set,
-          artwork_new_identifier);
-#endif
-
   return artwork_new_identifier;
 }
 
@@ -6112,24 +5803,14 @@ void ReloadCustomArtwork(int force_reload)
 
   print_timestamp_init("ReloadCustomArtwork");
 
-  game_status = GAME_MODE_LOADING;
+  SetGameStatus(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)
   {
@@ -6157,46 +5838,22 @@ void ReloadCustomArtwork(int force_reload)
     print_timestamp_time("InitMusic");
   }
 
-  game_status = last_game_status;      /* restore current game status */
+  InitArtworkDone();
 
-  init_last = init;                    /* switch to new busy animation */
+  SetGameStatus(last_game_status);     /* restore current game status */
 
-#if 0
-  printf("::: ----------------DELAY 1 ...\n");
-  Delay(3000);
-#endif
+  init_last = init;                    /* switch to new busy animation */
 
-#if 0
-  printf("::: FadeOut @ ReloadCustomArtwork ...\n");
-#endif
   FadeOut(REDRAW_ALL);
-#if 0
-  printf("::: FadeOut @ ReloadCustomArtwork done\n");
-#endif
 
-  RedrawBackground();
+  RedrawGlobalBorder();
 
   /* 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");
 
@@ -6250,7 +5907,7 @@ void DisplayExitMessage(char *format, va_list ap)
   sy += 3 * font_height;
 
   num_lines_printed =
-    DrawTextBuffer(sx, sy, program.error_filename, font_2,
+    DrawTextBuffer(sx, sy, program.log_filename[LOG_ERR_ID], font_2,
                   line_length, line_length, max_lines,
                   0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
 
@@ -6258,6 +5915,9 @@ void DisplayExitMessage(char *format, va_list ap)
 
   redraw_mask = REDRAW_ALL;
 
+  /* force drawing exit message even if screen updates are currently limited */
+  LimitScreenUpdates(FALSE);
+
   BackToFront();
 
   /* deactivate toons on error message screen */
@@ -6275,16 +5935,20 @@ void OpenAll()
 {
   print_timestamp_init("OpenAll");
 
-  game_status = GAME_MODE_LOADING;
+  SetGameStatus(GAME_MODE_LOADING);
 
-#if 1
   InitCounter();
-#endif
 
   InitGlobal();                        /* initialize some global variables */
 
   print_timestamp_time("[init global stuff]");
 
+  InitSetup();
+
+  print_timestamp_time("[init setup/config stuff (1)]");
+
+  InitScoresInfo();
+
   if (options.execute_command)
     Execute_Command(options.execute_command);
 
@@ -6299,10 +5963,6 @@ void OpenAll()
     exit(0);                   /* never reached, server loops forever */
   }
 
-  InitSetup();
-
-  print_timestamp_time("[init setup/config stuff (1)]");
-
   InitGameInfo();
   print_timestamp_time("[init setup/config stuff (2)]");
   InitPlayerInfo();
@@ -6314,10 +5974,6 @@ void OpenAll()
   InitMixer();
   print_timestamp_time("[init setup/config stuff (6)]");
 
-#if 0
-  InitCounter();
-#endif
-
   InitRND(NEW_RANDOMIZE);
   InitSimpleRandom(NEW_RANDOMIZE);
 
@@ -6328,7 +5984,7 @@ void OpenAll()
   InitVideoDisplay();
   InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
 
-  InitEventFilter(FilterEvents);
+  InitOverlayInfo();
 
   print_timestamp_time("[init video stuff]");
 
@@ -6360,15 +6016,12 @@ void OpenAll()
   InitMusic(NULL);             /* needs to know current level directory */
   print_timestamp_time("InitMusic");
 
+  InitArtworkDone();
+
   InitGfxBackground();
 
-#if 1
   em_open_all();
-#endif
-
-#if 1
   sp_open_all();
-#endif
 
   if (global.autoplay_leveldir)
   {
@@ -6386,16 +6039,11 @@ void OpenAll()
     return;
   }
 
-  game_status = GAME_MODE_MAIN;
+  SetGameStatus(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]");
 
@@ -6431,13 +6079,8 @@ void CloseAllAndExit(int exit_value)
   FreeAllMusic();
   CloseAudio();                /* called after freeing sounds (needed for SDL) */
 
-#if 1
   em_close_all();
-#endif
-
-#if 1
   sp_close_all();
-#endif
 
   FreeAllImages();