rnd-20031208-1-src
[rocksndiamonds.git] / src / libgame / setup.c
index 8be4c7a8a80e59312ae41a010d37117da914331c..b1e3b4439756a3307269cd94a56b6362775c294c 100644 (file)
 #include "misc.h"
 #include "hash.h"
 
 #include "misc.h"
 #include "hash.h"
 
-/* file names and filename extensions */
-#if !defined(PLATFORM_MSDOS)
-#define LEVELSETUP_DIRECTORY   "levelsetup"
-#define SETUP_FILENAME         "setup.conf"
-#define LEVELSETUP_FILENAME    "levelsetup.conf"
-#define LEVELINFO_FILENAME     "levelinfo.conf"
-#define GRAPHICSINFO_FILENAME  "graphicsinfo.conf"
-#define SOUNDSINFO_FILENAME    "soundsinfo.conf"
-#define MUSICINFO_FILENAME     "musicinfo.conf"
-#define LEVELFILE_EXTENSION    "level"
-#define TAPEFILE_EXTENSION     "tape"
-#define SCOREFILE_EXTENSION    "score"
-#else
-#define LEVELSETUP_DIRECTORY   "lvlsetup"
-#define SETUP_FILENAME         "setup.cnf"
-#define LEVELSETUP_FILENAME    "lvlsetup.cnf"
-#define LEVELINFO_FILENAME     "lvlinfo.cnf"
-#define GRAPHICSINFO_FILENAME  "gfxinfo.cnf"
-#define SOUNDSINFO_FILENAME    "sndinfo.cnf"
-#define MUSICINFO_FILENAME     "musinfo.cnf"
-#define LEVELFILE_EXTENSION    "lvl"
-#define TAPEFILE_EXTENSION     "tap"
-#define SCOREFILE_EXTENSION    "sco"
-#endif
 
 #define NUM_LEVELCLASS_DESC    8
 
 #define NUM_LEVELCLASS_DESC    8
+
 static char *levelclass_desc[NUM_LEVELCLASS_DESC] =
 {
   "Tutorial Levels",
 static char *levelclass_desc[NUM_LEVELCLASS_DESC] =
 {
   "Tutorial Levels",
@@ -61,64 +38,44 @@ static char *levelclass_desc[NUM_LEVELCLASS_DESC] =
   "DX Boulderdash"
 };
 
   "DX Boulderdash"
 };
 
-#define LEVELCOLOR(n)  (IS_LEVELCLASS_TUTORIAL(n) ?            FC_BLUE : \
-                        IS_LEVELCLASS_CLASSICS(n) ?            FC_RED : \
-                        IS_LEVELCLASS_BD(n) ?                  FC_GREEN : \
-                        IS_LEVELCLASS_EM(n) ?                  FC_YELLOW : \
-                        IS_LEVELCLASS_SP(n) ?                  FC_GREEN : \
-                        IS_LEVELCLASS_DX(n) ?                  FC_YELLOW : \
-                        IS_LEVELCLASS_CONTRIBUTION(n) ?        FC_GREEN : \
-                        IS_LEVELCLASS_USER(n) ?                FC_RED : \
+
+#define LEVELCOLOR(n)  (IS_LEVELCLASS_TUTORIAL(n) ?            FC_BLUE :    \
+                        IS_LEVELCLASS_CLASSICS(n) ?            FC_RED :     \
+                        IS_LEVELCLASS_BD(n) ?                  FC_GREEN :   \
+                        IS_LEVELCLASS_EM(n) ?                  FC_YELLOW :  \
+                        IS_LEVELCLASS_SP(n) ?                  FC_GREEN :   \
+                        IS_LEVELCLASS_DX(n) ?                  FC_YELLOW :  \
+                        IS_LEVELCLASS_CONTRIB(n) ?             FC_GREEN :   \
+                        IS_LEVELCLASS_PRIVATE(n) ?             FC_RED :     \
                         FC_BLUE)
 
                         FC_BLUE)
 
-#define LEVELSORTING(n)        (IS_LEVELCLASS_TUTORIAL(n) ?            0 : \
-                        IS_LEVELCLASS_CLASSICS(n) ?            1 : \
-                        IS_LEVELCLASS_BD(n) ?                  2 : \
-                        IS_LEVELCLASS_EM(n) ?                  3 : \
-                        IS_LEVELCLASS_SP(n) ?                  4 : \
-                        IS_LEVELCLASS_DX(n) ?                  5 : \
-                        IS_LEVELCLASS_CONTRIBUTION(n) ?        6 : \
-                        IS_LEVELCLASS_USER(n) ?                7 : \
+#define LEVELSORTING(n)        (IS_LEVELCLASS_TUTORIAL(n) ?            0 :     \
+                        IS_LEVELCLASS_CLASSICS(n) ?            1 :     \
+                        IS_LEVELCLASS_BD(n) ?                  2 :     \
+                        IS_LEVELCLASS_EM(n) ?                  3 :     \
+                        IS_LEVELCLASS_SP(n) ?                  4 :     \
+                        IS_LEVELCLASS_DX(n) ?                  5 :     \
+                        IS_LEVELCLASS_CONTRIB(n) ?             6 :     \
+                        IS_LEVELCLASS_PRIVATE(n) ?             7 :     \
                         9)
 
                         9)
 
-#define ARTWORKCOLOR(n)        (IS_ARTWORKCLASS_CLASSICS(n) ?          FC_RED : \
-                        IS_ARTWORKCLASS_CONTRIBUTION(n) ?      FC_YELLOW : \
-                        IS_ARTWORKCLASS_LEVEL(n) ?             FC_GREEN : \
-                        IS_ARTWORKCLASS_USER(n) ?              FC_RED : \
+#define ARTWORKCOLOR(n)        (IS_ARTWORKCLASS_CLASSICS(n) ?          FC_RED :     \
+                        IS_ARTWORKCLASS_CONTRIB(n) ?           FC_YELLOW :  \
+                        IS_ARTWORKCLASS_PRIVATE(n) ?           FC_RED :     \
+                        IS_ARTWORKCLASS_LEVEL(n) ?             FC_GREEN :   \
                         FC_BLUE)
 
                         FC_BLUE)
 
-#define ARTWORKSORTING(n) (IS_ARTWORKCLASS_CLASSICS(n) ?       0 : \
-                        IS_ARTWORKCLASS_CONTRIBUTION(n) ?      1 : \
-                        IS_ARTWORKCLASS_LEVEL(n) ?             2 : \
-                        IS_ARTWORKCLASS_USER(n) ?              3 : \
-                        9)
+#define ARTWORKSORTING(n) (IS_ARTWORKCLASS_CLASSICS(n) ?       0 :     \
+                          IS_ARTWORKCLASS_LEVEL(n) ?           1 :     \
+                          IS_ARTWORKCLASS_CONTRIB(n) ?         2 :     \
+                          IS_ARTWORKCLASS_PRIVATE(n) ?         3 :     \
+                          9)
 
 #define TOKEN_VALUE_POSITION           40
 #define TOKEN_COMMENT_POSITION         60
 
 #define MAX_COOKIE_LEN                 256
 
 
 #define TOKEN_VALUE_POSITION           40
 #define TOKEN_COMMENT_POSITION         60
 
 #define MAX_COOKIE_LEN                 256
 
-#define ARTWORKINFO_FILENAME(type)     ((type) == TREE_TYPE_GRAPHICS_DIR ? \
-                                        GRAPHICSINFO_FILENAME :            \
-                                        (type) == TREE_TYPE_SOUNDS_DIR ?   \
-                                        SOUNDSINFO_FILENAME :              \
-                                        (type) == TREE_TYPE_MUSIC_DIR ?    \
-                                        MUSICINFO_FILENAME : "")
-
-#define ARTWORK_DIRECTORY(type)                ((type) == TREE_TYPE_GRAPHICS_DIR ? \
-                                        GRAPHICS_DIRECTORY :               \
-                                        (type) == TREE_TYPE_SOUNDS_DIR ?   \
-                                        SOUNDS_DIRECTORY :                 \
-                                        (type) == TREE_TYPE_MUSIC_DIR ?    \
-                                        MUSIC_DIRECTORY : "")
-
-#define OPTIONS_ARTWORK_DIRECTORY(type)        ((type) == TREE_TYPE_GRAPHICS_DIR ? \
-                                        options.graphics_directory :       \
-                                        (type) == TREE_TYPE_SOUNDS_DIR ?   \
-                                        options.sounds_directory :         \
-                                        (type) == TREE_TYPE_MUSIC_DIR ?    \
-                                        options.music_directory : "")
-
 
 /* ------------------------------------------------------------------------- */
 /* file functions                                                            */
 
 /* ------------------------------------------------------------------------- */
 /* file functions                                                            */
@@ -151,23 +108,6 @@ static char *getUserLevelDir(char *level_subdir)
   return userlevel_dir;
 }
 
   return userlevel_dir;
 }
 
-static char *getTapeDir(char *level_subdir)
-{
-  static char *tape_dir = NULL;
-  char *data_dir = getUserDataDir();
-  char *tape_subdir = TAPES_DIRECTORY;
-
-  if (tape_dir)
-    free(tape_dir);
-
-  if (level_subdir != NULL)
-    tape_dir = getPath3(data_dir, tape_subdir, level_subdir);
-  else
-    tape_dir = getPath2(data_dir, tape_subdir);
-
-  return tape_dir;
-}
-
 static char *getScoreDir(char *level_subdir)
 {
   static char *score_dir = NULL;
 static char *getScoreDir(char *level_subdir)
 {
   static char *score_dir = NULL;
@@ -223,6 +163,37 @@ static char *getCurrentLevelDir()
   return getLevelDirFromTreeInfo(leveldir_current);
 }
 
   return getLevelDirFromTreeInfo(leveldir_current);
 }
 
