changed using improved pseudo-random number generator for UUID generation
[rocksndiamonds.git] / src / init.c
index 19c91ca787844c09114d0f2317cb44970224c747..114b177fb1578c19f30248069d85bf6a23acb350 100644 (file)
@@ -4,7 +4,7 @@
 // (c) 1995-2014 by Artsoft Entertainment
 //                         Holger Schemel
 //                 info@artsoft.org
-//                 http://www.artsoft.org/
+//                 https://www.artsoft.org/
 // ----------------------------------------------------------------------------
 // init.c
 // ============================================================================
@@ -77,6 +77,11 @@ static int copy_properties[][5] =
     EL_MOLE_LEFT,              EL_MOLE_RIGHT,
     EL_MOLE_UP,                        EL_MOLE_DOWN
   },
+  {
+    EL_SPRING,
+    EL_SPRING_LEFT,            EL_SPRING_RIGHT,
+    EL_SPRING_LEFT,            EL_SPRING_RIGHT,        // (to match array size)
+  },
   {
     -1,
     -1, -1, -1, -1
@@ -318,23 +323,6 @@ void InitImageTextures(void)
     CreateImageTextures(texture_graphics[i]);
 }
 
-#if 1
-// !!! FIX THIS (CHANGE TO USING NORMAL ELEMENT GRAPHIC DEFINITIONS) !!!
-void SetBitmaps_EM(Bitmap **em_bitmap)
-{
-  em_bitmap[0] = graphic_info[IMG_EMC_OBJECT].bitmap;
-  em_bitmap[1] = graphic_info[IMG_EMC_SPRITE].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;
@@ -345,6 +333,8 @@ static int getFontBitmapID(int font_nr)
     special = game_status;
   else if (game_status == GAME_MODE_PSEUDO_TYPENAME)
     special = GFX_SPECIAL_ARG_MAIN;
+  else if (game_status == GAME_MODE_PSEUDO_TYPENAMES)
+    special = GFX_SPECIAL_ARG_NAMES;
 
   if (special != -1)
     return font_info[font_nr].special_bitmap_id[special];
@@ -662,15 +652,14 @@ static void InitGlobalAnimGraphicInfo(void)
   }
 
 #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]);
+         Debug("init:InitGlobalAnimGraphicInfo",
+               "anim %d, part %d, mode %d => %d",
+               i, j, k, global_anim_info[i].graphic[j][k]);
 #endif
 }
 
@@ -712,14 +701,13 @@ static void InitGlobalAnimSoundInfo(void)
   }
 
 #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]);
+         Debug("init:InitGlobalAnimSoundInfo",
+               "anim %d, part %d, mode %d => %d",
+               i, j, k, global_anim_info[i].sound[j][k]);
 #endif
 }
 
@@ -761,14 +749,13 @@ static void InitGlobalAnimMusicInfo(void)
   }
 
 #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]);
+         Debug("init:InitGlobalAnimMusicInfo",
+               "anim %d, part %d, mode %d => %d",
+               i, j, k, global_anim_info[i].music[j][k]);
 #endif
 }
 
@@ -1236,13 +1223,13 @@ static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
 
     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, "-");
+      Warn("---");
+      Warn("error found in config file:");
+      Warn("- config file: '%s'", getImageConfigFilename());
+      Warn("error: invalid element token '%s'", value_raw);
+      Warn("custom graphic rejected for this element/action");
+      Warn("fallback done to undefined element for this graphic");
+      Warn("---");
     }
 
     return (value != NULL ? atoi(value) : EL_UNDEFINED);
@@ -1254,13 +1241,13 @@ static int get_graphic_parameter_value(char *value_raw, char *suffix, int type)
 
     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, "-");
+      Warn("---");
+      Warn("error found in config file:");
+      Warn("- config file: '%s'", getImageConfigFilename());
+      Warn("error: invalid graphic token '%s'", value_raw);
+      Warn("custom graphic rejected for this element/action");
+      Warn("fallback done to 'char_exclam' for this graphic");
+      Warn("---");
     }
 
     return (value != NULL ? atoi(value) : fallback_graphic);
@@ -1391,20 +1378,20 @@ static void set_graphic_parameters_ext(int graphic, int *parameter,
   {
     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, "-");
+      Warn("---");
+      Warn("invalid value %d for '%s.width' (fallback done to %d)",
+          g->width, getTokenFromImageID(graphic), TILEX);
+      Warn("---");
 
       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, "-");
