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;
}
return level_dir;
}
+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 *getCurrentLevelDir()
{
return getLevelDirFromTreeInfo(leveldir_current);
}
+char *getNewUserLevelSubdir()
+{
+ 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;
return LEVELDIR_ARTWORK_PATH(leveldir_current, type);
}
-char *getProgramConfigFilename(char *command_filename_ptr)
+char *getProgramMainDataPath(char *command_filename, char *base_path)
+{
+ /* 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 = getStringCopy(command_filename_ptr);
+ 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);
- return getStringCat2(command_filename, ".conf");
+ 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;
+
+ // 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)
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();
#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()
{
#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(),
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()
{
return getUserGameDataDir();
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 ?
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);
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);
}
if (!(file = openFile(filename, MODE_READ)))
{
- Error(ERR_WARN, "cannot open configuration file '%s'", filename);
+ Error(ERR_DEBUG, "cannot open configuration file '%s'", filename);
return FALSE;
}
#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;
{ 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" },
{ 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" },
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;
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;
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;
}
}
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);
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);
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;
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),
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()
+{
+ 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();
/* 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;
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");
}
freeTreeInfo(level_info);
free(filename);
+
+ return TRUE;
+}
+
+static void SaveUserLevelInfo()
+{
+ CreateUserLevelSet(getLoginName(), getLoginName(), getRealName(), 100, FALSE);
}
char *getSetupValue(int type, void *value)
freeSetupFileHash(level_setup_hash);
}
else
- Error(ERR_WARN, "using default setup values");
+ {
+ Error(ERR_DEBUG, "using default setup values");
+ }
free(filename);
}
LevelStats_setSolved(i, 0);
}
- checkSeriesInfo(leveldir_current);
+ checkSeriesInfo();
/* ----------------------------------------------------------------------- */
/* ~/.<program>/levelsetup/<level series>/levelsetup.conf */
freeSetupFileHash(level_setup_hash);
}
else
- Error(ERR_WARN, "using default setup values");
+ {
+ Error(ERR_DEBUG, "using default setup values");
+ }
free(filename);
}