+static char *getTapeDir(char *level_subdir)
+{
+  static char *tape_dir = NULL;
+  char *data_dir = getUserDataDir();
+  char *tape_subdir = TAPES_DIRECTORY;
+
+  if (tape_dir)
+    free(tape_dir);
+
+  if (level_subdir != NULL)
+    tape_dir = getPath3(data_dir, tape_subdir, level_subdir);
+  else
+    tape_dir = getPath2(data_dir, tape_subdir);
+
+  return tape_dir;
+}
+
+static char *getSolutionTapeDir()
+{
+  static char *tape_dir = NULL;
+  char *data_dir = getCurrentLevelDir();
+  char *tape_subdir = TAPES_DIRECTORY;
+
+  if (tape_dir)
+    free(tape_dir);
+
+  tape_dir = getPath2(data_dir, tape_subdir);
+
+  return tape_dir;
+}
+
 static char *getDefaultGraphicsDir(char *graphics_subdir)
 {
   static char *graphics_dir = NULL;
 static char *getDefaultGraphicsDir(char *graphics_subdir)
 {
   static char *graphics_dir = NULL;
@@ -268,6 +239,23 @@ static char *getDefaultMusicDir(char *music_subdir)
   return music_dir;
 }
 
   return music_dir;
 }
 
+static char *getDefaultArtworkSet(int type)
+{
+  return (type == TREE_TYPE_GRAPHICS_DIR ? GFX_CLASSIC_SUBDIR :
+         type == TREE_TYPE_SOUNDS_DIR   ? SND_CLASSIC_SUBDIR :
+         type == TREE_TYPE_MUSIC_DIR    ? MUS_CLASSIC_SUBDIR : "");
+}
+
+static char *getDefaultArtworkDir(int type)
+{
+  return (type == TREE_TYPE_GRAPHICS_DIR ?
+         getDefaultGraphicsDir(GFX_CLASSIC_SUBDIR) :
+         type == TREE_TYPE_SOUNDS_DIR ?
+         getDefaultSoundsDir(SND_CLASSIC_SUBDIR) :
+         type == TREE_TYPE_MUSIC_DIR ?
+         getDefaultMusicDir(MUS_CLASSIC_SUBDIR) : "");
+}
+
 static char *getUserGraphicsDir()
 {
   static char *usergraphics_dir = NULL;
 static char *getUserGraphicsDir()
 {
   static char *usergraphics_dir = NULL;
@@ -310,47 +298,67 @@ static char *getSetupArtworkDir(TreeInfo *ti)
   return artwork_dir;
 }
 
   return artwork_dir;
 }
 
-void setLevelArtworkDir(TreeInfo *ti)
+char *setLevelArtworkDir(TreeInfo *ti)
 {
 {
-  char **artwork_path_ptr, *artwork_set;
+  char **artwork_path_ptr, **artwork_set_ptr;
   TreeInfo *level_artwork;
 
   if (ti == NULL || leveldir_current == NULL)
   TreeInfo *level_artwork;
 
   if (ti == NULL || leveldir_current == NULL)
-    return;
-
-  artwork_path_ptr =
-    (ti->type == TREE_TYPE_GRAPHICS_DIR ? &leveldir_current->graphics_path :
-     ti->type == TREE_TYPE_SOUNDS_DIR   ? &leveldir_current->sounds_path :
-     &leveldir_current->music_path);
-
-  artwork_set =
-    (ti->type == TREE_TYPE_GRAPHICS_DIR ? leveldir_current->graphics_set :
-     ti->type == TREE_TYPE_SOUNDS_DIR   ? leveldir_current->sounds_set :
-     leveldir_current->music_set);
+    return NULL;
 
 
-  if ((level_artwork = getTreeInfoFromIdentifier(ti, artwork_set)) == NULL)
-    return;
+  artwork_path_ptr = &(LEVELDIR_ARTWORK_PATH(leveldir_current, ti->type));
+  artwork_set_ptr  = &(LEVELDIR_ARTWORK_SET( leveldir_current, ti->type));
 
   if (*artwork_path_ptr != NULL)
     free(*artwork_path_ptr);
 
 
   if (*artwork_path_ptr != NULL)
     free(*artwork_path_ptr);
 
-  *artwork_path_ptr = getStringCopy(getSetupArtworkDir(level_artwork));
+  if ((level_artwork = getTreeInfoFromIdentifier(ti, *artwork_set_ptr)))
+    *artwork_path_ptr = getStringCopy(getSetupArtworkDir(level_artwork));
+  else
+  {
+    /* No (or non-existing) artwork configured in "levelinfo.conf". This would
+       normally result in using the artwork configured in the setup menu. But
+       if an artwork subdirectory exists (which might contain custom artwork
+       or an artwork configuration file), this level artwork must be treated
+       as relative to the default "classic" artwork, not to the artwork that
+       is currently configured in the setup menu. */
+
+    char *dir = getPath2(getCurrentLevelDir(), ARTWORK_DIRECTORY(ti->type));
+
+    if (*artwork_set_ptr != NULL)
+      free(*artwork_set_ptr);
+
+    if (fileExists(dir))
+    {
+      *artwork_path_ptr = getStringCopy(getDefaultArtworkDir(ti->type));
+      *artwork_set_ptr = getStringCopy(getDefaultArtworkSet(ti->type));
+    }
+    else
+    {
+      *artwork_path_ptr = getStringCopy(UNDEFINED_FILENAME);
+      *artwork_set_ptr = NULL;
+    }
+
+    free(dir);
+  }
+
+  return *artwork_set_ptr;
 }
 
 }
 
-static char *getLevelArtworkDir(int type)
+inline static char *getLevelArtworkSet(int type)
 {
 {
-  char *artwork_path;
+  if (leveldir_current == NULL)
+    return NULL;
 
 
+  return LEVELDIR_ARTWORK_SET(leveldir_current, type);
+}
+
+inline static char *getLevelArtworkDir(int type)
+{
   if (leveldir_current == NULL)
     return UNDEFINED_FILENAME;
 
   if (leveldir_current == NULL)
     return UNDEFINED_FILENAME;
 
-  artwork_path =
-    (type == TREE_TYPE_GRAPHICS_DIR ? leveldir_current->graphics_path :
-     type == TREE_TYPE_SOUNDS_DIR   ? leveldir_current->sounds_path :
-     type == TREE_TYPE_MUSIC_DIR    ? leveldir_current->music_path :
-     UNDEFINED_FILENAME);
-
-  return artwork_path;
+  return LEVELDIR_ARTWORK_PATH(leveldir_current, type);
 }
 
 char *getLevelFilename(int nr)
 }
 
 char *getLevelFilename(int nr)
@@ -361,7 +369,11 @@ char *getLevelFilename(int nr)
   if (filename != NULL)
     free(filename);
 
   if (filename != NULL)
     free(filename);
 
-  sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION);
+  if (nr < 0)
+    sprintf(basename, "template.%s", LEVELFILE_EXTENSION);
+  else
+    sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION);
+
   filename = getPath2(getCurrentLevelDir(), basename);
 
   return filename;
   filename = getPath2(getCurrentLevelDir(), basename);
 
   return filename;
@@ -381,6 +393,20 @@ char *getTapeFilename(int nr)
   return filename;
 }
 
   return filename;
 }
 
+char *getSolutionTapeFilename(int nr)
+{
+  static char *filename = NULL;
+  char basename[MAX_FILENAME_LEN];
+
+  if (filename != NULL)
+    free(filename);
+
+  sprintf(basename, "%03d.%s", nr, TAPEFILE_EXTENSION);
+  filename = getPath2(getSolutionTapeDir(), basename);
+
+  return filename;
+}
+
 char *getScoreFilename(int nr)
 {
   static char *filename = NULL;
 char *getScoreFilename(int nr)
 {
   static char *filename = NULL;
@@ -407,7 +433,71 @@ char *getSetupFilename()
   return filename;
 }
 
   return filename;
 }
 
-static char *getCorrectedImageBasename(char *basename)
+char *getEditorSetupFilename()
+{
+  static char *filename = NULL;
+
+  if (filename != NULL)
+    free(filename);
+
+  filename = getPath2(getSetupDir(), EDITORSETUP_FILENAME);
+
+  return filename;
+}
+
+char *getHelpAnimFilename()
+{
+  static char *filename = NULL;
+
+  if (filename != NULL)
+    free(filename);
+
+  filename = getPath2(getCurrentLevelDir(), HELPANIM_FILENAME);
+
+  return filename;
+}
+
+char *getHelpTextFilename()
+{
+  static char *filename = NULL;
+
+  if (filename != NULL)
+    free(filename);
+
+  filename = getPath2(getCurrentLevelDir(), HELPTEXT_FILENAME);
+
+  return filename;
+}
+
+char *getLevelSetInfoFilename()
+{
+  static char *filename = NULL;
+  char *basenames[] =
+  {
+    "readme",
+    "readme.txt",
+    "README",
+    "README.txt",
+    "README.TXT",
+
+    NULL
+  };
+  int i;
+
+  for (i = 0; basenames[i] != NULL; i++)
+  {
+    if (filename != NULL)
+      free(filename);
+
+    filename = getPath2(getCurrentLevelDir(), basenames[i]);
+    if (fileExists(filename))
+      return filename;
+  }
+
+  return NULL;
+}
+
+static char *getCorrectedArtworkBasename(char *basename)
 {
   char *basename_corrected = basename;
 
 {
   char *basename_corrected = basename;
 
@@ -422,7 +512,7 @@ static char *getCorrectedImageBasename(char *basename)
     /* if corrected filename is still longer than standard MS-DOS filename
        size (8 characters + 1 dot + 3 characters file extension), shorten
        filename by writing file extension after 8th basename character */
     /* if corrected filename is still longer than standard MS-DOS filename
        size (8 characters + 1 dot + 3 characters file extension), shorten
        filename by writing file extension after 8th basename character */
-    if (strlen(basename_corrected) > 8+1+3)
+    if (strlen(basename_corrected) > 8 + 1 + 3)
     {
       static char *msdos_filename = NULL;
 
     {
       static char *msdos_filename = NULL;
 
@@ -430,7 +520,9 @@ static char *getCorrectedImageBasename(char *basename)
        free(msdos_filename);
 
       msdos_filename = getStringCopy(basename_corrected);
        free(msdos_filename);
 
       msdos_filename = getStringCopy(basename_corrected);
-      strncpy(&msdos_filename[8], &basename[strlen(basename) - 1+3], 1+3 + 1);
+      strncpy(&msdos_filename[8], &basename[strlen(basename) - (1+3)], 1+3 +1);
+
+      basename_corrected = msdos_filename;
     }
   }
 #endif
     }
   }
 #endif
