updated contact info in source file headers
[rocksndiamonds.git] / src / init.c
index 8f2fdf7d61696fa9e6623c6ecaedbe8f3129d78c..bbf595143e6254954283f20c18d235791af1b768 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"
 
@@ -38,9 +36,6 @@
 #define CONFIG_TOKEN_FONT_INITIAL              "font.initial"
 #define CONFIG_TOKEN_GLOBAL_BUSY               "global.busy"
 
-#define DEBUG_PRINT_INIT_TIMESTAMPS            TRUE
-#define DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH      1
-
 
 static struct FontBitmapInfo font_initial[NUM_INITIAL_FONTS];
 static struct GraphicInfo    anim_initial;
@@ -89,78 +84,12 @@ static int copy_properties[][5] =
 };
 
 
-static void print_timestamp_ext(char *message, char *mode)
-{
-#if DEBUG
-#if DEBUG_PRINT_INIT_TIMESTAMPS
-  static char *debug_message = NULL;
-  static char *last_message = NULL;
-  static int counter_nr = 0;
-  int max_depth = DEBUG_PRINT_INIT_TIMESTAMPS_DEPTH;
-
-  checked_free(debug_message);
-  debug_message = getStringCat3(mode, " ", message);
-
-  if (strEqual(mode, "INIT"))
-  {
-    debug_print_timestamp(counter_nr, NULL);
-
-    if (counter_nr + 1 < max_depth)
-      debug_print_timestamp(counter_nr, debug_message);
-
-    counter_nr++;
-
-    debug_print_timestamp(counter_nr, NULL);
-  }
-  else if (strEqual(mode, "DONE"))
-  {
-    counter_nr--;
-
-    if (counter_nr + 1 < max_depth ||
-       (counter_nr == 0 && max_depth == 1))
-    {
-      last_message = message;
-
-      if (counter_nr == 0 && max_depth == 1)
-      {
-       checked_free(debug_message);
-       debug_message = getStringCat3("TIME", " ", message);
-      }
-
-      debug_print_timestamp(counter_nr, debug_message);
-    }
-  }
-  else if (!strEqual(mode, "TIME") ||
-          !strEqual(message, last_message))
-  {
-    if (counter_nr < max_depth)
-      debug_print_timestamp(counter_nr, debug_message);
-  }
-#endif
-#endif
-}
-
-static void print_timestamp_init(char *message)
-{
-  print_timestamp_ext(message, "INIT");
-}
-
-static void print_timestamp_time(char *message)
-{
-  print_timestamp_ext(message, "TIME");
-}
-
-static void print_timestamp_done(char *message)
-{
-  print_timestamp_ext(message, "DONE");
-}
-
 void DrawInitAnim()
 {
   struct GraphicInfo *graphic_info_last = graphic_info;
   int graphic = 0;
-  static unsigned long action_delay = 0;
-  unsigned long action_delay_value = GameFrameDelay;
+  static unsigned int action_delay = 0;
+  unsigned int action_delay_value = GameFrameDelay;
   int sync_frame = FrameCounter;
   int x, y;
 
@@ -175,9 +104,9 @@ void DrawInitAnim()
 
 #if 0
   {
-    static unsigned long last_counter = -1;
-    unsigned long current_counter = Counter();
-    unsigned long delay = current_counter - last_counter;
+    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);
@@ -186,20 +115,8 @@ void DrawInitAnim()
   }
 #endif
 
-#if 0
-  anim_initial.anim_mode = ANIM_LOOP;
-  anim_initial.anim_start_frame = 0;
-  anim_initial.offset_x = anim_initial.width;
-  anim_initial.offset_y = 0;
-#endif
-
-#if 1
-  x = ALIGNED_TEXT_XPOS(&init.busy);
-  y = ALIGNED_TEXT_YPOS(&init.busy);
-#else
-  x = WIN_XSIZE / 2 - TILESIZE / 2;
-  y = WIN_YSIZE / 2 - TILESIZE / 2;
-#endif
+  x = ALIGNED_TEXT_XPOS(&init_last.busy);
+  y = ALIGNED_TEXT_YPOS(&init_last.busy);
 
   graphic_info = &anim_initial;                /* graphic == 0 => anim_initial */
 
@@ -229,7 +146,7 @@ void DrawInitAnim()
     int height = graphic_info[graphic].height;
     int frame = getGraphicAnimationFrame(graphic, sync_frame);
 
-    getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
+    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 !!! */
@@ -277,11 +194,14 @@ inline void InitElementSmallImagesScaledUp(int graphic)
   printf("::: '%s' -> '%s'\n", fi->token, fi->filename);
 #endif
 