+      Warn("---");
+      Warn("invalid value %d for '%s.height' (fallback done to %d)",
+          g->height, getTokenFromImageID(graphic), TILEY);
+      Warn("---");
 
       g->height = TILEY;       // will be checked to be inside bitmap later
     }
@@ -1662,18 +1649,18 @@ static void set_cloned_graphic_parameters(int graphic)
 
   if (num_references_followed >= max_num_images)
   {
-    Error(ERR_INFO_LINE, "-");
-    Error(ERR_INFO, "warning: error found in config file:");
-    Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
-    Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(graphic));
-    Error(ERR_INFO, "error: loop discovered when resolving cloned graphics");
-    Error(ERR_INFO, "custom graphic rejected for this element/action");
+    Warn("---");
+    Warn("error found in config file:");
+    Warn("- config file: '%s'", getImageConfigFilename());
+    Warn("- config token: '%s'", getTokenFromImageID(graphic));
+    Warn("error: loop discovered when resolving cloned graphics");
+    Warn("custom graphic rejected for this element/action");
 
     if (graphic == fallback_graphic)
-      Error(ERR_EXIT, "no fallback graphic available");
+      Fail("no fallback graphic available");
 
-    Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
-    Error(ERR_INFO_LINE, "-");
+    Warn("fallback done to 'char_exclam' for this graphic");
+    Warn("---");
 
     graphic_info[graphic] = graphic_info[fallback_graphic];
   }
@@ -1710,6 +1697,7 @@ static void InitGraphicInfo(void)
     IMG_BACKGROUND_TITLE_INITIAL,
     IMG_BACKGROUND_TITLE,
     IMG_BACKGROUND_MAIN,
+    IMG_BACKGROUND_NAMES,
     IMG_BACKGROUND_LEVELS,
     IMG_BACKGROUND_LEVELNR,
     IMG_BACKGROUND_SCORES,
@@ -1812,22 +1800,21 @@ static void InitGraphicInfo(void)
        src_x + width  > src_bitmap_width ||
        src_y + height > src_bitmap_height)
     {
-      Error(ERR_INFO_LINE, "-");
-      Error(ERR_INFO, "warning: error found in config file:");
-      Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
-      Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
-      Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
-      Error(ERR_INFO, "- 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");
+      Warn("---");
+      Warn("error found in config file:");
+      Warn("- config file: '%s'", getImageConfigFilename());
+      Warn("- config token: '%s'", getTokenFromImageID(i));
+      Warn("- image file: '%s'", src_bitmap->source_filename);
+      Warn("- frame size: %d, %d", width, height);
+      Warn("error: first animation frame out of bounds (%d, %d) [%d, %d]",
+          src_x, src_y, src_bitmap_width, src_bitmap_height);
+      Warn("custom graphic rejected for this element/action");
 
       if (i == fallback_graphic)
-       Error(ERR_EXIT, "no fallback graphic available");
+       Fail("no fallback graphic available");
 
-      Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
-      Error(ERR_INFO_LINE, "-");
+      Warn("fallback done to 'char_exclam' for this graphic");
+      Warn("---");
 
       graphic_info[i] = graphic_info[fallback_graphic];
 
@@ -1844,22 +1831,21 @@ static void InitGraphicInfo(void)
        src_x + width  > src_bitmap_width ||
        src_y + height > src_bitmap_height)
     {
-      Error(ERR_INFO_LINE, "-");
-      Error(ERR_INFO, "warning: error found in config file:");
-      Error(ERR_INFO, "- config file: '%s'", getImageConfigFilename());
-      Error(ERR_INFO, "- config token: '%s'", getTokenFromImageID(i));
-      Error(ERR_INFO, "- image file: '%s'", src_bitmap->source_filename);
-      Error(ERR_INFO, "- 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, "custom graphic rejected for this element/action");
+      Warn("---");
+      Warn("error found in config file:");
+      Warn("- config file: '%s'", getImageConfigFilename());
+      Warn("- config token: '%s'", getTokenFromImageID(i));
+      Warn("- image file: '%s'", src_bitmap->source_filename);
+      Warn("- frame size: %d, %d", width, height);
+      Warn("error: last animation frame (%d) out of bounds (%d, %d) [%d, %d]",
+          last_frame, src_x, src_y, src_bitmap_width, src_bitmap_height);
+      Warn("custom graphic rejected for this element/action");
 
       if (i == fallback_graphic)
-       Error(ERR_EXIT, "no fallback graphic available");
+       Fail("no fallback graphic available");
 
-      Error(ERR_INFO, "fallback done to 'char_exclam' for this graphic");
-      Error(ERR_INFO_LINE, "-");
+      Warn("fallback done to 'char_exclam' for this graphic");
+      Warn("---");
 
       graphic_info[i] = graphic_info[fallback_graphic];
     }
@@ -1896,7 +1882,10 @@ static void InitGraphicCompatibilityInfo(void)
        // 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);
+#if 0
+         Debug("init:InitGraphicCompatibilityInfo",
+               "special treatment needed for token '%s'", fi->token);
+#endif
 
          graphic_info[i].bitmaps = graphic_info[IMG_GLOBAL_DOOR].bitmaps;
          graphic_info[i].bitmap  = graphic_info[IMG_GLOBAL_DOOR].bitmap;
@@ -2374,6 +2363,8 @@ static int get_special_property_bit(int element, int property_bit_nr)
     { EL_SP_ELECTRON,          15      },
     { EL_BALLOON,              16      },
     { EL_SPRING,               17      },
+    { EL_SPRING_LEFT,          17      },
+    { EL_SPRING_RIGHT,         17      },
     { EL_EMC_ANDROID,          18      },
 
     { -1,                      -1      },
@@ -2452,7 +2443,7 @@ static void ResolveGroupElementExt(int group_element, int recursion_depth)
 
   if (recursion_depth > NUM_GROUP_ELEMENTS)    // recursion too deep
   {
-    Error(ERR_WARN, "recursion too deep when resolving group element %d",
+    Warn("recursion too deep when resolving group element %d",
          group_element - EL_GROUP_START + 1);
 
     // replace element which caused too deep recursion by question mark
@@ -2879,6 +2870,7 @@ void InitElementPropertiesStatic(void)
     EL_BOMB,
     EL_NUT,
     EL_AMOEBA_DROP,
+    EL_AMOEBA_DROPPING,
     EL_QUICKSAND_FULL,
     EL_QUICKSAND_FAST_FULL,
     EL_MAGIC_WALL_FULL,
@@ -4672,7 +4664,7 @@ void InitElementPropertiesEngine(int engine_version)
                                                  i == EL_BLACK_ORB));
 
     // ---------- COULD_MOVE_INTO_ACID ----------------------------------------
-    SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
+    SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (IS_PLAYER_ELEMENT(i) ||
                                              CAN_MOVE(i) ||
                                              IS_CUSTOM_ELEMENT(i)));
 