@@ -441,38 +533,49 @@ static char *getCorrectedImageBasename(char *basename)
 char *getCustomImageFilename(char *basename)
 {
   static char *filename = NULL;
 char *getCustomImageFilename(char *basename)
 {
   static char *filename = NULL;
+  boolean skip_setup_artwork = FALSE;
 
   if (filename != NULL)
     free(filename);
 
 
   if (filename != NULL)
     free(filename);
 
-  basename = getCorrectedImageBasename(basename);
+  basename = getCorrectedArtworkBasename(basename);
 
   if (!setup.override_level_graphics)
   {
 
   if (!setup.override_level_graphics)
   {
-    /* 1st try: look for special artwork configured in level series config */
-    filename = getPath2(getLevelArtworkDir(TREE_TYPE_GRAPHICS_DIR), basename);
+    /* 1st try: look for special artwork in current level series directory */
+    filename = getPath3(getCurrentLevelDir(), GRAPHICS_DIRECTORY, basename);
     if (fileExists(filename))
       return filename;
 
     free(filename);
 
     if (fileExists(filename))
       return filename;
 
     free(filename);
 
-    /* 2nd try: look for special artwork in current level series directory */
-    filename = getPath3(getCurrentLevelDir(), GRAPHICS_DIRECTORY, basename);
+    /* check if there is special artwork configured in level series config */
+    if (getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) != NULL)
+    {
+      /* 2nd try: look for special artwork configured in level series config */
+      filename = getPath2(getLevelArtworkDir(ARTWORK_TYPE_GRAPHICS), basename);
+      if (fileExists(filename))
+       return filename;
+
+      free(filename);
+
+      /* take missing artwork configured in level set config from default */
+      skip_setup_artwork = TRUE;
+    }
+  }
+
+  if (!skip_setup_artwork)
+  {
+    /* 3rd try: look for special artwork in configured artwork directory */
+    filename = getPath2(getSetupArtworkDir(artwork.gfx_current), basename);
     if (fileExists(filename))
       return filename;
 
     free(filename);
   }
 
     if (fileExists(filename))
       return filename;
 
     free(filename);
   }
 
-  /* 3rd try: look for special artwork in configured artwork directory */
-  filename = getPath2(getSetupArtworkDir(artwork.gfx_current), basename);
-  if (fileExists(filename))
-    return filename;
-
-  free(filename);
-
   /* 4th try: look for default artwork in new default artwork directory */
   /* 4th try: look for default artwork in new default artwork directory */
-  filename = getPath2(getDefaultGraphicsDir(GRAPHICS_SUBDIR), basename);
+  filename = getPath2(getDefaultGraphicsDir(GFX_CLASSIC_SUBDIR), basename);
   if (fileExists(filename))
     return filename;
 
   if (fileExists(filename))
     return filename;
 
@@ -489,43 +592,115 @@ char *getCustomImageFilename(char *basename)
 char *getCustomSoundFilename(char *basename)
 {
   static char *filename = NULL;
 char *getCustomSoundFilename(char *basename)
 {
   static char *filename = NULL;
+  boolean skip_setup_artwork = FALSE;
 
   if (filename != NULL)
     free(filename);
 
 
   if (filename != NULL)
     free(filename);
 
+  basename = getCorrectedArtworkBasename(basename);
+
   if (!setup.override_level_sounds)
   {
   if (!setup.override_level_sounds)
   {
-    /* 1st try: look for special artwork configured in level series config */
-    filename = getPath2(getLevelArtworkDir(TREE_TYPE_SOUNDS_DIR), basename);
+    /* 1st try: look for special artwork in current level series directory */
+    filename = getPath3(getCurrentLevelDir(), SOUNDS_DIRECTORY, basename);
     if (fileExists(filename))
       return filename;
 
     free(filename);
 
     if (fileExists(filename))
       return filename;
 
     free(filename);
 
-    /* 2nd try: look for special artwork in current level series directory */
-    filename = getPath3(getCurrentLevelDir(), SOUNDS_DIRECTORY, basename);
+    /* check if there is special artwork configured in level series config */
+    if (getLevelArtworkSet(ARTWORK_TYPE_SOUNDS) != NULL)
+    {
+      /* 2nd try: look for special artwork configured in level series config */
+      filename = getPath2(getLevelArtworkDir(TREE_TYPE_SOUNDS_DIR), basename);
+      if (fileExists(filename))
+       return filename;
+
+      free(filename);
+
+      /* take missing artwork configured in level set config from default */
+      skip_setup_artwork = TRUE;
+    }
+  }
+
+  if (!skip_setup_artwork)
+  {
+    /* 3rd try: look for special artwork in configured artwork directory */
+    filename = getPath2(getSetupArtworkDir(artwork.snd_current), basename);
     if (fileExists(filename))
       return filename;
 
     free(filename);
   }
 
     if (fileExists(filename))
       return filename;
 
     free(filename);
   }
 
-  /* 3rd try: look for special artwork in configured artwork directory */
-  filename = getPath2(getSetupArtworkDir(artwork.snd_current), basename);
+  /* 4th try: look for default artwork in new default artwork directory */
+  filename = getPath2(getDefaultSoundsDir(SND_CLASSIC_SUBDIR), basename);
   if (fileExists(filename))
     return filename;
 
   free(filename);
 
   if (fileExists(filename))
     return filename;
 
   free(filename);
 
+  /* 5th try: look for default artwork in old default artwork directory */
+  filename = getPath2(options.sounds_directory, basename);
+  if (fileExists(filename))
+    return filename;
+
+  return NULL;         /* cannot find specified artwork file anywhere */
+}
+
+char *getCustomMusicFilename(char *basename)
+{
+  static char *filename = NULL;
+  boolean skip_setup_artwork = FALSE;
+
+  if (filename != NULL)
+    free(filename);
+
+  basename = getCorrectedArtworkBasename(basename);
+
+  if (!setup.override_level_music)
+  {
+    /* 1st try: look for special artwork in current level series directory */
+    filename = getPath3(getCurrentLevelDir(), MUSIC_DIRECTORY, basename);
+    if (fileExists(filename))
+      return filename;
+
+    free(filename);
+
+    /* check if there is special artwork configured in level series config */
+    if (getLevelArtworkSet(ARTWORK_TYPE_MUSIC) != NULL)
+    {
+      /* 2nd try: look for special artwork configured in level series config */
+      filename = getPath2(getLevelArtworkDir(TREE_TYPE_MUSIC_DIR), basename);
+      if (fileExists(filename))
+       return filename;
+
+      free(filename);
+
+      /* take missing artwork configured in level set config from default */
+      skip_setup_artwork = TRUE;
+    }
+  }
+
+  if (!skip_setup_artwork)
+  {
+    /* 3rd try: look for special artwork in configured artwork directory */
+    filename = getPath2(getSetupArtworkDir(artwork.mus_current), basename);
+    if (fileExists(filename))
+      return filename;
+
+    free(filename);
+  }
+
   /* 4th try: look for default artwork in new default artwork directory */
   /* 4th try: look for default artwork in new default artwork directory */
-  filename = getPath2(getDefaultSoundsDir(SOUNDS_SUBDIR), basename);
+  filename = getPath2(getDefaultMusicDir(MUS_CLASSIC_SUBDIR), basename);
   if (fileExists(filename))
     return filename;
 
   free(filename);
 
   /* 5th try: look for default artwork in old default artwork directory */
   if (fileExists(filename))
     return filename;
 
   free(filename);
 
   /* 5th try: look for default artwork in old default artwork directory */
-  filename = getPath2(options.sounds_directory, basename);
+  filename = getPath2(options.music_directory, basename);
   if (fileExists(filename))
     return filename;
 
   if (fileExists(filename))
     return filename;
 
@@ -538,6 +713,8 @@ char *getCustomArtworkFilename(char *basename, int type)
     return getCustomImageFilename(basename);
   else if (type == ARTWORK_TYPE_SOUNDS)
     return getCustomSoundFilename(basename);
     return getCustomImageFilename(basename);
   else if (type == ARTWORK_TYPE_SOUNDS)
     return getCustomSoundFilename(basename);
+  else if (type == ARTWORK_TYPE_MUSIC)
+    return getCustomMusicFilename(basename);
   else
     return UNDEFINED_FILENAME;
 }
   else
     return UNDEFINED_FILENAME;
 }
@@ -547,39 +724,62 @@ char *getCustomArtworkConfigFilename(int type)
   return getCustomArtworkFilename(ARTWORKINFO_FILENAME(type), type);
 }
 
   return getCustomArtworkFilename(ARTWORKINFO_FILENAME(type), type);
 }
 