-  CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor);
+  CreateImageWithSmallImages(graphic, graphic_info[graphic].scale_up_factor,
+                            graphic_info[graphic].tile_size);
 }
 
 void InitElementSmallImages()
 {
+  print_timestamp_init("InitElementSmallImages");
+
   static int special_graphics[] =
   {
     IMG_EDITOR_ELEMENT_BORDER,
@@ -294,21 +214,30 @@ void InitElementSmallImages()
   int num_property_mappings = getImageListPropertyMappingSize();
   int i;
 
+  print_timestamp_time("getImageListPropertyMapping/Size");
+
+  print_timestamp_init("InitElementSmallImagesScaledUp (1)");
   /* initialize normal 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 */
   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) */
   for (i = 0; i < num_property_mappings; i++)
     InitElementSmallImagesScaledUp(property_mapping[i].artwork_index);
+  print_timestamp_time("InitElementSmallImagesScaledUp (3)");
 
   /* initialize special images from above list (non-element images) */
   for (i = 0; special_graphics[i] > -1; i++)
     InitElementSmallImagesScaledUp(special_graphics[i]);
+  print_timestamp_time("InitElementSmallImagesScaledUp (4)");
+
+  print_timestamp_done("InitElementSmallImages");
 }
 
 void InitScaledImages()
@@ -329,6 +258,14 @@ void SetBitmaps_EM(Bitmap **em_bitmap)
 }
 #endif
 
+#if 0
+/* !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!! */
+void SetBitmaps_SP(Bitmap **sp_bitmap)
+{
+  *sp_bitmap = graphic_info[IMG_SP_OBJECTS].bitmap;
+}
+#endif
+
 static int getFontBitmapID(int font_nr)
 {
   int special = -1;
@@ -344,6 +281,15 @@ static int getFontBitmapID(int font_nr)
     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];
   else
@@ -857,8 +803,8 @@ void InitElementGraphicInfo()
          if (swap_movement_tiles_always || swap_movement_tiles_autodetected)
          {
            /* get current (wrong) backside tile coordinates */
-           getGraphicSourceExt(graphic, 0, &dummy, &src_x_back, &src_y_back,
-                               TRUE);
+           getFixedGraphicSourceExt(graphic, 0, &dummy,
+                                    &src_x_back, &src_y_back, TRUE);
 
            /* set frontside tile coordinates to backside tile coordinates */
            g->src_x = src_x_back;
@@ -1191,7 +1137,6 @@ static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
   if (strEqual(value_raw, ARG_UNDEFINED))
     return ARG_UNDEFINED_VALUE;
 
-#if 1
   if (type == TYPE_ELEMENT)
   {
     char *value = getHashEntry(element_token_hash, value_raw);
@@ -1205,36 +1150,6 @@ static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
     return (value != NULL ? atoi(value) : IMG_UNDEFINED);
   }
 
-#else
-
-  int i;
-  int x = 0;
-
-  /* !!! THIS IS BUGGY !!! NOT SURE IF YOU GET ELEMENT ID OR GRAPHIC ID !!! */
-  /* !!! (possible reason why ".clone_from" with elements doesn't work) !!! */
-
-  /* !!! OPTIMIZE THIS BY USING HASH !!! */
-  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
-    if (strEqual(element_info[i].token_name, value_raw))
-      return i;
-
-  /* !!! OPTIMIZE THIS BY USING HASH !!! */
-  for (i = 0; image_config[i].token != NULL; i++)
-  {
-    int len_config_value = strlen(image_config[i].value);
-
-    if (!strEqual(&image_config[i].value[len_config_value - 4], ".pcx") &&
-       !strEqual(&image_config[i].value[len_config_value - 4], ".wav") &&
-       !strEqual(image_config[i].value, UNDEFINED_FILENAME))
-      continue;
-
-    if (strEqual(image_config[i].token, value_raw))
-      return x;
-
-    x++;
-  }
-#endif
-
   return -1;
 }
 
@@ -1277,6 +1192,7 @@ 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->anim_delay_fixed = 0;
   g->anim_delay_random = 0;
