rnd-20061019-1-src
[rocksndiamonds.git] / src / libgame / misc.c
index a502ec49026cd1baab8dc85ac4f267a8a1cd68c6..ec16eeee4568f1b7c95a23b5d810a64c1edfcad9 100644 (file)
@@ -1,7 +1,7 @@
 /***********************************************************
 * Artsoft Retro-Game Library                               *
 *----------------------------------------------------------*
-* (c) 1994-2002 Artsoft Entertainment                      *
+* (c) 1994-2006 Artsoft Entertainment                      *
 *               Holger Schemel                             *
 *               Detmolder Strasse 189                      *
 *               33604 Bielefeld                            *
 #include "image.h"
 
 
-/* ------------------------------------------------------------------------- */
+/* ========================================================================= */
 /* some generic helper functions                                             */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* platform independent wrappers for printf() et al. (newline aware)         */
 /* ------------------------------------------------------------------------- */
 
-void fprintf_line(FILE *stream, char *line_string, int line_length)
+static void vfprintf_newline(FILE *stream, char *format, va_list ap)
+{
+  char *newline = STRING_NEWLINE;
+
+  vfprintf(stream, format, ap);
+
+  fprintf(stream, "%s", newline);
+}
+
+static void fprintf_newline(FILE *stream, char *format, ...)
+{
+  if (format)
+  {
+    va_list ap;
+
+    va_start(ap, format);
+    vfprintf_newline(stream, format, ap);
+    va_end(ap);
+  }
+}
+
+void fprintf_line(FILE *stream, char *line_chars, int line_length)
 {
   int i;
 
   for (i = 0; i < line_length; i++)
-    fprintf(stream, "%s", line_string);
+    fprintf(stream, "%s", line_chars);
 
-  fprintf(stream, "\n");
+  fprintf_newline(stream, "");
 }
 
-void printf_line(char *line_string, int line_length)
+void printf_line(char *line_chars, int line_length)
 {
-  fprintf_line(stdout, line_string, line_length);
+  fprintf_line(stdout, line_chars, line_length);
 }
 
+void printf_line_with_prefix(char *prefix, char *line_chars, int line_length)
+{
+  fprintf(stdout, "%s", prefix);
+  fprintf_line(stdout, line_chars, line_length);
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* string functions                                                          */
+/* ------------------------------------------------------------------------- */
 
 /* int2str() returns a number converted to a string;
    the used memory is static, but will be overwritten by later calls,
@@ -206,14 +241,6 @@ static void sleep_milliseconds(unsigned long milliseconds_delay)
 {
   boolean do_busy_waiting = (milliseconds_delay < 5 ? TRUE : FALSE);
 
-#if 0
-#if defined(PLATFORM_MSDOS)
-  /* don't use select() to perform waiting operations under DOS
-     environment; always use a busy loop for waiting instead */
-  do_busy_waiting = TRUE;
-#endif
-#endif
-
   if (do_busy_waiting)
   {
     /* we want to wait only a few ms -- if we assume that we have a
@@ -423,36 +450,47 @@ char *getRealName()
   return real_name;
 }
 
-char *getHomeDir()
+
+/* ------------------------------------------------------------------------- */
+/* path manipulation functions                                               */
+/* ------------------------------------------------------------------------- */
+
+static char *getLastPathSeparatorPtr(char *filename)
 {
-  static char *dir = NULL;
+  char *last_separator = strrchr(filename, CHAR_PATH_SEPARATOR_UNIX);
 
-#if defined(PLATFORM_WIN32)
-  if (dir == NULL)
-  {
-    dir = checked_malloc(MAX_PATH + 1);
+  if (last_separator == NULL)  /* also try DOS/Windows variant */
+    last_separator = strrchr(filename, CHAR_PATH_SEPARATOR_DOS);
 
-    if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, dir)))
-      strcpy(dir, ".");
-  }
-#elif defined(PLATFORM_UNIX)
-  if (dir == NULL)
-  {
-    if ((dir = getenv("HOME")) == NULL)
-    {
-      struct passwd *pwd;
+  return last_separator;
+}
 
-      if ((pwd = getpwuid(getuid())) != NULL)
-       dir = getStringCopy(pwd->pw_dir);
-      else
-       dir = ".";
-    }
-  }
-#else
-  dir = ".";
-#endif
+char *getBaseNamePtr(char *filename)
+{
+  char *last_separator = getLastPathSeparatorPtr(filename);
 
-  return dir;
+  if (last_separator != NULL)
+    return last_separator + 1; /* separator found: strip base path */
+  else
+    return filename;           /* no separator found: filename has no path */
+}
+
+char *getBaseName(char *filename)
+{
+  return getStringCopy(getBaseNamePtr(filename));
+}
+
+char *getBasePath(char *filename)
+{
+  char *basepath = getStringCopy(filename);
+  char *last_separator = getLastPathSeparatorPtr(basepath);
+
+  if (last_separator != NULL)
+    *last_separator = '\0';    /* separator found: strip basename */
+  else
+    basepath = ".";            /* no separator found: use current path */
+
+  return basepath;
 }
 
 
@@ -462,21 +500,23 @@ char *getHomeDir()
 
 char *getPath2(char *path1, char *path2)
 {
+  char *sep = STRING_PATH_SEPARATOR;
   char *complete_path = checked_malloc(strlen(path1) + 1 +
                                       strlen(path2) + 1);
 
-  sprintf(complete_path, "%s/%s", path1, path2);
+  sprintf(complete_path, "%s%s%s", path1, sep, path2);
 
   return complete_path;
 }
 
 char *getPath3(char *path1, char *path2, char *path3)
 {
+  char *sep = STRING_PATH_SEPARATOR;
   char *complete_path = checked_malloc(strlen(path1) + 1 +
                                       strlen(path2) + 1 +
                                       strlen(path3) + 1);
 
-  sprintf(complete_path, "%s/%s/%s", path1, path2, path3);
+  sprintf(complete_path, "%s%s%s%s%s", path1, sep, path2, sep, path3);
 
   return complete_path;
 }
@@ -522,6 +562,14 @@ void setString(char **old_value, char *new_value)
   *old_value = getStringCopy(new_value);
 }
 
+boolean strEqual(char *s1, char *s2)
+{
+  return (s1 == NULL && s2 == NULL ? TRUE  :
+         s1 == NULL && s2 != NULL ? FALSE :
+         s1 != NULL && s2 == NULL ? FALSE :
+         strcmp(s1, s2) == 0);
+}
+
 
 /* ------------------------------------------------------------------------- */
 /* command line option handling functions                                    */