@@ -4793,7 +4785,7 @@ static void InitGlobal(void)
   {
     // check if element_name_info entry defined for each element in "main.h"
     if (i < MAX_NUM_ELEMENTS && element_name_info[i].token_name == NULL)
-      Error(ERR_EXIT, "undefined 'element_name_info' entry for element %d", i);
+      Fail("undefined 'element_name_info' entry for element %d", i);
 
     element_info[i].token_name = element_name_info[i].token_name;
     element_info[i].class_name = element_name_info[i].class_name;
@@ -4805,7 +4797,7 @@ static void InitGlobal(void)
     // check if global_anim_name_info defined for each entry in "main.h"
     if (i < NUM_GLOBAL_ANIM_TOKENS &&
        global_anim_name_info[i].token_name == NULL)
-      Error(ERR_EXIT, "undefined 'global_anim_name_info' entry for anim %d", i);
+      Fail("undefined 'global_anim_name_info' entry for anim %d", i);
 
     global_anim_info[i].token_name = global_anim_name_info[i].token_name;
   }
@@ -4909,8 +4901,12 @@ static void InitGlobal(void)
   }
 
   global.autoplay_leveldir = NULL;
+  global.patchtapes_leveldir = NULL;
   global.convert_leveldir = NULL;
-  global.create_images_dir = NULL;
+  global.dumplevel_leveldir = NULL;
+  global.dumptape_leveldir = NULL;
+  global.create_sketch_images_dir = NULL;
+  global.create_collect_images_dir = NULL;
 
   global.frames_per_second = 0;
   global.show_frames_per_second = FALSE;
@@ -4919,6 +4915,8 @@ static void InitGlobal(void)
   global.anim_status = global.anim_status_next = GAME_MODE_LOADING;
 
   global.use_envelope_request = FALSE;
+
+  global.user_names = NULL;
 }
 
 static void Execute_Command(char *command)
