#define MAX_COOKIE_LEN 256
+#define TREE_NODE_TYPE_DEFAULT 0
+#define TREE_NODE_TYPE_PARENT 1
+#define TREE_NODE_TYPE_GROUP 2
+#define TREE_NODE_TYPE_COPY 3
+
+#define TREE_NODE_TYPE(ti) (ti->node_group ? TREE_NODE_TYPE_GROUP : \
+ ti->parent_link ? TREE_NODE_TYPE_PARENT : \
+ ti->is_copy ? TREE_NODE_TYPE_COPY : \
+ TREE_NODE_TYPE_DEFAULT)
+
static void setTreeInfoToDefaults(TreeInfo *, int);
static TreeInfo *getTreeInfoCopy(TreeInfo *ti);
return "Unknown Level Class";
}
+static char *getCacheDir(void)
+{
+ static char *cache_dir = NULL;
+
+ if (cache_dir == NULL)
+ cache_dir = getPath2(getMainUserGameDataDir(), CACHE_DIRECTORY);
+
+ return cache_dir;
+}
+
static char *getScoreDir(char *level_subdir)
{
static char *score_dir = NULL;
return score_dir;
}
+static char *getScoreCacheDir(char *level_subdir)
+{
+ static char *score_dir = NULL;
+ static char *score_level_dir = NULL;
+ char *score_subdir = SCORES_DIRECTORY;
+
+ if (score_dir == NULL)
+ score_dir = getPath2(getCacheDir(), score_subdir);
+
+ if (level_subdir != NULL)
+ {
+ checked_free(score_level_dir);
+
+ score_level_dir = getPath2(score_dir, level_subdir);
+
+ return score_level_dir;
+ }
+
+ return score_dir;
+}
+
+static char *getScoreTapeDir(char *level_subdir, int nr)
+{
+ static char *score_tape_dir = NULL;
+ char tape_subdir[MAX_FILENAME_LEN];
+
+ checked_free(score_tape_dir);
+
+ sprintf(tape_subdir, "%03d", nr);
+ score_tape_dir = getPath2(getScoreDir(level_subdir), tape_subdir);
+
+ return score_tape_dir;
+}
+
static char *getUserSubdir(int nr)
{
static char user_subdir[16] = { 0 };
return levelsetup_dir;
}
-static char *getCacheDir(void)
-{
- static char *cache_dir = NULL;
-
- if (cache_dir == NULL)
- cache_dir = getPath2(getMainUserGameDataDir(), CACHE_DIRECTORY);
-
- return cache_dir;
-}
-
static char *getNetworkDir(void)
{
static char *network_dir = NULL;
return filename;
}
+char *getScoreCacheFilename(int nr)
+{
+ static char *filename = NULL;
+ char basename[MAX_FILENAME_LEN];
+
+ checked_free(filename);
+
+ sprintf(basename, "%03d.%s", nr, SCOREFILE_EXTENSION);
+
+ // used instead of "leveldir_current->subdir" (for network games)
+ filename = getPath2(getScoreCacheDir(levelset.identifier), basename);
+
+ return filename;
+}
+
+char *getScoreTapeBasename(char *name)
+{
+ static char basename[MAX_FILENAME_LEN];
+ char basename_raw[MAX_FILENAME_LEN];
+ char timestamp[20];
+
+ sprintf(timestamp, "%s", getCurrentTimestamp());
+ sprintf(basename_raw, "%s-%s", timestamp, name);
+ sprintf(basename, "%s-%08x", timestamp, get_hash_from_key(basename_raw));
+
+ return basename;
+}
+
+char *getScoreTapeFilename(char *basename_no_ext, int nr)
+{
+ static char *filename = NULL;
+ char basename[MAX_FILENAME_LEN];
+
+ checked_free(filename);
+
+ sprintf(basename, "%s.%s", basename_no_ext, TAPEFILE_EXTENSION);
+
+ // used instead of "leveldir_current->subdir" (for network games)
+ filename = getPath2(getScoreTapeDir(levelset.identifier, nr), basename);
+
+ return filename;
+}
+
char *getSetupFilename(void)
{
static char *filename = NULL;
createDirectory(getScoreDir(level_subdir), "level score", permissions);
}
+void InitScoreCacheDirectory(char *level_subdir)
+{
+ createDirectory(getMainUserGameDataDir(), "main user data", PERMS_PRIVATE);
+ createDirectory(getCacheDir(), "cache data", PERMS_PRIVATE);
+ createDirectory(getScoreCacheDir(NULL), "main score", PERMS_PRIVATE);
+ createDirectory(getScoreCacheDir(level_subdir), "level score", PERMS_PRIVATE);
+}
+
+void InitScoreTapeDirectory(char *level_subdir, int nr)
+{
+ int permissions = (program.global_scores ? PERMS_PUBLIC : PERMS_PRIVATE);
+
+ InitScoreDirectory(level_subdir);
+
+ createDirectory(getScoreTapeDir(level_subdir, nr), "score tape", permissions);
+}
+
static void SaveUserLevelInfo(void);
void InitUserLevelDirectory(char *level_subdir)
boolean validLevelSeries(TreeInfo *node)
{
- return (node != NULL && !node->node_group && !node->parent_link);
+ // in a number of cases, tree node is no valid level set
+ if (node == NULL || node->node_group || node->parent_link || node->is_copy)
+ return FALSE;
+
+ return TRUE;
+}
+
+TreeInfo *getValidLevelSeries(TreeInfo *node, TreeInfo *default_node)
+{
+ if (validLevelSeries(node))
+ return node;
+ else if (node->is_copy)
+ return getTreeInfoFromIdentifier(leveldir_first, node->identifier);
+ else
+ return getFirstValidTreeInfoEntry(default_node);
}
TreeInfo *getFirstValidTreeInfoEntry(TreeInfo *node)
}
static TreeInfo *getTreeInfoFromIdentifierExt(TreeInfo *node, char *identifier,
- boolean include_node_groups)
+ int node_type_wanted)
{
if (identifier == NULL)
return NULL;
while (node)
{
+ if (TREE_NODE_TYPE(node) == node_type_wanted &&
+ strEqual(identifier, node->identifier))
+ return node;
+
if (node->node_group)
{
- if (include_node_groups && strEqual(identifier, node->identifier))
- return node;
-
TreeInfo *node_group = getTreeInfoFromIdentifierExt(node->node_group,
identifier,
- include_node_groups);
+ node_type_wanted);
if (node_group)
return node_group;
}
- else if (!node->parent_link)
- {
- if (strEqual(identifier, node->identifier))
- return node;
- }
node = node->next;
}
TreeInfo *getTreeInfoFromIdentifier(TreeInfo *node, char *identifier)
{
- return getTreeInfoFromIdentifierExt(node, identifier, FALSE);
+ return getTreeInfoFromIdentifierExt(node, identifier, TREE_NODE_TYPE_DEFAULT);
}
static TreeInfo *cloneTreeNode(TreeInfo **node_top, TreeInfo *node_parent,
ti->sort_priority = LEVELCLASS_UNDEFINED; // default: least priority
ti->latest_engine = FALSE; // default: get from level
ti->parent_link = FALSE;
+ ti->is_copy = FALSE;
ti->in_user_dir = FALSE;
ti->user_defined = FALSE;
ti->color = 0;
ti->sort_priority = parent->sort_priority;
ti->latest_engine = parent->latest_engine;
ti->parent_link = FALSE;
+ ti->is_copy = FALSE;
ti->in_user_dir = parent->in_user_dir;
ti->user_defined = parent->user_defined;
ti->color = parent->color;
ti_copy->level_group = ti->level_group;
ti_copy->parent_link = ti->parent_link;
+ ti_copy->is_copy = ti->is_copy;
ti_copy->in_user_dir = ti->in_user_dir;
ti_copy->user_defined = ti->user_defined;
ti_copy->readonly = ti->readonly;
setString(&ti_new->subdir, STRING_PARENT_DIRECTORY);
setString(&ti_new->fullpath, node_parent->fullpath);
- ti_new->sort_priority = node_parent->sort_priority;
+ ti_new->sort_priority = LEVELCLASS_PARENT;
ti_new->latest_engine = node_parent->latest_engine;
setString(&ti_new->class_desc, getLevelClassDescription(ti_new));
ti_new->node_parent = NULL;
ti_new->parent_link = FALSE;
- setString(&ti_new->identifier, node_first->identifier);
+ setString(&ti_new->identifier, "top_tree_node");
setString(&ti_new->name, TREE_INFOTEXT(type));
setString(&ti_new->name_sorting, ti_new->name);
setString(&ti_new->subdir, STRING_TOP_DIRECTORY);
setString(&ti_new->fullpath, ".");
- ti_new->sort_priority = node_first->sort_priority;;
+ ti_new->sort_priority = LEVELCLASS_TOP;
ti_new->latest_engine = node_first->latest_engine;
setString(&ti_new->class_desc, TREE_INFOTEXT(type));
setTreeInfoToDefaultsFromParent(leveldir_new, leveldir_first);
leveldir_new->level_group = TRUE;
+ leveldir_new->sort_priority = LEVELCLASS_LAST_PLAYED_LEVEL;
setString(&leveldir_new->identifier, TOKEN_STR_LAST_LEVEL_SERIES);
setString(&leveldir_new->name, "<< (last played level sets)");
+ setString(&leveldir_new->name_sorting, leveldir_new->name);
pushTreeInfo(leveldir_top, 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;
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);
+ TREE_NODE_TYPE_GROUP);
if (leveldir_last == NULL)
return;
freeTreeInfo(*node_new);
+ *node_new = NULL;
+
for (i = 0; last_level_series[i] != NULL; i++)
{
LevelDirTree *node_last = getTreeInfoFromIdentifier(leveldir_first,
last_level_series[i]);
+ if (node_last == NULL)
+ continue;
*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)->is_copy = TRUE; // mark entry as node copy
+
(*node_new)->node_group = NULL;
(*node_new)->next = NULL;
node_new = &((*node_new)->next);
}
-
- if (reset_leveldir_current)
- leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
- last_level_series[0]);
}
static void UpdateLastPlayedLevels_List(void)
setString(&last_level_series[0], leveldir_current->identifier);
}
+static TreeInfo *StoreOrRestoreLastPlayedLevels(TreeInfo *node, boolean store)
+{
+ static char *identifier = NULL;
+
+ if (store)
+ {
+ setString(&identifier, (node && node->is_copy ? node->identifier : NULL));
+
+ return NULL; // not used
+ }
+ else
+ {
+ TreeInfo *node_new = getTreeInfoFromIdentifierExt(leveldir_first,
+ identifier,
+ TREE_NODE_TYPE_COPY);
+ return (node_new != NULL ? node_new : node);
+ }
+}
+
+void StoreLastPlayedLevels(TreeInfo *node)
+{
+ StoreOrRestoreLastPlayedLevels(node, TRUE);
+}
+
+void RestoreLastPlayedLevels(TreeInfo **node)
+{
+ *node = StoreOrRestoreLastPlayedLevels(*node, FALSE);
+}
+
void LoadLevelSetup_LastSeries(void)
{
// --------------------------------------------------------------------------