rnd-20131209-1-src
[rocksndiamonds.git] / src / libgame / setup.c
index b7e34adf1b3d2ab8267102e7cb48731f9d9be03d..921ffdadb079440c1afadfb047efa26727c4b502 100644 (file)
@@ -16,6 +16,7 @@
 #include <dirent.h>
 #include <string.h>
 #include <unistd.h>
+#include <errno.h>
 
 #include "platform.h"
 
@@ -1184,8 +1185,13 @@ void dumpTreeInfo(TreeInfo *node, int depth)
     for (i = 0; i < (depth + 1) * 3; i++)
       printf(" ");
 
+    printf("'%s' / '%s'\n", node->identifier, node->name);
+
+    /*
+    // use for dumping artwork info tree
     printf("subdir == '%s' ['%s', '%s'] [%d])\n",
           node->subdir, node->fullpath, node->basepath, node->in_user_dir);
+    */
 
     if (node->node_group != NULL)
       dumpTreeInfo(node->node_group, depth + 1);
@@ -1452,7 +1458,8 @@ void createDirectory(char *dir, char *text, int permission_class)
 
   if (!fileExists(dir))
     if (posix_mkdir(dir, dir_mode) != 0)
-      Error(ERR_WARN, "cannot create %s directory '%s'", text, dir);
+      Error(ERR_WARN, "cannot create %s directory '%s': %s",
+           text, dir, strerror(errno));
 
   if (permission_class == PERMS_PUBLIC && !running_setgid)
     chmod(dir, dir_mode);
@@ -1630,6 +1637,7 @@ SetupFileList *addListEntry(SetupFileList *list, char *token, char *value)
     return addListEntry(list->next, token, value);
 }
 
+#if 0
 #ifdef DEBUG
 static void printSetupFileList(SetupFileList *list)
 {
@@ -1642,6 +1650,7 @@ static void printSetupFileList(SetupFileList *list)
   printSetupFileList(list->next);
 }
 #endif
+#endif
 
 #ifdef DEBUG
 DEFINE_HASHTABLE_INSERT(insert_hash_entry, char, char);
@@ -2679,7 +2688,7 @@ static TreeInfo *getTreeInfoCopy(TreeInfo *ti)
   return ti_copy;
 }
 
-static void freeTreeInfo(TreeInfo *ti)
+void freeTreeInfo(TreeInfo *ti)
 {
   if (ti == NULL)
     return;
@@ -2770,7 +2779,7 @@ static int compareTreeInfoEntries(const void *object1, const void *object2)
 {
   const TreeInfo *entry1 = *((TreeInfo **)object1);
   const TreeInfo *entry2 = *((TreeInfo **)object2);
-  int class_sorting1, class_sorting2;
+  int class_sorting1 = 0, class_sorting2 = 0;
   int compare_result;
 
   if (entry1->type == TREE_TYPE_LEVEL_DIR)
@@ -2778,7 +2787,9 @@ static int compareTreeInfoEntries(const void *object1, const void *object2)
     class_sorting1 = LEVELSORTING(entry1);
     class_sorting2 = LEVELSORTING(entry2);
   }
-  else
+  else if (entry1->type == TREE_TYPE_GRAPHICS_DIR ||
+          entry1->type == TREE_TYPE_SOUNDS_DIR ||
+          entry1->type == TREE_TYPE_MUSIC_DIR)
   {
     class_sorting1 = ARTWORKSORTING(entry1);
     class_sorting2 = ARTWORKSORTING(entry2);
@@ -3061,8 +3072,8 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first,
                                          char *directory_name)
 {
 #if 0
-  static unsigned long progress_delay = 0;
-  unsigned long progress_delay_value = 100;    /* (in milliseconds) */
+  static unsigned int progress_delay = 0;
+  unsigned int progress_delay_value = 100;     /* (in milliseconds) */
 #endif
   char *directory_path = getPath2(level_directory, directory_name);
   char *filename = getPath2(directory_path, LEVELINFO_FILENAME);
@@ -3226,9 +3237,14 @@ static void LoadLevelInfoFromLevelDir(TreeInfo **node_first,
   struct dirent *dir_entry;
   boolean valid_entry_found = FALSE;
 
+#if 1
+  Error(ERR_INFO, "looking for levels in '%s' ...", level_directory);
+#endif
+
   if ((dir = opendir(level_directory)) == NULL)
   {
     Error(ERR_WARN, "cannot read level directory '%s'", level_directory);
+
     return;
   }
 
@@ -3625,8 +3641,8 @@ void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node,
                                  LevelDirTree *level_node)
 {
 #if 0
-  static unsigned long progress_delay = 0;
-  unsigned long progress_delay_value = 100;    /* (in milliseconds) */
+  static unsigned int progress_delay = 0;
+  unsigned int progress_delay_value = 100;     /* (in milliseconds) */
 #endif
   int type = (*artwork_node)->type;
 
@@ -3942,12 +3958,16 @@ void LoadLevelSetup_LastSeries()
   free(filename);
 }
 
-void SaveLevelSetup_LastSeries()
+static void SaveLevelSetup_LastSeries_Ext(boolean deactivate_last_level_series)
 {
   /* ----------------------------------------------------------------------- */
   /* ~/.<program>/levelsetup.conf                                            */
   /* ----------------------------------------------------------------------- */
 
+  // check if the current level directory structure is available at this point
+  if (leveldir_current == NULL)
+    return;
+
   char *filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME);
   char *level_subdir = leveldir_current->subdir;
   FILE *file;
@@ -3957,12 +3977,18 @@ void SaveLevelSetup_LastSeries()
   if (!(file = fopen(filename, MODE_WRITE)))
   {
     Error(ERR_WARN, "cannot write setup file '%s'", filename);
+
     free(filename);
+
     return;
   }
 
   fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
                                                 getCookie("LEVELSETUP")));
