X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Flibgame%2Fsetup.c;h=80ebcfa79382be6f226be8b0dedce125328c093f;hp=7439108a883e1ecb921b40c628b14df747fc5f02;hb=1f8fd7a79343ce670dc62fcb8be48ba78d0c9199;hpb=9965b1637d7919f7472eb2eab16abcf9fe2ba3f6 diff --git a/src/libgame/setup.c b/src/libgame/setup.c index 7439108a..80ebcfa7 100644 --- a/src/libgame/setup.c +++ b/src/libgame/setup.c @@ -31,6 +31,7 @@ #define ENABLE_UNUSED_CODE FALSE /* for currently unused functions */ +#define DEBUG_NO_CONFIG_FILE FALSE /* for extra-verbose debug output */ #define NUM_LEVELCLASS_DESC 8 @@ -114,34 +115,28 @@ static char *getLevelClassDescription(TreeInfo *ti) return "Unknown Level Class"; } -static char *getUserLevelDir(char *level_subdir) -{ - static char *userlevel_dir = NULL; - char *data_dir = getUserGameDataDir(); - char *userlevel_subdir = LEVELS_DIRECTORY; - - checked_free(userlevel_dir); - - if (level_subdir != NULL) - userlevel_dir = getPath3(data_dir, userlevel_subdir, level_subdir); - else - userlevel_dir = getPath2(data_dir, userlevel_subdir); - - return userlevel_dir; -} - static char *getScoreDir(char *level_subdir) { static char *score_dir = NULL; - char *data_dir = getCommonDataDir(); + static char *score_level_dir = NULL; char *score_subdir = SCORES_DIRECTORY; - checked_free(score_dir); + if (score_dir == NULL) + { + if (program.global_scores) + score_dir = getPath2(getCommonDataDir(), score_subdir); + else + score_dir = getPath2(getUserGameDataDir(), score_subdir); + } if (level_subdir != NULL) - score_dir = getPath3(data_dir, score_subdir, level_subdir); - else - score_dir = getPath2(data_dir, score_subdir); + { + checked_free(score_level_dir); + + score_level_dir = getPath2(score_dir, level_subdir); + + return score_level_dir; + } return score_dir; } @@ -162,7 +157,7 @@ static char *getLevelSetupDir(char *level_subdir) return levelsetup_dir; } -static char *getCacheDir() +static char *getCacheDir(void) { static char *cache_dir = NULL; @@ -172,6 +167,16 @@ static char *getCacheDir() return cache_dir; } +static char *getNetworkDir(void) +{ + static char *network_dir = NULL; + + if (network_dir == NULL) + network_dir = getPath2(getUserGameDataDir(), NETWORK_DIRECTORY); + + return network_dir; +} + static char *getLevelDirFromTreeInfo(TreeInfo *node) { static char *level_dir = NULL; @@ -187,11 +192,65 @@ static char *getLevelDirFromTreeInfo(TreeInfo *node) return level_dir; } -char *getCurrentLevelDir() +char *getUserLevelDir(char *level_subdir) +{ + static char *userlevel_dir = NULL; + char *data_dir = getUserGameDataDir(); + char *userlevel_subdir = LEVELS_DIRECTORY; + + checked_free(userlevel_dir); + + if (level_subdir != NULL) + userlevel_dir = getPath3(data_dir, userlevel_subdir, level_subdir); + else + userlevel_dir = getPath2(data_dir, userlevel_subdir); + + return userlevel_dir; +} + +char *getNetworkLevelDir(char *level_subdir) +{ + static char *network_level_dir = NULL; + char *data_dir = getNetworkDir(); + char *networklevel_subdir = LEVELS_DIRECTORY; + + checked_free(network_level_dir); + + if (level_subdir != NULL) + network_level_dir = getPath3(data_dir, networklevel_subdir, level_subdir); + else + network_level_dir = getPath2(data_dir, networklevel_subdir); + + return network_level_dir; +} + +char *getCurrentLevelDir(void) { return getLevelDirFromTreeInfo(leveldir_current); } +char *getNewUserLevelSubdir(void) +{ + static char *new_level_subdir = NULL; + char *subdir_prefix = getLoginName(); + char subdir_suffix[10]; + int max_suffix_number = 1000; + int i = 0; + + while (++i < max_suffix_number) + { + sprintf(subdir_suffix, "_%d", i); + + checked_free(new_level_subdir); + new_level_subdir = getStringCat2(subdir_prefix, subdir_suffix); + + if (!directoryExists(getUserLevelDir(new_level_subdir))) + break; + } + + return new_level_subdir; +} + static char *getTapeDir(char *level_subdir) { static char *tape_dir = NULL; @@ -208,7 +267,7 @@ static char *getTapeDir(char *level_subdir) return tape_dir; } -static char *getSolutionTapeDir() +static char *getSolutionTapeDir(void) { static char *tape_dir = NULL; char *data_dir = getCurrentLevelDir(); @@ -280,7 +339,7 @@ static char *getClassicArtworkDir(int type) getDefaultMusicDir(MUS_CLASSIC_SUBDIR) : ""); } -static char *getUserGraphicsDir() +static char *getUserGraphicsDir(void) { static char *usergraphics_dir = NULL; @@ -290,7 +349,7 @@ static char *getUserGraphicsDir() return usergraphics_dir; } -static char *getUserSoundsDir() +static char *getUserSoundsDir(void) { static char *usersounds_dir = NULL; @@ -300,7 +359,7 @@ static char *getUserSoundsDir() return usersounds_dir; } -static char *getUserMusicDir() +static char *getUserMusicDir(void) { static char *usermusic_dir = NULL; @@ -377,7 +436,7 @@ char *setLevelArtworkDir(TreeInfo *ti) return *artwork_set_ptr; } -inline static char *getLevelArtworkSet(int type) +static char *getLevelArtworkSet(int type) { if (leveldir_current == NULL) return NULL; @@ -385,7 +444,7 @@ inline static char *getLevelArtworkSet(int type) return LEVELDIR_ARTWORK_SET(leveldir_current, type); } -inline static char *getLevelArtworkDir(int type) +static char *getLevelArtworkDir(int type) { if (leveldir_current == NULL) return UNDEFINED_FILENAME; @@ -393,15 +452,74 @@ inline static char *getLevelArtworkDir(int type) return LEVELDIR_ARTWORK_PATH(leveldir_current, type); } -char *getProgramConfigFilename(char *command_filename_ptr) +char *getProgramMainDataPath(char *command_filename, char *base_path) { - char *command_filename = getStringCopy(command_filename_ptr); + /* check if the program's main data base directory is configured */ + if (!strEqual(base_path, ".")) + return base_path; + + /* if the program is configured to start from current directory (default), + determine program package directory from program binary (some versions + of KDE/Konqueror and Mac OS X (especially "Mavericks") apparently do not + set the current working directory to the program package directory) */ + char *main_data_path = getBasePath(command_filename); + +#if defined(PLATFORM_MACOSX) + if (strSuffix(main_data_path, MAC_APP_BINARY_SUBDIR)) + { + char *main_data_path_old = main_data_path; + + // cut relative path to Mac OS X application binary directory from path + main_data_path[strlen(main_data_path) - + strlen(MAC_APP_BINARY_SUBDIR)] = '\0'; + + // cut trailing path separator from path (but not if path is root directory) + if (strSuffix(main_data_path, "/") && !strEqual(main_data_path, "/")) + main_data_path[strlen(main_data_path) - 1] = '\0'; + + // replace empty path with current directory + if (strEqual(main_data_path, "")) + main_data_path = "."; + + // add relative path to Mac OS X application resources directory to path + main_data_path = getPath2(main_data_path, MAC_APP_FILES_SUBDIR); + + free(main_data_path_old); + } +#endif + + return main_data_path; +} + +char *getProgramConfigFilename(char *command_filename) +{ + char *command_filename_1 = getStringCopy(command_filename); // strip trailing executable suffix from command filename - if (strSuffix(command_filename, ".exe")) - command_filename[strlen(command_filename) - 4] = '\0'; + 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 *command_basepath = getBasePath(command_filename); + char *command_basename = getBaseNameNoSuffix(command_filename); + char *command_filename_2 = getPath2(command_basepath, command_basename); + + char *config_filename_1 = getStringCat2(command_filename_1, ".conf"); + char *config_filename_2 = getStringCat2(command_filename_2, ".conf"); + char *config_filename_3 = getPath2(conf_directory, SETUP_FILENAME); + + // 1st try: look for config file that exactly matches the binary filename + if (fileExists(config_filename_1)) + return config_filename_1; - return getStringCat2(command_filename, ".conf"); + // 2nd try: look for config file that matches binary filename without suffix + if (fileExists(config_filename_2)) + return config_filename_2; + + // 3rd try: return setup config filename in global program config directory + return config_filename_3; } char *getTapeFilename(int nr) @@ -451,12 +569,14 @@ char *getScoreFilename(int nr) checked_free(filename); sprintf(basename, "%03d.%s", nr, SCOREFILE_EXTENSION); - filename = getPath2(getScoreDir(leveldir_current->subdir), basename); + + /* used instead of "leveldir_current->subdir" (for network games) */ + filename = getPath2(getScoreDir(levelset.identifier), basename); return filename; } -char *getSetupFilename() +char *getSetupFilename(void) { static char *filename = NULL; @@ -467,12 +587,12 @@ char *getSetupFilename() return filename; } -char *getDefaultSetupFilename() +char *getDefaultSetupFilename(void) { return program.config_filename; } -char *getEditorSetupFilename() +char *getEditorSetupFilename(void) { static char *filename = NULL; @@ -488,7 +608,7 @@ char *getEditorSetupFilename() return filename; } -char *getHelpAnimFilename() +char *getHelpAnimFilename(void) { static char *filename = NULL; @@ -499,7 +619,7 @@ char *getHelpAnimFilename() return filename; } -char *getHelpTextFilename() +char *getHelpTextFilename(void) { static char *filename = NULL; @@ -510,7 +630,7 @@ char *getHelpTextFilename() return filename; } -char *getLevelSetInfoFilename() +char *getLevelSetInfoFilename(void) { static char *filename = NULL; char *basenames[] = @@ -539,7 +659,7 @@ char *getLevelSetInfoFilename() return NULL; } -char *getLevelSetTitleMessageBasename(int nr, boolean initial) +static char *getLevelSetTitleMessageBasename(int nr, boolean initial) { static char basename[32]; @@ -932,12 +1052,18 @@ void InitTapeDirectory(char *level_subdir) void InitScoreDirectory(char *level_subdir) { - createDirectory(getCommonDataDir(), "common data", PERMS_PUBLIC); - createDirectory(getScoreDir(NULL), "main score", PERMS_PUBLIC); - createDirectory(getScoreDir(level_subdir), "level score", PERMS_PUBLIC); + int permissions = (program.global_scores ? PERMS_PUBLIC : PERMS_PRIVATE); + + if (program.global_scores) + createDirectory(getCommonDataDir(), "common data", permissions); + else + createDirectory(getUserGameDataDir(), "user data", permissions); + + createDirectory(getScoreDir(NULL), "main score", permissions); + createDirectory(getScoreDir(level_subdir), "level score", permissions); } -static void SaveUserLevelInfo(); +static void SaveUserLevelInfo(void); void InitUserLevelDirectory(char *level_subdir) { @@ -951,6 +1077,17 @@ void InitUserLevelDirectory(char *level_subdir) } } +void InitNetworkLevelDirectory(char *level_subdir) +{ + if (!directoryExists(getNetworkLevelDir(level_subdir))) + { + createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE); + createDirectory(getNetworkDir(), "network data", PERMS_PRIVATE); + createDirectory(getNetworkLevelDir(NULL), "main network level", PERMS_PRIVATE); + createDirectory(getNetworkLevelDir(level_subdir), "network level", PERMS_PRIVATE); + } +} + void InitLevelSetupDirectory(char *level_subdir) { createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE); @@ -958,7 +1095,7 @@ void InitLevelSetupDirectory(char *level_subdir) createDirectory(getLevelSetupDir(level_subdir), "level setup", PERMS_PRIVATE); } -void InitCacheDirectory() +static void InitCacheDirectory(void) { createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE); createDirectory(getCacheDir(), "cache data", PERMS_PRIVATE); @@ -969,7 +1106,7 @@ void InitCacheDirectory() /* some functions to handle lists of level and artwork directories */ /* ------------------------------------------------------------------------- */ -TreeInfo *newTreeInfo() +TreeInfo *newTreeInfo(void) { return checked_calloc(sizeof(TreeInfo)); } @@ -1103,8 +1240,8 @@ TreeInfo *getTreeInfoFromIdentifier(TreeInfo *node, char *identifier) return NULL; } -TreeInfo *cloneTreeNode(TreeInfo **node_top, TreeInfo *node_parent, - TreeInfo *node, boolean skip_sets_without_levels) +static TreeInfo *cloneTreeNode(TreeInfo **node_top, TreeInfo *node_parent, + TreeInfo *node, boolean skip_sets_without_levels) { TreeInfo *node_new; @@ -1131,7 +1268,7 @@ TreeInfo *cloneTreeNode(TreeInfo **node_top, TreeInfo *node_parent, return node_new; } -void cloneTree(TreeInfo **ti_new, TreeInfo *ti, boolean skip_empty_sets) +static void cloneTree(TreeInfo **ti_new, TreeInfo *ti, boolean skip_empty_sets) { TreeInfo *ti_cloned = cloneTreeNode(ti_new, NULL, ti, skip_empty_sets); @@ -1284,16 +1421,19 @@ void sortTreeInfo(TreeInfo **node_first) #define MODE_X_ALL (S_IXUSR | S_IXGRP | S_IXOTH) #define MODE_W_PRIVATE (S_IWUSR) -#define MODE_W_PUBLIC (S_IWUSR | S_IWGRP) +#define MODE_W_PUBLIC_FILE (S_IWUSR | S_IWGRP) #define MODE_W_PUBLIC_DIR (S_IWUSR | S_IWGRP | S_ISGID) #define DIR_PERMS_PRIVATE (MODE_R_ALL | MODE_X_ALL | MODE_W_PRIVATE) #define DIR_PERMS_PUBLIC (MODE_R_ALL | MODE_X_ALL | MODE_W_PUBLIC_DIR) +#define DIR_PERMS_PUBLIC_ALL (MODE_R_ALL | MODE_X_ALL | MODE_W_ALL) #define FILE_PERMS_PRIVATE (MODE_R_ALL | MODE_W_PRIVATE) -#define FILE_PERMS_PUBLIC (MODE_R_ALL | MODE_W_PUBLIC) +#define FILE_PERMS_PUBLIC (MODE_R_ALL | MODE_W_PUBLIC_FILE) +#define FILE_PERMS_PUBLIC_ALL (MODE_R_ALL | MODE_W_ALL) -char *getHomeDir() + +char *getHomeDir(void) { static char *dir = NULL; @@ -1369,7 +1509,10 @@ char *getUserGameDataDir(void) #if defined(PLATFORM_ANDROID) if (user_game_data_dir == NULL) - user_game_data_dir = (char *)SDL_AndroidGetInternalStoragePath(); + user_game_data_dir = (char *)(SDL_AndroidGetExternalStorageState() & + SDL_ANDROID_EXTERNAL_STORAGE_WRITE ? + SDL_AndroidGetExternalStoragePath() : + SDL_AndroidGetInternalStoragePath()); #else if (user_game_data_dir == NULL) user_game_data_dir = getPath2(getPersonalDataDir(), @@ -1379,31 +1522,7 @@ char *getUserGameDataDir(void) return user_game_data_dir; } -void updateUserGameDataDir() -{ -#if defined(PLATFORM_MACOSX) - char *userdata_dir_old = getPath2(getHomeDir(), program.userdata_subdir_unix); - char *userdata_dir_new = getUserGameDataDir(); /* do not free() this */ - - /* convert old Unix style game data directory to Mac OS X style, if needed */ - if (directoryExists(userdata_dir_old) && !directoryExists(userdata_dir_new)) - { - if (rename(userdata_dir_old, userdata_dir_new) != 0) - { - Error(ERR_WARN, "cannot move game data directory '%s' to '%s'", - userdata_dir_old, userdata_dir_new); - - /* continue using Unix style data directory -- this should not happen */ - program.userdata_path = getPath2(getPersonalDataDir(), - program.userdata_subdir_unix); - } - } - - free(userdata_dir_old); -#endif -} - -char *getSetupDir() +char *getSetupDir(void) { return getUserGameDataDir(); } @@ -1426,7 +1545,7 @@ static int posix_mkdir(const char *pathname, mode_t mode) #endif } -static boolean posix_process_running_setgid() +static boolean posix_process_running_setgid(void) { #if defined(PLATFORM_UNIX) return (getgid() != getegid()); @@ -1437,6 +1556,9 @@ static boolean posix_process_running_setgid() void createDirectory(char *dir, char *text, int permission_class) { + if (directoryExists(dir)) + return; + /* leave "other" permissions in umask untouched, but ensure group parts of USERDATA_DIR_MODE are not masked */ mode_t dir_mode = (permission_class == PERMS_PRIVATE ? @@ -1445,18 +1567,20 @@ void createDirectory(char *dir, char *text, int permission_class) mode_t group_umask = ~(dir_mode & S_IRWXG); int running_setgid = posix_process_running_setgid(); - /* if we're setgid, protect files against "other" */ - /* else keep umask(0) to make the dir world-writable */ + if (permission_class == PERMS_PUBLIC) + { + /* if we're setgid, protect files against "other" */ + /* else keep umask(0) to make the dir world-writable */ - if (running_setgid) - posix_umask(last_umask & group_umask); - else - dir_mode |= MODE_W_ALL; + if (running_setgid) + posix_umask(last_umask & group_umask); + else + dir_mode = DIR_PERMS_PUBLIC_ALL; + } - if (!directoryExists(dir)) - if (posix_mkdir(dir, dir_mode) != 0) - Error(ERR_WARN, "cannot create %s directory '%s': %s", - text, dir, strerror(errno)); + if (posix_mkdir(dir, dir_mode) != 0) + Error(ERR_WARN, "cannot create %s directory '%s': %s", + text, dir, strerror(errno)); if (permission_class == PERMS_PUBLIC && !running_setgid) chmod(dir, dir_mode); @@ -1464,7 +1588,7 @@ void createDirectory(char *dir, char *text, int permission_class) posix_umask(last_umask); /* restore previous umask */ } -void InitUserDataDirectory() +void InitUserDataDirectory(void) { createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE); } @@ -1476,7 +1600,7 @@ void SetFilePermissions(char *filename, int permission_class) FILE_PERMS_PRIVATE : FILE_PERMS_PUBLIC); if (permission_class == PERMS_PUBLIC && !running_setgid) - perms |= MODE_W_ALL; + perms = FILE_PERMS_PUBLIC_ALL; chmod(filename, perms); } @@ -1491,7 +1615,7 @@ char *getCookie(char *file_type) sprintf(cookie, "%s_%s_FILE_VERSION_%d.%d", program.cookie_prefix, file_type, - program.version_major, program.version_minor); + program.version_super, program.version_major); return cookie; } @@ -1516,7 +1640,7 @@ int getFileVersionFromCookieString(const char *cookie) const int len_pattern1 = strlen(pattern1); const int len_pattern2 = strlen(pattern2); const int len_pattern = len_pattern1 + len_pattern2; - int version_major, version_minor; + int version_super, version_major; if (len_cookie <= len_pattern) return -1; @@ -1532,10 +1656,10 @@ int getFileVersionFromCookieString(const char *cookie) ptr_cookie2[2] < '0' || ptr_cookie2[2] > '9') return -1; - version_major = ptr_cookie2[0] - '0'; - version_minor = ptr_cookie2[2] - '0'; + version_super = ptr_cookie2[0] - '0'; + version_major = ptr_cookie2[2] - '0'; - return VERSION_IDENT(version_major, version_minor, 0, 0); + return VERSION_IDENT(version_super, version_major, 0, 0); } boolean checkCookieString(const char *cookie, const char *template) @@ -1708,7 +1832,7 @@ static int keys_are_equal(void *key1, void *key2) return (strEqual((char *)key1, (char *)key2)); } -SetupFileHash *newSetupFileHash() +SetupFileHash *newSetupFileHash(void) { SetupFileHash *new_hash = create_hashtable(16, 0.75, get_hash_from_key, keys_are_equal); @@ -1940,7 +2064,9 @@ static boolean loadSetupFileData(void *setup_file_data, char *filename, if (!(file = openFile(filename, MODE_READ))) { - Error(ERR_WARN, "cannot open configuration file '%s'", filename); +#if DEBUG_NO_CONFIG_FILE + Error(ERR_DEBUG, "cannot open configuration file '%s'", filename); +#endif return FALSE; } @@ -2081,7 +2207,7 @@ static boolean loadSetupFileData(void *setup_file_data, char *filename, return TRUE; } -void saveSetupFileHash(SetupFileHash *hash, char *filename) +static void saveSetupFileHash(SetupFileHash *hash, char *filename) { FILE *file; @@ -2152,27 +2278,30 @@ SetupFileHash *loadSetupFileHash(char *filename) #define LEVELINFO_TOKEN_NAME_SORTING 2 #define LEVELINFO_TOKEN_AUTHOR 3 #define LEVELINFO_TOKEN_YEAR 4 -#define LEVELINFO_TOKEN_IMPORTED_FROM 5 -#define LEVELINFO_TOKEN_IMPORTED_BY 6 -#define LEVELINFO_TOKEN_TESTED_BY 7 -#define LEVELINFO_TOKEN_LEVELS 8 -#define LEVELINFO_TOKEN_FIRST_LEVEL 9 -#define LEVELINFO_TOKEN_SORT_PRIORITY 10 -#define LEVELINFO_TOKEN_LATEST_ENGINE 11 -#define LEVELINFO_TOKEN_LEVEL_GROUP 12 -#define LEVELINFO_TOKEN_READONLY 13 -#define LEVELINFO_TOKEN_GRAPHICS_SET_ECS 14 -#define LEVELINFO_TOKEN_GRAPHICS_SET_AGA 15 -#define LEVELINFO_TOKEN_GRAPHICS_SET 16 -#define LEVELINFO_TOKEN_SOUNDS_SET 17 -#define LEVELINFO_TOKEN_MUSIC_SET 18 -#define LEVELINFO_TOKEN_FILENAME 19 -#define LEVELINFO_TOKEN_FILETYPE 20 -#define LEVELINFO_TOKEN_SPECIAL_FLAGS 21 -#define LEVELINFO_TOKEN_HANDICAP 22 -#define LEVELINFO_TOKEN_SKIP_LEVELS 23 - -#define NUM_LEVELINFO_TOKENS 24 +#define LEVELINFO_TOKEN_PROGRAM_TITLE 5 +#define LEVELINFO_TOKEN_PROGRAM_COPYRIGHT 6 +#define LEVELINFO_TOKEN_PROGRAM_COMPANY 7 +#define LEVELINFO_TOKEN_IMPORTED_FROM 8 +#define LEVELINFO_TOKEN_IMPORTED_BY 9 +#define LEVELINFO_TOKEN_TESTED_BY 10 +#define LEVELINFO_TOKEN_LEVELS 11 +#define LEVELINFO_TOKEN_FIRST_LEVEL 12 +#define LEVELINFO_TOKEN_SORT_PRIORITY 13 +#define LEVELINFO_TOKEN_LATEST_ENGINE 14 +#define LEVELINFO_TOKEN_LEVEL_GROUP 15 +#define LEVELINFO_TOKEN_READONLY 16 +#define LEVELINFO_TOKEN_GRAPHICS_SET_ECS 17 +#define LEVELINFO_TOKEN_GRAPHICS_SET_AGA 18 +#define LEVELINFO_TOKEN_GRAPHICS_SET 19 +#define LEVELINFO_TOKEN_SOUNDS_SET 20 +#define LEVELINFO_TOKEN_MUSIC_SET 21 +#define LEVELINFO_TOKEN_FILENAME 22 +#define LEVELINFO_TOKEN_FILETYPE 23 +#define LEVELINFO_TOKEN_SPECIAL_FLAGS 24 +#define LEVELINFO_TOKEN_HANDICAP 25 +#define LEVELINFO_TOKEN_SKIP_LEVELS 26 + +#define NUM_LEVELINFO_TOKENS 27 static LevelDirTree ldi; @@ -2184,6 +2313,9 @@ static struct TokenInfo levelinfo_tokens[] = { TYPE_STRING, &ldi.name_sorting, "name_sorting" }, { TYPE_STRING, &ldi.author, "author" }, { TYPE_STRING, &ldi.year, "year" }, + { TYPE_STRING, &ldi.program_title, "program_title" }, + { TYPE_STRING, &ldi.program_copyright, "program_copyright" }, + { TYPE_STRING, &ldi.program_company, "program_company" }, { TYPE_STRING, &ldi.imported_from, "imported_from" }, { TYPE_STRING, &ldi.imported_by, "imported_by" }, { TYPE_STRING, &ldi.tested_by, "tested_by" }, @@ -2213,6 +2345,9 @@ static struct TokenInfo artworkinfo_tokens[] = { TYPE_STRING, &ldi.name, "name" }, { TYPE_STRING, &ldi.name_sorting, "name_sorting" }, { TYPE_STRING, &ldi.author, "author" }, + { TYPE_STRING, &ldi.program_title, "program_title" }, + { TYPE_STRING, &ldi.program_copyright, "program_copyright" }, + { TYPE_STRING, &ldi.program_company, "program_company" }, { TYPE_INTEGER, &ldi.sort_priority, "sort_priority" }, { TYPE_STRING, &ldi.basepath, "basepath" }, { TYPE_STRING, &ldi.fullpath, "fullpath" }, @@ -2249,6 +2384,10 @@ static void setTreeInfoToDefaults(TreeInfo *ti, int type) ti->author = getStringCopy(ANONYMOUS_NAME); ti->year = NULL; + ti->program_title = NULL; + ti->program_copyright = NULL; + ti->program_company = NULL; + ti->sort_priority = LEVELCLASS_UNDEFINED; /* default: least priority */ ti->latest_engine = FALSE; /* default: get from level */ ti->parent_link = FALSE; @@ -2322,6 +2461,10 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ti, TreeInfo *parent) ti->author = getStringCopy(parent->author); ti->year = getStringCopy(parent->year); + ti->program_title = getStringCopy(parent->program_title); + ti->program_copyright = getStringCopy(parent->program_copyright); + ti->program_company = getStringCopy(parent->program_company); + ti->sort_priority = parent->sort_priority; ti->latest_engine = parent->latest_engine; ti->parent_link = FALSE; @@ -2338,28 +2481,28 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ti, TreeInfo *parent) ti->imported_by = getStringCopy(parent->imported_by); ti->tested_by = getStringCopy(parent->tested_by); - ti->graphics_set_ecs = NULL; - ti->graphics_set_aga = NULL; - ti->graphics_set = NULL; - ti->sounds_set = NULL; - ti->music_set = NULL; + ti->graphics_set_ecs = getStringCopy(parent->graphics_set_ecs); + ti->graphics_set_aga = getStringCopy(parent->graphics_set_aga); + ti->graphics_set = getStringCopy(parent->graphics_set); + ti->sounds_set = getStringCopy(parent->sounds_set); + ti->music_set = getStringCopy(parent->music_set); ti->graphics_path = getStringCopy(UNDEFINED_FILENAME); ti->sounds_path = getStringCopy(UNDEFINED_FILENAME); ti->music_path = getStringCopy(UNDEFINED_FILENAME); - ti->level_filename = NULL; - ti->level_filetype = NULL; + ti->level_filename = getStringCopy(parent->level_filename); + ti->level_filetype = getStringCopy(parent->level_filetype); ti->special_flags = getStringCopy(parent->special_flags); - ti->levels = 0; - ti->first_level = 0; - ti->last_level = 0; + ti->levels = parent->levels; + ti->first_level = parent->first_level; + ti->last_level = parent->last_level; ti->level_group = FALSE; - ti->handicap_level = 0; + ti->handicap_level = parent->handicap_level; ti->readonly = parent->readonly; - ti->handicap = TRUE; - ti->skip_levels = FALSE; + ti->handicap = parent->handicap; + ti->skip_levels = parent->skip_levels; } } @@ -2387,6 +2530,11 @@ static TreeInfo *getTreeInfoCopy(TreeInfo *ti) ti_copy->name_sorting = getStringCopy(ti->name_sorting); ti_copy->author = getStringCopy(ti->author); ti_copy->year = getStringCopy(ti->year); + + ti_copy->program_title = getStringCopy(ti->program_title); + ti_copy->program_copyright = getStringCopy(ti->program_copyright); + ti_copy->program_company = getStringCopy(ti->program_company); + ti_copy->imported_from = getStringCopy(ti->imported_from); ti_copy->imported_by = getStringCopy(ti->imported_by); ti_copy->tested_by = getStringCopy(ti->tested_by); @@ -2444,6 +2592,10 @@ void freeTreeInfo(TreeInfo *ti) checked_free(ti->author); checked_free(ti->year); + checked_free(ti->program_title); + checked_free(ti->program_copyright); + checked_free(ti->program_company); + checked_free(ti->class_desc); checked_free(ti->infotext); @@ -2519,6 +2671,10 @@ void setSetupInfo(struct TokenInfo *token_info, *(char **)setup_value = getStringCopy(token_value); break; + case TYPE_PLAYER: + *(int *)setup_value = get_player_nr_from_string(token_value); + break; + default: break; } @@ -2612,7 +2768,7 @@ static TreeInfo *createTopTreeInfoNode(TreeInfo *node_first) setString(&ti_new->name_sorting, ti_new->name); setString(&ti_new->subdir, STRING_TOP_DIRECTORY); - setString(&ti_new->fullpath, node_first->fullpath); + setString(&ti_new->fullpath, "."); ti_new->sort_priority = node_first->sort_priority;; ti_new->latest_engine = node_first->latest_engine; @@ -2635,7 +2791,7 @@ static TreeInfo *createTopTreeInfoNode(TreeInfo *node_first) /* functions for handling level and custom artwork info cache */ /* -------------------------------------------------------------------------- */ -static void LoadArtworkInfoCache() +static void LoadArtworkInfoCache(void) { InitCacheDirectory(); @@ -2657,7 +2813,7 @@ static void LoadArtworkInfoCache() artworkinfo_cache_new = newSetupFileHash(); } -static void SaveArtworkInfoCache() +static void SaveArtworkInfoCache(void) { char *filename = getPath2(getCacheDir(), ARTWORKINFO_CACHE_FILE); @@ -2736,22 +2892,13 @@ static TreeInfo *getArtworkInfoCacheEntry(LevelDirTree *level_node, int type) char *token = getCacheToken(token_prefix, artworkinfo_tokens[i].text); char *value = getHashEntry(artworkinfo_cache_old, token); - setSetupInfo(artworkinfo_tokens, i, value); - - /* check if cache entry for this item is invalid or incomplete */ - if (value == NULL) - { - Error(ERR_WARN, "cache entry '%s' invalid", token); - - cached = FALSE; - } + /* if defined, use value from cache, else keep default value */ + if (value != NULL) + setSetupInfo(artworkinfo_tokens, i, value); } *artwork_info = ldi; - } - if (cached) - { char *filename_levelinfo = getPath2(getLevelDirFromTreeInfo(level_node), LEVELINFO_FILENAME); char *filename_artworkinfo = getPath2(getSetupArtworkDir(artwork_info), @@ -2861,7 +3008,9 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first, if (setup_file_hash == NULL) { +#if DEBUG_NO_CONFIG_FILE Error(ERR_WARN, "ignoring level directory '%s'", directory_path); +#endif free(directory_path); free(filename); @@ -3019,7 +3168,7 @@ static void LoadLevelInfoFromLevelDir(TreeInfo **node_first, level_directory); } -boolean AdjustGraphicsForEMC() +boolean AdjustGraphicsForEMC(void) { boolean settings_changed = FALSE; @@ -3029,7 +3178,7 @@ boolean AdjustGraphicsForEMC() return settings_changed; } -void LoadLevelInfo() +void LoadLevelInfo(void) { InitUserLevelDirectory(getLoginName()); @@ -3099,8 +3248,10 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first, if (!valid_file_found) { +#if DEBUG_NO_CONFIG_FILE if (!strEqual(directory_name, ".")) Error(ERR_WARN, "ignoring artwork directory '%s'", directory_path); +#endif free(directory_path); free(filename); @@ -3272,7 +3423,7 @@ static TreeInfo *getDummyArtworkInfo(int type) return artwork_new; } -void LoadArtworkInfo() +void LoadArtworkInfo(void) { LoadArtworkInfoCache(); @@ -3352,8 +3503,8 @@ void LoadArtworkInfo() #endif } -void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node, - LevelDirTree *level_node) +static void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node, + LevelDirTree *level_node) { int type = (*artwork_node)->type; @@ -3408,7 +3559,7 @@ void LoadArtworkInfoFromLevelInfo(ArtworkDirTree **artwork_node, } } -void LoadLevelArtworkInfo() +void LoadLevelArtworkInfo(void) { print_timestamp_init("LoadLevelArtworkInfo"); @@ -3479,20 +3630,178 @@ void LoadLevelArtworkInfo() print_timestamp_done("LoadLevelArtworkInfo"); } -static void SaveUserLevelInfo() +static boolean AddUserLevelSetToLevelInfoExt(char *level_subdir_new) +{ + // get level info tree node of first (original) user level set + char *level_subdir_old = getLoginName(); + LevelDirTree *leveldir_old = getTreeInfoFromIdentifier(leveldir_first, + level_subdir_old); + if (leveldir_old == NULL) // should not happen + return FALSE; + + int draw_deactivation_mask = GetDrawDeactivationMask(); + + // override draw deactivation mask (temporarily disable drawing) + SetDrawDeactivationMask(REDRAW_ALL); + + // load new level set config and add it next to first user level set + LoadLevelInfoFromLevelConf(&leveldir_old->next, NULL, + leveldir_old->basepath, level_subdir_new); + + // set draw deactivation mask to previous value + SetDrawDeactivationMask(draw_deactivation_mask); + + // get level info tree node of newly added user level set + LevelDirTree *leveldir_new = getTreeInfoFromIdentifier(leveldir_first, + level_subdir_new); + if (leveldir_new == NULL) // should not happen + return FALSE; + + // correct top link and parent node link of newly created tree node + leveldir_new->node_top = leveldir_old->node_top; + leveldir_new->node_parent = leveldir_old->node_parent; + + // sort level info tree to adjust position of newly added level set + sortTreeInfo(&leveldir_first); + + return TRUE; +} + +void AddUserLevelSetToLevelInfo(char *level_subdir_new) +{ + if (!AddUserLevelSetToLevelInfoExt(level_subdir_new)) + Error(ERR_EXIT, "internal level set structure corrupted -- aborting"); +} + +char *getArtworkIdentifierForUserLevelSet(int type) +{ + char *classic_artwork_set = getClassicArtworkSet(type); + + /* check for custom artwork configured in "levelinfo.conf" */ + char *leveldir_artwork_set = + *LEVELDIR_ARTWORK_SET_PTR(leveldir_current, type); + boolean has_leveldir_artwork_set = + (leveldir_artwork_set != NULL && !strEqual(leveldir_artwork_set, + classic_artwork_set)); + + /* check for custom artwork in sub-directory "graphics" etc. */ + TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type); + char *leveldir_identifier = leveldir_current->identifier; + boolean has_artwork_subdir = + (getTreeInfoFromIdentifier(artwork_first_node, + leveldir_identifier) != NULL); + + return (has_leveldir_artwork_set ? leveldir_artwork_set : + has_artwork_subdir ? leveldir_identifier : + classic_artwork_set); +} + +TreeInfo *getArtworkTreeInfoForUserLevelSet(int type) +{ + char *artwork_set = getArtworkIdentifierForUserLevelSet(type); + TreeInfo *artwork_first_node = ARTWORK_FIRST_NODE(artwork, type); + + return getTreeInfoFromIdentifier(artwork_first_node, artwork_set); +} + +boolean checkIfCustomArtworkExistsForCurrentLevelSet(void) +{ + char *graphics_set = + getArtworkIdentifierForUserLevelSet(ARTWORK_TYPE_GRAPHICS); + char *sounds_set = + getArtworkIdentifierForUserLevelSet(ARTWORK_TYPE_SOUNDS); + char *music_set = + getArtworkIdentifierForUserLevelSet(ARTWORK_TYPE_MUSIC); + + return (!strEqual(graphics_set, GFX_CLASSIC_SUBDIR) || + !strEqual(sounds_set, SND_CLASSIC_SUBDIR) || + !strEqual(music_set, MUS_CLASSIC_SUBDIR)); +} + +boolean UpdateUserLevelSet(char *level_subdir, char *level_name, + char *level_author, int num_levels) +{ + char *filename = getPath2(getUserLevelDir(level_subdir), LEVELINFO_FILENAME); + char *filename_tmp = getStringCat2(filename, ".tmp"); + FILE *file = NULL; + FILE *file_tmp = NULL; + char line[MAX_LINE_LEN]; + boolean success = FALSE; + LevelDirTree *leveldir = getTreeInfoFromIdentifier(leveldir_first, + level_subdir); + // update values in level directory tree + + if (level_name != NULL) + setString(&leveldir->name, level_name); + + if (level_author != NULL) + setString(&leveldir->author, level_author); + + if (num_levels != -1) + leveldir->levels = num_levels; + + // update values that depend on other values + + setString(&leveldir->name_sorting, leveldir->name); + + leveldir->last_level = leveldir->first_level + leveldir->levels - 1; + + // sort order of level sets may have changed + sortTreeInfo(&leveldir_first); + + if ((file = fopen(filename, MODE_READ)) && + (file_tmp = fopen(filename_tmp, MODE_WRITE))) + { + while (fgets(line, MAX_LINE_LEN, file)) + { + if (strPrefix(line, "name:") && level_name != NULL) + fprintf(file_tmp, "%-32s%s\n", "name:", level_name); + else if (strPrefix(line, "author:") && level_author != NULL) + fprintf(file_tmp, "%-32s%s\n", "author:", level_author); + else if (strPrefix(line, "levels:") && num_levels != -1) + fprintf(file_tmp, "%-32s%d\n", "levels:", num_levels); + else + fputs(line, file_tmp); + } + + success = TRUE; + } + + if (file) + fclose(file); + + if (file_tmp) + fclose(file_tmp); + + if (success) + success = (rename(filename_tmp, filename) == 0); + + free(filename); + free(filename_tmp); + + return success; +} + +boolean CreateUserLevelSet(char *level_subdir, char *level_name, + char *level_author, int num_levels, + boolean use_artwork_set) { LevelDirTree *level_info; char *filename; FILE *file; int i; - filename = getPath2(getUserLevelDir(getLoginName()), LEVELINFO_FILENAME); + // create user level sub-directory, if needed + createDirectory(getUserLevelDir(level_subdir), "user level", PERMS_PRIVATE); + + filename = getPath2(getUserLevelDir(level_subdir), LEVELINFO_FILENAME); if (!(file = fopen(filename, MODE_WRITE))) { Error(ERR_WARN, "cannot write level info file '%s'", filename); free(filename); - return; + + return FALSE; } level_info = newTreeInfo(); @@ -3500,10 +3809,22 @@ static void SaveUserLevelInfo() /* always start with reliable default values */ setTreeInfoToDefaults(level_info, TREE_TYPE_LEVEL_DIR); - setString(&level_info->name, getLoginName()); - setString(&level_info->author, getRealName()); - level_info->levels = 100; + setString(&level_info->name, level_name); + setString(&level_info->author, level_author); + level_info->levels = num_levels; level_info->first_level = 1; + level_info->sort_priority = LEVELCLASS_PRIVATE_START; + level_info->readonly = FALSE; + + if (use_artwork_set) + { + level_info->graphics_set = + getStringCopy(getArtworkIdentifierForUserLevelSet(ARTWORK_TYPE_GRAPHICS)); + level_info->sounds_set = + getStringCopy(getArtworkIdentifierForUserLevelSet(ARTWORK_TYPE_SOUNDS)); + level_info->music_set = + getStringCopy(getArtworkIdentifierForUserLevelSet(ARTWORK_TYPE_MUSIC)); + } token_value_position = TOKEN_VALUE_POSITION_SHORT; @@ -3515,11 +3836,18 @@ static void SaveUserLevelInfo() if (i == LEVELINFO_TOKEN_NAME || i == LEVELINFO_TOKEN_AUTHOR || i == LEVELINFO_TOKEN_LEVELS || - i == LEVELINFO_TOKEN_FIRST_LEVEL) + i == LEVELINFO_TOKEN_FIRST_LEVEL || + i == LEVELINFO_TOKEN_SORT_PRIORITY || + i == LEVELINFO_TOKEN_READONLY || + (use_artwork_set && (i == LEVELINFO_TOKEN_GRAPHICS_SET || + i == LEVELINFO_TOKEN_SOUNDS_SET || + i == LEVELINFO_TOKEN_MUSIC_SET))) fprintf(file, "%s\n", getSetupLine(levelinfo_tokens, "", i)); /* just to make things nicer :) */ - if (i == LEVELINFO_TOKEN_AUTHOR) + if (i == LEVELINFO_TOKEN_AUTHOR || + i == LEVELINFO_TOKEN_FIRST_LEVEL || + (use_artwork_set && i == LEVELINFO_TOKEN_READONLY)) fprintf(file, "\n"); } @@ -3531,6 +3859,13 @@ static void SaveUserLevelInfo() freeTreeInfo(level_info); free(filename); + + return TRUE; +} + +static void SaveUserLevelInfo(void) +{ + CreateUserLevelSet(getLoginName(), getLoginName(), getRealName(), 100, FALSE); } char *getSetupValue(int type, void *value) @@ -3587,6 +3922,10 @@ char *getSetupValue(int type, void *value) strcpy(value_string, *(char **)value); break; + case TYPE_PLAYER: + sprintf(value_string, "player_%d", *(int *)value + 1); + break; + default: value_string[0] = '\0'; break; @@ -3636,7 +3975,7 @@ char *getSetupLine(struct TokenInfo *token_info, char *prefix, int token_nr) return line; } -void LoadLevelSetup_LastSeries() +void LoadLevelSetup_LastSeries(void) { /* ----------------------------------------------------------------------- */ /* ~/./levelsetup.conf */ @@ -3669,7 +4008,9 @@ void LoadLevelSetup_LastSeries() freeSetupFileHash(level_setup_hash); } else - Error(ERR_WARN, "using default setup values"); + { + Error(ERR_DEBUG, "using default setup values"); + } free(filename); } @@ -3714,17 +4055,17 @@ static void SaveLevelSetup_LastSeries_Ext(boolean deactivate_last_level_series) free(filename); } -void SaveLevelSetup_LastSeries() +void SaveLevelSetup_LastSeries(void) { SaveLevelSetup_LastSeries_Ext(FALSE); } -void SaveLevelSetup_LastSeries_Deactivate() +void SaveLevelSetup_LastSeries_Deactivate(void) { SaveLevelSetup_LastSeries_Ext(TRUE); } -static void checkSeriesInfo() +static void checkSeriesInfo(void) { static char *level_directory = NULL; Directory *dir; @@ -3746,7 +4087,7 @@ static void checkSeriesInfo() closeDirectory(dir); } -void LoadLevelSetup_SeriesInfo() +void LoadLevelSetup_SeriesInfo(void) { char *filename; SetupFileHash *level_setup_hash = NULL; @@ -3837,12 +4178,14 @@ void LoadLevelSetup_SeriesInfo() freeSetupFileHash(level_setup_hash); } else - Error(ERR_WARN, "using default setup values"); + { + Error(ERR_DEBUG, "using default setup values"); + } free(filename); } -void SaveLevelSetup_SeriesInfo() +void SaveLevelSetup_SeriesInfo(void) { char *filename; char *level_subdir = leveldir_current->subdir;