@@ -1289,6 +1205,8 @@ static void set_graphic_parameters_ext(int graphic, int *parameter,
   g->align = ALIGN_CENTER;             /* default for title screens */
   g->valign = VALIGN_MIDDLE;           /* default for title screens */
   g->sort_priority = 0;                        /* default for title screens */
+  g->class = 0;
+  g->style = STYLE_DEFAULT;
 
   g->bitmap = src_bitmap;
 
@@ -1300,6 +1218,14 @@ static void set_graphic_parameters_ext(int graphic, int *parameter,
     g->scale_up_factor = 1;            /* no scaling */
 #endif
 
+#if 1
+  /* 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 (g->tile_size < TILESIZE)
+    g->tile_size = TILESIZE;           /* standard tile size */
+#endif
+
 #if 1
   if (g->use_image_size)
   {
@@ -1327,6 +1253,29 @@ static void set_graphic_parameters_ext(int graphic, int *parameter,
   if (parameter[GFX_ARG_HEIGHT] != ARG_UNDEFINED_VALUE)
     g->height = parameter[GFX_ARG_HEIGHT];
 
+  if (src_bitmap)
+  {
+    if (g->width <= 0)
+    {
+      Error(ERR_INFO_LINE, "-");
+      Error(ERR_WARN, "invalid value %d for '%s.width' (fallback done to %d)",
+           g->width, getTokenFromImageID(graphic), TILEX);
+      Error(ERR_INFO_LINE, "-");
+
+      g->width = TILEX;                /* will be checked to be inside bitmap later */
+    }
+
+    if (g->height <= 0)
+    {
+      Error(ERR_INFO_LINE, "-");
+      Error(ERR_WARN, "invalid value %d for '%s.height' (fallback done to %d)",
+           g->height, getTokenFromImageID(graphic), TILEY);
+      Error(ERR_INFO_LINE, "-");
+
+      g->height = TILEY;       /* will be checked to be inside bitmap later */
+    }
+  }
+
 #if 0
   /* optional zoom factor for scaling up the image to a larger size */
   if (parameter[GFX_ARG_SCALE_UP_FACTOR] != ARG_UNDEFINED_VALUE)
@@ -1489,6 +1438,17 @@ static void set_graphic_parameters_ext(int graphic, int *parameter,
     g->valign = parameter[GFX_ARG_VALIGN];
   if (parameter[GFX_ARG_SORT_PRIORITY] != ARG_UNDEFINED_VALUE)
     g->sort_priority = parameter[GFX_ARG_SORT_PRIORITY];
+
+  if (parameter[GFX_ARG_CLASS] != ARG_UNDEFINED_VALUE)
+    g->class = parameter[GFX_ARG_CLASS];
+  if (parameter[GFX_ARG_STYLE] != ARG_UNDEFINED_VALUE)
+    g->style = parameter[GFX_ARG_STYLE];
+
+  /* this is only used for drawing menu buttons and text */
+  g->active_xoffset = parameter[GFX_ARG_ACTIVE_XOFFSET];
+  g->active_yoffset = parameter[GFX_ARG_ACTIVE_YOFFSET];
+  g->pressed_xoffset = parameter[GFX_ARG_PRESSED_XOFFSET];
+  g->pressed_yoffset = parameter[GFX_ARG_PRESSED_YOFFSET];
 }
 
 static void set_graphic_parameters(int graphic)
@@ -1812,14 +1772,6 @@ 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 long 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[] =
   {
@@ -1830,12 +1782,14 @@ static void InitGraphicInfo()
     IMG_BACKGROUND_ENVELOPE_2,
     IMG_BACKGROUND_ENVELOPE_3,
     IMG_BACKGROUND_ENVELOPE_4,
+    IMG_BACKGROUND_REQUEST,
 
     IMG_BACKGROUND,
     IMG_BACKGROUND_TITLE_INITIAL,
     IMG_BACKGROUND_TITLE,
     IMG_BACKGROUND_MAIN,
     IMG_BACKGROUND_LEVELS,
+    IMG_BACKGROUND_LEVELNR,
     IMG_BACKGROUND_SCORES,
     IMG_BACKGROUND_EDITOR,
     IMG_BACKGROUND_INFO,
@@ -1843,9 +1797,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,
@@ -1858,6 +1818,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
   };
 
@@ -1875,22 +1846,6 @@ static void InitGraphicInfo()
     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++)
     set_graphic_parameters(i);
@@ -1924,7 +1879,7 @@ static void InitGraphicInfo()
     /* check if first animation frame is inside specified bitmap */
 
     first_frame = 0;
-    getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
+    getFixedGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
 
 #if 1
     /* this avoids calculating wrong start position for out-of-bounds frame */
@@ -1958,7 +1913,7 @@ static void InitGraphicInfo()
     /* check if last animation frame is inside specified bitmap */
 
     last_frame = graphic_info[i].anim_frames - 1;
-    getGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
+    getFixedGraphicSource(i, last_frame, &src_bitmap, &src_x, &src_y);
 
     if (src_x < 0 || src_y < 0 ||
        src_x + width  > src_bitmap_width ||
@@ -1972,6 +1927,7 @@ static void InitGraphicInfo()
       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)
@@ -1982,40 +1938,108 @@ static void InitGraphicInfo()
 
       graphic_info[i] = graphic_info[fallback_graphic];
     }
+  }
+}
 
