fixed invalidating artwork info cache for non-existing artwork config file
[rocksndiamonds.git] / src / libgame / setup.c
index 718259ef43bf46759021cbbe284cba7bed029462..e1840b1d375e92491492ed31752ecaaf59c07b48 100644 (file)
@@ -96,6 +96,7 @@ static SetupFileHash *artworkinfo_cache_old = NULL;
 static SetupFileHash *artworkinfo_cache_new = NULL;
 static SetupFileHash *optional_tokens_hash = NULL;
 static boolean use_artworkinfo_cache = TRUE;
+static boolean update_artworkinfo_cache = FALSE;
 
 
 // ----------------------------------------------------------------------------
@@ -1163,6 +1164,16 @@ void pushTreeInfo(TreeInfo **node_first, TreeInfo *node_new)
   *node_first = node_new;
 }
 
+void removeTreeInfo(TreeInfo **node_first)
+{
+  TreeInfo *node_old = *node_first;
+
+  *node_first = node_old->next;
+  node_old->next = NULL;
+
+  freeTreeInfo(node_old);
+}
+
 int numTreeInfo(TreeInfo *node)
 {
   int num = 0;
@@ -1388,16 +1399,23 @@ static boolean adjustTreeSoundsForEMC(TreeInfo *node)
 
 void dumpTreeInfo(TreeInfo *node, int depth)
 {
+  char bullet_list[] = { '-', '*', 'o' };
   int i;
 
-  Debug("tree", "Dumping TreeInfo:");
+  if (depth == 0)
+    Debug("tree", "Dumping TreeInfo:");
 
   while (node)
   {
-    for (i = 0; i < (depth + 1) * 3; i++)
+    char bullet = bullet_list[depth % ARRAY_SIZE(bullet_list)];
+
+    for (i = 0; i < depth * 2; i++)
       DebugContinued("", " ");
 
-    DebugContinued("tree", "'%s' / '%s'\n", node->identifier, node->name);
+    DebugContinued("tree", "%c '%s' ['%s] [PARENT: '%s'] %s\n",
+                  bullet, node->name, node->identifier,
+                  (node->node_parent ? node->node_parent->identifier : "-"),
+                  (node->node_group ? "[GROUP]" : ""));
 
     /*
     // use for dumping artwork info tree
@@ -2865,7 +2883,7 @@ static TreeInfo *createParentTreeInfoNode(TreeInfo *node_parent)
   ti_new->parent_link = TRUE;
 
   setString(&ti_new->identifier, node_parent->identifier);
-  setString(&ti_new->name, ".. (parent directory)");
+  setString(&ti_new->name, BACKLINK_TEXT_PARENT);
   setString(&ti_new->name_sorting, ti_new->name);
 
   setString(&ti_new->subdir, STRING_PARENT_DIRECTORY);
@@ -2883,19 +2901,19 @@ static TreeInfo *createParentTreeInfoNode(TreeInfo *node_parent)
 
 static TreeInfo *createTopTreeInfoNode(TreeInfo *node_first)
 {
-  TreeInfo *ti_new, *ti_new2;
-
   if (node_first == NULL)
     return NULL;
 
-  ti_new = newTreeInfo();
-  setTreeInfoToDefaults(ti_new, TREE_TYPE_LEVEL_DIR);
+  TreeInfo *ti_new = newTreeInfo();
+  int type = node_first->type;
+
+  setTreeInfoToDefaults(ti_new, type);
 
   ti_new->node_parent = NULL;
   ti_new->parent_link = FALSE;
 
   setString(&ti_new->identifier, node_first->identifier);
-  setString(&ti_new->name, "level sets");
+  setString(&ti_new->name, TREE_INFOTEXT(type));
   setString(&ti_new->name_sorting, ti_new->name);
 
   setString(&ti_new->subdir, STRING_TOP_DIRECTORY);
@@ -2904,19 +2922,32 @@ static TreeInfo *createTopTreeInfoNode(TreeInfo *node_first)
   ti_new->sort_priority = node_first->sort_priority;;
   ti_new->latest_engine = node_first->latest_engine;
 
-  setString(&ti_new->class_desc, "level sets");
+  setString(&ti_new->class_desc, TREE_INFOTEXT(type));
 
   ti_new->node_group = node_first;
   ti_new->level_group = TRUE;
 
-  ti_new2 = createParentTreeInfoNode(ti_new);
+  TreeInfo *ti_new2 = createParentTreeInfoNode(ti_new);
 
-  setString(&ti_new2->name, ".. (main menu)");
+  setString(&ti_new2->name, TREE_BACKLINK_TEXT(type));
   setString(&ti_new2->name_sorting, ti_new2->name);
 
   return ti_new;
 }
 
+static void setTreeInfoParentNodes(TreeInfo *node, TreeInfo *node_parent)
+{
+  while (node)
+  {
+    if (node->node_group)
+      setTreeInfoParentNodes(node->node_group, node);
+
+    node->node_parent = node_parent;
+
+    node = node->next;
+  }
+}
+
 
 // ----------------------------------------------------------------------------
 // functions for handling level and custom artwork info cache
@@ -2942,10 +2973,15 @@ static void LoadArtworkInfoCache(void)
 
   if (artworkinfo_cache_new == NULL)
     artworkinfo_cache_new = newSetupFileHash();
+
+  update_artworkinfo_cache = FALSE;
 }
 
 static void SaveArtworkInfoCache(void)
 {
+  if (!update_artworkinfo_cache)
+    return;
+
   char *filename = getPath2(getCacheDir(), ARTWORKINFO_CACHE_FILE);
 
   InitCacheDirectory();
@@ -2990,6 +3026,9 @@ static boolean modifiedFileTimestamp(char *filename, char *timestamp_string)
   if (timestamp_string == NULL)
     return TRUE;
 
+  if (!fileExists(filename))                   // file does not exist
+    return (atoi(timestamp_string) != 0);
+
   if (stat(filename, &file_status) != 0)       // cannot stat file
     return TRUE;
 
@@ -3906,8 +3945,33 @@ void LoadArtworkInfo(void)
 #endif
 }
 
-static void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node,
-                                        LevelDirTree *level_node)
+static void MoveArtworkInfoIntoSubTree(ArtworkDirTree **artwork_node)
+{
+  ArtworkDirTree *artwork_new = newTreeInfo();
+  char *top_node_name = "dedicated custom artwork";
+
+  setTreeInfoToDefaults(artwork_new, (*artwork_node)->type);
+
+  artwork_new->level_group = TRUE;
+
+  setString(&artwork_new->identifier,   top_node_name);
+  setString(&artwork_new->name,         top_node_name);
+  setString(&artwork_new->name_sorting, top_node_name);
+
+  // create node to link back to current custom artwork directory
+  createParentTreeInfoNode(artwork_new);
+
+  // move existing custom artwork tree into newly created sub-tree
+  artwork_new->node_group->next = *artwork_node;
+
+  // change custom artwork tree to contain only newly created node
+  *artwork_node = artwork_new;
+}
+
+static void LoadArtworkInfoFromLevelInfoExt(ArtworkDirTree **artwork_node,
+                                           ArtworkDirTree *node_parent,
+                                           LevelDirTree *level_node,
+                                           boolean empty_level_set_mode)
 {
   int type = (*artwork_node)->type;
 
@@ -3915,8 +3979,10 @@ static void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node,
 
   while (level_node)
   {
+    boolean empty_level_set = (level_node->levels == 0);
+
     // check all tree entries for artwork, but skip parent link entries
-    if (!level_node->parent_link)
+    if (!level_node->parent_link && empty_level_set == empty_level_set_mode)
     {
       TreeInfo *artwork_new = getArtworkInfoCacheEntry(level_node, type);
       boolean cached = (artwork_new != NULL);
@@ -3943,6 +4009,8 @@ static void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node,
 
          artwork_new->sort_priority = level_node->sort_priority;
          artwork_new->color = LEVELCOLOR(artwork_new);
+
+         update_artworkinfo_cache = TRUE;
        }
 
        free(path);
@@ -3956,12 +4024,68 @@ static void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node,
     DrawInitText(level_node->name, 150, FC_YELLOW);
 
     if (level_node->node_group != NULL)
-      LoadArtworkInfoFromLevelInfo(artwork_node, level_node->node_group);
+    {
+      TreeInfo *artwork_new = newTreeInfo();
+
+      if (node_parent)
+       setTreeInfoToDefaultsFromParent(artwork_new, node_parent);
+      else
+       setTreeInfoToDefaults(artwork_new, type);
+
+      artwork_new->level_group = TRUE;
+
+      setString(&artwork_new->identifier,   level_node->subdir);
+
+      if (node_parent == NULL)         // check for top tree node
+      {
+       char *top_node_name = (empty_level_set_mode ?
+                              "artwork-only level sets" :
+                              "artwork from level sets");
+
+       setString(&artwork_new->name,         top_node_name);
+       setString(&artwork_new->name_sorting, top_node_name);
+      }
+      else
+      {
+       setString(&artwork_new->name,         level_node->name);
+       setString(&artwork_new->name_sorting, level_node->name_sorting);
+      }
+
+      pushTreeInfo(artwork_node, artwork_new);
+
+      // create node to link back to current custom artwork directory
+      createParentTreeInfoNode(artwork_new);
+
+      // recursively step into sub-directory and look for more custom artwork
+      LoadArtworkInfoFromLevelInfoExt(&artwork_new->node_group, artwork_new,
+                                     level_node->node_group,
+                                     empty_level_set_mode);
+
+      // if sub-tree has no custom artwork at all, remove it
+      if (artwork_new->node_group->next == NULL)
+       removeTreeInfo(artwork_node);
+    }
 
     level_node = level_node->next;
   }
 }
 
+static void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node)
+{
+  // move peviously loaded artwork tree into separate sub-tree
+  MoveArtworkInfoIntoSubTree(artwork_node);
+
+  // load artwork from level sets into separate sub-trees
+  LoadArtworkInfoFromLevelInfoExt(artwork_node, NULL, leveldir_first_all, TRUE);
+  LoadArtworkInfoFromLevelInfoExt(artwork_node, NULL, leveldir_first_all, FALSE);
+
+  // add top tree node over all three separate sub-trees
+  *artwork_node = createTopTreeInfoNode(*artwork_node);
+
+  // set all parent links (back links) in complete artwork tree
+  setTreeInfoParentNodes(*artwork_node, NULL);
+}
+
 void LoadLevelArtworkInfo(void)
 {
   print_timestamp_init("LoadLevelArtworkInfo");
@@ -3970,11 +4094,11 @@ void LoadLevelArtworkInfo(void)
 
   print_timestamp_time("DrawTimeText");
 
-  LoadArtworkInfoFromLevelInfo(&artwork.gfx_first, leveldir_first_all);
+  LoadArtworkInfoFromLevelInfo(&artwork.gfx_first);
   print_timestamp_time("LoadArtworkInfoFromLevelInfo (gfx)");
-  LoadArtworkInfoFromLevelInfo(&artwork.snd_first, leveldir_first_all);
+  LoadArtworkInfoFromLevelInfo(&artwork.snd_first);
   print_timestamp_time("LoadArtworkInfoFromLevelInfo (snd)");
-  LoadArtworkInfoFromLevelInfo(&artwork.mus_first, leveldir_first_all);
+  LoadArtworkInfoFromLevelInfo(&artwork.mus_first);
   print_timestamp_time("LoadArtworkInfoFromLevelInfo (mus)");
 
   SaveArtworkInfoCache();
@@ -4508,7 +4632,7 @@ void LoadLevelSetup_LastSeries(void)
   leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
 
   // start with empty history of last played level sets
-  setup.level_setup.last_level_series[0] = NULL;
+  setString(&setup.level_setup.last_level_series[0], NULL);
 
   if (!strEqual(DEFAULT_LEVELSET, UNDEFINED_LEVELSET))
   {
@@ -4540,11 +4664,11 @@ void LoadLevelSetup_LastSeries(void)
       leveldir_last = getTreeInfoFromIdentifier(leveldir_first,
                                                last_level_series);
       if (leveldir_last != NULL)
-       setup.level_setup.last_level_series[pos++] =
-         getStringCopy(last_level_series);
+       setString(&setup.level_setup.last_level_series[pos++],
+                 last_level_series);
     }
 
-    setup.level_setup.last_level_series[pos] = NULL;
+    setString(&setup.level_setup.last_level_series[pos], NULL);
 
     freeSetupFileHash(level_setup_hash);
   }