X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Flibgame%2Fsetup.c;h=0382a4d7a2e53b315d4fe68d68e7770238bd1e5f;hp=4cee439fcafd47cda4d9dcc700e0777733174e34;hb=6be86a90462c23c8b41937a92dc6f434d39e51a2;hpb=3c812299839bfafcdf7765b35f7e4683f8553b69 diff --git a/src/libgame/setup.c b/src/libgame/setup.c index 4cee439f..0382a4d7 100644 --- a/src/libgame/setup.c +++ b/src/libgame/setup.c @@ -43,46 +43,22 @@ static char *levelclass_desc[NUM_LEVELCLASS_DESC] = "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_GREEN : \ - IS_LEVELCLASS_SP(n) ? FC_GREEN : \ - IS_LEVELCLASS_DX(n) ? FC_GREEN : \ - IS_LEVELCLASS_SB(n) ? FC_GREEN : \ - IS_LEVELCLASS_CONTRIB(n) ? FC_GREEN : \ - IS_LEVELCLASS_PRIVATE(n) ? FC_RED : \ - 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_SB(n) ? 6 : \ - IS_LEVELCLASS_CONTRIB(n) ? 7 : \ - IS_LEVELCLASS_PRIVATE(n) ? 8 : \ - 9) - -#define ARTWORKCOLOR(n) (IS_ARTWORKCLASS_CLASSICS(n) ? FC_RED : \ - IS_ARTWORKCLASS_CONTRIB(n) ? FC_GREEN : \ - IS_ARTWORKCLASS_PRIVATE(n) ? FC_RED : \ - IS_ARTWORKCLASS_LEVEL(n) ? FC_GREEN : \ - FC_BLUE) - -#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_SHORT 32 #define TOKEN_VALUE_POSITION_DEFAULT 40 #define TOKEN_COMMENT_POSITION_DEFAULT 60 #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); @@ -94,6 +70,7 @@ static int token_comment_position = TOKEN_COMMENT_POSITION_DEFAULT; static SetupFileHash *artworkinfo_cache_old = NULL; static SetupFileHash *artworkinfo_cache_new = NULL; static SetupFileHash *optional_tokens_hash = NULL; +static SetupFileHash *missing_file_hash = NULL; static boolean use_artworkinfo_cache = TRUE; static boolean update_artworkinfo_cache = FALSE; @@ -102,6 +79,16 @@ static boolean update_artworkinfo_cache = FALSE; // file functions // ---------------------------------------------------------------------------- +static void WarnUsingFallback(char *filename) +{ + if (getHashEntry(missing_file_hash, filename) == NULL) + { + setHashEntry(missing_file_hash, filename, ""); + + Warn("cannot find artwork file '%s' (using fallback)", filename); + } +} + static char *getLevelClassDescription(TreeInfo *ti) { int position = ti->sort_priority / 100; @@ -112,6 +99,16 @@ static char *getLevelClassDescription(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; @@ -119,13 +116,29 @@ static char *getScoreDir(char *level_subdir) char *score_subdir = SCORES_DIRECTORY; if (score_dir == NULL) + score_dir = getPath2(getMainUserGameDataDir(), score_subdir); + + if (level_subdir != NULL) { - if (program.global_scores) - score_dir = getPath2(getCommonDataDir(), score_subdir); - else - score_dir = getPath2(getMainUserGameDataDir(), score_subdir); + checked_free(score_level_dir); + + score_level_dir = getPath2(score_dir, level_subdir); + + return score_level_dir; } + 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); @@ -138,6 +151,32 @@ static char *getScoreDir(char *level_subdir) 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 *getScoreCacheTapeDir(char *level_subdir, int nr) +{ + static char *score_cache_tape_dir = NULL; + char tape_subdir[MAX_FILENAME_LEN]; + + checked_free(score_cache_tape_dir); + + sprintf(tape_subdir, "%03d", nr); + score_cache_tape_dir = getPath2(getScoreCacheDir(level_subdir), tape_subdir); + + return score_cache_tape_dir; +} + static char *getUserSubdir(int nr) { static char user_subdir[16] = { 0 }; @@ -180,16 +219,6 @@ static char *getLevelSetupDir(char *level_subdir) 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; @@ -274,7 +303,7 @@ char *getNewUserLevelSubdir(void) return new_level_subdir; } -static char *getTapeDir(char *level_subdir) +char *getTapeDir(char *level_subdir) { static char *tape_dir = NULL; char *data_dir = getUserGameDataDir(); @@ -529,8 +558,8 @@ char *getProgramConfigFilename(char *command_filename) if (strSuffix(command_filename_1, ".exe")) command_filename_1[strlen(command_filename_1) - 4] = '\0'; - char *ro_base_path = getProgramMainDataPath(command_filename, RO_BASE_PATH); - char *conf_directory = getPath2(ro_base_path, CONF_DIRECTORY); + char *base_path = getProgramMainDataPath(command_filename, BASE_PATH); + char *conf_directory = getPath2(base_path, CONF_DIRECTORY); char *command_basepath = getBasePath(command_filename); char *command_basename = getBaseNameNoSuffix(command_filename); @@ -540,7 +569,7 @@ char *getProgramConfigFilename(char *command_filename) config_filename_2 = getStringCat2(command_filename_2, ".conf"); config_filename_3 = getPath2(conf_directory, SETUP_FILENAME); - checked_free(ro_base_path); + checked_free(base_path); checked_free(conf_directory); checked_free(command_basepath); @@ -577,7 +606,20 @@ char *getTapeFilename(int nr) return filename; } -char *getSolutionTapeFilename(int nr) +char *getTemporaryTapeFilename(void) +{ + static char *filename = NULL; + char basename[MAX_FILENAME_LEN]; + + checked_free(filename); + + sprintf(basename, "tmp.%s", TAPEFILE_EXTENSION); + filename = getPath2(getTapeDir(NULL), basename); + + return filename; +} + +char *getDefaultSolutionTapeFilename(int nr) { static char *filename = NULL; char basename[MAX_FILENAME_LEN]; @@ -587,17 +629,32 @@ char *getSolutionTapeFilename(int nr) sprintf(basename, "%03d.%s", nr, TAPEFILE_EXTENSION); filename = getPath2(getSolutionTapeDir(), basename); - if (!fileExists(filename)) - { - static char *filename_sln = NULL; + return filename; +} - checked_free(filename_sln); +char *getSokobanSolutionTapeFilename(int nr) +{ + static char *filename = NULL; + char basename[MAX_FILENAME_LEN]; + + checked_free(filename); - sprintf(basename, "%03d.sln", nr); - filename_sln = getPath2(getSolutionTapeDir(), basename); + sprintf(basename, "%03d.sln", nr); + filename = getPath2(getSolutionTapeDir(), basename); - if (fileExists(filename_sln)) - return filename_sln; + return filename; +} + +char *getSolutionTapeFilename(int nr) +{ + char *filename = getDefaultSolutionTapeFilename(nr); + + if (!fileExists(filename)) + { + char *filename2 = getSokobanSolutionTapeFilename(nr); + + if (fileExists(filename2)) + return filename2; } return filename; @@ -618,6 +675,64 @@ char *getScoreFilename(int nr) 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 *getScoreCacheTapeFilename(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(getScoreCacheTapeDir(levelset.identifier, nr), basename); + + return filename; +} + char *getSetupFilename(void) { static char *filename = NULL; @@ -777,6 +892,65 @@ char *getLevelSetTitleMessageFilename(int nr, boolean initial) return NULL; // cannot find specified artwork file anywhere } +static char *getCreditsBasename(int nr) +{ + static char basename[32]; + + sprintf(basename, "credits_%d.txt", nr + 1); + + return basename; +} + +char *getCreditsFilename(int nr, boolean global) +{ + char *basename = getCreditsBasename(nr); + char *basepath = NULL; + static char *credits_subdir = NULL; + static char *filename = NULL; + + if (credits_subdir == NULL) + credits_subdir = getPath2(DOCS_DIRECTORY, CREDITS_DIRECTORY); + + checked_free(filename); + + // look for credits file in the game's base or current level set directory + basepath = (global ? options.base_directory : getCurrentLevelDir()); + + filename = getPath3(basepath, credits_subdir, basename); + if (fileExists(filename)) + return filename; + + return NULL; // cannot find credits file +} + +static char *getProgramInfoBasename(int nr) +{ + static char basename[32]; + + sprintf(basename, "program_%d.txt", nr + 1); + + return basename; +} + +char *getProgramInfoFilename(int nr) +{ + char *basename = getProgramInfoBasename(nr); + static char *info_subdir = NULL; + static char *filename = NULL; + + if (info_subdir == NULL) + info_subdir = getPath2(DOCS_DIRECTORY, PROGRAM_INFO_DIRECTORY); + + checked_free(filename); + + // look for program info file in the game's base directory + filename = getPath3(options.base_directory, info_subdir, basename); + if (fileExists(filename)) + return filename; + + return NULL; // cannot find program info file +} + static char *getCorrectedArtworkBasename(char *basename) { return basename; @@ -841,7 +1015,7 @@ char *getCustomImageFilename(char *basename) { free(filename); - Warn("cannot find artwork file '%s' (using fallback)", basename); + WarnUsingFallback(basename); // 6th try: look for fallback artwork in old default artwork directory // (needed to prevent errors when trying to access unused artwork files) @@ -912,7 +1086,7 @@ char *getCustomSoundFilename(char *basename) { free(filename); - Warn("cannot find artwork file '%s' (using fallback)", basename); + WarnUsingFallback(basename); // 6th try: look for fallback artwork in old default artwork directory // (needed to prevent errors when trying to access unused artwork files) @@ -983,7 +1157,7 @@ char *getCustomMusicFilename(char *basename) { free(filename); - Warn("cannot find artwork file '%s' (using fallback)", basename); + WarnUsingFallback(basename); // 6th try: look for fallback artwork in old default artwork directory // (needed to prevent errors when trying to access unused artwork files) @@ -1079,24 +1253,81 @@ char *getCustomMusicDirectory(void) return NULL; // cannot find specified artwork file anywhere } +void MarkTapeDirectoryUploadsAsComplete(char *level_subdir) +{ + char *filename = getPath2(getTapeDir(level_subdir), UPLOADED_FILENAME); + + touchFile(filename); + + checked_free(filename); +} + +void MarkTapeDirectoryUploadsAsIncomplete(char *level_subdir) +{ + char *filename = getPath2(getTapeDir(level_subdir), UPLOADED_FILENAME); + + unlink(filename); + + checked_free(filename); +} + +boolean CheckTapeDirectoryUploadsComplete(char *level_subdir) +{ + char *filename = getPath2(getTapeDir(level_subdir), UPLOADED_FILENAME); + boolean success = fileExists(filename); + + checked_free(filename); + + return success; +} + +void InitMissingFileHash(void) +{ + if (missing_file_hash == NULL) + freeSetupFileHash(missing_file_hash); + + missing_file_hash = newSetupFileHash(); +} + void InitTapeDirectory(char *level_subdir) { + boolean new_tape_dir = !directoryExists(getTapeDir(level_subdir)); + createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE); createDirectory(getTapeDir(NULL), "main tape", PERMS_PRIVATE); createDirectory(getTapeDir(level_subdir), "level tape", PERMS_PRIVATE); + + if (new_tape_dir) + MarkTapeDirectoryUploadsAsComplete(level_subdir); } void InitScoreDirectory(char *level_subdir) { - int permissions = (program.global_scores ? PERMS_PUBLIC : PERMS_PRIVATE); + createDirectory(getMainUserGameDataDir(), "main user data", PERMS_PRIVATE); + createDirectory(getScoreDir(NULL), "main score", PERMS_PRIVATE); + createDirectory(getScoreDir(level_subdir), "level score", PERMS_PRIVATE); +} - if (program.global_scores) - createDirectory(getCommonDataDir(), "common data", permissions); - else - createDirectory(getMainUserGameDataDir(), "main user data", 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) +{ + InitScoreDirectory(level_subdir); - createDirectory(getScoreDir(NULL), "main score", permissions); - createDirectory(getScoreDir(level_subdir), "level score", permissions); + createDirectory(getScoreTapeDir(level_subdir, nr), "score tape", PERMS_PRIVATE); +} + +void InitScoreCacheTapeDirectory(char *level_subdir, int nr) +{ + InitScoreCacheDirectory(level_subdir); + + createDirectory(getScoreCacheTapeDir(level_subdir, nr), "score tape", PERMS_PRIVATE); } static void SaveUserLevelInfo(void); @@ -1188,25 +1419,52 @@ int numTreeInfo(TreeInfo *node) 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 *getFirstValidTreeInfoEntry(TreeInfo *node) +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); +} + +static TreeInfo *getValidTreeInfoEntryExt(TreeInfo *node, boolean get_next_node) { if (node == NULL) return NULL; - if (node->node_group) // enter level group (step down into tree) + if (node->node_group) // enter node group (step down into tree) return getFirstValidTreeInfoEntry(node->node_group); - else if (node->parent_link) // skip start entry of level group - { - if (node->next) // get first real level series entry - return getFirstValidTreeInfoEntry(node->next); - else // leave empty level group and go on - return getFirstValidTreeInfoEntry(node->node_parent->next); - } - else // this seems to be a regular level series + + if (node->parent_link) // skip first node (back link) of node group + get_next_node = TRUE; + + if (!get_next_node) // get current regular tree node return node; + + // get next regular tree node, or step up until one is found + while (node->next == NULL && node->node_parent != NULL) + node = node->node_parent; + + return getFirstValidTreeInfoEntry(node->next); +} + +TreeInfo *getFirstValidTreeInfoEntry(TreeInfo *node) +{ + return getValidTreeInfoEntryExt(node, FALSE); +} + +TreeInfo *getNextValidTreeInfoEntry(TreeInfo *node) +{ + return getValidTreeInfoEntryExt(node, TRUE); } TreeInfo *getTreeInfoFirstGroupEntry(TreeInfo *node) @@ -1260,29 +1518,25 @@ TreeInfo *getTreeInfoFromPos(TreeInfo *node, int pos) } 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; } @@ -1292,7 +1546,7 @@ static TreeInfo *getTreeInfoFromIdentifierExt(TreeInfo *node, char *identifier, 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, @@ -1396,9 +1650,10 @@ static boolean adjustTreeSoundsForEMC(TreeInfo *node) return settings_changed; } -void dumpTreeInfo(TreeInfo *node, int depth) +int dumpTreeInfo(TreeInfo *node, int depth) { char bullet_list[] = { '-', '*', 'o' }; + int num_leaf_nodes = 0; int i; if (depth == 0) @@ -1414,7 +1669,11 @@ void dumpTreeInfo(TreeInfo *node, int depth) 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]" : "")); + (node->node_group ? "[GROUP]" : + node->is_copy ? "[COPY]" : "")); + + if (!node->node_group && !node->parent_link) + num_leaf_nodes++; /* // use for dumping artwork info tree @@ -1423,10 +1682,15 @@ void dumpTreeInfo(TreeInfo *node, int depth) */ if (node->node_group != NULL) - dumpTreeInfo(node->node_group, depth + 1); + num_leaf_nodes += dumpTreeInfo(node->node_group, depth + 1); node = node->next; } + + if (depth == 0) + Debug("tree", "Summary: %d leaf nodes found", num_leaf_nodes); + + return num_leaf_nodes; } void sortTreeInfoBySortFunction(TreeInfo **node_first, @@ -1545,6 +1809,8 @@ char *getHomeDir(void) if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, dir))) strcpy(dir, "."); } +#elif defined(PLATFORM_EMSCRIPTEN) + dir = PERSISTENT_DIRECTORY; #elif defined(PLATFORM_UNIX) if (dir == NULL) { @@ -1565,29 +1831,6 @@ char *getHomeDir(void) return dir; } -char *getCommonDataDir(void) -{ - static char *common_data_dir = NULL; - -#if defined(PLATFORM_WIN32) - if (common_data_dir == NULL) - { - char *dir = checked_malloc(MAX_PATH + 1); - - if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_COMMON_DOCUMENTS, NULL, 0, dir)) - && !strEqual(dir, "")) // empty for Windows 95/98 - common_data_dir = getPath2(dir, program.userdata_subdir); - else - common_data_dir = options.rw_base_directory; - } -#else - if (common_data_dir == NULL) - common_data_dir = options.rw_base_directory; -#endif - - return common_data_dir; -} - char *getPersonalDataDir(void) { static char *personal_data_dir = NULL; @@ -1945,7 +2188,7 @@ unsigned int get_hash_from_key(void *key) return hash; } -static int keys_are_equal(void *key1, void *key2) +int hash_keys_are_equal(void *key1, void *key2) { return (strEqual((char *)key1, (char *)key2)); } @@ -1953,7 +2196,7 @@ static int keys_are_equal(void *key1, void *key2) SetupFileHash *newSetupFileHash(void) { SetupFileHash *new_hash = - create_hashtable(16, 0.75, get_hash_from_key, keys_are_equal); + create_hashtable(16, 0.75, get_hash_from_key, hash_keys_are_equal); if (new_hash == NULL) Fail("create_hashtable() failed -- out of memory"); @@ -2364,6 +2607,8 @@ static void saveSetupFileHash(SetupFileHash *hash, char *filename) return; } + fprintf(file, "%s\n\n", getFormattedSetupEntry("program.version", + program.version_string)); for (i = 0; i < item_count; i++) fprintf(file, "%s\n", getFormattedSetupEntry(sort_array[i].token, sort_array[i].value)); @@ -2445,11 +2690,13 @@ SetupFileHash *loadSetupFileHash(char *filename) #define LEVELINFO_TOKEN_FILENAME 24 #define LEVELINFO_TOKEN_FILETYPE 25 #define LEVELINFO_TOKEN_SPECIAL_FLAGS 26 -#define LEVELINFO_TOKEN_HANDICAP 27 -#define LEVELINFO_TOKEN_SKIP_LEVELS 28 -#define LEVELINFO_TOKEN_USE_EMC_TILES 29 +#define LEVELINFO_TOKEN_EMPTY_LEVEL_NAME 27 +#define LEVELINFO_TOKEN_FORCE_LEVEL_NAME 28 +#define LEVELINFO_TOKEN_HANDICAP 29 +#define LEVELINFO_TOKEN_SKIP_LEVELS 30 +#define LEVELINFO_TOKEN_USE_EMC_TILES 31 -#define NUM_LEVELINFO_TOKENS 30 +#define NUM_LEVELINFO_TOKENS 32 static LevelDirTree ldi; @@ -2483,6 +2730,8 @@ static struct TokenInfo levelinfo_tokens[] = { TYPE_STRING, &ldi.level_filename, "filename" }, { TYPE_STRING, &ldi.level_filetype, "filetype" }, { TYPE_STRING, &ldi.special_flags, "special_flags" }, + { TYPE_STRING, &ldi.empty_level_name, "empty_level_name" }, + { TYPE_BOOLEAN, &ldi.force_level_name, "force_level_name" }, { TYPE_BOOLEAN, &ldi.handicap, "handicap" }, { TYPE_BOOLEAN, &ldi.skip_levels, "skip_levels" }, { TYPE_BOOLEAN, &ldi.use_emc_tiles, "use_emc_tiles" } @@ -2503,7 +2752,6 @@ static struct TokenInfo artworkinfo_tokens[] = { TYPE_STRING, &ldi.basepath, "basepath" }, { TYPE_STRING, &ldi.fullpath, "fullpath" }, { TYPE_BOOLEAN, &ldi.in_user_dir, "in_user_dir" }, - { TYPE_INTEGER, &ldi.color, "color" }, { TYPE_STRING, &ldi.class_desc, "class_desc" }, { -1, NULL, NULL }, @@ -2551,6 +2799,7 @@ static void setTreeInfoToDefaults(TreeInfo *ti, int type) 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; @@ -2580,6 +2829,9 @@ static void setTreeInfoToDefaults(TreeInfo *ti, int type) ti->special_flags = NULL; + ti->empty_level_name = NULL; + ti->force_level_name = FALSE; + ti->levels = 0; ti->first_level = 0; ti->last_level = 0; @@ -2632,6 +2884,7 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ti, TreeInfo *parent) 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; @@ -2661,6 +2914,9 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ti, TreeInfo *parent) ti->special_flags = getStringCopy(parent->special_flags); + ti->empty_level_name = getStringCopy(parent->empty_level_name); + ti->force_level_name = parent->force_level_name; + ti->levels = parent->levels; ti->first_level = parent->first_level; ti->last_level = parent->last_level; @@ -2723,6 +2979,9 @@ static TreeInfo *getTreeInfoCopy(TreeInfo *ti) ti_copy->special_flags = getStringCopy(ti->special_flags); + ti_copy->empty_level_name = getStringCopy(ti->empty_level_name); + ti_copy->force_level_name = ti->force_level_name; + ti_copy->levels = ti->levels; ti_copy->first_level = ti->first_level; ti_copy->last_level = ti->last_level; @@ -2732,6 +2991,7 @@ static TreeInfo *getTreeInfoCopy(TreeInfo *ti) 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; @@ -2858,34 +3118,13 @@ static int compareTreeInfoEntries(const void *object1, const void *object2) { const TreeInfo *entry1 = *((TreeInfo **)object1); const TreeInfo *entry2 = *((TreeInfo **)object2); - int class_sorting1 = 0, class_sorting2 = 0; - int compare_result; + int tree_sorting1 = TREE_SORTING(entry1); + int tree_sorting2 = TREE_SORTING(entry2); - if (entry1->type == TREE_TYPE_LEVEL_DIR) - { - class_sorting1 = LEVELSORTING(entry1); - class_sorting2 = LEVELSORTING(entry2); - } - 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); - } - - if (entry1->parent_link || entry2->parent_link) - compare_result = (entry1->parent_link ? -1 : +1); - else if (entry1->level_group != entry2->level_group) - compare_result = (entry1->level_group ? -1 : +1); - else if (entry1->sort_priority == entry2->sort_priority) - compare_result = strcasecmp(entry1->name_sorting, entry2->name_sorting); - else if (class_sorting1 == class_sorting2) - compare_result = entry1->sort_priority - entry2->sort_priority; + if (tree_sorting1 != tree_sorting2) + return (tree_sorting1 - tree_sorting2); else - compare_result = class_sorting1 - class_sorting2; - - return compare_result; + return strcasecmp(entry1->name_sorting, entry2->name_sorting); } static TreeInfo *createParentTreeInfoNode(TreeInfo *node_parent) @@ -2908,7 +3147,7 @@ static TreeInfo *createParentTreeInfoNode(TreeInfo *node_parent) 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)); @@ -2931,14 +3170,14 @@ static TreeInfo *createTopTreeInfoNode(TreeInfo *node_first) 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)); @@ -2967,6 +3206,17 @@ static void setTreeInfoParentNodes(TreeInfo *node, TreeInfo *node_parent) } } +TreeInfo *addTopTreeInfoNode(TreeInfo *node_first) +{ + // add top tree node with back link node in previous tree + node_first = createTopTreeInfoNode(node_first); + + // set all parent links (back links) in complete tree + setTreeInfoParentNodes(node_first, NULL); + + return node_first; +} + // ---------------------------------------------------------------------------- // functions for handling level and custom artwork info cache @@ -2983,6 +3233,17 @@ static void LoadArtworkInfoCache(void) // try to load artwork info hash from already existing cache file artworkinfo_cache_old = loadSetupFileHash(filename); + // try to get program version that artwork info cache was written with + char *version = getHashEntry(artworkinfo_cache_old, "program.version"); + + // check program version of artwork info cache against current version + if (!strEqual(version, program.version_string)) + { + freeSetupFileHash(artworkinfo_cache_old); + + artworkinfo_cache_old = NULL; + } + // if no artwork info cache file was found, start with empty hash if (artworkinfo_cache_old == NULL) artworkinfo_cache_old = newSetupFileHash(); @@ -3502,15 +3763,13 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first, leveldir_new->user_defined = (leveldir_new->in_user_dir && IS_LEVELCLASS_PRIVATE(leveldir_new)); - leveldir_new->color = LEVELCOLOR(leveldir_new); - setString(&leveldir_new->class_desc, getLevelClassDescription(leveldir_new)); leveldir_new->handicap_level = // set handicap to default value (leveldir_new->user_defined || !leveldir_new->handicap ? leveldir_new->last_level : leveldir_new->first_level); - DrawInitText(leveldir_new->name, 150, FC_YELLOW); + DrawInitTextItem(leveldir_new->name); pushTreeInfo(node_first, leveldir_new); @@ -3626,7 +3885,7 @@ void LoadLevelInfo(void) { InitUserLevelDirectory(getLoginName()); - DrawInitText("Loading level series", 120, FC_GREEN); + DrawInitTextHead("Loading level series"); LoadLevelInfoFromLevelDir(&leveldir_first, NULL, options.level_directory); LoadLevelInfoFromLevelDir(&leveldir_first, NULL, getUserLevelDir(NULL)); @@ -3747,9 +4006,6 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first, artwork_new->in_user_dir = (!strEqual(artwork_new->basepath, OPTIONS_ARTWORK_DIRECTORY(type))); - // (may use ".sort_priority" from "setup_file_hash" above) - artwork_new->color = ARTWORKCOLOR(artwork_new); - setString(&artwork_new->class_desc, getLevelClassDescription(artwork_new)); if (setup_file_hash == NULL) // (after determining ".user_defined") @@ -3767,9 +4023,6 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first, artwork_new->sort_priority = ARTWORKCLASS_CLASSICS; } - // set to new values after changing ".sort_priority" - artwork_new->color = ARTWORKCOLOR(artwork_new); - setString(&artwork_new->class_desc, getLevelClassDescription(artwork_new)); } @@ -3905,7 +4158,7 @@ void LoadArtworkInfo(void) { LoadArtworkInfoCache(); - DrawInitText("Looking for custom artwork", 120, FC_GREEN); + DrawInitTextHead("Looking for custom artwork"); LoadArtworkInfoFromArtworkDir(&artwork.gfx_first, NULL, options.graphics_directory, @@ -4027,7 +4280,7 @@ static void LoadArtworkInfoFromLevelInfoExt(ArtworkDirTree **artwork_node, setString(&artwork_new->name_sorting, level_node->name_sorting); artwork_new->sort_priority = level_node->sort_priority; - artwork_new->color = LEVELCOLOR(artwork_new); + artwork_new->in_user_dir = level_node->in_user_dir; update_artworkinfo_cache = TRUE; } @@ -4040,7 +4293,7 @@ static void LoadArtworkInfoFromLevelInfoExt(ArtworkDirTree **artwork_node, setArtworkInfoCacheEntry(artwork_new, level_node, type); } - DrawInitText(level_node->name, 150, FC_YELLOW); + DrawInitTextItem(level_node->name); if (level_node->node_group != NULL) { @@ -4098,18 +4351,15 @@ static void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node) 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); + // add top tree node over all sub-trees and set parent links + *artwork_node = addTopTreeInfoNode(*artwork_node); } void LoadLevelArtworkInfo(void) { print_timestamp_init("LoadLevelArtworkInfo"); - DrawInitText("Looking for custom level artwork", 120, FC_GREEN); + DrawInitTextHead("Looking for custom level artwork"); print_timestamp_time("DrawTimeText"); @@ -4557,9 +4807,11 @@ static void InitLastPlayedLevels_ParentNode(void) 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); @@ -4570,7 +4822,6 @@ static void InitLastPlayedLevels_ParentNode(void) 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; @@ -4580,13 +4831,9 @@ void UpdateLastPlayedLevels_TreeInfo(void) 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; @@ -4594,16 +4841,22 @@ void UpdateLastPlayedLevels_TreeInfo(void) 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; @@ -4611,10 +4864,6 @@ void UpdateLastPlayedLevels_TreeInfo(void) node_new = &((*node_new)->next); } - - if (reset_leveldir_current) - leveldir_current = getTreeInfoFromIdentifier(leveldir_first, - last_level_series[0]); } static void UpdateLastPlayedLevels_List(void) @@ -4636,6 +4885,35 @@ 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) { // -------------------------------------------------------------------------- @@ -4737,7 +5015,7 @@ static void SaveLevelSetup_LastSeries_Ext(boolean deactivate_last_level_series) for (i = 0; last_level_series[i] != NULL; i++) { - char token[strlen(TOKEN_STR_LAST_LEVEL_SERIES) + 10]; + char token[strlen(TOKEN_STR_LAST_LEVEL_SERIES) + 1 + 10 + 1]; sprintf(token, "%s.%03d", TOKEN_STR_LAST_LEVEL_SERIES, i);