+
+  if (deactivate_last_level_series)
+    fprintf(file, "# %s\n# ", "the following level set may have caused a problem and was deactivated");
+
   fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_LAST_LEVEL_SERIES,
                                               level_subdir));
 
@@ -3973,11 +3999,23 @@ void SaveLevelSetup_LastSeries()
   free(filename);
 }
 
+void SaveLevelSetup_LastSeries()
+{
+  SaveLevelSetup_LastSeries_Ext(FALSE);
+}
+
+void SaveLevelSetup_LastSeries_Deactivate()
+{
+  SaveLevelSetup_LastSeries_Ext(TRUE);
+}
+
 static void checkSeriesInfo()
 {
   static char *level_directory = NULL;
   DIR *dir;
+#if 0
   struct dirent *dir_entry;
+#endif
 
   /* check for more levels besides the 'levels' field of 'levelinfo.conf' */
 
@@ -3989,9 +4027,11 @@ static void checkSeriesInfo()
   if ((dir = opendir(level_directory)) == NULL)
   {
     Error(ERR_WARN, "cannot read level directory '%s'", level_directory);
+
     return;
   }
 
+#if 0
   while ((dir_entry = readdir(dir)) != NULL)   /* last directory entry */
   {
     if (strlen(dir_entry->d_name) > 4 &&
@@ -4006,7 +4046,6 @@ static void checkSeriesInfo()
 
       levelnum_value = atoi(levelnum_str);
 
-#if 0
       if (levelnum_value < leveldir_current->first_level)
       {
        Error(ERR_WARN, "additional level %d found", levelnum_value);
@@ -4017,9 +4056,9 @@ static void checkSeriesInfo()
        Error(ERR_WARN, "additional level %d found", levelnum_value);
        leveldir_current->last_level = levelnum_value;
       }
-#endif
     }
   }
+#endif
 
   closedir(dir);
 }
@@ -4029,10 +4068,17 @@ void LoadLevelSetup_SeriesInfo()
   char *filename;
   SetupFileHash *level_setup_hash = NULL;
   char *level_subdir = leveldir_current->subdir;
+  int i;
 
   /* always start with reliable default values */
   level_nr = leveldir_current->first_level;
 
+  for (i = 0; i < MAX_LEVELS; i++)
+  {
+    LevelStats_setPlayed(i, 0);
+    LevelStats_setSolved(i, 0);
+  }
+
   checkSeriesInfo(leveldir_current);
 
   /* ----------------------------------------------------------------------- */