-#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
-    /* currently we only need a tile clip mask from the first frame */
-    getGraphicSource(i, first_frame, &src_bitmap, &src_x, &src_y);
+static void InitGraphicCompatibilityInfo()
+{
+  struct FileInfo *fi_global_door =
+    getImageListEntryFromImageID(IMG_GLOBAL_DOOR);
+  int num_images = getImageListSize();
+  int i;
 
-    if (copy_clipmask_gc == None)
+  /* the following compatibility handling is needed for the following case:
+     versions up to 3.3.0.0 used one large bitmap "global.door" for various
+     graphics mainly used for door and panel graphics, like editor, tape and
+     in-game buttons with hard-coded bitmap positions and button sizes; as
+     these graphics now have individual definitions, redefining "global.door"
+     to change all these graphics at once like before does not work anymore
+     (because all those individual definitions still have their default values);
+     to solve this, remap all those individual definitions that are not
+     redefined to the new bitmap of "global.door" if it was redefined */
+
+  /* special compatibility handling if image "global.door" was redefined */
+  if (fi_global_door->redefined)
+  {
+    for (i = 0; i < num_images; i++)
     {
-      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);
+      struct FileInfo *fi = getImageListEntryFromImageID(i);
+
+      /* process only those images that still use the default settings */
+      if (!fi->redefined)
+      {
+       /* process all images which default to same image as "global.door" */
+       if (strEqual(fi->default_filename, fi_global_door->default_filename))
+       {
+         // printf("::: special treatment needed for token '%s'\n", fi->token);
+
+         graphic_info[i].bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
+       }
+      }
     }
+  }
+
+#if 1
+  InitGraphicCompatibilityInfo_Doors();
+#endif
+
+#if 0
+  struct
+  {
+    int graphic;
+    int *width, *height;
+    boolean right_wing;
+  }
+  doors[] =
+  {
+    { IMG_DOOR_1_WING_LEFT,    &door_1.width,  &door_1.height, FALSE   },
+    { IMG_DOOR_1_WING_RIGHT,   &door_1.width,  &door_1.height, TRUE    },
+    { IMG_DOOR_2_WING_LEFT,    &door_2.width,  &door_2.height, FALSE   },
+    { IMG_DOOR_2_WING_RIGHT,   &door_2.width,  &door_2.height, TRUE    },
+
+    { 0,                       NULL,           NULL,           FALSE   }
+  };
 
-    graphic_info[i].clip_mask =
-      XCreatePixmap(display, window->drawable, TILEX, TILEY, 1);
+  for (i = 0; doors[i].graphic != 0; i++)
+  {
+    int graphic = doors[i].graphic;
+    int *width  = doors[i].width;
+    int *height = doors[i].height;
+    boolean right_wing = doors[i].right_wing;
 
-    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);
+    struct FileInfo *fi = getImageListEntryFromImageID(graphic);
+    struct GraphicInfo *g = &graphic_info[graphic];
 
-    clip_gc_values.graphics_exposures = False;
-    clip_gc_values.clip_mask = graphic_info[i].clip_mask;
-    clip_gc_valuemask = GCGraphicsExposures | GCClipMask;
+    if (!fi->redefined)
+    {
+      if (*width != -1)
+      {
+       // correct start position for right wing of "standard" door graphic
+       if (right_wing)
+         g->src_x += g->width - *width;
 
-    graphic_info[i].clip_gc =
-      XCreateGC(display, window->drawable, clip_gc_valuemask, &clip_gc_values);
-#endif
+       g->width = *width;
+      }
+
+      if (*height != -1)
+       g->height = *height;
+    }
   }
+#endif
 
-#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
-  if (copy_clipmask_gc)
-    XFreeGC(display, copy_clipmask_gc);
+#if 0
+  for (i = 0; i < num_images; i++)
+  {
+    struct FileInfo *fi = getImageListEntryFromImageID(i);
 
-  clipmasks_initialized = TRUE;
+    if (i == IMG_GLOBAL_DOOR)
+    {
+      printf("::: %s, %s, %d\n",
+            fi->default_filename,
+            fi->filename,
+            fi->redefined);
+    }
+  }
 #endif
 }
 