+char *getCustomArtworkLevelConfigFilename(int type)
+{
+  static char *filename = NULL;
+
+  if (filename != NULL)
+    free(filename);
+
+  filename = getPath2(getLevelArtworkDir(type), ARTWORKINFO_FILENAME(type));
+
+  return filename;
+}
+
 char *getCustomMusicDirectory(void)
 {
   static char *directory = NULL;
 char *getCustomMusicDirectory(void)
 {
   static char *directory = NULL;
+  boolean skip_setup_artwork = FALSE;
 
   if (directory != NULL)
     free(directory);
 
   if (!setup.override_level_music)
   {
 
   if (directory != NULL)
     free(directory);
 
   if (!setup.override_level_music)
   {
-    /* 1st try: look for special artwork configured in level series config */
-    directory = getStringCopy(getLevelArtworkDir(TREE_TYPE_MUSIC_DIR));
+    /* 1st try: look for special artwork in current level series directory */
+    directory = getPath2(getCurrentLevelDir(), MUSIC_DIRECTORY);
     if (fileExists(directory))
       return directory;
 
     free(directory);
 
     if (fileExists(directory))
       return directory;
 
     free(directory);
 
-    /* 2nd try: look for special artwork in current level series directory */
-    directory = getPath2(getCurrentLevelDir(), MUSIC_DIRECTORY);
+    /* check if there is special artwork configured in level series config */
+    if (getLevelArtworkSet(ARTWORK_TYPE_MUSIC) != NULL)
+    {
+      /* 2nd try: look for special artwork configured in level series config */
+      directory = getStringCopy(getLevelArtworkDir(TREE_TYPE_MUSIC_DIR));
+      if (fileExists(directory))
+       return directory;
+
+      free(directory);
+
+      /* take missing artwork configured in level set config from default */
+      skip_setup_artwork = TRUE;
+    }
+  }
+
+  if (!skip_setup_artwork)
+  {
+    /* 3rd try: look for special artwork in configured artwork directory */
+    directory = getStringCopy(getSetupArtworkDir(artwork.mus_current));
     if (fileExists(directory))
       return directory;
 
     free(directory);
   }
 
     if (fileExists(directory))
       return directory;
 
     free(directory);
   }
 
-  /* 3rd try: look for special artwork in configured artwork directory */
-  directory = getStringCopy(getSetupArtworkDir(artwork.mus_current));
-  if (fileExists(directory))
-    return directory;
-
-  free(directory);
-
   /* 4th try: look for default artwork in new default artwork directory */
   /* 4th try: look for default artwork in new default artwork directory */
-  directory = getStringCopy(getDefaultMusicDir(MUSIC_SUBDIR));
+  directory = getStringCopy(getDefaultMusicDir(MUS_CLASSIC_SUBDIR));
   if (fileExists(directory))
     return directory;
 
   if (fileExists(directory))
     return directory;
 
@@ -766,11 +966,16 @@ void dumpTreeInfo(TreeInfo *node, int depth)
 
   while (node)
   {
 
   while (node)
   {
-    for (i=0; i<(depth + 1) * 3; i++)
+    for (i = 0; i < (depth + 1) * 3; i++)
       printf(" ");
 
       printf(" ");
 
+#if 1
+    printf("filename == '%s' ['%s', '%s'] [%d])\n",
+          node->filename, node->fullpath, node->basepath, node->user_defined);
+#else
     printf("filename == '%s' (%s) [%s] (%d)\n",
           node->filename, node->name, node->identifier, node->sort_priority);
     printf("filename == '%s' (%s) [%s] (%d)\n",
           node->filename, node->name, node->identifier, node->sort_priority);
+#endif
 
     if (node->node_group != NULL)
       dumpTreeInfo(node->node_group, depth + 1);
 
     if (node->node_group != NULL)
       dumpTreeInfo(node->node_group, depth + 1);
@@ -807,7 +1012,7 @@ void sortTreeInfo(TreeInfo **node_first,
        compare_function);
 
   /* update the linkage of list elements with the sorted node array */
        compare_function);
 
   /* update the linkage of list elements with the sorted node array */
-  for (i=0; i<num_nodes - 1; i++)
+  for (i = 0; i < num_nodes - 1; i++)
     sort_array[i]->next = sort_array[i + 1];
   sort_array[num_nodes - 1]->next = NULL;
 
     sort_array[i]->next = sort_array[i + 1];
   sort_array[num_nodes - 1]->next = NULL;
 
@@ -1001,7 +1206,7 @@ int getFileVersionFromCookieString(const char *cookie)
   version_major = ptr_cookie2[0] - '0';
   version_minor = ptr_cookie2[2] - '0';
 
   version_major = ptr_cookie2[0] - '0';
   version_minor = ptr_cookie2[2] - '0';
 
-  return VERSION_IDENT(version_major, version_minor, 0);
+  return VERSION_IDENT(version_major, version_minor, 0, 0);
 }
 
 boolean checkCookieString(const char *cookie, const char *template)
 }
 
 boolean checkCookieString(const char *cookie, const char *template)
@@ -1029,9 +1234,13 @@ char *getFormattedSetupEntry(char *token, char *value)
   int i;
   static char entry[MAX_LINE_LEN];
 
   int i;
   static char entry[MAX_LINE_LEN];
 
+  /* if value is an empty string, just return token without value */
+  if (*value == '\0')
+    return token;
+
   /* start with the token and some spaces to format output line */
   sprintf(entry, "%s:", token);
   /* start with the token and some spaces to format output line */
   sprintf(entry, "%s:", token);
-  for (i=strlen(entry); i<TOKEN_VALUE_POSITION; i++)
+  for (i = strlen(entry); i < TOKEN_VALUE_POSITION; i++)
     strcat(entry, " ");
 
   /* continue with the token's value */
     strcat(entry, " ");
 
   /* continue with the token's value */
@@ -1077,10 +1286,10 @@ char *getListEntry(SetupFileList *list, char *token)
     return getListEntry(list->next, token);
 }
 
     return getListEntry(list->next, token);
 }
 
-void setListEntry(SetupFileList *list, char *token, char *value)
+SetupFileList *setListEntry(SetupFileList *list, char *token, char *value)
 {
   if (list == NULL)
 {
   if (list == NULL)
-    return;
+    return NULL;
 
   if (strcmp(list->token, token) == 0)
   {
 
   if (strcmp(list->token, token) == 0)
   {
@@ -1088,11 +1297,24 @@ void setListEntry(SetupFileList *list, char *token, char *value)
       free(list->value);
 
     list->value = getStringCopy(value);
       free(list->value);
 
     list->value = getStringCopy(value);
+
+    return list;
   }
   else if (list->next == NULL)
   }
   else if (list->next == NULL)
-    list->next = newSetupFileList(token, value);
+    return (list->next = newSetupFileList(token, value));
+  else
+    return setListEntry(list->next, token, value);
+}
+
+SetupFileList *addListEntry(SetupFileList *list, char *token, char *value)
+{
+  if (list == NULL)
+    return NULL;
+
+  if (list->next == NULL)
+    return (list->next = newSetupFileList(token, value));
   else
   else
-    setListEntry(list->next, token, value);
+    return addListEntry(list->next, token, value);
 }
 
 #ifdef DEBUG
 }
 
 #ifdef DEBUG
@@ -1125,11 +1347,19 @@ static unsigned int get_hash_from_key(void *key)
   /*
     djb2
 
   /*
     djb2
 
-    this algorithm (k=33) was first reported by dan bernstein many years ago in
-    comp.lang.c. another version of this algorithm (now favored by bernstein)
-    uses xor: hash(i) = hash(i - 1) * 33 ^ str[i]; the magic of number 33 (why
+    This algorithm (k=33) was first reported by Dan Bernstein many years ago in
+    'comp.lang.c'. Another version of this algorithm (now favored by Bernstein)
+    uses XOR: hash(i) = hash(i - 1) * 33 ^ str[i]; the magic of number 33 (why
     it works better than many other constants, prime or not) has never been
     adequately explained.
     it works better than many other constants, prime or not) has never been
     adequately explained.
+
+    If you just want to have a good hash function, and cannot wait, djb2
+    is one of the best string hash functions i know. It has excellent
+    distribution and speed on many different sets of keys and table sizes.
+    You are not likely to do better with one of the "well known" functions
+    such as PJW, K&R, etc.
+
+    Ozan (oz) Yigit [http://www.cs.yorku.ca/~oz/hash.html]
   */
 
   char *str = (char *)key;
   */
 
   char *str = (char *)key;
@@ -1152,6 +1382,9 @@ SetupFileHash *newSetupFileHash()
   SetupFileHash *new_hash =
     create_hashtable(16, 0.75, get_hash_from_key, keys_are_equal);
 
   SetupFileHash *new_hash =
     create_hashtable(16, 0.75, get_hash_from_key, keys_are_equal);
 
+  if (new_hash == NULL)
+    Error(ERR_EXIT, "create_hashtable() failed -- out of memory");
+
   return new_hash;
 }
 
   return new_hash;
 }
 
@@ -1186,30 +1419,18 @@ void setHashEntry(SetupFileHash *hash, char *token, char *value)
       Error(ERR_EXIT, "cannot insert into hash -- aborting");
 }
 
       Error(ERR_EXIT, "cannot insert into hash -- aborting");
 }
 