@@ -4047,6 +4093,8 @@ void LoadLevelSetup_SeriesInfo()
   {
     char *token_value;
 
+    /* get last played level in this level set */
+
     token_value = getHashEntry(level_setup_hash, TOKEN_STR_LAST_PLAYED_LEVEL);
 
     if (token_value)
@@ -4059,6 +4107,8 @@ void LoadLevelSetup_SeriesInfo()
        level_nr = leveldir_current->last_level;
     }
 
+    /* get handicap level in this level set */
+
     token_value = getHashEntry(level_setup_hash, TOKEN_STR_HANDICAP_LEVEL);
 
     if (token_value)
@@ -4076,6 +4126,31 @@ void LoadLevelSetup_SeriesInfo()
       leveldir_current->handicap_level = level_nr;
     }
 
+    /* get number of played and solved levels in this level set */
+
+    BEGIN_HASH_ITERATION(level_setup_hash, itr)
+    {
+      char *token = HASH_ITERATION_TOKEN(itr);
+      char *value = HASH_ITERATION_VALUE(itr);
+
+      if (strlen(token) == 3 &&
+         token[0] >= '0' && token[0] <= '9' &&
+         token[1] >= '0' && token[1] <= '9' &&
+         token[2] >= '0' && token[2] <= '9')
+      {
+       int level_nr = atoi(token);
+
+       if (value != NULL)
+         LevelStats_setPlayed(level_nr, atoi(value));  /* read 1st column */
+
+       value = strchr(value, ' ');
+
+       if (value != NULL)
+         LevelStats_setSolved(level_nr, atoi(value));  /* read 2nd column */
+      }
+    }
+    END_HASH_ITERATION(hash, itr)
+
     checkSetupFileHashIdentifier(level_setup_hash, filename,
                                 getCookie("LEVELSETUP"));
 
@@ -4094,6 +4169,7 @@ void SaveLevelSetup_SeriesInfo()
   char *level_nr_str = int2str(level_nr, 0);
   char *handicap_level_str = int2str(leveldir_current->handicap_level, 0);
   FILE *file;
+  int i;
 
   /* ----------------------------------------------------------------------- */
   /* ~/.<program>/levelsetup/<level series>/levelsetup.conf                  */
@@ -4114,8 +4190,24 @@ void SaveLevelSetup_SeriesInfo()
                                                 getCookie("LEVELSETUP")));
   fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_LAST_PLAYED_LEVEL,
                                               level_nr_str));
-  fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_HANDICAP_LEVEL,
-                                              handicap_level_str));
+  fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_HANDICAP_LEVEL,
+                                                handicap_level_str));
+
+  for (i = leveldir_current->first_level; i <= leveldir_current->last_level;
+       i++)
+  {
+    if (LevelStats_getPlayed(i) > 0 ||
+       LevelStats_getSolved(i) > 0)
+    {
+      char token[16];
+      char value[16];
+
+      sprintf(token, "%03d", i);
+      sprintf(value, "%d %d", LevelStats_getPlayed(i), LevelStats_getSolved(i));
+
+      fprintf(file, "%s\n", getFormattedSetupEntry(token, value));
+    }
+  }
 
   fclose(file);
 
@@ -4123,3 +4215,37 @@ void SaveLevelSetup_SeriesInfo()
 
   free(filename);
 }
+
+int LevelStats_getPlayed(int nr)
+{
+  return (nr >= 0 && nr < MAX_LEVELS ? level_stats[nr].played : 0);
+}
+
+int LevelStats_getSolved(int nr)
+{
+  return (nr >= 0 && nr < MAX_LEVELS ? level_stats[nr].solved : 0);
+}
+
+void LevelStats_setPlayed(int nr, int value)
+{
+  if (nr >= 0 && nr < MAX_LEVELS)
+    level_stats[nr].played = value;
+}
+
+void LevelStats_setSolved(int nr, int value)
+{
+  if (nr >= 0 && nr < MAX_LEVELS)
+    level_stats[nr].solved = value;
+}
+
+void LevelStats_incPlayed(int nr)
+{
+  if (nr >= 0 && nr < MAX_LEVELS)
+    level_stats[nr].played++;
+}
+
+void LevelStats_incSolved(int nr)
+{
+  if (nr >= 0 && nr < MAX_LEVELS)
+    level_stats[nr].solved++;
+}