@@ -2397,6 +2421,10 @@ static void ReinitializeGraphics()
 {
   print_timestamp_init("ReinitializeGraphics");
 
+#if NEW_GAME_TILESIZE
+  InitGfxTileSizeInfo(game.tile_size, TILESIZE);
+#endif
+
   InitGraphicInfo();                   /* graphic properties mapping */
   print_timestamp_time("InitGraphicInfo");
   InitElementGraphicInfo();            /* element game graphic mapping */
@@ -2414,6 +2442,9 @@ static void ReinitializeGraphics()
   InitGraphicInfo_EM();                        /* graphic mapping for EM engine */
   print_timestamp_time("InitGraphicInfo_EM");
 
+  InitGraphicCompatibilityInfo();
+  print_timestamp_time("InitGraphicCompatibilityInfo");
+
   SetMainBackgroundImage(IMG_BACKGROUND);
   print_timestamp_time("SetMainBackgroundImage");
   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
@@ -2423,6 +2454,8 @@ static void ReinitializeGraphics()
   print_timestamp_time("InitGadgets");
   InitToons();
   print_timestamp_time("InitToons");
+  InitDoors();
+  print_timestamp_time("InitDoors");
 
   print_timestamp_done("ReinitializeGraphics");
 }
@@ -2820,8 +2853,12 @@ void InitElementPropertiesStatic()
     EL_SIGN_FRANKIE,
     EL_STEEL_EXIT_CLOSED,
     EL_STEEL_EXIT_OPEN,
+    EL_STEEL_EXIT_OPENING,
+    EL_STEEL_EXIT_CLOSING,
     EL_EM_STEEL_EXIT_CLOSED,
     EL_EM_STEEL_EXIT_OPEN,
+    EL_EM_STEEL_EXIT_OPENING,
+    EL_EM_STEEL_EXIT_CLOSING,
     EL_DC_STEELWALL_1_LEFT,
     EL_DC_STEELWALL_1_RIGHT,
     EL_DC_STEELWALL_1_TOP,
@@ -3144,10 +3181,16 @@ 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,
@@ -4159,6 +4202,7 @@ void InitElementPropertiesStatic()
     EL_PLAYER_2,
     EL_PLAYER_3,
     EL_PLAYER_4,
+    EL_SOKOBAN_FIELD_PLAYER,
     EL_SP_MURPHY,
     EL_YAMYAM,
     EL_YAMYAM_LEFT,
@@ -4849,6 +4893,14 @@ void InitElementPropertiesEngine(int engine_version)
       -1
     };
 
+    static int ep_em_explodes_by_fire[] =
+    {
+      EL_EM_DYNAMITE,
+      EL_EM_DYNAMITE_ACTIVE,
+      EL_MOLE,
+      -1
+    };
+
     /* special EM style gems behaviour */
     for (i = 0; ep_em_slippery_wall[i] != -1; i++)
       SET_PROPERTY(ep_em_slippery_wall[i], EP_EM_SLIPPERY_WALL,
@@ -4858,6 +4910,11 @@ void InitElementPropertiesEngine(int engine_version)
     SET_PROPERTY(EL_EXPANDABLE_WALL_GROWING, EP_EM_SLIPPERY_WALL,
                 (level.em_slippery_gems &&
                  engine_version > VERSION_IDENT(2,0,1,0)));
+
+    /* special EM style explosion behaviour regarding chain reactions */
+    for (i = 0; ep_em_explodes_by_fire[i] != -1; i++)
+      SET_PROPERTY(ep_em_explodes_by_fire[i], EP_EXPLODES_BY_FIRE,
+                  level.em_explodes_by_fire);
   }
 
   /* this is needed because some graphics depend on element properties */
@@ -4884,6 +4941,18 @@ void InitElementPropertiesAfterLoading(int engine_version)
   }
 }
 