@@ -5020,38 +5018,71 @@ static void Execute_Command(char *command)
   {
     char *filename = &command[11];
 
-    if (!fileExists(filename))
-      Error(ERR_EXIT, "cannot open file '%s'", filename);
+    if (fileExists(filename))
+    {
+      LoadLevelFromFilename(&level, filename);
+      DumpLevel(&level);
+
+      exit(0);
+    }
+
+    char *leveldir = getStringCopy(filename);  // read command parameters
+    char *level_nr = strchr(leveldir, ' ');
 
-    LoadLevelFromFilename(&level, filename);
-    DumpLevel(&level);
+    if (level_nr == NULL)
+      Fail("cannot open file '%s'", filename);
 
-    exit(0);
+    *level_nr++ = '\0';
+
+    global.dumplevel_leveldir = leveldir;
+    global.dumplevel_level_nr = atoi(level_nr);
+
+    program.headless = TRUE;
   }
   else if (strPrefix(command, "dump tape "))
   {
     char *filename = &command[10];
 
-    if (!fileExists(filename))
-      Error(ERR_EXIT, "cannot open file '%s'", filename);
+    if (fileExists(filename))
+    {
+      LoadTapeFromFilename(filename);
+      DumpTape(&tape);
 
-    LoadTapeFromFilename(filename);
-    DumpTape(&tape);
+      exit(0);
+    }
 
-    exit(0);
+    char *leveldir = getStringCopy(filename);  // read command parameters
+    char *level_nr = strchr(leveldir, ' ');
+
+    if (level_nr == NULL)
+      Fail("cannot open file '%s'", filename);
+
+    *level_nr++ = '\0';
+
+    global.dumptape_leveldir = leveldir;
+    global.dumptape_level_nr = atoi(level_nr);
+
+    program.headless = TRUE;
   }
-  else if (strPrefix(command, "autotest ") ||
-          strPrefix(command, "autoplay ") ||
+  else if (strPrefix(command, "autoplay ") ||
           strPrefix(command, "autoffwd ") ||
-          strPrefix(command, "autowarp "))
+          strPrefix(command, "autowarp ") ||
+          strPrefix(command, "autotest ") ||
+          strPrefix(command, "autosave ") ||
+          strPrefix(command, "autoupload ") ||
+          strPrefix(command, "autofix "))
   {
-    char *str_ptr = getStringCopy(&command[9]);        // read command parameters
+    char *arg_ptr = strchr(command, ' ');
+    char *str_ptr = getStringCopy(arg_ptr);    // read command parameters
 
     global.autoplay_mode =
-      (strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
-       strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
+      (strPrefix(command, "autoplay") ? AUTOPLAY_MODE_PLAY :
        strPrefix(command, "autoffwd") ? AUTOPLAY_MODE_FFWD :
        strPrefix(command, "autowarp") ? AUTOPLAY_MODE_WARP :
+       strPrefix(command, "autotest") ? AUTOPLAY_MODE_TEST :
+       strPrefix(command, "autosave") ? AUTOPLAY_MODE_SAVE :
+       strPrefix(command, "autoupload") ? AUTOPLAY_MODE_UPLOAD :
+       strPrefix(command, "autofix")  ? AUTOPLAY_MODE_FIX :
        AUTOPLAY_MODE_NONE);
 
     while (*str_ptr != '\0')                   // continue parsing string
@@ -5086,9 +5117,68 @@ static void Execute_Command(char *command)
        str_ptr++;
     }
 
-    if (global.autoplay_mode == AUTOPLAY_MODE_TEST)
+    if (global.autoplay_mode & AUTOPLAY_WARP_NO_DISPLAY)
       program.headless = TRUE;
   }
+  else if (strPrefix(command, "patch tapes "))
+  {
+    char *str_ptr = getStringCopy(&command[12]); // read command parameters
+
+    // skip leading whitespace
+    while (*str_ptr == ' ' || *str_ptr == '\t')
+      str_ptr++;
+
+    if (*str_ptr == '\0')
+      Fail("cannot find MODE in command '%s'", command);
+
+    global.patchtapes_mode = str_ptr;          // store patch mode
+
+    // advance to next whitespace (or end of string)
+    while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
+      str_ptr++;
+
+    while (*str_ptr != '\0')                   // continue parsing string
+    {
+      // cut leading whitespace from string, replace it by string terminator
+      while (*str_ptr == ' ' || *str_ptr == '\t')
+       *str_ptr++ = '\0';
+
+      if (*str_ptr == '\0')                    // end of string reached
+       break;
+
+      if (global.patchtapes_leveldir == NULL)  // read level set string
+      {
+       global.patchtapes_leveldir = str_ptr;
+       global.patchtapes_all = TRUE;           // default: patch all tapes
+
+       for (i = 0; i < MAX_TAPES_PER_SET; i++)
+         global.patchtapes_level[i] = FALSE;
+      }
+      else                                     // read level number string
+      {
+       int level_nr = atoi(str_ptr);           // get level_nr value
+
+       if (level_nr >= 0 && level_nr < MAX_TAPES_PER_SET)
+         global.patchtapes_level[level_nr] = TRUE;
+
+       global.patchtapes_all = FALSE;
+      }
+
+      // advance string pointer to the next whitespace (or end of string)
+      while (*str_ptr != ' ' && *str_ptr != '\t' && *str_ptr != '\0')
+       str_ptr++;
+    }
+
+    if (global.patchtapes_leveldir == NULL)
+    {
+      if (strEqual(global.patchtapes_mode, "help"))
+       global.patchtapes_leveldir = UNDEFINED_LEVELSET;
+      else
+       Fail("cannot find LEVELDIR in command '%s'", command);
+    }
+
+    program.headless = TRUE;
+  }
   else if (strPrefix(command, "convert "))
   {
     char *str_copy = getStringCopy(strchr(command, ' ') + 1);
@@ -5105,13 +5195,21 @@ static void Execute_Command(char *command)
 
     program.headless = TRUE;
   }