@@ -529,19 +577,34 @@ void setString(char **old_value, char *new_value)
 
 void GetOptions(char *argv[], void (*print_usage_function)(void))
 {
+  char *ro_base_path = RO_BASE_PATH;
+  char *rw_base_path = RW_BASE_PATH;
   char **options_left = &argv[1];
 
+#if !defined(PLATFORM_MACOSX)
+  /* if the program is configured to start from current directory (default),
+     determine program package directory (KDE/Konqueror does not do this by
+     itself and fails otherwise); on Mac OS X, the program binary is stored
+     in an application package directory -- do not try to use this directory
+     as the program data directory (Mac OS X handles this correctly anyway) */
+
+  if (strEqual(ro_base_path, "."))
+    ro_base_path = program.command_basepath;
+  if (strEqual(rw_base_path, "."))
+    rw_base_path = program.command_basepath;
+#endif
+
   /* initialize global program options */
   options.display_name = NULL;
   options.server_host = NULL;
   options.server_port = 0;
-  options.ro_base_directory = RO_BASE_PATH;
-  options.rw_base_directory = RW_BASE_PATH;
-  options.level_directory = RO_BASE_PATH "/" LEVELS_DIRECTORY;
-  options.graphics_directory = RO_BASE_PATH "/" GRAPHICS_DIRECTORY;
-  options.sounds_directory = RO_BASE_PATH "/" SOUNDS_DIRECTORY;
-  options.music_directory = RO_BASE_PATH "/" MUSIC_DIRECTORY;
-  options.docs_directory = RO_BASE_PATH "/" DOCS_DIRECTORY;
+  options.ro_base_directory = ro_base_path;
+  options.rw_base_directory = rw_base_path;
+  options.level_directory    = getPath2(ro_base_path, LEVELS_DIRECTORY);
+  options.graphics_directory = getPath2(ro_base_path, GRAPHICS_DIRECTORY);
+  options.sounds_directory   = getPath2(ro_base_path, SOUNDS_DIRECTORY);
+  options.music_directory    = getPath2(ro_base_path, MUSIC_DIRECTORY);
+  options.docs_directory     = getPath2(ro_base_path, DOCS_DIRECTORY);
   options.execute_command = NULL;
   options.serveronly = FALSE;
   options.network = FALSE;
@@ -567,7 +630,7 @@ void GetOptions(char *argv[], void (*print_usage_function)(void))
     strcpy(option_str, option);                        /* copy argument into buffer */
     option = option_str;
 
-    if (strcmp(option, "--") == 0)             /* stop scanning arguments */
+    if (strEqual(option, "--"))                        /* stop scanning arguments */
       break;
 
     if (strncmp(option, "--", 2) == 0)         /* treat '--' like '-' */
@@ -585,7 +648,7 @@ void GetOptions(char *argv[], void (*print_usage_function)(void))
 
     option_len = strlen(option);
 
-    if (strcmp(option, "-") == 0)
+    if (strEqual(option, "-"))
       Error(ERR_EXIT_HELP, "unrecognized option '%s'", option);
     else if (strncmp(option, "-help", option_len) == 0)
     {
@@ -608,22 +671,17 @@ void GetOptions(char *argv[], void (*print_usage_function)(void))
        Error(ERR_EXIT_HELP, "option '%s' requires an argument", option_str);
 
       /* this should be extended to separate options for ro and rw data */
-      options.ro_base_directory = option_arg;
-      options.rw_base_directory = option_arg;
+      options.ro_base_directory = ro_base_path = option_arg;
+      options.rw_base_directory = rw_base_path = option_arg;
       if (option_arg == next_option)
        options_left++;
 
       /* adjust paths for sub-directories in base directory accordingly */
-      options.level_directory =
-       getPath2(options.ro_base_directory, LEVELS_DIRECTORY);
-      options.graphics_directory =
-       getPath2(options.ro_base_directory, GRAPHICS_DIRECTORY);
-      options.sounds_directory =
-       getPath2(options.ro_base_directory, SOUNDS_DIRECTORY);
-      options.music_directory =
-       getPath2(options.ro_base_directory, MUSIC_DIRECTORY);
-      options.docs_directory =
-       getPath2(options.ro_base_directory, DOCS_DIRECTORY);
+      options.level_directory    = getPath2(ro_base_path, LEVELS_DIRECTORY);
+      options.graphics_directory = getPath2(ro_base_path, GRAPHICS_DIRECTORY);
+      options.sounds_directory   = getPath2(ro_base_path, SOUNDS_DIRECTORY);
+      options.music_directory    = getPath2(ro_base_path, MUSIC_DIRECTORY);
+      options.docs_directory     = getPath2(ro_base_path, DOCS_DIRECTORY);
     }
     else if (strncmp(option, "-levels", option_len) == 0)
     {
@@ -686,10 +744,8 @@ void GetOptions(char *argv[], void (*print_usage_function)(void))
       if (option_arg == next_option)
        options_left++;
 
-#if 1
       /* when doing batch processing, always enable verbose mode (warnings) */
       options.verbose = TRUE;
-#endif
     }
     else if (*option == '-')
     {
@@ -738,8 +794,6 @@ void Error(int mode, char *format, ...)
 {
   static boolean last_line_was_separator = FALSE;
   char *process_name = "";
-  FILE *error = stderr;
-  char *newline = "\n";
 
   /* display warnings only when running in verbose mode */
   if (mode & ERR_WARN && !options.verbose)
@@ -748,7 +802,7 @@ void Error(int mode, char *format, ...)
   if (mode == ERR_RETURN_LINE)
   {
     if (!last_line_was_separator)
-      fprintf_line(error, format, 79);
+      fprintf_line(program.error_file, format, 79);
 
     last_line_was_separator = TRUE;
 
@@ -757,16 +811,6 @@ void Error(int mode, char *format, ...)
 
   last_line_was_separator = FALSE;
 
-#if defined(PLATFORM_MSDOS)
-  newline = "\r\n";
-
-  if ((error = openErrorFile()) == NULL)
-  {
-    printf("Cannot write to error output file!%s", newline);
-    program.exit_function(1);
-  }
-#endif
-
   if (mode & ERR_SOUND_SERVER)
     process_name = " sound server";
   else if (mode & ERR_NETWORK_SERVER)
@@ -778,28 +822,25 @@ void Error(int mode, char *format, ...)
   {
     va_list ap;
 
-    fprintf(error, "%s%s: ", program.command_basename, process_name);
+    fprintf(program.error_file, "%s%s: ", program.command_basename,
+           process_name);
 
     if (mode & ERR_WARN)
-      fprintf(error, "warning: ");
+      fprintf(program.error_file, "warning: ");
 
     va_start(ap, format);
-    vfprintf(error, format, ap);
+    vfprintf_newline(program.error_file, format, ap);
     va_end(ap);
-  
-    fprintf(error, "%s", newline);
   }
   
   if (mode & ERR_HELP)
-    fprintf(error, "%s: Try option '--help' for more information.%s",
-           program.command_basename, newline);
+    fprintf_newline(program.error_file,
+                   "%s: Try option '--help' for more information.",
+                   program.command_basename);
 
   if (mode & ERR_EXIT)
-    fprintf(error, "%s%s: aborting%s",
-           program.command_basename, process_name, newline);
-
-  if (error != stderr)
-    fclose(error);
+    fprintf_newline(program.error_file, "%s%s: aborting",
+                   program.command_basename, process_name);
 
   if (mode & ERR_EXIT)
   {
@@ -880,6 +921,25 @@ inline void swap_number_pairs(int *x1, int *y1, int *x2, int *y2)
   *y2 = help_y;
 }
 
+/* the "put" variants of the following file access functions check for the file
+   pointer being != NULL and return the number of bytes they have or would have
+   written; this allows for chunk writing functions to first determine the size
+   of the (not yet written) chunk, write the correct chunk size and finally
+   write the chunk itself */
+
+int getFile8BitInteger(FILE *file)
+{
+  return fgetc(file);
+}
+
+int putFile8BitInteger(FILE *file, int value)
+{
+  if (file != NULL)
+    fputc(value, file);
+
+  return 1;
+}
+
 int getFile16BitInteger(FILE *file, int byte_order)
 {
   if (byte_order == BYTE_ORDER_BIG_ENDIAN)
@@ -890,18 +950,23 @@ int getFile16BitInteger(FILE *file, int byte_order)
            (fgetc(file) << 8));
 }
 
-void putFile16BitInteger(FILE *file, int value, int byte_order)
+int putFile16BitInteger(FILE *file, int value, int byte_order)
 {
-  if (byte_order == BYTE_ORDER_BIG_ENDIAN)
+  if (file != NULL)
   {
-    fputc((value >> 8) & 0xff, file);
-    fputc((value >> 0) & 0xff, file);
-  }
-  else          /* BYTE_ORDER_LITTLE_ENDIAN */
-  {
-    fputc((value >> 0) & 0xff, file);
-    fputc((value >> 8) & 0xff, file);
+    if (byte_order == BYTE_ORDER_BIG_ENDIAN)
+    {
+      fputc((value >> 8) & 0xff, file);
+      fputc((value >> 0) & 0xff, file);
+    }
+    else          /* BYTE_ORDER_LITTLE_ENDIAN */
+    {
+      fputc((value >> 0) & 0xff, file);
+      fputc((value >> 8) & 0xff, file);
+    }
   }
+
+  return 2;
 }
 
 int getFile32BitInteger(FILE *file, int byte_order)
@@ -918,22 +983,27 @@ int getFile32BitInteger(FILE *file, int byte_order)
            (fgetc(file) << 24));
 }
 
-void putFile32BitInteger(FILE *file, int value, int byte_order)
+int putFile32BitInteger(FILE *file, int value, int byte_order)
 {
-  if (byte_order == BYTE_ORDER_BIG_ENDIAN)
+  if (file != NULL)
   {
-    fputc((value >> 24) & 0xff, file);
-    fputc((value >> 16) & 0xff, file);
-    fputc((value >>  8) & 0xff, file);
-    fputc((value >>  0) & 0xff, file);
-  }
-  else          /* BYTE_ORDER_LITTLE_ENDIAN */
-  {
-    fputc((value >>  0) & 0xff, file);
-    fputc((value >>  8) & 0xff, file);
-    fputc((value >> 16) & 0xff, file);
-    fputc((value >> 24) & 0xff, file);
+    if (byte_order == BYTE_ORDER_BIG_ENDIAN)
+    {
+      fputc((value >> 24) & 0xff, file);
+      fputc((value >> 16) & 0xff, file);
+      fputc((value >>  8) & 0xff, file);
+      fputc((value >>  0) & 0xff, file);
+    }
+    else          /* BYTE_ORDER_LITTLE_ENDIAN */
+    {
+      fputc((value >>  0) & 0xff, file);
+      fputc((value >>  8) & 0xff, file);
+      fputc((value >> 16) & 0xff, file);
+      fputc((value >> 24) & 0xff, file);
+    }
   }
+
+  return 4;
 }
 
 boolean getFileChunk(FILE *file, char *chunk_name, int *chunk_size,
@@ -953,17 +1023,27 @@ boolean getFileChunk(FILE *file, char *chunk_name, int *chunk_size,
   return (feof(file) || ferror(file) ? FALSE : TRUE);
 }
 
-void putFileChunk(FILE *file, char *chunk_name, int chunk_size,
-                 int byte_order)
+int putFileChunk(FILE *file, char *chunk_name, int chunk_size,
+                int byte_order)
 {
+  int num_bytes = 0;
+
   /* write chunk name */
-  fputs(chunk_name, file);
+  if (file != NULL)
+    fputs(chunk_name, file);
+
+  num_bytes += strlen(chunk_name);
 
   if (chunk_size >= 0)
   {
     /* write chunk size */
-    putFile32BitInteger(file, chunk_size, byte_order);
+    if (file != NULL)
+      putFile32BitInteger(file, chunk_size, byte_order);
+
+    num_bytes += 4;
   }
+
+  return num_bytes;
 }
 
 int getFileVersion(FILE *file)
@@ -977,17 +1057,38 @@ int getFileVersion(FILE *file)
                       version_build);
 }
 