+void InitElementPropertiesGfxElement()
+{
+  int i;
+
+  for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+  {
+    struct ElementInfo *ei = &element_info[i];
+
+    ei->gfx_element = (ei->use_gfx_element ? ei->gfx_element_initial : i);
+  }
+}
+
 static void InitGlobal()
 {
   int graphic;
@@ -4921,7 +4990,8 @@ static void InitGlobal()
   /* create hash from graphic token list */
   graphic_token_hash = newSetupFileHash();
   for (graphic = 0, i = 0; image_config[i].token != NULL; i++)
-    if (strSuffix(image_config[i].value, ".pcx") ||
+    if (strSuffix(image_config[i].value, ".png") ||
+       strSuffix(image_config[i].value, ".pcx") ||
        strSuffix(image_config[i].value, ".wav") ||
        strEqual(image_config[i].value, UNDEFINED_FILENAME))
       setHashEntry(graphic_token_hash,
@@ -4987,6 +5057,8 @@ static void InitGlobal()
   global.fading_status = GAME_MODE_MAIN;
   global.fading_type = TYPE_ENTER_MENU;
 #endif
+
+  global.use_envelope_request = FALSE;
 }
 
 void Execute_Command(char *command)
@@ -5084,7 +5156,7 @@ void Execute_Command(char *command)
 
     exit(0);
   }
-  else if (strncmp(command, "dump level ", 11) == 0)
+  else if (strPrefix(command, "dump level "))
   {
     char *filename = &command[11];
 
@@ -5096,7 +5168,7 @@ void Execute_Command(char *command)
 
     exit(0);
   }
-  else if (strncmp(command, "dump tape ", 10) == 0)
+  else if (strPrefix(command, "dump tape "))
   {
     char *filename = &command[10];
 
@@ -5108,7 +5180,7 @@ void Execute_Command(char *command)
 
     exit(0);
   }
-  else if (strncmp(command, "autoplay ", 9) == 0)
+  else if (strPrefix(command, "autoplay "))
   {
     char *str_ptr = getStringCopy(&command[9]);        /* read command parameters */
 
@@ -5144,9 +5216,9 @@ void Execute_Command(char *command)
        str_ptr++;
     }
   }
-  else if (strncmp(command, "convert ", 8) == 0)
+  else if (strPrefix(command, "convert "))
   {
-    char *str_copy = getStringCopy(&command[8]);
+    char *str_copy = getStringCopy(strchr(command, ' ') + 1);
     char *str_ptr = strchr(str_copy, ' ');
 
     global.convert_leveldir = str_copy;
@@ -5158,21 +5230,66 @@ void Execute_Command(char *command)
       global.convert_level_nr = atoi(str_ptr); /* get level_nr value */
     }
   }
-  else if (strncmp(command, "create images ", 14) == 0)
+  else if (strPrefix(command, "create images "))
   {
-#if defined(TARGET_SDL)
     global.create_images_dir = getStringCopy(&command[14]);
 
     if (access(global.create_images_dir, W_OK) != 0)
       Error(ERR_EXIT, "image target directory '%s' not found or not writable",
            global.create_images_dir);
-#else
-    Error(ERR_EXIT, "command only available for SDL target");
-#endif
   }
 
 #if DEBUG
-#if defined(TARGET_SDL)
+#if defined(TARGET_SDL2)
+  else if (strEqual(command, "SDL_ListModes"))
+  {
+    SDL_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"))
   {
     SDL_Rect **modes;
@@ -5198,10 +5315,10 @@ void Execute_Command(char *command)
     }
     else
     {
-      printf("Available Modes:\n");
+      printf("Available display modes:\n");
 
-      for(i = 0; modes[i]; i++)
-       printf("  %d x %d\n", modes[i]->w, modes[i]->h);
+      for (i = 0; modes[i]; i++)
+       printf("- %d x %d\n", modes[i]->w, modes[i]->h);
     }
 
     exit(0);
@@ -5401,6 +5518,35 @@ static void InitMixer()
   StartMixer();
 }
 