-  else if (strPrefix(command, "create images "))
+  else if (strPrefix(command, "create sketch images "))
+  {
+    global.create_sketch_images_dir = getStringCopy(&command[21]);
+
+    if (access(global.create_sketch_images_dir, W_OK) != 0)
+      Fail("image target directory '%s' not found or not writable",
+          global.create_sketch_images_dir);
+  }
+  else if (strPrefix(command, "create collect image "))
   {
-    global.create_images_dir = getStringCopy(&command[14]);
+    global.create_collect_images_dir = getStringCopy(&command[21]);
 
-    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);
+    if (access(global.create_collect_images_dir, W_OK) != 0)
+      Fail("image target directory '%s' not found or not writable",
+          global.create_collect_images_dir);
   }
   else if (strPrefix(command, "create CE image "))
   {
@@ -5121,7 +5219,7 @@ static void Execute_Command(char *command)
   }
   else
   {
-    Error(ERR_EXIT_HELP, "unrecognized command '%s'", command);
+    FailWithHelp("unrecognized command '%s'", command);
   }
 
   // disable networking if any valid command was recognized
@@ -5130,8 +5228,10 @@ static void Execute_Command(char *command)
 
 static void InitSetup(void)
 {
+  LoadUserNames();                             // global user names
+  LoadUserSetup();                             // global user number
+
   LoadSetup();                                 // global setup info
-  LoadSetup_AutoSetup();                       // global auto setup info
 
   // set some options from setup file
 
@@ -5146,7 +5246,9 @@ static void InitGameInfo(void)
 {
   game.restart_level = FALSE;
   game.restart_game_message = NULL;
+
   game.request_active = FALSE;
+  game.request_active_or_moving = FALSE;
 }
 
 static void InitPlayerInfo(void)
@@ -5412,7 +5514,7 @@ static void InitGfx(void)
   }
 
   if (filename_font_initial == NULL)   // should not happen
-    Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
+    Fail("cannot get filename for '%s'", CONFIG_TOKEN_FONT_INITIAL);
 
   InitGfxBuffers();
   InitGfxCustomArtworkInfo();
@@ -5427,7 +5529,7 @@ static void InitGfx(void)
 
   DrawProgramInfo();
 
-  DrawInitText("Loading graphics", 120, FC_GREEN);
+  DrawInitTextHead("Loading graphics");
 
   // initialize settings for busy animation with default values
   int parameter[NUM_GFX_ARGS];
@@ -5498,7 +5600,7 @@ static void InitGfx(void)
   }
 
   if (filename_anim_initial == NULL)   // should not happen