-void putFileVersion(FILE *file, int version)
+int putFileVersion(FILE *file, int version)
+{
+  if (file != NULL)
+  {
+    int version_major = VERSION_MAJOR(version);
+    int version_minor = VERSION_MINOR(version);
+    int version_patch = VERSION_PATCH(version);
+    int version_build = VERSION_BUILD(version);
+
+    fputc(version_major, file);
+    fputc(version_minor, file);
+    fputc(version_patch, file);
+    fputc(version_build, file);
+  }
+
+  return 4;
+}
+
+void ReadBytesFromFile(FILE *file, byte *buffer, unsigned long bytes)
+{
+  int i;
+
+  for(i = 0; i < bytes && !feof(file); i++)
+    buffer[i] = fgetc(file);
+}
+
+void WriteBytesToFile(FILE *file, byte *buffer, unsigned long bytes)
 {
-  int version_major = VERSION_MAJOR(version);
-  int version_minor = VERSION_MINOR(version);
-  int version_patch = VERSION_PATCH(version);
-  int version_build = VERSION_BUILD(version);
+  int i;
 
-  fputc(version_major, file);
-  fputc(version_minor, file);
-  fputc(version_patch, file);
-  fputc(version_build, file);
+  for(i = 0; i < bytes; i++)
+    fputc(buffer[i], file);
 }
 
 void ReadUnusedBytesFromFile(FILE *file, unsigned long bytes)
@@ -1097,16 +1198,16 @@ void translate_keyname(Key *keysym, char **x11name, char **name, int mode)
 
     /* more ASCII keys */
     { KSYM_bracketleft,        "XK_bracketleft",       "[" },
-    { KSYM_backslash,  "XK_backslash",         "backslash" },
+    { KSYM_backslash,  "XK_backslash",         "\\" },
     { KSYM_bracketright,"XK_bracketright",     "]" },
-    { KSYM_asciicircum,        "XK_asciicircum",       "circumflex" },
+    { KSYM_asciicircum,        "XK_asciicircum",       "^" },
     { KSYM_underscore, "XK_underscore",        "_" },
     { KSYM_grave,      "XK_grave",             "grave" },
     { KSYM_quoteleft,  "XK_quoteleft",         "quote left" },
     { KSYM_braceleft,  "XK_braceleft",         "brace left" },
     { KSYM_bar,                "XK_bar",               "bar" },
     { KSYM_braceright, "XK_braceright",        "brace right" },