+void InitGfxBuffers()
+{
+  /* 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);
+#if 0
+  ReCreateBitmap(&bitmap_db_door, 3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
+#endif
+  ReCreateBitmap(&bitmap_db_door_1, 3 * DXSIZE, DYSIZE, DEFAULT_DEPTH);
+  ReCreateBitmap(&bitmap_db_door_2, 3 * VXSIZE, VYSIZE, DEFAULT_DEPTH);
+  ReCreateBitmap(&bitmap_db_toons, FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
+
+  /* initialize screen properties */
+  InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
+                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
+                  bitmap_db_field);
+  InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
+  InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
+  InitGfxDoor3Info(EX, EY, EXSIZE, EYSIZE);
+  InitGfxWindowInfo(WIN_XSIZE, WIN_YSIZE);
+  InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
+  InitGfxClipRegion(FALSE, -1, -1, -1, -1);
+
+  InitGfxBuffers_EM();
+  InitGfxBuffers_SP();
+}
+
 void InitGfx()
 {
   struct GraphicInfo *graphic_info_last = graphic_info;
@@ -5447,20 +5593,7 @@ void InitGfx()
   if (filename_font_initial == NULL)   /* should not happen */
     Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
 
-  /* create additional image buffers for double-buffering and cross-fading */
-  bitmap_db_cross = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
-  bitmap_db_field = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
-  bitmap_db_panel = CreateBitmap(DXSIZE, DYSIZE, DEFAULT_DEPTH);
-  bitmap_db_door  = CreateBitmap(3 * DXSIZE, DYSIZE + VYSIZE, DEFAULT_DEPTH);
-  bitmap_db_toons = CreateBitmap(FULL_SXSIZE, FULL_SYSIZE, DEFAULT_DEPTH);
-
-  /* initialize screen properties */
-  InitGfxFieldInfo(SX, SY, SXSIZE, SYSIZE,
-                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
-                  bitmap_db_field);
-  InitGfxDoor1Info(DX, DY, DXSIZE, DYSIZE);
-  InitGfxDoor2Info(VX, VY, VXSIZE, VYSIZE);
-  InitGfxScrollbufferInfo(FXSIZE, FYSIZE);
+  InitGfxBuffers();
   InitGfxCustomArtworkInfo();
 
   bitmap_font_initial = LoadCustomImage(filename_font_initial);
@@ -5472,15 +5605,16 @@ void InitGfx()
 
   font_height = getFontHeight(FC_RED);
 
-#if 1
-  DrawInitText(getWindowTitleString(), 20, FC_YELLOW);
+#if 0
+  DrawInitTextAlways(getWindowTitleString(), 20, FC_YELLOW);
 #else
-  DrawInitText(getProgramInitString(), 20, FC_YELLOW);
+  DrawInitTextAlways(getProgramInitString(), 20, FC_YELLOW);
 #endif
-  DrawInitText(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
-  DrawInitText(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height, FC_RED);
+  DrawInitTextAlways(PROGRAM_COPYRIGHT_STRING, 50, FC_RED);
+  DrawInitTextAlways(PROGRAM_WEBSITE_STRING, WIN_YSIZE - 20 - font_height,
+                    FC_RED);
 
-  DrawInitText("Loading graphics", 120, FC_GREEN);
+  DrawInitTextAlways("Loading graphics", 120, FC_GREEN);
 
 #if 1
 #if 1
@@ -5574,6 +5708,9 @@ void InitGfx()
 
   InitMenuDesignSettings_Static();
   InitGfxDrawBusyAnimFunction(DrawInitAnim);
+
+  /* use copy of busy animation to prevent change while reloading artwork */
+  init_last = init;
 #endif
 }
 
@@ -6053,6 +6190,8 @@ void ReloadCustomArtwork(int force_reload)
 
   game_status = last_game_status;      /* restore current game status */
 
+  init_last = init;                    /* switch to new busy animation */
+
 #if 0
   printf("::: ----------------DELAY 1 ...\n");
   Delay(3000);
@@ -6091,6 +6230,8 @@ void ReloadCustomArtwork(int force_reload)
 #endif
 
   print_timestamp_done("ReloadCustomArtwork");
+
+  LimitScreenUpdates(FALSE);
 }
 
 void KeyboardAutoRepeatOffUnlessAutoplay()
@@ -6099,6 +6240,63 @@ void KeyboardAutoRepeatOffUnlessAutoplay()
     KeyboardAutoRepeatOff();
 }
 