-    Error(ERR_EXIT, "cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
+    Fail("cannot get filename for '%s'", CONFIG_TOKEN_GLOBAL_BUSY);
 
   anim_initial.bitmaps =
     checked_calloc(sizeof(Bitmap *) * NUM_IMG_BITMAP_POINTERS);
@@ -5570,36 +5672,36 @@ static void InitImages(void)
   print_timestamp_init("InitImages");
 
 #if 0
-  printf("::: leveldir_current->identifier == '%s'\n",
-        leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
-  printf("::: leveldir_current->graphics_path == '%s'\n",
-        leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
-  printf("::: leveldir_current->graphics_set == '%s'\n",
-        leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
-  printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
-        leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
+  Debug("init:InitImages", "leveldir_current->identifier == '%s'",
+       leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
+  Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
+       leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
+  Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
+       leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
+  Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
+       leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
 #endif
 
   setLevelArtworkDir(artwork.gfx_first);
 
 #if 0
-  printf("::: leveldir_current->identifier == '%s'\n",
-        leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
-  printf("::: leveldir_current->graphics_path == '%s'\n",
-        leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
-  printf("::: leveldir_current->graphics_set == '%s'\n",
+  Debug("init:InitImages", "leveldir_current->identifier == '%s'",
+       leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
+  Debug("init:InitImages", "leveldir_current->graphics_path == '%s'",
+       leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
+  Debug("init:InitImages", "leveldir_current->graphics_set == '%s'",
         leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
-  printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
-        leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
+  Debug("init:InitImages", "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
+       leveldir_current == NULL ? "[NULL]" : LEVELDIR_ARTWORK_SET(leveldir_current, ARTWORK_TYPE_GRAPHICS));
 #endif
 
 #if 0
-  printf("::: InitImages for '%s' ['%s', '%s'] ['%s', '%s']\n",
-        leveldir_current->identifier,
-        artwork.gfx_current_identifier,
-        artwork.gfx_current->identifier,
-        leveldir_current->graphics_set,
-        leveldir_current->graphics_path);
+  Debug("init:InitImages", "InitImages for '%s' ['%s', '%s'] ['%s', '%s']",
+       leveldir_current->identifier,
+       artwork.gfx_current_identifier,
+       artwork.gfx_current->identifier,
+       leveldir_current->graphics_set,
+       leveldir_current->graphics_path);
 #endif
 
   UPDATE_BUSY_STATE();
@@ -5758,22 +5860,27 @@ static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
   setLevelArtworkDir(ARTWORK_FIRST_NODE(artwork, type));
 
 #if 0
-  printf("::: leveldir_current->identifier == '%s'\n",
-        leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
-  printf("::: leveldir_current->graphics_path == '%s'\n",
-        leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
-  printf("::: leveldir_current->graphics_set == '%s'\n",
-        leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
-  printf("::: getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'\n",
-        leveldir_current == NULL ? "[NULL]" :
-        LEVELDIR_ARTWORK_SET(leveldir_current, type));
+  Debug("init:CheckArtworkTypeForRedefinedCustomElements",
+       "leveldir_current->identifier == '%s'",
+       leveldir_current == NULL ? "[NULL]" : leveldir_current->identifier);
+  Debug("init:CheckArtworkTypeForRedefinedCustomElements",
+       "leveldir_current->graphics_path == '%s'",
+       leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_path);
+  Debug("init:CheckArtworkTypeForRedefinedCustomElements",
+       "leveldir_current->graphics_set == '%s'",
+       leveldir_current == NULL ? "[NULL]" : leveldir_current->graphics_set);
+  Debug("init:CheckArtworkTypeForRedefinedCustomElements",
+       "getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) == '%s'",
+       leveldir_current == NULL ? "[NULL]" :
+       LEVELDIR_ARTWORK_SET(leveldir_current, type));
 #endif
 
   // first look for special artwork configured in level series config
   filename_base = getCustomArtworkLevelConfigFilename(type);
 
 #if 0
-  printf("::: filename_base == '%s'\n", filename_base);
+  Debug("init:CheckArtworkTypeForRedefinedCustomElements",
+       "filename_base == '%s'", filename_base);
 #endif
 
   if (fileExists(filename_base))
@@ -5782,14 +5889,16 @@ static boolean CheckArtworkTypeForRedefinedCustomElements(int type)
   filename_local = getCustomArtworkConfigFilename(type);
 
 #if 0
-  printf("::: filename_local == '%s'\n", filename_local);
+  Debug("init:CheckArtworkTypeForRedefinedCustomElements",
+       "filename_local == '%s'", filename_local);
 #endif
 
   if (filename_local != NULL && !strEqual(filename_base, filename_local))
     redefined_ce_found |= CheckArtworkConfigForCustomElements(filename_local);
 
 #if 0
-  printf("::: redefined_ce_found == %d\n", redefined_ce_found);
+  Debug("init:CheckArtworkTypeForRedefinedCustomElements",
+       "redefined_ce_found == %d", redefined_ce_found);
 #endif
 
   return redefined_ce_found;
@@ -5814,7 +5923,8 @@ static void InitOverrideArtwork(void)
        CheckArtworkTypeForRedefinedCustomElements(ARTWORK_TYPE_MUSIC));
 
 #if 0
-  printf("::: redefined_ce_found == %d\n", redefined_ce_found);
+  Debug("init:InitOverrideArtwork", "redefined_ce_found == %d",
+       redefined_ce_found);
 #endif
 
   if (redefined_ce_found)
@@ -5833,16 +5943,17 @@ static void InitOverrideArtwork(void)
   }
 
 #if 0
-  printf("::: => %d, %d, %d\n",
-        gfx.override_level_graphics,
-        gfx.override_level_sounds,
-        gfx.override_level_music);
+  Debug("init:InitOverrideArtwork", "%d, %d, %d",
+       gfx.override_level_graphics,
+       gfx.override_level_sounds,
+       gfx.override_level_music);
 #endif
 }
 
 static char *getNewArtworkIdentifier(int type)
 {
-  static char *leveldir_current_identifier[3] = { NULL, NULL, NULL };
+  static char *last_leveldir_identifier[3] = { NULL, NULL, NULL };
+  static char *last_artwork_identifier[3] = { NULL, NULL, NULL };
   static boolean last_override_level_artwork[3] = { FALSE, FALSE, FALSE };
   static boolean last_has_level_artwork_set[3] = { FALSE, FALSE, FALSE };
   static boolean initialized[3] = { FALSE, FALSE, FALSE };
@@ -5877,16 +5988,15 @@ static char *getNewArtworkIdentifier(int type)
   else
     artwork_current_identifier = setup_artwork_set;
 
-
   /* 2nd step: check if it is really needed to reload artwork set
      ------------------------------------------------------------ */
 
   // ---------- reload if level set and also artwork set has changed ----------
-  if (leveldir_current_identifier[type] != leveldir_identifier &&
+  if (last_leveldir_identifier[type] != leveldir_identifier &&
       (last_has_level_artwork_set[type] || has_level_artwork_set))
     artwork_new_identifier = artwork_current_identifier;
 
-  leveldir_current_identifier[type] = leveldir_identifier;
+  last_leveldir_identifier[type] = leveldir_identifier;
   last_has_level_artwork_set[type] = has_level_artwork_set;
 
   // ---------- reload if "override artwork" setting has changed --------------
@@ -5896,11 +6006,13 @@ static char *getNewArtworkIdentifier(int type)
   last_override_level_artwork[type] = setup_override_artwork;
 
   // ---------- reload if current artwork identifier has changed --------------
-  if (!strEqual(ARTWORK_CURRENT_IDENTIFIER(artwork, type),
-               artwork_current_identifier))
+  if (!strEqual(last_artwork_identifier[type], artwork_current_identifier))
     artwork_new_identifier = artwork_current_identifier;
 
-  *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type))= artwork_current_identifier;
+  // (we cannot compare string pointers here, so copy string content itself)
+  setString(&last_artwork_identifier[type], artwork_current_identifier);
+
+  *(ARTWORK_CURRENT_IDENTIFIER_PTR(artwork, type)) = artwork_current_identifier;
 
   // ---------- do not reload directly after starting -------------------------
   if (!initialized[type])
@@ -5924,7 +6036,8 @@ void ReloadCustomArtwork(int force_reload)
 
   InitOverrideArtwork();
 
-  force_reload_gfx |= AdjustGraphicsForEMC();
+  AdjustGraphicsForEMC();
+  AdjustSoundsForEMC();
 
   gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
   snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
@@ -5951,11 +6064,12 @@ void ReloadCustomArtwork(int force_reload)
   if (gfx_new_identifier != NULL || force_reload_gfx)
   {
 #if 0
-    printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
-          artwork.gfx_current_identifier,
-          gfx_new_identifier,
-          artwork.gfx_current->identifier,
-          leveldir_current->graphics_set);
+    Debug("init:ReloadCustomArtwork",
+         "RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']",
+         artwork.gfx_current_identifier,
+         gfx_new_identifier,
+         artwork.gfx_current->identifier,
+         leveldir_current->graphics_set);
 #endif
 
     InitImages();
@@ -6081,14 +6195,16 @@ void OpenAll(void)
 
   InitGlobal();                        // initialize some global variables
 
+  InitRND(NEW_RANDOMIZE);
+  InitSimpleRandom(NEW_RANDOMIZE);
+  InitBetterRandom(NEW_RANDOMIZE);
+
   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);
 
@@ -6101,7 +6217,7 @@ void OpenAll(void)
 #if defined(PLATFORM_UNIX)
     NetworkServer(network.server_port, TRUE);
 #else
-    Error(ERR_WARN, "networking only supported in Unix version");
+    Warn("networking only supported in Unix version");
 #endif
 
     exit(0);                   // never reached, server loops forever
@@ -6118,9 +6234,6 @@ void OpenAll(void)
   InitMixer();
   print_timestamp_time("[init setup/config stuff (6)]");
 
-  InitRND(NEW_RANDOMIZE);
-  InitSimpleRandom(NEW_RANDOMIZE);
-
   InitJoysticks();
 
   print_timestamp_time("[init setup/config stuff]");
@@ -6172,7 +6285,12 @@ void OpenAll(void)
 
   if (global.autoplay_leveldir)
   {
-    AutoPlayTape();
+    AutoPlayTapes();
+    return;
+  }
+  else if (global.patchtapes_leveldir)
+  {
+    PatchTapes();
     return;
   }
   else if (global.convert_leveldir)
@@ -6180,11 +6298,26 @@ void OpenAll(void)
     ConvertLevels();
     return;
   }
-  else if (global.create_images_dir)
+  else if (global.dumplevel_leveldir)
+  {
+    DumpLevels();
+    return;
+  }
+  else if (global.dumptape_leveldir)
+  {
+    DumpTapes();
+    return;
+  }
+  else if (global.create_sketch_images_dir)
   {
     CreateLevelSketchImages();
     return;
   }
+  else if (global.create_collect_images_dir)
+  {
+    CreateCollectElementImages();
+    return;
+  }
 
   InitNetworkServer();
 
@@ -6198,19 +6331,22 @@ void OpenAll(void)
 
   print_timestamp_done("OpenAll");
 
+  if (setup.ask_for_remaining_tapes)
+    setup.ask_for_uploading_tapes = TRUE;
+
   DrawMainMenu();
 
 #if 0
-  Error(ERR_DEBUG, "::: SDL_GetBasePath() == '%s'",
+  Debug("internal:path", "SDL_GetBasePath() == '%s'",
        SDL_GetBasePath());
-  Error(ERR_DEBUG, "::: SDL_GetPrefPath() == '%s'",
+  Debug("internal:path", "SDL_GetPrefPath() == '%s'",
        SDL_GetPrefPath("artsoft", "rocksndiamonds"));
 #if defined(PLATFORM_ANDROID)
-  Error(ERR_DEBUG, "::: SDL_AndroidGetInternalStoragePath() == '%s'",
+  Debug("internal:path", "SDL_AndroidGetInternalStoragePath() == '%s'",
        SDL_AndroidGetInternalStoragePath());
-  Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStoragePath() == '%s'",
+  Debug("internal:path", "SDL_AndroidGetExternalStoragePath() == '%s'",
        SDL_AndroidGetExternalStoragePath());
-  Error(ERR_DEBUG, "::: SDL_AndroidGetExternalStorageState() == '%s'",
+  Debug("internal:path", "SDL_AndroidGetExternalStorageState() == '%s'",
        (SDL_AndroidGetExternalStorageState() &
         SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? "writable" :
         SDL_AndroidGetExternalStorageState() &
@@ -6219,8 +6355,44 @@ void OpenAll(void)
 #endif
 }
 
+static boolean WaitForApiThreads(void)
+{
+  unsigned int thread_delay = 0;
+  unsigned int thread_delay_value = 10000;
+
+  if (program.api_thread_count == 0)
+    return TRUE;
+
+  // deactivate global animations (not accessible in game state "loading")
+  setup.toons = FALSE;
+
+  // set game state to "loading" to be able to show busy animation
+  SetGameStatus(GAME_MODE_LOADING);
+
+  ResetDelayCounter(&thread_delay);
+
+  // wait for threads to finish (and fail on timeout)
+  while (program.api_thread_count > 0)
+  {
+    if (DelayReached(&thread_delay, thread_delay_value))
+    {
+      Error("failed waiting for threads - TIMEOUT");
+
+      return FALSE;
+    }
+
+    UPDATE_BUSY_STATE();
+
+    Delay(20);
+  }
+
+  return TRUE;
+}
+
 void CloseAllAndExit(int exit_value)
 {
+  WaitForApiThreads();
+
   StopSounds();
   FreeAllSounds();
   FreeAllMusic();
@@ -6236,8 +6408,8 @@ void CloseAllAndExit(int exit_value)
   // using SDL_WaitThread()
   //
   // Code used with SDL 1.2:
-  // if (network_server)       // terminate network server
-  //   SDL_KillThread(server_thread);
+  // if (network.server_thread)        // terminate network server
+  //   SDL_KillThread(network.server_thread);
 
   CloseVideoDisplay();
   ClosePlatformDependentStuff();