-    { KSYM_asciitilde, "XK_asciitilde",        "ascii tilde" },
+    { KSYM_asciitilde, "XK_asciitilde",        "~" },
 
     /* special (non-ASCII) keys */
     { KSYM_Adiaeresis, "XK_Adiaeresis",        "Ä" },
@@ -1137,7 +1238,7 @@ void translate_keyname(Key *keysym, char **x11name, char **name, int mode)
     else if (key >= KSYM_KP_0 && key <= KSYM_KP_9)
       sprintf(name_buffer, "keypad %c", '0' + (char)(key - KSYM_KP_0));
     else if (key >= KSYM_FKEY_FIRST && key <= KSYM_FKEY_LAST)
-      sprintf(name_buffer, "function F%d", (int)(key - KSYM_FKEY_FIRST + 1));
+      sprintf(name_buffer, "F%d", (int)(key - KSYM_FKEY_FIRST + 1));
     else if (key == KSYM_UNDEFINED)
       strcpy(name_buffer, "(undefined)");
     else
@@ -1204,7 +1305,7 @@ void translate_keyname(Key *keysym, char **x11name, char **name, int mode)
     i = 0;
     do
     {
-      if (strcmp(translate_key[i].name, *name) == 0)
+      if (strEqual(translate_key[i].name, *name))
       {
        key = translate_key[i].key;
        break;
@@ -1259,7 +1360,7 @@ void translate_keyname(Key *keysym, char **x11name, char **name, int mode)
 
       do
       {
-       if (strcmp(name_ptr, translate_key[i].x11name) == 0)
+       if (strEqual(name_ptr, translate_key[i].x11name))
        {
          key = translate_key[i].key;
          break;
@@ -1341,9 +1442,9 @@ char getCharFromKey(Key key)
 
   if (strlen(keyname) == 1)
     letter = keyname[0];
-  else if (strcmp(keyname, "space") == 0)
+  else if (strEqual(keyname, "space"))
     letter = ' ';
-  else if (strcmp(keyname, "circumflex") == 0)
+  else if (strEqual(keyname, "circumflex"))
     letter = '^';
 
   return letter;
@@ -1381,14 +1482,14 @@ int get_integer_from_string(char *s)
 
   for (i = 0; number_text[i][0] != NULL; i++)
     for (j = 0; j < 3; j++)
-      if (strcmp(s_lower, number_text[i][j]) == 0)
+      if (strEqual(s_lower, number_text[i][j]))
        result = i;
 
   if (result == -1)
   {
-    if (strcmp(s_lower, "false") == 0)
+    if (strEqual(s_lower, "false"))
       result = 0;
-    else if (strcmp(s_lower, "true") == 0)
+    else if (strEqual(s_lower, "true"))
       result = 1;
     else
       result = atoi(s);
@@ -1404,9 +1505,9 @@ boolean get_boolean_from_string(char *s)
   char *s_lower = getStringToLower(s);
   boolean result = FALSE;
 
-  if (strcmp(s_lower, "true") == 0 ||
-      strcmp(s_lower, "yes") == 0 ||
-      strcmp(s_lower, "on") == 0 ||
+  if (strEqual(s_lower, "true") ||
+      strEqual(s_lower, "yes") ||
+      strEqual(s_lower, "on") ||
       get_integer_from_string(s) == 1)
     result = TRUE;
 
@@ -1429,10 +1530,6 @@ void addNodeToList(ListNode **node_first, char *key, void *content)
 {
   ListNode *node_new = newListNode();
 
-#if 0
-  printf("LIST: adding node with key '%s'\n", key);
-#endif
-
   node_new->key = getStringCopy(key);
   node_new->content = content;
   node_new->next = *node_first;
@@ -1445,18 +1542,9 @@ void deleteNodeFromList(ListNode **node_first, char *key,
   if (node_first == NULL || *node_first == NULL)
     return;
 
-#if 0
-  printf("[CHECKING LIST KEY '%s' == '%s']\n",
-        (*node_first)->key, key);
-#endif
-
-  if (strcmp((*node_first)->key, key) == 0)
+  if (strEqual((*node_first)->key, key))
   {
-#if 0
-    printf("[DELETING LIST ENTRY]\n");
-#endif
-
-    free((*node_first)->key);
+    checked_free((*node_first)->key);
     if (destructor_function)
       destructor_function((*node_first)->content);
     *node_first = (*node_first)->next;
@@ -1470,7 +1558,7 @@ ListNode *getNodeFromKey(ListNode *node_first, char *key)
   if (node_first == NULL)
     return NULL;
 
-  if (strcmp(node_first->key, key) == 0)
+  if (strEqual(node_first->key, key))
     return node_first;
   else
     return getNodeFromKey(node_first->next, key);
@@ -1505,10 +1593,6 @@ boolean fileExists(char *filename)
   if (filename == NULL)
     return FALSE;
 
-#if 0
-  printf("checking file '%s'\n", filename);
-#endif
-
   return (access(filename, F_OK) == 0);
 }
 
@@ -1550,7 +1634,7 @@ boolean fileHasSuffix(char *basename, char *suffix)
 
   if (basename_length > suffix_length + 1 &&
       basename_lower[basename_length - suffix_length - 1] == '.' &&
-      strcmp(&basename_lower[basename_length - suffix_length], suffix) == 0)
+      strEqual(&basename_lower[basename_length - suffix_length], suffix))
     return TRUE;
 
   return FALSE;
@@ -1558,27 +1642,21 @@ boolean fileHasSuffix(char *basename, char *suffix)
 
 boolean FileIsGraphic(char *filename)
 {
-  char *basename = strrchr(filename, '/');
-
-  basename = (basename != NULL ? basename + 1 : filename);
+  char *basename = getBaseNamePtr(filename);
 
   return fileHasSuffix(basename, "pcx");
 }
 
 boolean FileIsSound(char *filename)
 {
-  char *basename = strrchr(filename, '/');
-
-  basename = (basename != NULL ? basename + 1 : filename);
+  char *basename = getBaseNamePtr(filename);
 
   return fileHasSuffix(basename, "wav");
 }
 
 boolean FileIsMusic(char *filename)
 {
-  char *basename = strrchr(filename, '/');
-
-  basename = (basename != NULL ? basename + 1 : filename);
+  char *basename = getBaseNamePtr(filename);
 
   if (FileIsSound(basename))
     return TRUE;
@@ -1671,36 +1749,52 @@ static boolean string_has_parameter(char *s, char *s_contained)
   return string_has_parameter(substring, s_contained);
 }
 
-int get_parameter_value(char *suffix, char *value_raw, int type)
+int get_parameter_value(char *value_raw, char *suffix, int type)
 {
   char *value = getStringToLower(value_raw);
   int result = 0;      /* probably a save default value */
 
-  if (strcmp(suffix, ".direction") == 0)
-  {
-    result = (strcmp(value, "left")  == 0 ? MV_LEFT :
-             strcmp(value, "right") == 0 ? MV_RIGHT :
-             strcmp(value, "up")    == 0 ? MV_UP :
-             strcmp(value, "down")  == 0 ? MV_DOWN : MV_NO_MOVING);
-  }
-  else if (strcmp(suffix, ".anim_mode") == 0)
-  {
-    result = (string_has_parameter(value, "none")       ? ANIM_NONE :
-             string_has_parameter(value, "loop")       ? ANIM_LOOP :
-             string_has_parameter(value, "linear")     ? ANIM_LINEAR :
-             string_has_parameter(value, "pingpong")   ? ANIM_PINGPONG :
-             string_has_parameter(value, "pingpong2")  ? ANIM_PINGPONG2 :
-             string_has_parameter(value, "random")     ? ANIM_RANDOM :
-             string_has_parameter(value, "horizontal") ? ANIM_HORIZONTAL :
-             string_has_parameter(value, "vertical")   ? ANIM_VERTICAL :
+  if (strEqual(suffix, ".direction"))
+  {
+    result = (strEqual(value, "left")  ? MV_LEFT :
+             strEqual(value, "right") ? MV_RIGHT :
+             strEqual(value, "up")    ? MV_UP :
+             strEqual(value, "down")  ? MV_DOWN : MV_NONE);
+  }
+  else if (strEqual(suffix, ".align"))
+  {
+    result = (strEqual(value, "left")   ? ALIGN_LEFT :
+             strEqual(value, "right")  ? ALIGN_RIGHT :
+             strEqual(value, "center") ? ALIGN_CENTER : ALIGN_DEFAULT);
+  }
+  else if (strEqual(suffix, ".anim_mode"))
+  {
+    result = (string_has_parameter(value, "none")      ? ANIM_NONE :
+             string_has_parameter(value, "loop")       ? ANIM_LOOP :
+             string_has_parameter(value, "linear")     ? ANIM_LINEAR :
+             string_has_parameter(value, "pingpong")   ? ANIM_PINGPONG :
+             string_has_parameter(value, "pingpong2")  ? ANIM_PINGPONG2 :
+             string_has_parameter(value, "random")     ? ANIM_RANDOM :
+             string_has_parameter(value, "ce_value")   ? ANIM_CE_VALUE :
+             string_has_parameter(value, "ce_score")   ? ANIM_CE_SCORE :
+             string_has_parameter(value, "ce_delay")   ? ANIM_CE_DELAY :
+             string_has_parameter(value, "horizontal") ? ANIM_HORIZONTAL :
+             string_has_parameter(value, "vertical")   ? ANIM_VERTICAL :
+             string_has_parameter(value, "centered")   ? ANIM_CENTERED :
              ANIM_DEFAULT);
 
     if (string_has_parameter(value, "reverse"))
       result |= ANIM_REVERSE;
+
+    if (string_has_parameter(value, "opaque_player"))
+      result |= ANIM_OPAQUE_PLAYER;
+
+    if (string_has_parameter(value, "static_panel"))
+      result |= ANIM_STATIC_PANEL;
   }
   else         /* generic parameter of type integer or boolean */
   {
-    result = (strcmp(value, ARG_UNDEFINED) == 0 ? ARG_UNDEFINED_VALUE :
+    result = (strEqual(value, ARG_UNDEFINED) ? ARG_UNDEFINED_VALUE :
              type == TYPE_INTEGER ? get_integer_from_string(value) :
              type == TYPE_BOOLEAN ? get_boolean_from_string(value) :
              ARG_UNDEFINED_VALUE);
@@ -1722,7 +1816,49 @@ int get_auto_parameter_value(char *token, char *value_raw)
   if (suffix == NULL)
     suffix = token;
 
-  return get_parameter_value(suffix, value_raw, TYPE_INTEGER);
+  return get_parameter_value(value_raw, suffix, TYPE_INTEGER);
+}
+
+struct ScreenModeInfo *get_screen_mode_from_string(char *screen_mode_string)
+{
+  static struct ScreenModeInfo screen_mode;
+  char *screen_mode_string_x = strchr(screen_mode_string, 'x');
+  char *screen_mode_string_copy;
+  char *screen_mode_string_pos_w;
+  char *screen_mode_string_pos_h;
+
+  if (screen_mode_string_x == NULL)    /* invalid screen mode format */
+    return NULL;
+
+  screen_mode_string_copy = getStringCopy(screen_mode_string);
+
+  screen_mode_string_pos_w = screen_mode_string_copy;
+  screen_mode_string_pos_h = strchr(screen_mode_string_copy, 'x');
+  *screen_mode_string_pos_h++ = '\0';
+
+  screen_mode.width  = atoi(screen_mode_string_pos_w);
+  screen_mode.height = atoi(screen_mode_string_pos_h);
+
+  return &screen_mode;
+}
+
+void get_aspect_ratio_from_screen_mode(struct ScreenModeInfo *screen_mode,
+                                      int *x, int *y)
+{
+  float aspect_ratio = (float)screen_mode->width / (float)screen_mode->height;
+  float aspect_ratio_new;
+  int i = 1;
+
+  do
+  {
+    *x = i * aspect_ratio + 0.000001;
+    *y = i;
+
+    aspect_ratio_new = (float)*x / (float)*y;
+
+    i++;
+  }
+  while (aspect_ratio_new != aspect_ratio && *y < screen_mode->height);
 }
 
 static void FreeCustomArtworkList(struct ArtworkListInfo *,
@@ -1782,8 +1918,8 @@ struct FileInfo *getFileListFromConfigList(struct ConfigInfo *config_list,
       int len_suffix = strlen(suffix_list[j].token);
 
       if (len_suffix < len_config_token &&
-         strcmp(&config_list[i].token[len_config_token - len_suffix],
-                suffix_list[j].token) == 0)
+         strEqual(&config_list[i].token[len_config_token - len_suffix],
+                  suffix_list[j].token))
       {
        setString(&file_list[list_pos].default_parameter[j],
                  config_list[i].value);
@@ -1795,7 +1931,7 @@ struct FileInfo *getFileListFromConfigList(struct ConfigInfo *config_list,
 
     /* the following tokens are no file definitions, but other config tokens */
     for (j = 0; ignore_tokens[j] != NULL; j++)
-      if (strcmp(config_list[i].token, ignore_tokens[j]) == 0)
+      if (strEqual(config_list[i].token, ignore_tokens[j]))
        is_file_entry = FALSE;
 
     if (is_file_entry)
@@ -1807,9 +1943,9 @@ struct FileInfo *getFileListFromConfigList(struct ConfigInfo *config_list,
        break;
 
       /* simple sanity check if this is really a file definition */
-      if (strcmp(&config_list[i].value[len_config_value - 4], ".pcx") != 0 &&
-         strcmp(&config_list[i].value[len_config_value - 4], ".wav") != 0 &&
-         strcmp(config_list[i].value, UNDEFINED_FILENAME) != 0)
+      if (!strEqual(&config_list[i].value[len_config_value - 4], ".pcx") &&
+         !strEqual(&config_list[i].value[len_config_value - 4], ".wav") &&
+         !strEqual(config_list[i].value, UNDEFINED_FILENAME))
       {
        Error(ERR_RETURN, "Configuration directive '%s' -> '%s':",
              config_list[i].token, config_list[i].value);
@@ -1841,11 +1977,6 @@ static boolean token_suffix_match(char *token, char *suffix, int start_pos)
   int len_token = strlen(token);
   int len_suffix = strlen(suffix);
 
-#if 0
-  if (IS_PARENT_PROCESS())
-    printf(":::::::::: check '%s' for '%s' ::::::::::\n", token, suffix);
-#endif
-
   if (start_pos < 0)   /* compare suffix from end of string */
     start_pos += len_token;
 
@@ -1888,16 +2019,6 @@ static void read_token_parameters(SetupFileHash *setup_file_hash,
     /* mark config file token as well known from default config */
     setHashEntry(setup_file_hash, file_list_entry->token, known_token_value);
   }
-#if 0
-  else
-  {
-    if (strcmp(file_list_entry->filename,
-              file_list_entry->default_filename) != 0)
-      printf("___ resetting '%s' to default\n", file_list_entry->token);
-
-    setString(&file_list_entry->filename, file_list_entry->default_filename);
-  }
-#endif
 
   /* check for config tokens that can be build by base token and suffixes */
   for (i = 0; suffix_list[i].token != NULL; i++)
@@ -1927,11 +2048,6 @@ static void add_dynamic_file_list_entry(struct FileInfo **list,
   struct FileInfo *new_list_entry;
   int parameter_array_size = num_suffix_list_entries * sizeof(char *);
 
-#if 0
-  if (IS_PARENT_PROCESS())
-    printf("===> found dynamic definition '%s'\n", token);
-#endif
-
   (*num_list_entries)++;
   *list = checked_realloc(*list, *num_list_entries * sizeof(struct FileInfo));
   new_list_entry = &(*list)[*num_list_entries - 1];
@@ -1994,7 +2110,7 @@ static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info,
     return;
 
 #if 0
-  printf("::: LoadArtworkConfigFromFilename: '%s'\n", filename);
+  printf("LoadArtworkConfigFromFilename '%s' ...\n", filename);
 #endif
 
   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
@@ -2015,7 +2131,6 @@ static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info,
   /* at this point, we do not need the setup file hash anymore -- free it */
   freeSetupFileHash(setup_file_hash);
 
-#if 1
   /* map deprecated to current tokens (using prefix match and replace) */
   BEGIN_HASH_ITERATION(valid_file_hash, itr)
   {
@@ -2036,7 +2151,6 @@ static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info,
     }
   }
   END_HASH_ITERATION(valid_file_hash, itr)
-#endif
 
   /* read parameters for all known config file tokens */
   for (i = 0; i < num_file_list_entries; i++)
@@ -2052,7 +2166,7 @@ static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info,
   {
     char *value = HASH_ITERATION_VALUE(itr);
 
-    if (strcmp(value, known_token_value) != 0)
+    if (!strEqual(value, known_token_value))
       setHashEntry(extra_file_hash, HASH_ITERATION_TOKEN(itr), value);
   }
   END_HASH_ITERATION(valid_file_hash, itr)
@@ -2081,6 +2195,10 @@ static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info,
     boolean base_prefix_found = FALSE;
     boolean parameter_suffix_found = FALSE;
 
+#if 0
+    printf("::: examining '%s' -> '%s'\n", token, HASH_ITERATION_VALUE(itr));
+#endif
+
     /* skip all parameter definitions (handled by read_token_parameters()) */
     for (i = 0; i < num_suffix_list_entries && !parameter_suffix_found; i++)
     {
@@ -2090,16 +2208,6 @@ static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info,
        parameter_suffix_found = TRUE;
     }
 
-#if 0
-    if (IS_PARENT_PROCESS())
-    {
-      if (parameter_suffix_found)
-       printf("---> skipping token '%s' (parameter token)\n", token);
-      else
-       printf("---> examining token '%s': search prefix ...\n", token);
-    }
-#endif
-
     if (parameter_suffix_found)
       continue;
 
@@ -2287,7 +2395,7 @@ static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info,
 
     BEGIN_HASH_ITERATION(extra_file_hash, itr)
     {
-      if (strcmp(HASH_ITERATION_VALUE(itr), known_token_value) == 0)
+      if (strEqual(HASH_ITERATION_VALUE(itr), known_token_value))
        dynamic_tokens_found = TRUE;
       else
        unknown_tokens_found = TRUE;
@@ -2304,7 +2412,7 @@ static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info,
       {
        char *value = getHashEntry(extra_file_hash, list->token);
 
-       if (value != NULL && strcmp(value, known_token_value) == 0)
+       if (value != NULL && strEqual(value, known_token_value))
          Error(ERR_RETURN, "- dynamic token: '%s'", list->token);
       }
 
@@ -2321,7 +2429,7 @@ static void LoadArtworkConfigFromFilename(struct ArtworkListInfo *artwork_info,
       {
        char *value = getHashEntry(extra_file_hash, list->token);
 
-       if (value != NULL && strcmp(value, known_token_value) != 0)
+       if (value != NULL && !strEqual(value, known_token_value))
          Error(ERR_RETURN, "- dynamic token: '%s'", list->token);
       }
 
@@ -2371,10 +2479,6 @@ void LoadArtworkConfig(struct ArtworkListInfo *artwork_info)
   char *filename_base = UNDEFINED_FILENAME, *filename_local;
   int i, j;
 
-#if 0
-  printf("GOT CUSTOM ARTWORK CONFIG FILE '%s'\n", filename);
-#endif
-
   DrawInitText("Loading artwork config:", 120, FC_GREEN);
   DrawInitText(ARTWORKINFO_FILENAME(artwork_info->type), 150, FC_YELLOW);
 
@@ -2427,7 +2531,7 @@ void LoadArtworkConfig(struct ArtworkListInfo *artwork_info)
 
   filename_local = getCustomArtworkConfigFilename(artwork_info->type);
 
-  if (filename_local != NULL && strcmp(filename_base, filename_local) != 0)
+  if (filename_local != NULL && !strEqual(filename_base, filename_local))
     LoadArtworkConfigFromFilename(artwork_info, filename_local);
 }
 
@@ -2438,25 +2542,14 @@ static void deleteArtworkListEntry(struct ArtworkListInfo *artwork_info,
   {
     char *filename = (*listnode)->source_filename;
 
-#if 0
-    printf("[decrementing reference counter of artwork '%s']\n", filename);
-#endif
-
     if (--(*listnode)->num_references <= 0)
-    {
-#if 0
-      printf("[deleting artwork '%s']\n", filename);
-#endif
-
       deleteNodeFromList(&artwork_info->content_list, filename,
                         artwork_info->free_artwork);
-    }
 
     *listnode = NULL;
   }
 }
 
-#if 1
 static void replaceArtworkListEntry(struct ArtworkListInfo *artwork_info,
                                    struct ListNodeInfo **listnode,
                                    struct FileInfo *file_list_entry)
@@ -2479,7 +2572,7 @@ static void replaceArtworkListEntry(struct ArtworkListInfo *artwork_info,
     basename = file_list_entry->default_filename;
 
     /* dynamic artwork has no default filename / skip empty default artwork */
-    if (basename == NULL || strcmp(basename, UNDEFINED_FILENAME) == 0)
+    if (basename == NULL || strEqual(basename, UNDEFINED_FILENAME))
       return;
 
     file_list_entry->fallback_to_default = TRUE;
@@ -2503,102 +2596,7 @@ static void replaceArtworkListEntry(struct ArtworkListInfo *artwork_info,
   }
 
   /* check if the old and the new artwork file are the same */
-  if (*listnode && strcmp((*listnode)->source_filename, filename) == 0)
-  {
-    /* The old and new artwork are the same (have the same filename and path).
-       This usually means that this artwork does not exist in this artwork set
-       and a fallback to the existing artwork is done. */
-
-#if 0
-    printf("[artwork '%s' already exists (same list entry)]\n", filename);
-#endif
-
-    return;
-  }
-
-  /* delete existing artwork file entry */
-  deleteArtworkListEntry(artwork_info, listnode);
-
-  /* check if the new artwork file already exists in the list of artworks */
-  if ((node = getNodeFromKey(artwork_info->content_list, filename)) != NULL)
-  {
-#if 0
-      printf("[artwork '%s' already exists (other list entry)]\n", filename);
-#endif
-
-      *listnode = (struct ListNodeInfo *)node->content;
-      (*listnode)->num_references++;
-
-      return;
-  }
-
-#if 0
-  printf("::: %s: '%s'\n", init_text[artwork_info->type], basename);
-#endif
-
-  DrawInitText(init_text[artwork_info->type], 120, FC_GREEN);
-  DrawInitText(basename, 150, FC_YELLOW);
-
-  if ((*listnode = artwork_info->load_artwork(filename)) != NULL)
-  {
-#if 0
-      printf("[adding new artwork '%s']\n", filename);
-#endif
-
-    (*listnode)->num_references = 1;
-    addNodeToList(&artwork_info->content_list, (*listnode)->source_filename,
-                 *listnode);
-  }
-  else
-  {
-    int error_mode = ERR_WARN;
-
-#if 1
-    /* we can get away without sounds and music, but not without graphics */
-    if (artwork_info->type == ARTWORK_TYPE_GRAPHICS)
-      error_mode = ERR_EXIT;
-#endif
-
-    Error(error_mode, "cannot load artwork file '%s'", basename);
-    return;
-  }
-}
-
-#else
-
-static void replaceArtworkListEntry(struct ArtworkListInfo *artwork_info,
-                                   struct ListNodeInfo **listnode,
-                                   char *basename)
-{
-  char *init_text[] =
-  {
-    "Loading graphics:",
-    "Loading sounds:",
-    "Loading music:"
-  };
-
-  ListNode *node;
-  char *filename = getCustomArtworkFilename(basename, artwork_info->type);
-
-  if (filename == NULL)
-  {
-    int error_mode = ERR_WARN;
-
-#if 1
-    /* !!! NEW ARTWORK FALLBACK CODE !!! NEARLY UNTESTED !!! */
-    /* before failing, try fallback to default artwork */
-#else
-    /* we can get away without sounds and music, but not without graphics */
-    if (*listnode == NULL && artwork_info->type == ARTWORK_TYPE_GRAPHICS)
-      error_mode = ERR_EXIT;
-#endif
-
-    Error(error_mode, "cannot find artwork file '%s'", basename);
-    return;
-  }
-
-  /* check if the old and the new artwork file are the same */
-  if (*listnode && strcmp((*listnode)->source_filename, filename) == 0)
+  if (*listnode && strEqual((*listnode)->source_filename, filename))
   {
     /* The old and new artwork are the same (have the same filename and path).
        This usually means that this artwork does not exist in this artwork set
@@ -2627,10 +2625,6 @@ static void replaceArtworkListEntry(struct ArtworkListInfo *artwork_info,
       return;
   }
 
-#if 0
-  printf("::: %s: '%s'\n", init_text[artwork_info->type], basename);
-#endif
-
   DrawInitText(init_text[artwork_info->type], 120, FC_GREEN);
   DrawInitText(basename, 150, FC_YELLOW);
 
@@ -2648,19 +2642,15 @@ static void replaceArtworkListEntry(struct ArtworkListInfo *artwork_info,
   {
     int error_mode = ERR_WARN;
 
-#if 1
     /* we can get away without sounds and music, but not without graphics */
     if (artwork_info->type == ARTWORK_TYPE_GRAPHICS)
       error_mode = ERR_EXIT;
-#endif
 
     Error(error_mode, "cannot load artwork file '%s'", basename);
     return;
   }
 }
-#endif
 
-#if 1
 static void LoadCustomArtwork(struct ArtworkListInfo *artwork_info,
                              struct ListNodeInfo **listnode,
                              struct FileInfo *file_list_entry)
@@ -2669,7 +2659,7 @@ static void LoadCustomArtwork(struct ArtworkListInfo *artwork_info,
   printf("GOT CUSTOM ARTWORK FILE '%s'\n", filename);
 #endif
 
-  if (strcmp(file_list_entry->filename, UNDEFINED_FILENAME) == 0)
+  if (strEqual(file_list_entry->filename, UNDEFINED_FILENAME))
   {
     deleteArtworkListEntry(artwork_info, listnode);
     return;
@@ -2678,86 +2668,6 @@ static void LoadCustomArtwork(struct ArtworkListInfo *artwork_info,
   replaceArtworkListEntry(artwork_info, listnode, file_list_entry);
 }
 
-#else
-
-static void LoadCustomArtwork(struct ArtworkListInfo *artwork_info,
-                             struct ListNodeInfo **listnode,
-                             char *basename)
-{
-#if 0
-  printf("GOT CUSTOM ARTWORK FILE '%s'\n", filename);
-#endif
-
-  if (strcmp(basename, UNDEFINED_FILENAME) == 0)
-  {
-    deleteArtworkListEntry(artwork_info, listnode);
-    return;
-  }
-
-  replaceArtworkListEntry(artwork_info, listnode, basename);
-}
-#endif
-
-#if 1
-static void LoadArtworkToList(struct ArtworkListInfo *artwork_info,
-                             struct ListNodeInfo **listnode,
-                             struct FileInfo *file_list_entry)
-{
-#if 0
-  if (artwork_info->artwork_list == NULL ||
-      list_pos >= artwork_info->num_file_list_entries)
-    return;
-#endif
-
-#if 0
-  printf("loading artwork '%s' ...  [%d]\n",
-        basename, getNumNodes(artwork_info->content_list));
-#endif
-
-#if 1
-  LoadCustomArtwork(artwork_info, listnode, file_list_entry);
-#else
-  LoadCustomArtwork(artwork_info, &artwork_info->artwork_list[list_pos],
-                   basename);
-#endif
-
-#if 0
-  printf("loading artwork '%s' done [%d]\n",
-        basename, getNumNodes(artwork_info->content_list));
-#endif
-}
-
-#else
-
-static void LoadArtworkToList(struct ArtworkListInfo *artwork_info,
-                             struct ListNodeInfo **listnode,
-                             char *basename, int list_pos)
-{
-#if 0
-  if (artwork_info->artwork_list == NULL ||
-      list_pos >= artwork_info->num_file_list_entries)
-    return;
-#endif
-
-#if 0
-  printf("loading artwork '%s' ...  [%d]\n",
-        basename, getNumNodes(artwork_info->content_list));
-#endif
-
-#if 1
-  LoadCustomArtwork(artwork_info, listnode, basename);
-#else
-  LoadCustomArtwork(artwork_info, &artwork_info->artwork_list[list_pos],
-                   basename);
-#endif
-
-#if 0
-  printf("loading artwork '%s' done [%d]\n",
-        basename, getNumNodes(artwork_info->content_list));
-#endif
-}
-#endif
-
 void ReloadCustomArtworkList(struct ArtworkListInfo *artwork_info)
 {
   struct FileInfo *file_list = artwork_info->file_list;
@@ -2767,73 +2677,13 @@ void ReloadCustomArtworkList(struct ArtworkListInfo *artwork_info)
     artwork_info->num_dynamic_file_list_entries;
   int i;
 
-#if 0
-  printf("DEBUG: reloading %d static artwork files ...\n",
-        num_file_list_entries);
-#endif
-
   for (i = 0; i < num_file_list_entries; i++)
-  {
-#if 0
-    if (strcmp(file_list[i].token, "background") == 0)
-      printf("::: '%s' -> '%s'\n", file_list[i].token, file_list[i].filename);
-#endif
-
-#if 1
-    LoadArtworkToList(artwork_info, &artwork_info->artwork_list[i],
+    LoadCustomArtwork(artwork_info, &artwork_info->artwork_list[i],
                      &file_list[i]);
-#else
-    LoadArtworkToList(artwork_info, &artwork_info->artwork_list[i],
-                     file_list[i].filename, i);
-#endif
-
-#if 0
-    /* !!! NEW ARTWORK FALLBACK CODE !!! NEARLY UNTESTED !!! */
-    if (artwork_info->artwork_list[i] == NULL &&
-       strcmp(file_list[i].filename, UNDEFINED_FILENAME) != 0 &&
-       strcmp(file_list[i].default_filename, file_list[i].filename) != 0 &&
-       strcmp(file_list[i].default_filename, UNDEFINED_FILENAME) != 0)
-    {
-      Error(ERR_WARN, "trying default artwork file '%s'",
-           file_list[i].default_filename);
-
-      LoadArtworkToList(artwork_info, &artwork_info->artwork_list[i],
-                       file_list[i].default_filename, i);
-
-      /* even the fallback to default artwork was not successful -- fail now */
-      if (artwork_info->artwork_list[i] == NULL &&
-         artwork_info->type == ARTWORK_TYPE_GRAPHICS)
-       Error(ERR_EXIT, "cannot find artwork file '%s' or default file '%s'",
-             file_list[i].filename, file_list[i].default_filename);
-
-      file_list[i].fallback_to_default = TRUE;
-    }
-#endif
-  }
-
-#if 0
-  printf("DEBUG: reloading %d dynamic artwork files ...\n",
-        num_dynamic_file_list_entries);
-#endif
 
   for (i = 0; i < num_dynamic_file_list_entries; i++)
-  {
-#if 1
-    LoadArtworkToList(artwork_info, &artwork_info->dynamic_artwork_list[i],
+    LoadCustomArtwork(artwork_info, &artwork_info->dynamic_artwork_list[i],
                      &dynamic_file_list[i]);
-#else
-    LoadArtworkToList(artwork_info, &artwork_info->dynamic_artwork_list[i],
-                     dynamic_file_list[i].filename, i);
-#endif
-
-#if 0
-    printf("::: '%s', '0x%08x'\n",
-          dynamic_file_list[i].filename,
-          dynamic_file_list[i].default_filename);
-#endif
-
-    /* dynamic artwork does not have default filename! */
-  }
 
 #if 0
   dumpList(artwork_info->content_list);
@@ -2862,46 +2712,43 @@ void FreeCustomArtworkLists(struct ArtworkListInfo *artwork_info)
   if (artwork_info == NULL)
     return;
 
-#if 0
-  printf("%s: FREEING ARTWORK ...\n",
-        IS_CHILD_PROCESS() ? "CHILD" : "PARENT");
-#endif
-
   FreeCustomArtworkList(artwork_info, &artwork_info->artwork_list,
                        &artwork_info->num_file_list_entries);
 
   FreeCustomArtworkList(artwork_info, &artwork_info->dynamic_artwork_list,
                        &artwork_info->num_dynamic_file_list_entries);
-
-#if 0
-  printf("%s: FREEING ARTWORK -- DONE\n",
-        IS_CHILD_PROCESS() ? "CHILD" : "PARENT");
-#endif
 }
 
 
 /* ------------------------------------------------------------------------- */
 /* functions only needed for non-Unix (non-command-line) systems             */
 /* (MS-DOS only; SDL/Windows creates files "stdout.txt" and "stderr.txt")    */
+/* (now also added for Windows, to create files in user data directory)      */
 /* ------------------------------------------------------------------------- */
 
-#if defined(PLATFORM_MSDOS)
-
-#define ERROR_FILENAME         "stderr.txt"
+char *getErrorFilename(char *basename)
+{
+  return getPath2(getUserGameDataDir(), basename);
+}
 
-void initErrorFile()
+void openErrorFile()
 {
-  unlink(ERROR_FILENAME);
+  InitUserDataDirectory();
+
+  if ((program.error_file = fopen(program.error_filename, MODE_WRITE)) == NULL)
+    fprintf_newline(stderr, "ERROR: cannot open file '%s' for writing!",
+                   program.error_filename);
 }
 
-FILE *openErrorFile()
+void closeErrorFile()
 {
-  return fopen(ERROR_FILENAME, MODE_APPEND);
+  if (program.error_file != stderr)    /* do not close stream 'stderr' */
+    fclose(program.error_file);
 }
 
 void dumpErrorFile()
 {
-  FILE *error_file = fopen(ERROR_FILENAME, MODE_READ);
+  FILE *error_file = fopen(program.error_filename, MODE_READ);
 
   if (error_file != NULL)
   {
@@ -2911,7 +2758,18 @@ void dumpErrorFile()
     fclose(error_file);
   }
 }
+
+void NotifyUserAboutErrorFile()
+{
+#if defined(PLATFORM_WIN32)
+  char *title_text = getStringCat2(program.program_title, " Error Message");
+  char *error_text = getStringCat2("The program was aborted due to an error; "
+                                  "for details, see the following error file:"
+                                  STRING_NEWLINE, program.error_filename);
+
+  MessageBox(NULL, error_text, title_text, MB_OK);
 #endif
+}
 
 
 /* ------------------------------------------------------------------------- */