-#if 0
-#ifdef DEBUG
-static void printSetupFileHash(SetupFileHash *hash)
+char *removeHashEntry(SetupFileHash *hash, char *token)
 {
 {
-#if 0
   if (hash == NULL)
   if (hash == NULL)
-    return;
-
-  /* iterator constructor only returns valid iterator for non-empty hash */
-  if (hash != NULL && hashtable_count(hash) > 0)
-  {
-    struct hashtable_itr *itr = hashtable_iterator(hash);
-
-    do
-    {
-      printf("token: '%s'\n", (char *)hashtable_iterator_key(itr));
-      printf("value: '%s'\n", (char *)hashtable_iterator_value(itr));
-    }
-    while (hashtable_iterator_advance(itr));
+    return NULL;
 
 
-    free(itr);
-  }
-#endif
+  return remove_hash_entry(hash, token);
+}
 
 
+#if 0
+#ifdef DEBUG
+static void printSetupFileHash(SetupFileHash *hash)
+{
   BEGIN_HASH_ITERATION(hash, itr)
   {
     printf("token: '%s'\n", HASH_ITERATION_TOKEN(itr));
   BEGIN_HASH_ITERATION(hash, itr)
   {
     printf("token: '%s'\n", HASH_ITERATION_TOKEN(itr));
@@ -1222,16 +1443,16 @@ static void printSetupFileHash(SetupFileHash *hash)
 
 static void *loadSetupFileData(char *filename, boolean use_hash)
 {
 
 static void *loadSetupFileData(char *filename, boolean use_hash)
 {
-  int line_len;
-  char line[MAX_LINE_LEN];
+  char line[MAX_LINE_LEN], previous_line[MAX_LINE_LEN];
   char *token, *value, *line_ptr;
   char *token, *value, *line_ptr;
-  void *setup_file_data;
+  void *setup_file_data, *insert_ptr = NULL;
+  boolean read_continued_line = FALSE;
   FILE *file;
 
   if (use_hash)
     setup_file_data = newSetupFileHash();
   else
   FILE *file;
 
   if (use_hash)
     setup_file_data = newSetupFileHash();
   else
-    setup_file_data = newSetupFileList("", "");
+    insert_ptr = setup_file_data = newSetupFileList("", "");
 
   if (!(file = fopen(filename, MODE_READ)))
   {
 
   if (!(file = fopen(filename, MODE_READ)))
   {
@@ -1239,16 +1460,48 @@ static void *loadSetupFileData(char *filename, boolean use_hash)
     return NULL;
   }
 
     return NULL;
   }
 
-  while(!feof(file))
+  while (!feof(file))
   {
     /* read next line of input file */
     if (!fgets(line, MAX_LINE_LEN, file))
       break;
 
   {
     /* read next line of input file */
     if (!fgets(line, MAX_LINE_LEN, file))
       break;
 
-    /* cut trailing comment or whitespace from input line */
+    /* cut trailing newline or carriage return */
+    for (line_ptr = &line[strlen(line)]; line_ptr >= line; line_ptr--)
+      if ((*line_ptr == '\n' || *line_ptr == '\r') && *(line_ptr + 1) == '\0')
+       *line_ptr = '\0';
+
+    if (read_continued_line)
+    {
+      /* cut leading whitespaces from input line */
+      for (line_ptr = line; *line_ptr; line_ptr++)
+       if (*line_ptr != ' ' && *line_ptr != '\t')
+         break;
+
+      /* append new line to existing line, if there is enough space */
+      if (strlen(previous_line) + strlen(line_ptr) < MAX_LINE_LEN)
+       strcat(previous_line, line_ptr);
+
+      strcpy(line, previous_line);     /* copy storage buffer to line */
+
+      read_continued_line = FALSE;
+    }
+
+    /* if the last character is '\', continue at next line */
+    if (strlen(line) > 0 && line[strlen(line) - 1] == '\\')
+    {
+      line[strlen(line) - 1] = '\0';   /* cut off trailing backslash */
+      strcpy(previous_line, line);     /* copy line to storage buffer */
+
+      read_continued_line = TRUE;
+
+      continue;
+    }
+
+    /* cut trailing comment from input line */
     for (line_ptr = line; *line_ptr; line_ptr++)
     {
     for (line_ptr = line; *line_ptr; line_ptr++)
     {
-      if (*line_ptr == '#' || *line_ptr == '\n' || *line_ptr == '\r')
+      if (*line_ptr == '#')
       {
        *line_ptr = '\0';
        break;
       {
        *line_ptr = '\0';
        break;
@@ -1256,47 +1509,50 @@ static void *loadSetupFileData(char *filename, boolean use_hash)
     }
 
     /* cut trailing whitespaces from input line */
     }
 
     /* cut trailing whitespaces from input line */
-    for (line_ptr = &line[strlen(line)]; line_ptr > line; line_ptr--)
-      if ((*line_ptr == ' ' || *line_ptr == '\t') && line_ptr[1] == '\0')
+    for (line_ptr = &line[strlen(line)]; line_ptr >= line; line_ptr--)
+      if ((*line_ptr == ' ' || *line_ptr == '\t') && *(line_ptr + 1) == '\0')
        *line_ptr = '\0';
 
     /* ignore empty lines */
     if (*line == '\0')
       continue;
 
        *line_ptr = '\0';
 
     /* ignore empty lines */
     if (*line == '\0')
       continue;
 
-    line_len = strlen(line);
-
     /* cut leading whitespaces from token */
     for (token = line; *token; token++)
       if (*token != ' ' && *token != '\t')
        break;
 
     /* cut leading whitespaces from token */
     for (token = line; *token; token++)
       if (*token != ' ' && *token != '\t')
        break;
 
-    /* find end of token */
+    /* start with empty value as reliable default */
+    value = "";
+
+    /* find end of token to determine start of value */
     for (line_ptr = token; *line_ptr; line_ptr++)
     {
       if (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == ':')
       {
     for (line_ptr = token; *line_ptr; line_ptr++)
     {
       if (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == ':')
       {
-       *line_ptr = '\0';
+       *line_ptr = '\0';               /* terminate token string */
+       value = line_ptr + 1;           /* set beginning of value */
+
        break;
       }
     }
 
        break;
       }
     }
 
-    if (line_ptr < line + line_len)
-      value = line_ptr + 1;
-    else
-      value = "\0";
-
     /* cut leading whitespaces from value */
     for (; *value; value++)
       if (*value != ' ' && *value != '\t')
        break;
 
     /* cut leading whitespaces from value */
     for (; *value; value++)
       if (*value != ' ' && *value != '\t')
        break;
 
-    if (*token && *value)
+#if 0
+    if (*value == '\0')
+      value = "true";  /* treat tokens without value as "true" */
+#endif
+
+    if (*token)
     {
       if (use_hash)
        setHashEntry((SetupFileHash *)setup_file_data, token, value);
       else
     {
       if (use_hash)
        setHashEntry((SetupFileHash *)setup_file_data, token, value);
       else
-       setListEntry((SetupFileList *)setup_file_data, token, value);
+       insert_ptr = addListEntry((SetupFileList *)insert_ptr, token, value);
     }
   }
 
     }
   }
 
@@ -1363,13 +1619,14 @@ void checkSetupFileHashIdentifier(SetupFileHash *setup_file_hash,
 #define LEVELINFO_TOKEN_LEVELS         5
 #define LEVELINFO_TOKEN_FIRST_LEVEL    6
 #define LEVELINFO_TOKEN_SORT_PRIORITY  7
 #define LEVELINFO_TOKEN_LEVELS         5
 #define LEVELINFO_TOKEN_FIRST_LEVEL    6
 #define LEVELINFO_TOKEN_SORT_PRIORITY  7
-#define LEVELINFO_TOKEN_LEVEL_GROUP    8
-#define LEVELINFO_TOKEN_READONLY       9
-#define LEVELINFO_TOKEN_GRAPHICS_SET   10
-#define LEVELINFO_TOKEN_SOUNDS_SET     11
-#define LEVELINFO_TOKEN_MUSIC_SET      12
+#define LEVELINFO_TOKEN_LATEST_ENGINE  8
+#define LEVELINFO_TOKEN_LEVEL_GROUP    9
+#define LEVELINFO_TOKEN_READONLY       10
+#define LEVELINFO_TOKEN_GRAPHICS_SET   11
+#define LEVELINFO_TOKEN_SOUNDS_SET     12
+#define LEVELINFO_TOKEN_MUSIC_SET      13
 
 
-#define NUM_LEVELINFO_TOKENS           13
+#define NUM_LEVELINFO_TOKENS           14
 
 static LevelDirTree ldi;
 
 
 static LevelDirTree ldi;
 
@@ -1384,6 +1641,7 @@ static struct TokenInfo levelinfo_tokens[] =
   { TYPE_INTEGER, &ldi.levels,         "levels"        },
   { TYPE_INTEGER, &ldi.first_level,    "first_level"   },
   { TYPE_INTEGER, &ldi.sort_priority,  "sort_priority" },
   { TYPE_INTEGER, &ldi.levels,         "levels"        },
   { TYPE_INTEGER, &ldi.first_level,    "first_level"   },
   { TYPE_INTEGER, &ldi.sort_priority,  "sort_priority" },
+  { TYPE_BOOLEAN, &ldi.latest_engine,  "latest_engine" },
   { TYPE_BOOLEAN, &ldi.level_group,    "level_group"   },
   { TYPE_BOOLEAN, &ldi.readonly,       "readonly"      },
   { TYPE_STRING,  &ldi.graphics_set,   "graphics_set"  },
   { TYPE_BOOLEAN, &ldi.level_group,    "level_group"   },
   { TYPE_BOOLEAN, &ldi.readonly,       "readonly"      },
   { TYPE_STRING,  &ldi.graphics_set,   "graphics_set"  },
@@ -1417,6 +1675,7 @@ static void setTreeInfoToDefaults(TreeInfo *ldi, int type)
   ldi->author = getStringCopy(ANONYMOUS_NAME);
 
   ldi->sort_priority = LEVELCLASS_UNDEFINED;   /* default: least priority */
   ldi->author = getStringCopy(ANONYMOUS_NAME);
 
   ldi->sort_priority = LEVELCLASS_UNDEFINED;   /* default: least priority */
+  ldi->latest_engine = FALSE;                  /* default: get from level */
   ldi->parent_link = FALSE;
   ldi->user_defined = FALSE;
   ldi->color = 0;
   ldi->parent_link = FALSE;
   ldi->user_defined = FALSE;
   ldi->color = 0;
@@ -1425,12 +1684,14 @@ static void setTreeInfoToDefaults(TreeInfo *ldi, int type)
   if (ldi->type == TREE_TYPE_LEVEL_DIR)
   {
     ldi->imported_from = NULL;
   if (ldi->type == TREE_TYPE_LEVEL_DIR)
   {
     ldi->imported_from = NULL;
+
     ldi->graphics_set = NULL;
     ldi->sounds_set = NULL;
     ldi->music_set = NULL;
     ldi->graphics_path = getStringCopy(UNDEFINED_FILENAME);
     ldi->sounds_path = getStringCopy(UNDEFINED_FILENAME);
     ldi->music_path = getStringCopy(UNDEFINED_FILENAME);
     ldi->graphics_set = NULL;
     ldi->sounds_set = NULL;
     ldi->music_set = NULL;
     ldi->graphics_path = getStringCopy(UNDEFINED_FILENAME);
     ldi->sounds_path = getStringCopy(UNDEFINED_FILENAME);
     ldi->music_path = getStringCopy(UNDEFINED_FILENAME);
+
     ldi->levels = 0;
     ldi->first_level = 0;
     ldi->last_level = 0;
     ldi->levels = 0;
     ldi->first_level = 0;
     ldi->last_level = 0;
@@ -1446,10 +1707,61 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ldi, TreeInfo *parent)
   {
     Error(ERR_WARN, "setTreeInfoToDefaultsFromParent(): parent == NULL");
 
   {
     Error(ERR_WARN, "setTreeInfoToDefaultsFromParent(): parent == NULL");
 
-    setTreeInfoToDefaults(ldi, TREE_TYPE_GENERIC);
+    setTreeInfoToDefaults(ldi, TREE_TYPE_UNDEFINED);
+
     return;
   }
 
     return;
   }
 
+#if 1
+  /* copy all values from the parent structure */
+
+  ldi->type = parent->type;
+
+  ldi->node_top = parent->node_top;
+  ldi->node_parent = parent;
+  ldi->node_group = NULL;
+  ldi->next = NULL;
+
+  ldi->cl_first = -1;
+  ldi->cl_cursor = -1;
+
+  ldi->filename = NULL;
+  ldi->fullpath = NULL;
+  ldi->basepath = NULL;
+  ldi->identifier = NULL;
+  ldi->name = getStringCopy(ANONYMOUS_NAME);
+  ldi->name_sorting = NULL;
+  ldi->author = getStringCopy(parent->author);
+
+  ldi->sort_priority = parent->sort_priority;
+  ldi->latest_engine = parent->latest_engine;
+  ldi->parent_link = FALSE;
+  ldi->user_defined = parent->user_defined;
+  ldi->color = parent->color;
+  ldi->class_desc = getStringCopy(parent->class_desc);
+
+  if (ldi->type == TREE_TYPE_LEVEL_DIR)
+  {
+    ldi->imported_from = getStringCopy(parent->imported_from);
+
+    ldi->graphics_set = NULL;
+    ldi->sounds_set = NULL;
+    ldi->music_set = NULL;
+    ldi->graphics_path = getStringCopy(UNDEFINED_FILENAME);
+    ldi->sounds_path = getStringCopy(UNDEFINED_FILENAME);
+    ldi->music_path = getStringCopy(UNDEFINED_FILENAME);
+
+    ldi->levels = 0;
+    ldi->first_level = 0;
+    ldi->last_level = 0;
+    ldi->level_group = FALSE;
+    ldi->handicap_level = 0;
+    ldi->readonly = TRUE;
+  }
+
+
+#else
+
   /* first copy all values from the parent structure ... */
   *ldi = *parent;
 
   /* first copy all values from the parent structure ... */
   *ldi = *parent;
 
@@ -1467,7 +1779,16 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ldi, TreeInfo *parent)
   ldi->name = getStringCopy(ANONYMOUS_NAME);
   ldi->name_sorting = NULL;
   ldi->author = getStringCopy(parent->author);
   ldi->name = getStringCopy(ANONYMOUS_NAME);
   ldi->name_sorting = NULL;
   ldi->author = getStringCopy(parent->author);
+
   ldi->imported_from = getStringCopy(parent->imported_from);
   ldi->imported_from = getStringCopy(parent->imported_from);
+  ldi->class_desc = getStringCopy(parent->class_desc);
+
+  ldi->graphics_set = NULL;
+  ldi->sounds_set = NULL;
+  ldi->music_set = NULL;
+  ldi->graphics_path = NULL;
+  ldi->sounds_path = NULL;
+  ldi->music_path = NULL;
 
   ldi->level_group = FALSE;
   ldi->parent_link = FALSE;
 
   ldi->level_group = FALSE;
   ldi->parent_link = FALSE;
@@ -1476,6 +1797,47 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ldi, TreeInfo *parent)
   ldi->node_parent = parent;
   ldi->node_group = NULL;
   ldi->next = NULL;
   ldi->node_parent = parent;
   ldi->node_group = NULL;
   ldi->next = NULL;
+
+#endif
+}
+
+static void freeTreeInfo(TreeInfo *ldi)
+{
+  if (ldi->filename)
+    free(ldi->filename);
+  if (ldi->fullpath)
+    free(ldi->fullpath);
+  if (ldi->basepath)
+    free(ldi->basepath);
+  if (ldi->identifier)
+    free(ldi->identifier);
+
+  if (ldi->name)
+    free(ldi->name);
+  if (ldi->name_sorting)
+    free(ldi->name_sorting);
+  if (ldi->author)
+    free(ldi->author);
+
+  if (ldi->class_desc)
+    free(ldi->class_desc);
+
+  if (ldi->type == TREE_TYPE_LEVEL_DIR)
+  {
+    if (ldi->graphics_set)
+      free(ldi->graphics_set);
+    if (ldi->sounds_set)
+      free(ldi->sounds_set);
+    if (ldi->music_set)
+      free(ldi->music_set);
+
+    if (ldi->graphics_path)
+      free(ldi->graphics_path);
+    if (ldi->sounds_path)
+      free(ldi->sounds_path);
+    if (ldi->music_path)
+      free(ldi->music_path);
+  }
 }
 
 void setSetupInfo(struct TokenInfo *token_info,
 }
 
 void setSetupInfo(struct TokenInfo *token_info,
@@ -1569,6 +1931,19 @@ static void createParentTreeInfoNode(TreeInfo *node_parent)
   ti_new->node_parent = node_parent;
   ti_new->parent_link = TRUE;
 
   ti_new->node_parent = node_parent;
   ti_new->parent_link = TRUE;
 
+#if 1
+  setString(&ti_new->identifier, node_parent->identifier);
+  setString(&ti_new->name, ".. (parent directory)");
+  setString(&ti_new->name_sorting, ti_new->name);
+
+  setString(&ti_new->filename, "..");
+  setString(&ti_new->fullpath, node_parent->fullpath);
+
+  ti_new->sort_priority = node_parent->sort_priority;
+  ti_new->latest_engine = node_parent->latest_engine;
+
+  setString(&ti_new->class_desc, getLevelClassDescription(ti_new));
+#else
   ti_new->identifier = getStringCopy(node_parent->identifier);
   ti_new->name = ".. (parent directory)";
   ti_new->name_sorting = getStringCopy(ti_new->name);
   ti_new->identifier = getStringCopy(node_parent->identifier);
   ti_new->name = ".. (parent directory)";
   ti_new->name_sorting = getStringCopy(ti_new->name);
@@ -1577,7 +1952,10 @@ static void createParentTreeInfoNode(TreeInfo *node_parent)
   ti_new->fullpath = getStringCopy(node_parent->fullpath);
 
   ti_new->sort_priority = node_parent->sort_priority;
   ti_new->fullpath = getStringCopy(node_parent->fullpath);
 
   ti_new->sort_priority = node_parent->sort_priority;
+  ti_new->latest_engine = node_parent->latest_engine;
+
   ti_new->class_desc = getLevelClassDescription(ti_new);
   ti_new->class_desc = getLevelClassDescription(ti_new);
+#endif
 
   pushTreeInfo(&node_parent->node_group, ti_new);
 }
 
   pushTreeInfo(&node_parent->node_group, ti_new);
 }
@@ -1619,16 +1997,21 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first,
 
   /* set all structure fields according to the token/value pairs */
   ldi = *leveldir_new;
 
   /* set all structure fields according to the token/value pairs */
   ldi = *leveldir_new;
-  for (i=0; i<NUM_LEVELINFO_TOKENS; i++)
+  for (i = 0; i < NUM_LEVELINFO_TOKENS; i++)
     setSetupInfo(levelinfo_tokens, i,
                 getHashEntry(setup_file_hash, levelinfo_tokens[i].text));
   *leveldir_new = ldi;
 
     setSetupInfo(levelinfo_tokens, i,
                 getHashEntry(setup_file_hash, levelinfo_tokens[i].text));
   *leveldir_new = ldi;
 
+#if 1
+  if (strcmp(leveldir_new->name, ANONYMOUS_NAME) == 0)
+    setString(&leveldir_new->name, leveldir_new->filename);
+#else
   if (strcmp(leveldir_new->name, ANONYMOUS_NAME) == 0)
   {
     free(leveldir_new->name);
     leveldir_new->name = getStringCopy(leveldir_new->filename);
   }
   if (strcmp(leveldir_new->name, ANONYMOUS_NAME) == 0)
   {
     free(leveldir_new->name);
     leveldir_new->name = getStringCopy(leveldir_new->filename);
   }
+#endif
 
   DrawInitText(leveldir_new->name, 150, FC_YELLOW);
 
 
   DrawInitText(leveldir_new->name, 150, FC_YELLOW);
 
@@ -1640,12 +2023,12 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first,
 
   if (node_parent == NULL)             /* top level group */
   {
 
   if (node_parent == NULL)             /* top level group */
   {
-    leveldir_new->basepath = level_directory;
-    leveldir_new->fullpath = leveldir_new->filename;
+    leveldir_new->basepath = getStringCopy(level_directory);
+    leveldir_new->fullpath = getStringCopy(leveldir_new->filename);
   }
   else                                 /* sub level group */
   {
   }
   else                                 /* sub level group */
   {
-    leveldir_new->basepath = node_parent->basepath;
+    leveldir_new->basepath = getStringCopy(node_parent->basepath);
     leveldir_new->fullpath = getPath2(node_parent->fullpath, directory_name);
   }
 
     leveldir_new->fullpath = getPath2(node_parent->fullpath, directory_name);
   }
 
@@ -1655,11 +2038,20 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first,
   leveldir_new->last_level =
     leveldir_new->first_level + leveldir_new->levels - 1;
 
   leveldir_new->last_level =
     leveldir_new->first_level + leveldir_new->levels - 1;
 
+#if 1
+  leveldir_new->user_defined =
+    (strcmp(leveldir_new->basepath, options.level_directory) != 0);
+#else
   leveldir_new->user_defined =
     (leveldir_new->basepath == options.level_directory ? FALSE : TRUE);
   leveldir_new->user_defined =
     (leveldir_new->basepath == options.level_directory ? FALSE : TRUE);
+#endif
 
   leveldir_new->color = LEVELCOLOR(leveldir_new);
 
   leveldir_new->color = LEVELCOLOR(leveldir_new);
+#if 1
+  setString(&leveldir_new->class_desc, getLevelClassDescription(leveldir_new));
+#else
   leveldir_new->class_desc = getLevelClassDescription(leveldir_new);
   leveldir_new->class_desc = getLevelClassDescription(leveldir_new);
+#endif
 
   leveldir_new->handicap_level =       /* set handicap to default value */
     (leveldir_new->user_defined ?
 
   leveldir_new->handicap_level =       /* set handicap to default value */
     (leveldir_new->user_defined ?
@@ -1835,16 +2227,21 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first,
 
     /* set all structure fields according to the token/value pairs */
     ldi = *artwork_new;
 
     /* set all structure fields according to the token/value pairs */
     ldi = *artwork_new;
-    for (i=0; i<NUM_LEVELINFO_TOKENS; i++)
+    for (i = 0; i < NUM_LEVELINFO_TOKENS; i++)
       setSetupInfo(levelinfo_tokens, i,
                   getHashEntry(setup_file_hash, levelinfo_tokens[i].text));
     *artwork_new = ldi;
 
       setSetupInfo(levelinfo_tokens, i,
                   getHashEntry(setup_file_hash, levelinfo_tokens[i].text));
     *artwork_new = ldi;
 
+#if 1
+    if (strcmp(artwork_new->name, ANONYMOUS_NAME) == 0)
+      setString(&artwork_new->name, artwork_new->filename);
+#else
     if (strcmp(artwork_new->name, ANONYMOUS_NAME) == 0)
     {
       free(artwork_new->name);
       artwork_new->name = getStringCopy(artwork_new->filename);
     }
     if (strcmp(artwork_new->name, ANONYMOUS_NAME) == 0)
     {
       free(artwork_new->name);
       artwork_new->name = getStringCopy(artwork_new->filename);
     }
+#endif
 
 #if 0
     DrawInitText(artwork_new->name, 150, FC_YELLOW);
 
 #if 0
     DrawInitText(artwork_new->name, 150, FC_YELLOW);
@@ -1868,42 +2265,86 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first,
     artwork_new->fullpath = getPath2(node_parent->fullpath, directory_name);
   }
 
     artwork_new->fullpath = getPath2(node_parent->fullpath, directory_name);
   }
 
+#if 1
+  artwork_new->user_defined =
+    (strcmp(artwork_new->basepath, OPTIONS_ARTWORK_DIRECTORY(type)) != 0);
+#else
   artwork_new->user_defined =
     (artwork_new->basepath == OPTIONS_ARTWORK_DIRECTORY(type) ? FALSE : TRUE);
   artwork_new->user_defined =
     (artwork_new->basepath == OPTIONS_ARTWORK_DIRECTORY(type) ? FALSE : TRUE);
+#endif
 
   /* (may use ".sort_priority" from "setup_file_hash" above) */
   artwork_new->color = ARTWORKCOLOR(artwork_new);
 
   /* (may use ".sort_priority" from "setup_file_hash" above) */
   artwork_new->color = ARTWORKCOLOR(artwork_new);
+#if 1
+  setString(&artwork_new->class_desc, getLevelClassDescription(artwork_new));
+#else
   artwork_new->class_desc = getLevelClassDescription(artwork_new);
   artwork_new->class_desc = getLevelClassDescription(artwork_new);
+#endif
 
   if (setup_file_hash == NULL) /* (after determining ".user_defined") */
   {
 
   if (setup_file_hash == NULL) /* (after determining ".user_defined") */
   {
+#if 0
     if (artwork_new->name != NULL)
     if (artwork_new->name != NULL)
+    {
       free(artwork_new->name);
       free(artwork_new->name);
+      artwork_new->name = NULL;
+    }
+#endif
+
+#if 0
+    if (artwork_new->identifier != NULL)
+    {
+      free(artwork_new->identifier);
+      artwork_new->identifier = NULL;
+    }
+#endif
 
     if (strcmp(artwork_new->filename, ".") == 0)
     {
       if (artwork_new->user_defined)
       {
 
     if (strcmp(artwork_new->filename, ".") == 0)
     {
       if (artwork_new->user_defined)
       {
+#if 1
+       setString(&artwork_new->identifier, "private");
+#else
        artwork_new->identifier = getStringCopy("private");
        artwork_new->identifier = getStringCopy("private");
-       artwork_new->sort_priority = ARTWORKCLASS_USER;
+#endif
+       artwork_new->sort_priority = ARTWORKCLASS_PRIVATE;
       }
       else
       {
       }
       else
       {
+#if 1
+       setString(&artwork_new->identifier, "classic");
+#else
        artwork_new->identifier = getStringCopy("classic");
        artwork_new->identifier = getStringCopy("classic");
+#endif
        artwork_new->sort_priority = ARTWORKCLASS_CLASSICS;
       }
 
       /* set to new values after changing ".sort_priority" */
       artwork_new->color = ARTWORKCOLOR(artwork_new);
        artwork_new->sort_priority = ARTWORKCLASS_CLASSICS;
       }
 
       /* set to new values after changing ".sort_priority" */
       artwork_new->color = ARTWORKCOLOR(artwork_new);
+#if 1
+      setString(&artwork_new->class_desc,
+               getLevelClassDescription(artwork_new));
+#else
       artwork_new->class_desc = getLevelClassDescription(artwork_new);
       artwork_new->class_desc = getLevelClassDescription(artwork_new);
+#endif
     }
     else
     {
     }
     else
     {
+#if 1
+      setString(&artwork_new->identifier, artwork_new->filename);
+#else
       artwork_new->identifier = getStringCopy(artwork_new->filename);
       artwork_new->identifier = getStringCopy(artwork_new->filename);
+#endif
     }
 
     }
 
+#if 1
+    setString(&artwork_new->name, artwork_new->identifier);
+    setString(&artwork_new->name_sorting, artwork_new->name);
+#else
     artwork_new->name = getStringCopy(artwork_new->identifier);
     artwork_new->name_sorting = getStringCopy(artwork_new->name);
     artwork_new->name = getStringCopy(artwork_new->identifier);
     artwork_new->name_sorting = getStringCopy(artwork_new->name);
+#endif
   }
 
   DrawInitText(artwork_new->name, 150, FC_YELLOW);
   }
 
   DrawInitText(artwork_new->name, 150, FC_YELLOW);
@@ -1981,6 +2422,15 @@ static TreeInfo *getDummyArtworkInfo(int type)
 
   setTreeInfoToDefaults(artwork_new, type);
 
 
   setTreeInfoToDefaults(artwork_new, type);
 
+#if 1
+  setString(&artwork_new->filename, UNDEFINED_FILENAME);
+  setString(&artwork_new->fullpath, UNDEFINED_FILENAME);
+  setString(&artwork_new->basepath, UNDEFINED_FILENAME);
+
+  setString(&artwork_new->identifier,   UNDEFINED_FILENAME);
+  setString(&artwork_new->name,         UNDEFINED_FILENAME);
+  setString(&artwork_new->name_sorting, UNDEFINED_FILENAME);
+#else
   artwork_new->filename = getStringCopy(UNDEFINED_FILENAME);
   artwork_new->fullpath = getStringCopy(UNDEFINED_FILENAME);
   artwork_new->basepath = getStringCopy(UNDEFINED_FILENAME);
   artwork_new->filename = getStringCopy(UNDEFINED_FILENAME);
   artwork_new->fullpath = getStringCopy(UNDEFINED_FILENAME);
   artwork_new->basepath = getStringCopy(UNDEFINED_FILENAME);
@@ -1991,6 +2441,7 @@ static TreeInfo *getDummyArtworkInfo(int type)
   artwork_new->identifier   = getStringCopy(UNDEFINED_FILENAME);
   artwork_new->name         = getStringCopy(UNDEFINED_FILENAME);
   artwork_new->name_sorting = getStringCopy(UNDEFINED_FILENAME);
   artwork_new->identifier   = getStringCopy(UNDEFINED_FILENAME);
   artwork_new->name         = getStringCopy(UNDEFINED_FILENAME);
   artwork_new->name_sorting = getStringCopy(UNDEFINED_FILENAME);
+#endif
 
   return artwork_new;
 }
 
   return artwork_new;
 }
@@ -2030,16 +2481,25 @@ void LoadArtworkInfo()
   /* before sorting, the first entries will be from the user directory */
   artwork.gfx_current =
     getTreeInfoFromIdentifier(artwork.gfx_first, setup.graphics_set);
   /* before sorting, the first entries will be from the user directory */
   artwork.gfx_current =
     getTreeInfoFromIdentifier(artwork.gfx_first, setup.graphics_set);
+  if (artwork.gfx_current == NULL)
+    artwork.gfx_current =
+      getTreeInfoFromIdentifier(artwork.gfx_first, GFX_CLASSIC_SUBDIR);
   if (artwork.gfx_current == NULL)
     artwork.gfx_current = getFirstValidTreeInfoEntry(artwork.gfx_first);
 
   artwork.snd_current =
     getTreeInfoFromIdentifier(artwork.snd_first, setup.sounds_set);
   if (artwork.gfx_current == NULL)
     artwork.gfx_current = getFirstValidTreeInfoEntry(artwork.gfx_first);
 
   artwork.snd_current =
     getTreeInfoFromIdentifier(artwork.snd_first, setup.sounds_set);
+  if (artwork.snd_current == NULL)
+    artwork.snd_current =
+      getTreeInfoFromIdentifier(artwork.snd_first, SND_CLASSIC_SUBDIR);
   if (artwork.snd_current == NULL)
     artwork.snd_current = getFirstValidTreeInfoEntry(artwork.snd_first);
 
   artwork.mus_current =
     getTreeInfoFromIdentifier(artwork.mus_first, setup.music_set);
   if (artwork.snd_current == NULL)
     artwork.snd_current = getFirstValidTreeInfoEntry(artwork.snd_first);
 
   artwork.mus_current =
     getTreeInfoFromIdentifier(artwork.mus_first, setup.music_set);
+  if (artwork.mus_current == NULL)
+    artwork.mus_current =
+      getTreeInfoFromIdentifier(artwork.mus_first, MUS_CLASSIC_SUBDIR);
   if (artwork.mus_current == NULL)
     artwork.mus_current = getFirstValidTreeInfoEntry(artwork.mus_first);
 
   if (artwork.mus_current == NULL)
     artwork.mus_current = getFirstValidTreeInfoEntry(artwork.mus_first);
 
@@ -2120,10 +2580,14 @@ void LoadLevelArtworkInfo()
   LoadArtworkInfoFromLevelInfo(&artwork.mus_first, leveldir_first);
 
   /* needed for reloading level artwork not known at ealier stage */
   LoadArtworkInfoFromLevelInfo(&artwork.mus_first, leveldir_first);
 
   /* needed for reloading level artwork not known at ealier stage */
+
   if (strcmp(artwork.gfx_current_identifier, setup.graphics_set) != 0)
   {
     artwork.gfx_current =
       getTreeInfoFromIdentifier(artwork.gfx_first, setup.graphics_set);
   if (strcmp(artwork.gfx_current_identifier, setup.graphics_set) != 0)
   {
     artwork.gfx_current =
       getTreeInfoFromIdentifier(artwork.gfx_first, setup.graphics_set);
+    if (artwork.gfx_current == NULL)
+      artwork.gfx_current =
+       getTreeInfoFromIdentifier(artwork.gfx_first, GFX_CLASSIC_SUBDIR);
     if (artwork.gfx_current == NULL)
       artwork.gfx_current = getFirstValidTreeInfoEntry(artwork.gfx_first);
   }
     if (artwork.gfx_current == NULL)
       artwork.gfx_current = getFirstValidTreeInfoEntry(artwork.gfx_first);
   }
@@ -2132,6 +2596,9 @@ void LoadLevelArtworkInfo()
   {
     artwork.snd_current =
       getTreeInfoFromIdentifier(artwork.snd_first, setup.sounds_set);
   {
     artwork.snd_current =
       getTreeInfoFromIdentifier(artwork.snd_first, setup.sounds_set);
+    if (artwork.snd_current == NULL)
+      artwork.snd_current =
+       getTreeInfoFromIdentifier(artwork.snd_first, SND_CLASSIC_SUBDIR);
     if (artwork.snd_current == NULL)
       artwork.snd_current = getFirstValidTreeInfoEntry(artwork.snd_first);
   }
     if (artwork.snd_current == NULL)
       artwork.snd_current = getFirstValidTreeInfoEntry(artwork.snd_first);
   }
@@ -2140,6 +2607,9 @@ void LoadLevelArtworkInfo()
   {
     artwork.mus_current =
       getTreeInfoFromIdentifier(artwork.mus_first, setup.music_set);
   {
     artwork.mus_current =
       getTreeInfoFromIdentifier(artwork.mus_first, setup.music_set);
+    if (artwork.mus_current == NULL)
+      artwork.mus_current =
+       getTreeInfoFromIdentifier(artwork.mus_first, MUS_CLASSIC_SUBDIR);
     if (artwork.mus_current == NULL)
       artwork.mus_current = getFirstValidTreeInfoEntry(artwork.mus_first);
   }
     if (artwork.mus_current == NULL)
       artwork.mus_current = getFirstValidTreeInfoEntry(artwork.mus_first);
   }
@@ -2157,6 +2627,7 @@ void LoadLevelArtworkInfo()
 
 static void SaveUserLevelInfo()
 {
 
 static void SaveUserLevelInfo()
 {
+  LevelDirTree *level_info;
   char *filename;
   FILE *file;
   int i;
   char *filename;
   FILE *file;
   int i;
@@ -2170,32 +2641,49 @@ static void SaveUserLevelInfo()
     return;
   }
 
     return;
   }
 
-  /* always start with reliable default values */
-  setTreeInfoToDefaults(&ldi, TREE_TYPE_LEVEL_DIR);
+  level_info = newTreeInfo();
 
 
+  /* always start with reliable default values */
+  setTreeInfoToDefaults(level_info, TREE_TYPE_LEVEL_DIR);
+
+#if 1
+  setString(&level_info->name, getLoginName());
+  setString(&level_info->author, getRealName());
+  level_info->levels = 100;
+  level_info->first_level = 1;
+  level_info->sort_priority = LEVELCLASS_PRIVATE_START;
+  level_info->readonly = FALSE;
+  setString(&level_info->graphics_set, GFX_CLASSIC_SUBDIR);
+  setString(&level_info->sounds_set,   SND_CLASSIC_SUBDIR);
+  setString(&level_info->music_set,    MUS_CLASSIC_SUBDIR);
+#else
   ldi.name = getStringCopy(getLoginName());
   ldi.author = getStringCopy(getRealName());
   ldi.levels = 100;
   ldi.first_level = 1;
   ldi.name = getStringCopy(getLoginName());
   ldi.author = getStringCopy(getRealName());
   ldi.levels = 100;
   ldi.first_level = 1;
-  ldi.sort_priority = LEVELCLASS_USER_START;
+  ldi.sort_priority = LEVELCLASS_PRIVATE_START;
   ldi.readonly = FALSE;
   ldi.readonly = FALSE;
-  ldi.graphics_set = getStringCopy(GRAPHICS_SUBDIR);
-  ldi.sounds_set = getStringCopy(SOUNDS_SUBDIR);
-  ldi.music_set = getStringCopy(MUSIC_SUBDIR);
+  ldi.graphics_set = getStringCopy(GFX_CLASSIC_SUBDIR);
+  ldi.sounds_set = getStringCopy(SND_CLASSIC_SUBDIR);
+  ldi.music_set = getStringCopy(MUS_CLASSIC_SUBDIR);
+#endif
 
   fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
                                                 getCookie("LEVELINFO")));
 
 
   fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
                                                 getCookie("LEVELINFO")));
 
