*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;
return numTreeInfo(getTreeInfoFirstGroupEntry(node));
}
-int posTreeInfo(TreeInfo *node)
+int getPosFromTreeInfo(TreeInfo *node)
{
TreeInfo *node_cmp = getTreeInfoFirstGroupEntry(node);
int pos = 0;
return node_default;
}
-TreeInfo *getTreeInfoFromIdentifier(TreeInfo *node, char *identifier)
+static TreeInfo *getTreeInfoFromIdentifierExt(TreeInfo *node, char *identifier,
+ boolean include_node_groups)
{
if (identifier == NULL)
return NULL;
{
if (node->node_group)
{
- TreeInfo *node_group;
-
- node_group = getTreeInfoFromIdentifier(node->node_group, identifier);
+ if (include_node_groups && strEqual(identifier, node->identifier))
+ return node;
+ TreeInfo *node_group = getTreeInfoFromIdentifierExt(node->node_group,
+ identifier,
+ include_node_groups);
if (node_group)
return node_group;
}
return NULL;
}
+TreeInfo *getTreeInfoFromIdentifier(TreeInfo *node, char *identifier)
+{
+ return getTreeInfoFromIdentifierExt(node, identifier, FALSE);
+}
+
static TreeInfo *cloneTreeNode(TreeInfo **node_top, TreeInfo *node_parent,
TreeInfo *node, boolean skip_sets_without_levels)
{
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
static TreeInfo *createTopTreeInfoNode(TreeInfo *node_first)
{
- TreeInfo *ti_new, *ti_new2;
-
if (node_first == NULL)
return NULL;
- ti_new = newTreeInfo();
+ TreeInfo *ti_new = newTreeInfo();
+
setTreeInfoToDefaults(ti_new, TREE_TYPE_LEVEL_DIR);
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, INFOTEXT_LEVEL_DIR);
setString(&ti_new->name_sorting, ti_new->name);
setString(&ti_new->subdir, STRING_TOP_DIRECTORY);
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, INFOTEXT_LEVEL_DIR);
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_sorting, ti_new2->name);
#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;
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);
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)
+{
+ MoveArtworkInfoIntoSubTree(artwork_node);
+
+ LoadArtworkInfoFromLevelInfoExt(artwork_node, NULL, leveldir_first_all, TRUE);
+ LoadArtworkInfoFromLevelInfoExt(artwork_node, NULL, leveldir_first_all, FALSE);
+}
+
void LoadLevelArtworkInfo(void)
{
print_timestamp_init("LoadLevelArtworkInfo");
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();
return line;
}
+static void InitLastPlayedLevels_ParentNode(void)
+{
+ LevelDirTree **leveldir_top = &leveldir_first->node_group->next;
+ LevelDirTree *leveldir_new = NULL;
+
+ // check if parent node for last played levels already exists
+ if (strEqual((*leveldir_top)->identifier, TOKEN_STR_LAST_LEVEL_SERIES))
+ return;
+
+ leveldir_new = newTreeInfo();
+
+ setTreeInfoToDefaultsFromParent(leveldir_new, leveldir_first);
+
+ leveldir_new->level_group = TRUE;
+
+ setString(&leveldir_new->identifier, TOKEN_STR_LAST_LEVEL_SERIES);
+ setString(&leveldir_new->name, "<< (last played level sets)");
+
+ pushTreeInfo(leveldir_top, leveldir_new);
+
+ // create node to link back to current level directory
+ createParentTreeInfoNode(leveldir_new);
+}
+
+void UpdateLastPlayedLevels_TreeInfo(void)
+{
+ char **last_level_series = setup.level_setup.last_level_series;
+ boolean reset_leveldir_current = FALSE;
+ LevelDirTree *leveldir_last;
+ TreeInfo **node_new = NULL;
+ int i;
+
+ if (last_level_series[0] == NULL)
+ return;
+
+ InitLastPlayedLevels_ParentNode();
+
+ // check if current level set is from "last played" sub-tree to be rebuilt
+ reset_leveldir_current = strEqual(leveldir_current->node_parent->identifier,
+ TOKEN_STR_LAST_LEVEL_SERIES);
+
+ leveldir_last = getTreeInfoFromIdentifierExt(leveldir_first,
+ TOKEN_STR_LAST_LEVEL_SERIES,
+ TRUE);
+ if (leveldir_last == NULL)
+ return;
+
+ node_new = &leveldir_last->node_group->next;
+
+ freeTreeInfo(*node_new);
+
+ for (i = 0; last_level_series[i] != NULL; i++)
+ {
+ LevelDirTree *node_last = getTreeInfoFromIdentifier(leveldir_first,
+ last_level_series[i]);
+
+ *node_new = getTreeInfoCopy(node_last); // copy complete node
+
+ (*node_new)->node_top = &leveldir_first; // correct top node link
+ (*node_new)->node_parent = leveldir_last; // correct parent node link
+
+ (*node_new)->node_group = NULL;
+ (*node_new)->next = NULL;
+
+ (*node_new)->cl_first = -1; // force setting tree cursor
+
+ node_new = &((*node_new)->next);
+ }
+
+ if (reset_leveldir_current)
+ leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
+ last_level_series[0]);
+}
+
+static void UpdateLastPlayedLevels_List(void)
+{
+ char **last_level_series = setup.level_setup.last_level_series;
+ int pos = MAX_LEVELDIR_HISTORY - 1;
+ int i;
+
+ // search for potentially already existing entry in list of level sets
+ for (i = 0; last_level_series[i] != NULL; i++)
+ if (strEqual(last_level_series[i], leveldir_current->identifier))
+ pos = i;
+
+ // move list of level sets one entry down (using potentially free entry)
+ for (i = pos; i > 0; i--)
+ setString(&last_level_series[i], last_level_series[i - 1]);
+
+ // put last played level set at top position
+ setString(&last_level_series[0], leveldir_current->identifier);
+}
+
void LoadLevelSetup_LastSeries(void)
{
// --------------------------------------------------------------------------
char *filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME);
SetupFileHash *level_setup_hash = NULL;
+ int pos = 0;
+ int i;
// always start with reliable default values
leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
+ // start with empty history of last played level sets
+ setString(&setup.level_setup.last_level_series[0], NULL);
+
if (!strEqual(DEFAULT_LEVELSET, UNDEFINED_LEVELSET))
{
leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
if (leveldir_current == NULL)
leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
+ for (i = 0; i < MAX_LEVELDIR_HISTORY; i++)
+ {
+ char token[strlen(TOKEN_STR_LAST_LEVEL_SERIES) + 10];
+ LevelDirTree *leveldir_last;
+
+ sprintf(token, "%s.%03d", TOKEN_STR_LAST_LEVEL_SERIES, i);
+
+ last_level_series = getHashEntry(level_setup_hash, token);
+
+ leveldir_last = getTreeInfoFromIdentifier(leveldir_first,
+ last_level_series);
+ if (leveldir_last != NULL)
+ setString(&setup.level_setup.last_level_series[pos++],
+ last_level_series);
+ }
+
+ setString(&setup.level_setup.last_level_series[pos], NULL);
+
freeSetupFileHash(level_setup_hash);
}
else
if (leveldir_current == NULL)
return;
+ char **last_level_series = setup.level_setup.last_level_series;
char *filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME);
- char *level_subdir = leveldir_current->subdir;
FILE *file;
+ int i;
InitUserDataDirectory();
+ UpdateLastPlayedLevels_List();
+
if (!(file = fopen(filename, MODE_WRITE)))
{
Warn("cannot write setup file '%s'", filename);
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));
+ fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_LAST_LEVEL_SERIES,
+ leveldir_current->identifier));
+
+ for (i = 0; last_level_series[i] != NULL; i++)
+ {
+ char token[strlen(TOKEN_STR_LAST_LEVEL_SERIES) + 10];
+
+ sprintf(token, "%s.%03d", TOKEN_STR_LAST_LEVEL_SERIES, i);
+
+ fprintf(file, "%s\n", getFormattedSetupEntry(token, last_level_series[i]));
+ }
fclose(file);