+void DisplayExitMessage(char *format, va_list ap)
+{
+  // check if draw buffer and fonts for exit message are already available
+  if (drawto == NULL || font_initial[NUM_INITIAL_FONTS - 1].bitmap == NULL)
+    return;
+
+  int font_1 = FC_RED;
+  int font_2 = FC_YELLOW;
+  int font_3 = FC_BLUE;
+  int font_width = getFontWidth(font_2);
+  int font_height = getFontHeight(font_2);
+  int sx = SX;
+  int sy = SY;
+  int sxsize = WIN_XSIZE - 2 * sx;
+  int sysize = WIN_YSIZE - 2 * sy;
+  int line_length = sxsize / font_width;
+  int max_lines = sysize / font_height;
+  int num_lines_printed;
+
+  gfx.sx = sx;
+  gfx.sy = sy;
+  gfx.sxsize = sxsize;
+  gfx.sysize = sysize;
+
+  sy = 20;
+
+  ClearRectangle(drawto, 0, 0, WIN_XSIZE, WIN_YSIZE);
+
+  DrawTextSCentered(sy, font_1, "Fatal error:");
+  sy += 3 * font_height;;
+
+  num_lines_printed =
+    DrawTextBufferVA(sx, sy, format, ap, font_2,
+                    line_length, line_length, max_lines,
+                    0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
+  sy += (num_lines_printed + 3) * font_height;
+
+  DrawTextSCentered(sy, font_1, "For details, see the following error file:");
+  sy += 3 * font_height;
+
+  num_lines_printed =
+    DrawTextBuffer(sx, sy, program.error_filename, font_2,
+                  line_length, line_length, max_lines,
+                  0, BLIT_ON_BACKGROUND, TRUE, TRUE, FALSE);
+
+  DrawTextSCentered(SYSIZE - 20, font_3, "Press any key or button to exit");
+
+  redraw_mask = REDRAW_ALL;
+
+  BackToFront();
+
+  /* deactivate toons on error message screen */
+  setup.toons = FALSE;
+
+  WaitForEventToContinue();
+}
+
 
 /* ========================================================================= */
 /* OpenAll()                                                                 */
@@ -6110,8 +6308,14 @@ void OpenAll()
 
   game_status = GAME_MODE_LOADING;
 
+#if 1
+  InitCounter();
+#endif
+
   InitGlobal();                        /* initialize some global variables */
 
+  print_timestamp_time("[init global stuff]");
+
   if (options.execute_command)
     Execute_Command(options.execute_command);
 
@@ -6128,30 +6332,42 @@ void OpenAll()
 
   InitSetup();
 
+  print_timestamp_time("[init setup/config stuff (1)]");
+
   InitGameInfo();
+  print_timestamp_time("[init setup/config stuff (2)]");
   InitPlayerInfo();
+  print_timestamp_time("[init setup/config stuff (3)]");
   InitArtworkInfo();           /* needed before loading gfx, sound & music */
+  print_timestamp_time("[init setup/config stuff (4)]");
   InitArtworkConfig();         /* needed before forking sound child process */
+  print_timestamp_time("[init setup/config stuff (5)]");
   InitMixer();
+  print_timestamp_time("[init setup/config stuff (6)]");
 
+#if 0
   InitCounter();
+#endif
 
   InitRND(NEW_RANDOMIZE);
   InitSimpleRandom(NEW_RANDOMIZE);
 
   InitJoysticks();
 
-  print_timestamp_time("[pre-video]");
+  print_timestamp_time("[init setup/config stuff]");
 
   InitVideoDisplay();
   InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
 
-  InitEventFilter(FilterMouseMotionEvents);
+  InitEventFilter(FilterEvents);
+
+  print_timestamp_time("[init video stuff]");
 
   InitElementPropertiesStatic();
   InitElementPropertiesEngine(GAME_VERSION_ACTUAL);
+  InitElementPropertiesGfxElement();
 
-  print_timestamp_time("[post-video]");
+  print_timestamp_time("[init element properties stuff]");
 
   InitGfx();
 
@@ -6181,6 +6397,10 @@ void OpenAll()
   em_open_all();
 #endif
 
+#if 1
+  sp_open_all();
+#endif
+
   if (global.autoplay_leveldir)
   {
     AutoPlayTape();
@@ -6215,6 +6435,24 @@ void OpenAll()
   DrawMainMenu();
 
   InitNetworkServer();
+
+#if 0
+  Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
+       SDL_GetBasePath());
+  Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
+       SDL_GetPrefPath("artsoft", "rocksndiamonds"));
+#if defined(PLATFORM_ANDROID)
+  Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
+       SDL_AndroidGetInternalStoragePath());
+  Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
+       SDL_AndroidGetExternalStoragePath());
+  Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
+       (SDL_AndroidGetExternalStorageState() ==
+        SDL_ANDROID_EXTERNAL_STORAGE_READ ? "read" :
+        SDL_AndroidGetExternalStorageState() ==
+        SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "write" : "not available"));
+#endif
+#endif
 }
 
 void CloseAllAndExit(int exit_value)
@@ -6228,18 +6466,35 @@ void CloseAllAndExit(int exit_value)
   em_close_all();
 #endif
 
+#if 1
+  sp_close_all();
+#endif
+
   FreeAllImages();
 
 #if defined(TARGET_SDL)
+#if defined(TARGET_SDL2)
+  // !!! TODO !!!
+  // set a flag to tell the network server thread to quit and wait for it
+  // using SDL_WaitThread()
+#else
   if (network_server)  /* terminate network server */
     SDL_KillThread(server_thread);
+#endif
 #endif
 
   CloseVideoDisplay();
   ClosePlatformDependentStuff();
 
   if (exit_value != 0)
-    NotifyUserAboutErrorFile();
+  {
+    /* fall back to default level set (current set may have caused an error) */
+    SaveLevelSetup_LastSeries_Deactivate();
+
+    /* tell user where to find error log file which may contain more details */
+    // (error notification now directly displayed on screen inside R'n'D
+    // NotifyUserAboutErrorFile();     /* currently only works for Windows */
+  }
 
   exit(exit_value);
 }