-  for (i=0; i<NUM_LEVELINFO_TOKENS; i++)
+  ldi = *level_info;
+  for (i = 0; i < NUM_LEVELINFO_TOKENS; i++)
     if (i != LEVELINFO_TOKEN_IDENTIFIER &&
        i != LEVELINFO_TOKEN_NAME_SORTING &&
        i != LEVELINFO_TOKEN_IMPORTED_FROM)
       fprintf(file, "%s\n", getSetupLine(levelinfo_tokens, "", i));
 
   fclose(file);
     if (i != LEVELINFO_TOKEN_IDENTIFIER &&
        i != LEVELINFO_TOKEN_NAME_SORTING &&
        i != LEVELINFO_TOKEN_IMPORTED_FROM)
       fprintf(file, "%s\n", getSetupLine(levelinfo_tokens, "", i));
 
   fclose(file);
-  free(filename);
 
   SetFilePermissions(filename, PERMS_PRIVATE);
 
   SetFilePermissions(filename, PERMS_PRIVATE);
+
+  freeTreeInfo(level_info);
+  free(filename);
 }
 
 char *getSetupValue(int type, void *value)
 }
 
 char *getSetupValue(int type, void *value)
@@ -2270,7 +2758,7 @@ char *getSetupLine(struct TokenInfo *token_info, char *prefix, int token_nr)
     {
       /* add at least one whitespace */
       strcat(line, " ");
     {
       /* add at least one whitespace */
       strcat(line, " ");
-      for (i=strlen(line); i<TOKEN_COMMENT_POSITION; i++)
+      for (i = strlen(line); i < TOKEN_COMMENT_POSITION; i++)
        strcat(line, " ");
 
       strcat(line, "# ");
        strcat(line, " ");
 
       strcat(line, "# ");
@@ -2283,17 +2771,15 @@ char *getSetupLine(struct TokenInfo *token_info, char *prefix, int token_nr)
 
 void LoadLevelSetup_LastSeries()
 {
 
 void LoadLevelSetup_LastSeries()
 {
-  char *filename;
-  SetupFileHash *level_setup_hash = NULL;
-
-  /* always start with reliable default values */
-  leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
-
   /* ----------------------------------------------------------------------- */
   /* ~/.<program>/levelsetup.conf                                            */
   /* ----------------------------------------------------------------------- */
 
   /* ----------------------------------------------------------------------- */
   /* ~/.<program>/levelsetup.conf                                            */
   /* ----------------------------------------------------------------------- */
 
-  filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME);
+  char *filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME);
+  SetupFileHash *level_setup_hash = NULL;
+
+  /* always start with reliable default values */
+  leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
 
   if ((level_setup_hash = loadSetupFileHash(filename)))
   {
 
   if ((level_setup_hash = loadSetupFileHash(filename)))
   {
@@ -2317,17 +2803,15 @@ void LoadLevelSetup_LastSeries()
 
 void SaveLevelSetup_LastSeries()
 {
 
 void SaveLevelSetup_LastSeries()
 {
-  char *filename;
-  char *level_subdir = leveldir_current->filename;
-  FILE *file;
-
   /* ----------------------------------------------------------------------- */
   /* ~/.<program>/levelsetup.conf                                            */
   /* ----------------------------------------------------------------------- */
 
   /* ----------------------------------------------------------------------- */
   /* ~/.<program>/levelsetup.conf                                            */
   /* ----------------------------------------------------------------------- */
 
-  InitUserDataDirectory();
+  char *filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME);
+  char *level_subdir = leveldir_current->filename;
+  FILE *file;
 
 
-  filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME);
+  InitUserDataDirectory();
 
   if (!(file = fopen(filename, MODE_WRITE)))
   {
 
   if (!(file = fopen(filename, MODE_WRITE)))
   {
@@ -2342,9 +2826,10 @@ void SaveLevelSetup_LastSeries()
                                               level_subdir));
 
   fclose(file);
                                               level_subdir));
 
   fclose(file);
-  free(filename);
 
   SetFilePermissions(filename, PERMS_PRIVATE);
 
   SetFilePermissions(filename, PERMS_PRIVATE);
+
+  free(filename);
 }
 
 static void checkSeriesInfo()
 }
 
 static void checkSeriesInfo()
@@ -2380,6 +2865,7 @@ static void checkSeriesInfo()
 
       levelnum_value = atoi(levelnum_str);
 
 
       levelnum_value = atoi(levelnum_str);
 
+#if 0
       if (levelnum_value < leveldir_current->first_level)
       {
        Error(ERR_WARN, "additional level %d found", levelnum_value);
       if (levelnum_value < leveldir_current->first_level)
       {
        Error(ERR_WARN, "additional level %d found", levelnum_value);
@@ -2390,6 +2876,7 @@ static void checkSeriesInfo()
        Error(ERR_WARN, "additional level %d found", levelnum_value);
        leveldir_current->last_level = levelnum_value;
       }
        Error(ERR_WARN, "additional level %d found", levelnum_value);
        leveldir_current->last_level = levelnum_value;
       }
+#endif
     }
   }
 
     }
   }
 
@@ -2489,7 +2976,8 @@ void SaveLevelSetup_SeriesInfo()
                                               handicap_level_str));
 
   fclose(file);
                                               handicap_level_str));
 
   fclose(file);
-  free(filename);
 
   SetFilePermissions(filename, PERMS_PRIVATE);
 
   SetFilePermissions(filename, PERMS_PRIVATE);
+
+  free(filename);
 }
 }