#include "joystick.h"
#include "text.h"
#include "misc.h"
+#include "hash.h"
-/* file names and filename extensions */
-#if !defined(PLATFORM_MSDOS)
-#define LEVELSETUP_DIRECTORY "levelsetup"
-#define SETUP_FILENAME "setup.conf"
-#define LEVELSETUP_FILENAME "levelsetup.conf"
-#define LEVELINFO_FILENAME "levelinfo.conf"
-#define GRAPHICSINFO_FILENAME "graphicsinfo.conf"
-#define SOUNDSINFO_FILENAME "soundsinfo.conf"
-#define MUSICINFO_FILENAME "musicinfo.conf"
-#define LEVELFILE_EXTENSION "level"
-#define TAPEFILE_EXTENSION "tape"
-#define SCOREFILE_EXTENSION "score"
-#else
-#define LEVELSETUP_DIRECTORY "lvlsetup"
-#define SETUP_FILENAME "setup.cnf"
-#define LEVELSETUP_FILENAME "lvlsetup.cnf"
-#define LEVELINFO_FILENAME "lvlinfo.cnf"
-#define GRAPHICSINFO_FILENAME "gfxinfo.cnf"
-#define SOUNDSINFO_FILENAME "sndinfo.cnf"
-#define MUSICINFO_FILENAME "musinfo.cnf"
-#define LEVELFILE_EXTENSION "lvl"
-#define TAPEFILE_EXTENSION "tap"
-#define SCOREFILE_EXTENSION "sco"
-#endif
#define NUM_LEVELCLASS_DESC 8
+
static char *levelclass_desc[NUM_LEVELCLASS_DESC] =
{
"Tutorial Levels",
"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_YELLOW : \
- IS_LEVELCLASS_SP(n) ? FC_GREEN : \
- IS_LEVELCLASS_DX(n) ? FC_YELLOW : \
- IS_LEVELCLASS_CONTRIBUTION(n) ? FC_GREEN : \
- IS_LEVELCLASS_USER(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_CONTRIBUTION(n) ? 6 : \
- IS_LEVELCLASS_USER(n) ? 7 : \
- 9)
-#define ARTWORKCOLOR(n) (IS_ARTWORKCLASS_CLASSICS(n) ? FC_RED : \
- IS_ARTWORKCLASS_CONTRIBUTION(n) ? FC_YELLOW : \
- IS_ARTWORKCLASS_LEVEL(n) ? FC_GREEN : \
- IS_ARTWORKCLASS_USER(n) ? FC_RED : \
+#define LEVELCOLOR(n) (IS_LEVELCLASS_TUTORIAL(n) ? FC_BLUE : \
+ IS_LEVELCLASS_CLASSICS(n) ? FC_RED : \
+ IS_LEVELCLASS_BD(n) ? FC_YELLOW : \
+ IS_LEVELCLASS_EM(n) ? FC_YELLOW : \
+ IS_LEVELCLASS_SP(n) ? FC_YELLOW : \
+ IS_LEVELCLASS_DX(n) ? FC_YELLOW : \
+ IS_LEVELCLASS_SB(n) ? FC_YELLOW : \
+ IS_LEVELCLASS_CONTRIB(n) ? FC_GREEN : \
+ IS_LEVELCLASS_PRIVATE(n) ? FC_RED : \
FC_BLUE)
-#define ARTWORKSORTING(n) (IS_ARTWORKCLASS_CLASSICS(n) ? 0 : \
- IS_ARTWORKCLASS_CONTRIBUTION(n) ? 1 : \
- IS_ARTWORKCLASS_LEVEL(n) ? 2 : \
- IS_ARTWORKCLASS_USER(n) ? 3 : \
+#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 TOKEN_VALUE_POSITION 40
-#define TOKEN_COMMENT_POSITION 60
+#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_YELLOW : \
+ FC_BLUE)
-#define MAX_COOKIE_LEN 256
+#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 ARTWORKINFO_FILENAME(type) ((type) == TREE_TYPE_GRAPHICS_DIR ? \
- GRAPHICSINFO_FILENAME : \
- (type) == TREE_TYPE_SOUNDS_DIR ? \
- SOUNDSINFO_FILENAME : \
- (type) == TREE_TYPE_MUSIC_DIR ? \
- MUSICINFO_FILENAME : "")
+#define TOKEN_VALUE_POSITION_SHORT 32
+#define TOKEN_VALUE_POSITION_DEFAULT 40
+#define TOKEN_COMMENT_POSITION_DEFAULT 60
-#define ARTWORK_DIRECTORY(type) ((type) == TREE_TYPE_GRAPHICS_DIR ? \
- GRAPHICS_DIRECTORY : \
- (type) == TREE_TYPE_SOUNDS_DIR ? \
- SOUNDS_DIRECTORY : \
- (type) == TREE_TYPE_MUSIC_DIR ? \
- MUSIC_DIRECTORY : "")
+#define MAX_COOKIE_LEN 256
-#define OPTIONS_ARTWORK_DIRECTORY(type) ((type) == TREE_TYPE_GRAPHICS_DIR ? \
- options.graphics_directory : \
- (type) == TREE_TYPE_SOUNDS_DIR ? \
- options.sounds_directory : \
- (type) == TREE_TYPE_MUSIC_DIR ? \
- options.music_directory : "")
+static int token_value_position = TOKEN_VALUE_POSITION_DEFAULT;
+static int token_comment_position = TOKEN_COMMENT_POSITION_DEFAULT;
/* ------------------------------------------------------------------------- */
char *data_dir = getUserDataDir();
char *userlevel_subdir = LEVELS_DIRECTORY;
- if (userlevel_dir)
- free(userlevel_dir);
+ checked_free(userlevel_dir);
if (level_subdir != NULL)
userlevel_dir = getPath3(data_dir, userlevel_subdir, level_subdir);
return userlevel_dir;
}
-static char *getTapeDir(char *level_subdir)
-{
- static char *tape_dir = NULL;
- char *data_dir = getUserDataDir();
- char *tape_subdir = TAPES_DIRECTORY;
-
- if (tape_dir)
- free(tape_dir);
-
- if (level_subdir != NULL)
- tape_dir = getPath3(data_dir, tape_subdir, level_subdir);
- else
- tape_dir = getPath2(data_dir, tape_subdir);
-
- return tape_dir;
-}
-
static char *getScoreDir(char *level_subdir)
{
static char *score_dir = NULL;
- char *data_dir = options.rw_base_directory;
+ char *data_dir = getCommonDataDir();
char *score_subdir = SCORES_DIRECTORY;
- if (score_dir)
- free(score_dir);
+ checked_free(score_dir);
if (level_subdir != NULL)
score_dir = getPath3(data_dir, score_subdir, level_subdir);
char *data_dir = getUserDataDir();
char *levelsetup_subdir = LEVELSETUP_DIRECTORY;
- if (levelsetup_dir)
- free(levelsetup_dir);
+ checked_free(levelsetup_dir);
if (level_subdir != NULL)
levelsetup_dir = getPath3(data_dir, levelsetup_subdir, level_subdir);
if (node == NULL)
return options.level_directory;
- if (level_dir)
- free(level_dir);
+ checked_free(level_dir);
- level_dir = getPath2((node->user_defined ? getUserLevelDir(NULL) :
+ level_dir = getPath2((node->in_user_dir ? getUserLevelDir(NULL) :
options.level_directory), node->fullpath);
return level_dir;
}
-static char *getCurrentLevelDir()
+char *getCurrentLevelDir()
{
return getLevelDirFromTreeInfo(leveldir_current);
}
+static char *getTapeDir(char *level_subdir)
+{
+ static char *tape_dir = NULL;
+ char *data_dir = getUserDataDir();
+ char *tape_subdir = TAPES_DIRECTORY;
+
+ checked_free(tape_dir);
+
+ if (level_subdir != NULL)
+ tape_dir = getPath3(data_dir, tape_subdir, level_subdir);
+ else
+ tape_dir = getPath2(data_dir, tape_subdir);
+
+ return tape_dir;
+}
+
+static char *getSolutionTapeDir()
+{
+ static char *tape_dir = NULL;
+ char *data_dir = getCurrentLevelDir();
+ char *tape_subdir = TAPES_DIRECTORY;
+
+ checked_free(tape_dir);
+
+ tape_dir = getPath2(data_dir, tape_subdir);
+
+ return tape_dir;
+}
+
static char *getDefaultGraphicsDir(char *graphics_subdir)
{
static char *graphics_dir = NULL;
if (graphics_subdir == NULL)
return options.graphics_directory;
- if (graphics_dir)
- free(graphics_dir);
+ checked_free(graphics_dir);
graphics_dir = getPath2(options.graphics_directory, graphics_subdir);
if (sounds_subdir == NULL)
return options.sounds_directory;
- if (sounds_dir)
- free(sounds_dir);
+ checked_free(sounds_dir);
sounds_dir = getPath2(options.sounds_directory, sounds_subdir);
if (music_subdir == NULL)
return options.music_directory;
- if (music_dir)
- free(music_dir);
+ checked_free(music_dir);
music_dir = getPath2(options.music_directory, music_subdir);
return music_dir;
}
+static char *getDefaultArtworkSet(int type)
+{
+ return (type == TREE_TYPE_GRAPHICS_DIR ? GFX_CLASSIC_SUBDIR :
+ type == TREE_TYPE_SOUNDS_DIR ? SND_CLASSIC_SUBDIR :
+ type == TREE_TYPE_MUSIC_DIR ? MUS_CLASSIC_SUBDIR : "");
+}
+
+static char *getDefaultArtworkDir(int type)
+{
+ return (type == TREE_TYPE_GRAPHICS_DIR ?
+ getDefaultGraphicsDir(GFX_CLASSIC_SUBDIR) :
+ type == TREE_TYPE_SOUNDS_DIR ?
+ getDefaultSoundsDir(SND_CLASSIC_SUBDIR) :
+ type == TREE_TYPE_MUSIC_DIR ?
+ getDefaultMusicDir(MUS_CLASSIC_SUBDIR) : "");
+}
+
static char *getUserGraphicsDir()
{
static char *usergraphics_dir = NULL;
return usermusic_dir;
}
-char *getLevelFilename(int nr)
+static char *getSetupArtworkDir(TreeInfo *ti)
+{
+ static char *artwork_dir = NULL;
+
+ checked_free(artwork_dir);
+
+ artwork_dir = getPath2(ti->basepath, ti->fullpath);
+
+ return artwork_dir;
+}
+
+char *setLevelArtworkDir(TreeInfo *ti)
+{
+ char **artwork_path_ptr, **artwork_set_ptr;
+ TreeInfo *level_artwork;
+
+ if (ti == NULL || leveldir_current == NULL)
+ return NULL;
+
+ artwork_path_ptr = LEVELDIR_ARTWORK_PATH_PTR(leveldir_current, ti->type);
+ artwork_set_ptr = LEVELDIR_ARTWORK_SET_PTR( leveldir_current, ti->type);
+
+ checked_free(*artwork_path_ptr);
+
+ if ((level_artwork = getTreeInfoFromIdentifier(ti, *artwork_set_ptr)))
+ *artwork_path_ptr = getStringCopy(getSetupArtworkDir(level_artwork));
+ else
+ {
+ /* No (or non-existing) artwork configured in "levelinfo.conf". This would
+ normally result in using the artwork configured in the setup menu. But
+ if an artwork subdirectory exists (which might contain custom artwork
+ or an artwork configuration file), this level artwork must be treated
+ as relative to the default "classic" artwork, not to the artwork that
+ is currently configured in the setup menu. */
+
+ char *dir = getPath2(getCurrentLevelDir(), ARTWORK_DIRECTORY(ti->type));
+
+ checked_free(*artwork_set_ptr);
+
+ if (fileExists(dir))
+ {
+ *artwork_path_ptr = getStringCopy(getDefaultArtworkDir(ti->type));
+ *artwork_set_ptr = getStringCopy(getDefaultArtworkSet(ti->type));
+ }
+ else
+ {
+ *artwork_path_ptr = getStringCopy(UNDEFINED_FILENAME);
+ *artwork_set_ptr = NULL;
+ }
+
+ free(dir);
+ }
+
+ return *artwork_set_ptr;
+}
+
+inline static char *getLevelArtworkSet(int type)
+{
+ if (leveldir_current == NULL)
+ return NULL;
+
+ return LEVELDIR_ARTWORK_SET(leveldir_current, type);
+}
+
+inline static char *getLevelArtworkDir(int type)
+{
+ if (leveldir_current == NULL)
+ return UNDEFINED_FILENAME;
+
+ return LEVELDIR_ARTWORK_PATH(leveldir_current, type);
+}
+
+char *getTapeFilename(int nr)
{
static char *filename = NULL;
char basename[MAX_FILENAME_LEN];
- if (filename != NULL)
- free(filename);
+ checked_free(filename);
- sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION);
- filename = getPath2(getCurrentLevelDir(), basename);
+ sprintf(basename, "%03d.%s", nr, TAPEFILE_EXTENSION);
+ filename = getPath2(getTapeDir(leveldir_current->subdir), basename);
return filename;
}
-char *getTapeFilename(int nr)
+char *getSolutionTapeFilename(int nr)
{
static char *filename = NULL;
char basename[MAX_FILENAME_LEN];
- if (filename != NULL)
- free(filename);
+ checked_free(filename);
sprintf(basename, "%03d.%s", nr, TAPEFILE_EXTENSION);
- filename = getPath2(getTapeDir(leveldir_current->filename), basename);
+ filename = getPath2(getSolutionTapeDir(), basename);
return filename;
}
static char *filename = NULL;
char basename[MAX_FILENAME_LEN];
- if (filename != NULL)
- free(filename);
+ checked_free(filename);
sprintf(basename, "%03d.%s", nr, SCOREFILE_EXTENSION);
- filename = getPath2(getScoreDir(leveldir_current->filename), basename);
+ filename = getPath2(getScoreDir(leveldir_current->subdir), basename);
return filename;
}
{
static char *filename = NULL;
- if (filename != NULL)
- free(filename);
+ checked_free(filename);
filename = getPath2(getSetupDir(), SETUP_FILENAME);
return filename;
}
-static char *getSetupArtworkDir(TreeInfo *ti)
+char *getEditorSetupFilename()
{
- static char *artwork_dir = NULL;
+ static char *filename = NULL;
- if (artwork_dir != NULL)
- free(artwork_dir);
+ checked_free(filename);
+ filename = getPath2(getCurrentLevelDir(), EDITORSETUP_FILENAME);
- artwork_dir = getPath2(ti->basepath, ti->fullpath);
+ if (fileExists(filename))
+ return filename;
- return artwork_dir;
+ checked_free(filename);
+ filename = getPath2(getSetupDir(), EDITORSETUP_FILENAME);
+
+ return filename;
+}
+
+char *getHelpAnimFilename()
+{
+ static char *filename = NULL;
+
+ checked_free(filename);
+
+ filename = getPath2(getCurrentLevelDir(), HELPANIM_FILENAME);
+
+ return filename;
+}
+
+char *getHelpTextFilename()
+{
+ static char *filename = NULL;
+
+ checked_free(filename);
+
+ filename = getPath2(getCurrentLevelDir(), HELPTEXT_FILENAME);
+
+ return filename;
+}
+
+char *getLevelSetInfoFilename()
+{
+ static char *filename = NULL;
+ char *basenames[] =
+ {
+ "README",
+ "README.TXT",
+ "README.txt",
+ "Readme",
+ "Readme.txt",
+ "readme",
+ "readme.txt",
+
+ NULL
+ };
+ int i;
+
+ for (i = 0; basenames[i] != NULL; i++)
+ {
+ checked_free(filename);
+ filename = getPath2(getCurrentLevelDir(), basenames[i]);
+
+ if (fileExists(filename))
+ return filename;
+ }
+
+ return NULL;
}
-static char *getCorrectedImageBasename(char *basename)
+static char *getCorrectedArtworkBasename(char *basename)
{
- char *result = basename;
+ char *basename_corrected = basename;
#if defined(PLATFORM_MSDOS)
if (program.filename_prefix != NULL)
int prefix_len = strlen(program.filename_prefix);
if (strncmp(basename, program.filename_prefix, prefix_len) == 0)
- result = &basename[prefix_len];
- }
-#endif
+ basename_corrected = &basename[prefix_len];
- return result;
-}
+ /* if corrected filename is still longer than standard MS-DOS filename
+ size (8 characters + 1 dot + 3 characters file extension), shorten
+ filename by writing file extension after 8th basename character */
+ if (strlen(basename_corrected) > 8 + 1 + 3)
+ {
+ static char *msdos_filename = NULL;
-static boolean fileExists(char *filename)
-{
-#if 0
- printf("checking file '%s'\n", filename);
+ checked_free(msdos_filename);
+
+ msdos_filename = getStringCopy(basename_corrected);
+ strncpy(&msdos_filename[8], &basename[strlen(basename) - (1+3)], 1+3 +1);
+
+ basename_corrected = msdos_filename;
+ }
+ }
#endif
- return (access(filename, F_OK) == 0);
+ return basename_corrected;
}
char *getCustomImageFilename(char *basename)
{
static char *filename = NULL;
+ boolean skip_setup_artwork = FALSE;
- if (filename != NULL)
- free(filename);
+ checked_free(filename);
- basename = getCorrectedImageBasename(basename);
+ basename = getCorrectedArtworkBasename(basename);
if (!setup.override_level_graphics)
{
filename = getPath3(getCurrentLevelDir(), GRAPHICS_DIRECTORY, basename);
if (fileExists(filename))
return filename;
+
+ free(filename);
+
+ /* check if there is special artwork configured in level series config */
+ if (getLevelArtworkSet(ARTWORK_TYPE_GRAPHICS) != NULL)
+ {
+ /* 2nd try: look for special artwork configured in level series config */
+ filename = getPath2(getLevelArtworkDir(ARTWORK_TYPE_GRAPHICS), basename);
+ if (fileExists(filename))
+ return filename;
+
+ free(filename);
+
+ /* take missing artwork configured in level set config from default */
+ skip_setup_artwork = TRUE;
+ }
}
- /* 2nd try: look for special artwork in configured artwork directory */
- filename = getPath2(getSetupArtworkDir(artwork.gfx_current), basename);
- if (fileExists(filename))
- return filename;
+ if (!skip_setup_artwork)
+ {
+ /* 3rd try: look for special artwork in configured artwork directory */
+ filename = getPath2(getSetupArtworkDir(artwork.gfx_current), basename);
+ if (fileExists(filename))
+ return filename;
+
+ free(filename);
+ }
- /* 3rd try: look for default artwork in new default artwork directory */
- filename = getPath2(getDefaultGraphicsDir(GRAPHICS_SUBDIR), basename);
+ /* 4th try: look for default artwork in new default artwork directory */
+ filename = getPath2(getDefaultGraphicsDir(GFX_CLASSIC_SUBDIR), basename);
if (fileExists(filename))
return filename;
- /* 4th try: look for default artwork in old default artwork directory */
+ free(filename);
+
+ /* 5th try: look for default artwork in old default artwork directory */
filename = getPath2(options.graphics_directory, basename);
if (fileExists(filename))
return filename;
char *getCustomSoundFilename(char *basename)
{
static char *filename = NULL;
+ boolean skip_setup_artwork = FALSE;
- if (filename != NULL)
- free(filename);
+ checked_free(filename);
+
+ basename = getCorrectedArtworkBasename(basename);
if (!setup.override_level_sounds)
{
filename = getPath3(getCurrentLevelDir(), SOUNDS_DIRECTORY, basename);
if (fileExists(filename))
return filename;
+
+ free(filename);
+
+ /* check if there is special artwork configured in level series config */
+ if (getLevelArtworkSet(ARTWORK_TYPE_SOUNDS) != NULL)
+ {
+ /* 2nd try: look for special artwork configured in level series config */
+ filename = getPath2(getLevelArtworkDir(TREE_TYPE_SOUNDS_DIR), basename);
+ if (fileExists(filename))
+ return filename;
+
+ free(filename);
+
+ /* take missing artwork configured in level set config from default */
+ skip_setup_artwork = TRUE;
+ }
+ }
+
+ if (!skip_setup_artwork)
+ {
+ /* 3rd try: look for special artwork in configured artwork directory */
+ filename = getPath2(getSetupArtworkDir(artwork.snd_current), basename);
+ if (fileExists(filename))
+ return filename;
+
+ free(filename);
}
- /* 2nd try: look for special artwork in configured artwork directory */
- filename = getPath2(getSetupArtworkDir(artwork.snd_current), basename);
+ /* 4th try: look for default artwork in new default artwork directory */
+ filename = getPath2(getDefaultSoundsDir(SND_CLASSIC_SUBDIR), basename);
if (fileExists(filename))
return filename;
- /* 3rd try: look for default artwork in new default artwork directory */
- filename = getPath2(getDefaultSoundsDir(SOUNDS_SUBDIR), basename);
+ free(filename);
+
+ /* 5th try: look for default artwork in old default artwork directory */
+ filename = getPath2(options.sounds_directory, basename);
if (fileExists(filename))
return filename;
- /* 4th try: look for default artwork in old default artwork directory */
- filename = getPath2(options.sounds_directory, basename);
+ return NULL; /* cannot find specified artwork file anywhere */
+}
+
+char *getCustomMusicFilename(char *basename)
+{
+ static char *filename = NULL;
+ boolean skip_setup_artwork = FALSE;
+
+ checked_free(filename);
+
+ basename = getCorrectedArtworkBasename(basename);
+
+ if (!setup.override_level_music)
+ {
+ /* 1st try: look for special artwork in current level series directory */
+ filename = getPath3(getCurrentLevelDir(), MUSIC_DIRECTORY, basename);
+ if (fileExists(filename))
+ return filename;
+
+ free(filename);
+
+ /* check if there is special artwork configured in level series config */
+ if (getLevelArtworkSet(ARTWORK_TYPE_MUSIC) != NULL)
+ {
+ /* 2nd try: look for special artwork configured in level series config */
+ filename = getPath2(getLevelArtworkDir(TREE_TYPE_MUSIC_DIR), basename);
+ if (fileExists(filename))
+ return filename;
+
+ free(filename);
+
+ /* take missing artwork configured in level set config from default */
+ skip_setup_artwork = TRUE;
+ }
+ }
+
+ if (!skip_setup_artwork)
+ {
+ /* 3rd try: look for special artwork in configured artwork directory */
+ filename = getPath2(getSetupArtworkDir(artwork.mus_current), basename);
+ if (fileExists(filename))
+ return filename;
+
+ free(filename);
+ }
+
+ /* 4th try: look for default artwork in new default artwork directory */
+ filename = getPath2(getDefaultMusicDir(MUS_CLASSIC_SUBDIR), basename);
+ if (fileExists(filename))
+ return filename;
+
+ free(filename);
+
+ /* 5th try: look for default artwork in old default artwork directory */
+ filename = getPath2(options.music_directory, basename);
if (fileExists(filename))
return filename;
return NULL; /* cannot find specified artwork file anywhere */
}
-char *getCustomSoundConfigFilename()
+char *getCustomArtworkFilename(char *basename, int type)
+{
+ if (type == ARTWORK_TYPE_GRAPHICS)
+ return getCustomImageFilename(basename);
+ else if (type == ARTWORK_TYPE_SOUNDS)
+ return getCustomSoundFilename(basename);
+ else if (type == ARTWORK_TYPE_MUSIC)
+ return getCustomMusicFilename(basename);
+ else
+ return UNDEFINED_FILENAME;
+}
+
+char *getCustomArtworkConfigFilename(int type)
+{
+ return getCustomArtworkFilename(ARTWORKINFO_FILENAME(type), type);
+}
+
+char *getCustomArtworkLevelConfigFilename(int type)
{
- return getCustomSoundFilename(SOUNDSINFO_FILENAME);
+ static char *filename = NULL;
+
+ checked_free(filename);
+
+ filename = getPath2(getLevelArtworkDir(type), ARTWORKINFO_FILENAME(type));
+
+ return filename;
}
char *getCustomMusicDirectory(void)
{
static char *directory = NULL;
+ boolean skip_setup_artwork = FALSE;
- if (directory != NULL)
- free(directory);
+ checked_free(directory);
if (!setup.override_level_music)
{
directory = getPath2(getCurrentLevelDir(), MUSIC_DIRECTORY);
if (fileExists(directory))
return directory;
+
+ free(directory);
+
+ /* check if there is special artwork configured in level series config */
+ if (getLevelArtworkSet(ARTWORK_TYPE_MUSIC) != NULL)
+ {
+ /* 2nd try: look for special artwork configured in level series config */
+ directory = getStringCopy(getLevelArtworkDir(TREE_TYPE_MUSIC_DIR));
+ if (fileExists(directory))
+ return directory;
+
+ free(directory);
+
+ /* take missing artwork configured in level set config from default */
+ skip_setup_artwork = TRUE;
+ }
+ }
+
+ if (!skip_setup_artwork)
+ {
+ /* 3rd try: look for special artwork in configured artwork directory */
+ directory = getStringCopy(getSetupArtworkDir(artwork.mus_current));
+ if (fileExists(directory))
+ return directory;
+
+ free(directory);
}
- /* 2nd try: look for special artwork in configured artwork directory */
- directory = getStringCopy(getSetupArtworkDir(artwork.mus_current));
+ /* 4th try: look for default artwork in new default artwork directory */
+ directory = getStringCopy(getDefaultMusicDir(MUS_CLASSIC_SUBDIR));
if (fileExists(directory))
return directory;
- /* 3rd try: look for default artwork in new default artwork directory */
- directory = getStringCopy(getDefaultMusicDir(MUSIC_SUBDIR));
- if (fileExists(directory))
- return directory;
+ free(directory);
- /* 4th try: look for default artwork in old default artwork directory */
+ /* 5th try: look for default artwork in old default artwork directory */
directory = getStringCopy(options.music_directory);
if (fileExists(directory))
return directory;
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);
}
void InitUserLevelDirectory(char *level_subdir)
{
- if (access(getUserLevelDir(level_subdir), F_OK) != 0)
+ if (!fileExists(getUserLevelDir(level_subdir)))
{
createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE);
createDirectory(getUserLevelDir(NULL), "main user level", PERMS_PRIVATE);
/* ------------------------------------------------------------------------- */
-/* some functions to handle lists of level directories */
+/* some functions to handle lists of level and artwork directories */
/* ------------------------------------------------------------------------- */
TreeInfo *newTreeInfo()
return node_default;
}
-TreeInfo *getTreeInfoFromFilenameExt(TreeInfo *node, char *filename)
+TreeInfo *getTreeInfoFromIdentifier(TreeInfo *node, char *identifier)
{
- if (filename == NULL)
+ if (identifier == NULL)
return NULL;
while (node)
{
TreeInfo *node_group;
- node_group = getTreeInfoFromFilenameExt(node->node_group, filename);
+ node_group = getTreeInfoFromIdentifier(node->node_group, identifier);
if (node_group)
return node_group;
}
else if (!node->parent_link)
{
- if (strcmp(filename, node->filename) == 0)
- return node;
-
- /* special case when looking for level series artwork:
- node->name_short contains level series filename */
- if (strcmp(node->filename, ".") == 0 &&
- strcmp(filename, node->name_short) == 0)
+ if (strcmp(identifier, node->identifier) == 0)
return node;
}
return NULL;
}
-TreeInfo *getTreeInfoFromFilename(TreeInfo *ti, char *filename)
+TreeInfo *cloneTreeNode(TreeInfo **node_top, TreeInfo *node_parent,
+ TreeInfo *node, boolean skip_sets_without_levels)
+{
+ TreeInfo *node_new;
+
+ if (node == NULL)
+ return NULL;
+
+ if (!node->parent_link && !node->level_group &&
+ skip_sets_without_levels && node->levels == 0)
+ return cloneTreeNode(node_top, node_parent, node->next,
+ skip_sets_without_levels);
+
+ node_new = newTreeInfo();
+
+ *node_new = *node; /* copy complete node */
+
+ node_new->node_top = node_top; /* correct top node link */
+ node_new->node_parent = node_parent; /* correct parent node link */
+
+ if (node->level_group)
+ node_new->node_group = cloneTreeNode(node_top, node_new, node->node_group,
+ skip_sets_without_levels);
+
+ node_new->next = cloneTreeNode(node_top, node_parent, node->next,
+ skip_sets_without_levels);
+
+ return node_new;
+}
+
+void cloneTree(TreeInfo **ti_new, TreeInfo *ti, boolean skip_empty_sets)
{
- return getTreeInfoFromFilenameExt(ti, filename);
+ TreeInfo *ti_cloned = cloneTreeNode(ti_new, NULL, ti, skip_empty_sets);
+
+ *ti_new = ti_cloned;
}
void dumpTreeInfo(TreeInfo *node, int depth)
while (node)
{
- for (i=0; i<(depth + 1) * 3; i++)
+ for (i = 0; i < (depth + 1) * 3; i++)
printf(" ");
- printf("filename == '%s' (%s) [%s] (%d)\n",
- node->filename, node->name, node->name_short, node->sort_priority);
+ printf("subdir == '%s' ['%s', '%s'] [%d])\n",
+ node->subdir, node->fullpath, node->basepath, node->in_user_dir);
if (node->node_group != NULL)
dumpTreeInfo(node->node_group, depth + 1);
compare_function);
/* update the linkage of list elements with the sorted node array */
- for (i=0; i<num_nodes - 1; i++)
+ for (i = 0; i < num_nodes - 1; i++)
sort_array[i]->next = sort_array[i + 1];
sort_array[num_nodes - 1]->next = NULL;
{
static char *userdata_dir = NULL;
- if (!userdata_dir)
+ if (userdata_dir == NULL)
+ userdata_dir = getPath2(getHomeDir(), program.userdata_directory);
+
+ return userdata_dir;
+}
+
+char *getCommonDataDir(void)
+{
+ static char *common_data_dir = NULL;
+
+#if defined(PLATFORM_WIN32)
+ if (common_data_dir == NULL)
{
- char *home_dir = getHomeDir();
- char *data_dir = program.userdata_directory;
+ char *dir = checked_malloc(MAX_PATH + 1);
- userdata_dir = getPath2(home_dir, data_dir);
+ if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_COMMON_DOCUMENTS, NULL, 0, dir))
+ && strcmp(dir, "") != 0) /* empty for Windows 95/98 */
+ common_data_dir = getPath2(dir, program.userdata_directory);
+ else
+ common_data_dir = options.rw_base_directory;
}
+#else
+ if (common_data_dir == NULL)
+ common_data_dir = options.rw_base_directory;
+#endif
- return userdata_dir;
+ return common_data_dir;
}
char *getSetupDir()
mode_t group_umask = ~(dir_mode & S_IRWXG);
posix_umask(normal_umask & group_umask);
- if (access(dir, F_OK) != 0)
+ if (!fileExists(dir))
if (posix_mkdir(dir, dir_mode) != 0)
Error(ERR_WARN, "cannot create %s directory '%s'", text, dir);
version_major = ptr_cookie2[0] - '0';
version_minor = ptr_cookie2[2] - '0';
- return VERSION_IDENT(version_major, version_minor, 0);
+ return VERSION_IDENT(version_major, version_minor, 0, 0);
+}
+
+boolean checkCookieString(const char *cookie, const char *template)
+{
+ const char *pattern = "_FILE_VERSION_?.?";
+ const int len_cookie = strlen(cookie);
+ const int len_template = strlen(template);
+ const int len_pattern = strlen(pattern);
+
+ if (len_cookie != len_template)
+ return FALSE;
+
+ if (strncmp(cookie, template, len_cookie - len_pattern) != 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+/* ------------------------------------------------------------------------- */
+/* setup file list and hash handling functions */
+/* ------------------------------------------------------------------------- */
+
+char *getFormattedSetupEntry(char *token, char *value)
+{
+ int i;
+ static char entry[MAX_LINE_LEN];
+
+ /* if value is an empty string, just return token without value */
+ if (*value == '\0')
+ return token;
+
+ /* start with the token and some spaces to format output line */
+ sprintf(entry, "%s:", token);
+ for (i = strlen(entry); i < token_value_position; i++)
+ strcat(entry, " ");
+
+ /* continue with the token's value */
+ strcat(entry, value);
+
+ return entry;
+}
+
+SetupFileList *newSetupFileList(char *token, char *value)
+{
+ SetupFileList *new = checked_malloc(sizeof(SetupFileList));
+
+ new->token = getStringCopy(token);
+ new->value = getStringCopy(value);
+
+ new->next = NULL;
+
+ return new;
}
-boolean checkCookieString(const char *cookie, const char *template)
+void freeSetupFileList(SetupFileList *list)
{
- const char *pattern = "_FILE_VERSION_?.?";
- const int len_cookie = strlen(cookie);
- const int len_template = strlen(template);
- const int len_pattern = strlen(pattern);
+ if (list == NULL)
+ return;
- if (len_cookie != len_template)
- return FALSE;
+ checked_free(list->token);
+ checked_free(list->value);
- if (strncmp(cookie, template, len_cookie - len_pattern) != 0)
- return FALSE;
+ if (list->next)
+ freeSetupFileList(list->next);
- return TRUE;
+ free(list);
}
-/* ------------------------------------------------------------------------- */
-/* setup file list handling functions */
-/* ------------------------------------------------------------------------- */
-
-int get_string_integer_value(char *s)
-{
- static char *number_text[][3] =
- {
- { "0", "zero", "null", },
- { "1", "one", "first" },
- { "2", "two", "second" },
- { "3", "three", "third" },
- { "4", "four", "fourth" },
- { "5", "five", "fifth" },
- { "6", "six", "sixth" },
- { "7", "seven", "seventh" },
- { "8", "eight", "eighth" },
- { "9", "nine", "ninth" },
- { "10", "ten", "tenth" },
- { "11", "eleven", "eleventh" },
- { "12", "twelve", "twelfth" },
- };
+char *getListEntry(SetupFileList *list, char *token)
+{
+ if (list == NULL)
+ return NULL;
- int i, j;
- char *s_lower = getStringToLower(s);
- int result = -1;
+ if (strcmp(list->token, token) == 0)
+ return list->value;
+ else
+ return getListEntry(list->next, token);
+}
- for (i=0; i<13; i++)
- for (j=0; j<3; j++)
- if (strcmp(s_lower, number_text[i][j]) == 0)
- result = i;
+SetupFileList *setListEntry(SetupFileList *list, char *token, char *value)
+{
+ if (list == NULL)
+ return NULL;
- if (result == -1)
- result = atoi(s);
+ if (strcmp(list->token, token) == 0)
+ {
+ checked_free(list->value);
- free(s_lower);
+ list->value = getStringCopy(value);
- return result;
+ return list;
+ }
+ else if (list->next == NULL)
+ return (list->next = newSetupFileList(token, value));
+ else
+ return setListEntry(list->next, token, value);
}
-boolean get_string_boolean_value(char *s)
+SetupFileList *addListEntry(SetupFileList *list, char *token, char *value)
{
- char *s_lower = getStringToLower(s);
- boolean result = FALSE;
+ if (list == NULL)
+ return NULL;
+
+ if (list->next == NULL)
+ return (list->next = newSetupFileList(token, value));
+ else
+ return addListEntry(list->next, token, value);
+}
- if (strcmp(s_lower, "true") == 0 ||
- strcmp(s_lower, "yes") == 0 ||
- strcmp(s_lower, "on") == 0 ||
- get_string_integer_value(s) == 1)
- result = TRUE;
+#ifdef DEBUG
+static void printSetupFileList(SetupFileList *list)
+{
+ if (!list)
+ return;
- free(s_lower);
+ printf("token: '%s'\n", list->token);
+ printf("value: '%s'\n", list->value);
- return result;
+ printSetupFileList(list->next);
}
+#endif
-char *getFormattedSetupEntry(char *token, char *value)
+#ifdef DEBUG
+DEFINE_HASHTABLE_INSERT(insert_hash_entry, char, char);
+DEFINE_HASHTABLE_SEARCH(search_hash_entry, char, char);
+DEFINE_HASHTABLE_CHANGE(change_hash_entry, char, char);
+DEFINE_HASHTABLE_REMOVE(remove_hash_entry, char, char);
+#else
+#define insert_hash_entry hashtable_insert
+#define search_hash_entry hashtable_search
+#define change_hash_entry hashtable_change
+#define remove_hash_entry hashtable_remove
+#endif
+
+static unsigned int get_hash_from_key(void *key)
{
- int i;
- static char entry[MAX_LINE_LEN];
+ /*
+ djb2
- /* start with the token and some spaces to format output line */
- sprintf(entry, "%s:", token);
- for (i=strlen(entry); i<TOKEN_VALUE_POSITION; i++)
- strcat(entry, " ");
+ This algorithm (k=33) was first reported by Dan Bernstein many years ago in
+ 'comp.lang.c'. Another version of this algorithm (now favored by Bernstein)
+ uses XOR: hash(i) = hash(i - 1) * 33 ^ str[i]; the magic of number 33 (why
+ it works better than many other constants, prime or not) has never been
+ adequately explained.
- /* continue with the token's value */
- strcat(entry, value);
+ If you just want to have a good hash function, and cannot wait, djb2
+ is one of the best string hash functions i know. It has excellent
+ distribution and speed on many different sets of keys and table sizes.
+ You are not likely to do better with one of the "well known" functions
+ such as PJW, K&R, etc.
- return entry;
+ Ozan (oz) Yigit [http://www.cs.yorku.ca/~oz/hash.html]
+ */
+
+ char *str = (char *)key;
+ unsigned int hash = 5381;
+ int c;
+
+ while ((c = *str++))
+ hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
+
+ return hash;
}
-void freeSetupFileList(struct SetupFileList *setup_file_list)
+static int keys_are_equal(void *key1, void *key2)
{
- if (!setup_file_list)
- return;
-
- if (setup_file_list->token)
- free(setup_file_list->token);
- if (setup_file_list->value)
- free(setup_file_list->value);
- if (setup_file_list->next)
- freeSetupFileList(setup_file_list->next);
- free(setup_file_list);
+ return (strcmp((char *)key1, (char *)key2) == 0);
}
-static struct SetupFileList *newSetupFileList(char *token, char *value)
+SetupFileHash *newSetupFileHash()
{
- struct SetupFileList *new = checked_malloc(sizeof(struct SetupFileList));
+ SetupFileHash *new_hash =
+ create_hashtable(16, 0.75, get_hash_from_key, keys_are_equal);
- new->token = checked_malloc(strlen(token) + 1);
- strcpy(new->token, token);
+ if (new_hash == NULL)
+ Error(ERR_EXIT, "create_hashtable() failed -- out of memory");
- new->value = checked_malloc(strlen(value) + 1);
- strcpy(new->value, value);
+ return new_hash;
+}
- new->next = NULL;
+void freeSetupFileHash(SetupFileHash *hash)
+{
+ if (hash == NULL)
+ return;
- return new;
+ hashtable_destroy(hash, 1); /* 1 == also free values stored in hash */
}
-char *getTokenValue(struct SetupFileList *setup_file_list, char *token)
+char *getHashEntry(SetupFileHash *hash, char *token)
{
- if (!setup_file_list)
+ if (hash == NULL)
return NULL;
- if (strcmp(setup_file_list->token, token) == 0)
- return setup_file_list->value;
- else
- return getTokenValue(setup_file_list->next, token);
+ return search_hash_entry(hash, token);
}
-static void setTokenValue(struct SetupFileList *setup_file_list,
- char *token, char *value)
+void setHashEntry(SetupFileHash *hash, char *token, char *value)
{
- if (!setup_file_list)
+ char *value_copy;
+
+ if (hash == NULL)
return;
- if (strcmp(setup_file_list->token, token) == 0)
- {
- free(setup_file_list->value);
- setup_file_list->value = checked_malloc(strlen(value) + 1);
- strcpy(setup_file_list->value, value);
- }
- else if (setup_file_list->next == NULL)
- setup_file_list->next = newSetupFileList(token, value);
- else
- setTokenValue(setup_file_list->next, token, value);
+ value_copy = getStringCopy(value);
+
+ /* change value; if it does not exist, insert it as new */
+ if (!change_hash_entry(hash, token, value_copy))
+ if (!insert_hash_entry(hash, getStringCopy(token), value_copy))
+ Error(ERR_EXIT, "cannot insert into hash -- aborting");
}
-#ifdef DEBUG
-static void printSetupFileList(struct SetupFileList *setup_file_list)
+char *removeHashEntry(SetupFileHash *hash, char *token)
{
- if (!setup_file_list)
- return;
+ if (hash == NULL)
+ return NULL;
- printf("token: '%s'\n", setup_file_list->token);
- printf("value: '%s'\n", setup_file_list->value);
+ return remove_hash_entry(hash, token);
+}
- printSetupFileList(setup_file_list->next);
+#if 0
+static void printSetupFileHash(SetupFileHash *hash)
+{
+ BEGIN_HASH_ITERATION(hash, itr)
+ {
+ printf("token: '%s'\n", HASH_ITERATION_TOKEN(itr));
+ printf("value: '%s'\n", HASH_ITERATION_VALUE(itr));
+ }
+ END_HASH_ITERATION(hash, itr)
}
#endif
-struct SetupFileList *loadSetupFileList(char *filename)
+static void *loadSetupFileData(char *filename, boolean use_hash)
{
- int line_len;
- char line[MAX_LINE_LEN];
+ char line[MAX_LINE_LEN], previous_line[MAX_LINE_LEN];
char *token, *value, *line_ptr;
- struct SetupFileList *setup_file_list = newSetupFileList("", "");
- struct SetupFileList *first_valid_list_entry;
-
+ void *setup_file_data, *insert_ptr = NULL;
+ boolean read_continued_line = FALSE;
FILE *file;
if (!(file = fopen(filename, MODE_READ)))
{
Error(ERR_WARN, "cannot open configuration file '%s'", filename);
+
return NULL;
}
- while(!feof(file))
+ if (use_hash)
+ setup_file_data = newSetupFileHash();
+ else
+ insert_ptr = setup_file_data = newSetupFileList("", "");
+
+ while (!feof(file))
{
/* read next line of input file */
if (!fgets(line, MAX_LINE_LEN, file))
break;
- /* cut trailing comment or whitespace from input line */
+ /* cut trailing newline or carriage return */
+ for (line_ptr = &line[strlen(line)]; line_ptr >= line; line_ptr--)
+ if ((*line_ptr == '\n' || *line_ptr == '\r') && *(line_ptr + 1) == '\0')
+ *line_ptr = '\0';
+
+ if (read_continued_line)
+ {
+ /* cut leading whitespaces from input line */
+ for (line_ptr = line; *line_ptr; line_ptr++)
+ if (*line_ptr != ' ' && *line_ptr != '\t')
+ break;
+
+ /* append new line to existing line, if there is enough space */
+ if (strlen(previous_line) + strlen(line_ptr) < MAX_LINE_LEN)
+ strcat(previous_line, line_ptr);
+
+ strcpy(line, previous_line); /* copy storage buffer to line */
+
+ read_continued_line = FALSE;
+ }
+
+ /* if the last character is '\', continue at next line */
+ if (strlen(line) > 0 && line[strlen(line) - 1] == '\\')
+ {
+ line[strlen(line) - 1] = '\0'; /* cut off trailing backslash */
+ strcpy(previous_line, line); /* copy line to storage buffer */
+
+ read_continued_line = TRUE;
+
+ continue;
+ }
+
+ /* cut trailing comment from input line */
for (line_ptr = line; *line_ptr; line_ptr++)
{
- if (*line_ptr == '#' || *line_ptr == '\n' || *line_ptr == '\r')
+ if (*line_ptr == '#')
{
*line_ptr = '\0';
break;
}
/* cut trailing whitespaces from input line */
- for (line_ptr = &line[strlen(line)]; line_ptr > line; line_ptr--)
- if ((*line_ptr == ' ' || *line_ptr == '\t') && line_ptr[1] == '\0')
+ for (line_ptr = &line[strlen(line)]; line_ptr >= line; line_ptr--)
+ if ((*line_ptr == ' ' || *line_ptr == '\t') && *(line_ptr + 1) == '\0')
*line_ptr = '\0';
/* ignore empty lines */
if (*line == '\0')
continue;
- line_len = strlen(line);
-
/* cut leading whitespaces from token */
for (token = line; *token; token++)
if (*token != ' ' && *token != '\t')
break;
- /* find end of token */
+ /* start with empty value as reliable default */
+ value = "";
+
+ /* find end of token to determine start of value */
for (line_ptr = token; *line_ptr; line_ptr++)
{
if (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == ':')
{
- *line_ptr = '\0';
+ *line_ptr = '\0'; /* terminate token string */
+ value = line_ptr + 1; /* set beginning of value */
+
break;
}
}
- if (line_ptr < line + line_len)
- value = line_ptr + 1;
- else
- value = "\0";
-
/* cut leading whitespaces from value */
for (; *value; value++)
if (*value != ' ' && *value != '\t')
break;
- if (*token && *value)
- setTokenValue(setup_file_list, token, value);
+#if 0
+ if (*value == '\0')
+ value = "true"; /* treat tokens without value as "true" */
+#endif
+
+ if (*token)
+ {
+ if (use_hash)
+ setHashEntry((SetupFileHash *)setup_file_data, token, value);
+ else
+ insert_ptr = addListEntry((SetupFileList *)insert_ptr, token, value);
+ }
}
fclose(file);
- first_valid_list_entry = setup_file_list->next;
+ if (use_hash)
+ {
+ if (hashtable_count((SetupFileHash *)setup_file_data) == 0)
+ Error(ERR_WARN, "configuration file '%s' is empty", filename);
+ }
+ else
+ {
+ SetupFileList *setup_file_list = (SetupFileList *)setup_file_data;
+ SetupFileList *first_valid_list_entry = setup_file_list->next;
- /* free empty list header */
- setup_file_list->next = NULL;
- freeSetupFileList(setup_file_list);
+ /* free empty list header */
+ setup_file_list->next = NULL;
+ freeSetupFileList(setup_file_list);
+ setup_file_data = first_valid_list_entry;
- if (first_valid_list_entry == NULL)
- Error(ERR_WARN, "configuration file '%s' is empty", filename);
+ if (first_valid_list_entry == NULL)
+ Error(ERR_WARN, "configuration file '%s' is empty", filename);
+ }
- return first_valid_list_entry;
+ return setup_file_data;
}
-void checkSetupFileListIdentifier(struct SetupFileList *setup_file_list,
- char *identifier)
+SetupFileList *loadSetupFileList(char *filename)
{
- if (!setup_file_list)
- return;
+ return (SetupFileList *)loadSetupFileData(filename, FALSE);
+}
- if (strcmp(setup_file_list->token, TOKEN_STR_FILE_IDENTIFIER) == 0)
- {
- if (!checkCookieString(setup_file_list->value, identifier))
- {
- Error(ERR_WARN, "configuration file has wrong file identifier");
- return;
- }
- else
- return;
- }
+SetupFileHash *loadSetupFileHash(char *filename)
+{
+ return (SetupFileHash *)loadSetupFileData(filename, TRUE);
+}
- if (setup_file_list->next)
- checkSetupFileListIdentifier(setup_file_list->next, identifier);
- else
- {
- Error(ERR_WARN, "configuration file has no file identifier");
- return;
- }
+void checkSetupFileHashIdentifier(SetupFileHash *setup_file_hash,
+ char *filename, char *identifier)
+{
+ char *value = getHashEntry(setup_file_hash, TOKEN_STR_FILE_IDENTIFIER);
+
+ if (value == NULL)
+ Error(ERR_WARN, "config file '%s' has no file identifier", filename);
+ else if (!checkCookieString(value, identifier))
+ Error(ERR_WARN, "config file '%s' has wrong file identifier", filename);
}
#define TOKEN_STR_HANDICAP_LEVEL "handicap_level"
/* level directory info */
-#define LEVELINFO_TOKEN_NAME 0
-#define LEVELINFO_TOKEN_NAME_SHORT 1
+#define LEVELINFO_TOKEN_IDENTIFIER 0
+#define LEVELINFO_TOKEN_NAME 1
#define LEVELINFO_TOKEN_NAME_SORTING 2
#define LEVELINFO_TOKEN_AUTHOR 3
#define LEVELINFO_TOKEN_IMPORTED_FROM 4
-#define LEVELINFO_TOKEN_LEVELS 5
-#define LEVELINFO_TOKEN_FIRST_LEVEL 6
-#define LEVELINFO_TOKEN_SORT_PRIORITY 7
-#define LEVELINFO_TOKEN_LEVEL_GROUP 8
-#define LEVELINFO_TOKEN_READONLY 9
-
-#define NUM_LEVELINFO_TOKENS 10
+#define LEVELINFO_TOKEN_IMPORTED_BY 5
+#define LEVELINFO_TOKEN_LEVELS 6
+#define LEVELINFO_TOKEN_FIRST_LEVEL 7
+#define LEVELINFO_TOKEN_SORT_PRIORITY 8
+#define LEVELINFO_TOKEN_LATEST_ENGINE 9
+#define LEVELINFO_TOKEN_LEVEL_GROUP 10
+#define LEVELINFO_TOKEN_READONLY 11
+#define LEVELINFO_TOKEN_GRAPHICS_SET 12
+#define LEVELINFO_TOKEN_SOUNDS_SET 13
+#define LEVELINFO_TOKEN_MUSIC_SET 14
+#define LEVELINFO_TOKEN_FILENAME 15
+#define LEVELINFO_TOKEN_FILETYPE 16
+#define LEVELINFO_TOKEN_HANDICAP 17
+#define LEVELINFO_TOKEN_SKIP_LEVELS 18
+
+#define NUM_LEVELINFO_TOKENS 19
static LevelDirTree ldi;
static struct TokenInfo levelinfo_tokens[] =
{
/* level directory info */
- { TYPE_STRING, &ldi.name, "name" },
- { TYPE_STRING, &ldi.name_short, "name_short" },
- { TYPE_STRING, &ldi.name_sorting, "name_sorting" },
- { TYPE_STRING, &ldi.author, "author" },
- { TYPE_STRING, &ldi.imported_from, "imported_from" },
- { TYPE_INTEGER, &ldi.levels, "levels" },
- { TYPE_INTEGER, &ldi.first_level, "first_level" },
- { TYPE_INTEGER, &ldi.sort_priority, "sort_priority" },
- { TYPE_BOOLEAN, &ldi.level_group, "level_group" },
- { TYPE_BOOLEAN, &ldi.readonly, "readonly" }
+ { TYPE_STRING, &ldi.identifier, "identifier" },
+ { TYPE_STRING, &ldi.name, "name" },
+ { TYPE_STRING, &ldi.name_sorting, "name_sorting" },
+ { TYPE_STRING, &ldi.author, "author" },
+ { TYPE_STRING, &ldi.imported_from, "imported_from" },
+ { TYPE_STRING, &ldi.imported_by, "imported_by" },
+ { TYPE_INTEGER, &ldi.levels, "levels" },
+ { TYPE_INTEGER, &ldi.first_level, "first_level" },
+ { TYPE_INTEGER, &ldi.sort_priority, "sort_priority" },
+ { TYPE_BOOLEAN, &ldi.latest_engine, "latest_engine" },
+ { TYPE_BOOLEAN, &ldi.level_group, "level_group" },
+ { TYPE_BOOLEAN, &ldi.readonly, "readonly" },
+ { TYPE_STRING, &ldi.graphics_set, "graphics_set" },
+ { TYPE_STRING, &ldi.sounds_set, "sounds_set" },
+ { TYPE_STRING, &ldi.music_set, "music_set" },
+ { TYPE_STRING, &ldi.level_filename, "filename" },
+ { TYPE_STRING, &ldi.level_filetype, "filetype" },
+ { TYPE_BOOLEAN, &ldi.handicap, "handicap" },
+ { TYPE_BOOLEAN, &ldi.skip_levels, "skip_levels" }
};
static void setTreeInfoToDefaults(TreeInfo *ldi, int type)
ldi->cl_first = -1;
ldi->cl_cursor = -1;
- ldi->filename = NULL;
+ ldi->subdir = NULL;
ldi->fullpath = NULL;
ldi->basepath = NULL;
+ ldi->identifier = NULL;
ldi->name = getStringCopy(ANONYMOUS_NAME);
- ldi->name_short = NULL;
ldi->name_sorting = NULL;
ldi->author = getStringCopy(ANONYMOUS_NAME);
ldi->sort_priority = LEVELCLASS_UNDEFINED; /* default: least priority */
+ ldi->latest_engine = FALSE; /* default: get from level */
ldi->parent_link = FALSE;
+ ldi->in_user_dir = FALSE;
ldi->user_defined = FALSE;
ldi->color = 0;
ldi->class_desc = NULL;
if (ldi->type == TREE_TYPE_LEVEL_DIR)
{
ldi->imported_from = NULL;
+ ldi->imported_by = NULL;
+
+ ldi->graphics_set = NULL;
+ ldi->sounds_set = NULL;
+ ldi->music_set = NULL;
+ ldi->graphics_path = getStringCopy(UNDEFINED_FILENAME);
+ ldi->sounds_path = getStringCopy(UNDEFINED_FILENAME);
+ ldi->music_path = getStringCopy(UNDEFINED_FILENAME);
+
+ ldi->level_filename = NULL;
+ ldi->level_filetype = NULL;
+
ldi->levels = 0;
ldi->first_level = 0;
ldi->last_level = 0;
ldi->level_group = FALSE;
ldi->handicap_level = 0;
ldi->readonly = TRUE;
+ ldi->handicap = TRUE;
+ ldi->skip_levels = FALSE;
}
}
{
Error(ERR_WARN, "setTreeInfoToDefaultsFromParent(): parent == NULL");
- setTreeInfoToDefaults(ldi, TREE_TYPE_GENERIC);
+ setTreeInfoToDefaults(ldi, TREE_TYPE_UNDEFINED);
+
return;
}
- /* first copy all values from the parent structure ... */
- *ldi = *parent;
+ /* copy all values from the parent structure */
- /* ... then set all fields to default that cannot be inherited from parent.
- This is especially important for all those fields that can be set from
- the 'levelinfo.conf' config file, because the function 'setSetupInfo()'
- calls 'free()' for all already set token values which requires that no
- other structure's pointer may point to them!
- */
+ ldi->type = parent->type;
+
+ ldi->node_top = parent->node_top;
+ ldi->node_parent = parent;
+ ldi->node_group = NULL;
+ ldi->next = NULL;
+
+ ldi->cl_first = -1;
+ ldi->cl_cursor = -1;
- ldi->filename = NULL;
+ ldi->subdir = NULL;
ldi->fullpath = NULL;
ldi->basepath = NULL;
+ ldi->identifier = NULL;
ldi->name = getStringCopy(ANONYMOUS_NAME);
- ldi->name_short = NULL;
ldi->name_sorting = NULL;
ldi->author = getStringCopy(parent->author);
- ldi->imported_from = getStringCopy(parent->imported_from);
- ldi->level_group = FALSE;
+ ldi->sort_priority = parent->sort_priority;
+ ldi->latest_engine = parent->latest_engine;
ldi->parent_link = FALSE;
+ ldi->in_user_dir = parent->in_user_dir;
+ ldi->user_defined = parent->user_defined;
+ ldi->color = parent->color;
+ ldi->class_desc = getStringCopy(parent->class_desc);
- ldi->node_top = parent->node_top;
- ldi->node_parent = parent;
- ldi->node_group = NULL;
- ldi->next = NULL;
+ if (ldi->type == TREE_TYPE_LEVEL_DIR)
+ {
+ ldi->imported_from = getStringCopy(parent->imported_from);
+ ldi->imported_by = getStringCopy(parent->imported_by);
+
+ ldi->graphics_set = NULL;
+ ldi->sounds_set = NULL;
+ ldi->music_set = NULL;
+ ldi->graphics_path = getStringCopy(UNDEFINED_FILENAME);
+ ldi->sounds_path = getStringCopy(UNDEFINED_FILENAME);
+ ldi->music_path = getStringCopy(UNDEFINED_FILENAME);
+
+ ldi->level_filename = NULL;
+ ldi->level_filetype = NULL;
+
+ ldi->levels = 0;
+ ldi->first_level = 0;
+ ldi->last_level = 0;
+ ldi->level_group = FALSE;
+ ldi->handicap_level = 0;
+ ldi->readonly = TRUE;
+ ldi->handicap = TRUE;
+ ldi->skip_levels = FALSE;
+ }
+}
+
+static void freeTreeInfo(TreeInfo *ldi)
+{
+ checked_free(ldi->subdir);
+ checked_free(ldi->fullpath);
+ checked_free(ldi->basepath);
+ checked_free(ldi->identifier);
+
+ checked_free(ldi->name);
+ checked_free(ldi->name_sorting);
+ checked_free(ldi->author);
+
+ checked_free(ldi->class_desc);
+
+ if (ldi->type == TREE_TYPE_LEVEL_DIR)
+ {
+ checked_free(ldi->imported_from);
+ checked_free(ldi->imported_by);
+
+ checked_free(ldi->graphics_set);
+ checked_free(ldi->sounds_set);
+ checked_free(ldi->music_set);
+
+ checked_free(ldi->graphics_path);
+ checked_free(ldi->sounds_path);
+ checked_free(ldi->music_path);
+
+ checked_free(ldi->level_filename);
+ checked_free(ldi->level_filetype);
+ }
}
void setSetupInfo(struct TokenInfo *token_info,
{
case TYPE_BOOLEAN:
case TYPE_SWITCH:
- *(boolean *)setup_value = get_string_boolean_value(token_value);
+ *(boolean *)setup_value = get_boolean_from_string(token_value);
break;
case TYPE_KEY:
break;
case TYPE_INTEGER:
- *(int *)setup_value = get_string_integer_value(token_value);
+ *(int *)setup_value = get_integer_from_string(token_value);
break;
case TYPE_STRING:
- if (*(char **)setup_value != NULL)
- free(*(char **)setup_value);
+ checked_free(*(char **)setup_value);
*(char **)setup_value = getStringCopy(token_value);
break;
ti_new->node_parent = node_parent;
ti_new->parent_link = TRUE;
- ti_new->name = ".. (parent directory)";
- ti_new->name_short = getStringCopy(ti_new->name);
- ti_new->name_sorting = getStringCopy(ti_new->name);
+ setString(&ti_new->identifier, node_parent->identifier);
+ setString(&ti_new->name, ".. (parent directory)");
+ setString(&ti_new->name_sorting, ti_new->name);
- ti_new->filename = "..";
- ti_new->fullpath = getStringCopy(node_parent->fullpath);
+ setString(&ti_new->subdir, "..");
+ setString(&ti_new->fullpath, node_parent->fullpath);
ti_new->sort_priority = node_parent->sort_priority;
- ti_new->class_desc = getLevelClassDescription(ti_new);
+ ti_new->latest_engine = node_parent->latest_engine;
+
+ setString(&ti_new->class_desc, getLevelClassDescription(ti_new));
pushTreeInfo(&node_parent->node_group, ti_new);
}
{
char *directory_path = getPath2(level_directory, directory_name);
char *filename = getPath2(directory_path, LEVELINFO_FILENAME);
- struct SetupFileList *setup_file_list = loadSetupFileList(filename);
+ SetupFileHash *setup_file_hash;
LevelDirTree *leveldir_new = NULL;
int i;
- if (setup_file_list == NULL)
+ /* unless debugging, silently ignore directories without "levelinfo.conf" */
+ if (!options.debug && !fileExists(filename))
+ {
+ free(directory_path);
+ free(filename);
+
+ return FALSE;
+ }
+
+ setup_file_hash = loadSetupFileHash(filename);
+
+ if (setup_file_hash == NULL)
{
Error(ERR_WARN, "ignoring level directory '%s'", directory_path);
else
setTreeInfoToDefaults(leveldir_new, TREE_TYPE_LEVEL_DIR);
- leveldir_new->filename = getStringCopy(directory_name);
+ leveldir_new->subdir = getStringCopy(directory_name);
- checkSetupFileListIdentifier(setup_file_list, getCookie("LEVELINFO"));
+ checkSetupFileHashIdentifier(setup_file_hash, filename,
+ getCookie("LEVELINFO"));
/* set all structure fields according to the token/value pairs */
ldi = *leveldir_new;
- for (i=0; i<NUM_LEVELINFO_TOKENS; i++)
+ for (i = 0; i < NUM_LEVELINFO_TOKENS; i++)
setSetupInfo(levelinfo_tokens, i,
- getTokenValue(setup_file_list, levelinfo_tokens[i].text));
+ getHashEntry(setup_file_hash, levelinfo_tokens[i].text));
*leveldir_new = ldi;
if (strcmp(leveldir_new->name, ANONYMOUS_NAME) == 0)
- {
- free(leveldir_new->name);
- leveldir_new->name = getStringCopy(leveldir_new->filename);
- }
+ setString(&leveldir_new->name, leveldir_new->subdir);
DrawInitText(leveldir_new->name, 150, FC_YELLOW);
- if (leveldir_new->name_short == NULL)
- leveldir_new->name_short = getStringCopy(leveldir_new->name);
+ if (leveldir_new->identifier == NULL)
+ leveldir_new->identifier = getStringCopy(leveldir_new->subdir);
if (leveldir_new->name_sorting == NULL)
leveldir_new->name_sorting = getStringCopy(leveldir_new->name);
if (node_parent == NULL) /* top level group */
{
- leveldir_new->basepath = level_directory;
- leveldir_new->fullpath = leveldir_new->filename;
+ leveldir_new->basepath = getStringCopy(level_directory);
+ leveldir_new->fullpath = getStringCopy(leveldir_new->subdir);
}
else /* sub level group */
{
- leveldir_new->basepath = node_parent->basepath;
+ leveldir_new->basepath = getStringCopy(node_parent->basepath);
leveldir_new->fullpath = getPath2(node_parent->fullpath, directory_name);
}
+#if 0
if (leveldir_new->levels < 1)
leveldir_new->levels = 1;
+#endif
leveldir_new->last_level =
leveldir_new->first_level + leveldir_new->levels - 1;
+ leveldir_new->in_user_dir =
+ (strcmp(leveldir_new->basepath, options.level_directory) != 0);
+
+ /* adjust some settings if user's private level directory was detected */
+ if (leveldir_new->sort_priority == LEVELCLASS_UNDEFINED &&
+ leveldir_new->in_user_dir &&
+ (strcmp(leveldir_new->subdir, getLoginName()) == 0 ||
+ strcmp(leveldir_new->name, getLoginName()) == 0 ||
+ strcmp(leveldir_new->author, getRealName()) == 0))
+ {
+ leveldir_new->sort_priority = LEVELCLASS_PRIVATE_START;
+ leveldir_new->readonly = FALSE;
+ }
+
leveldir_new->user_defined =
- (leveldir_new->basepath == options.level_directory ? FALSE : TRUE);
+ (leveldir_new->in_user_dir && IS_LEVELCLASS_PRIVATE(leveldir_new));
leveldir_new->color = LEVELCOLOR(leveldir_new);
- leveldir_new->class_desc = getLevelClassDescription(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->last_level :
- leveldir_new->first_level);
+ (leveldir_new->user_defined || !leveldir_new->handicap ?
+ leveldir_new->last_level : leveldir_new->first_level);
+
+#if 0
+ /* !!! don't skip sets without levels (else artwork base sets are missing) */
+#if 1
+ if (leveldir_new->levels < 1 && !leveldir_new->level_group)
+ {
+ /* skip level sets without levels (which are probably artwork base sets) */
+
+ freeSetupFileHash(setup_file_hash);
+ free(directory_path);
+ free(filename);
+
+ return FALSE;
+ }
+#endif
+#endif
pushTreeInfo(node_first, leveldir_new);
- freeSetupFileList(setup_file_list);
+ freeSetupFileHash(setup_file_hash);
if (leveldir_new->level_group)
{
closedir(dir);
- if (!valid_entry_found)
+ /* special case: top level directory may directly contain "levelinfo.conf" */
+ if (node_parent == NULL && !valid_entry_found)
{
/* check if this directory directly contains a file "levelinfo.conf" */
valid_entry_found |= LoadLevelInfoFromLevelConf(node_first, node_parent,
LoadLevelInfoFromLevelDir(&leveldir_first, NULL, options.level_directory);
LoadLevelInfoFromLevelDir(&leveldir_first, NULL, getUserLevelDir(NULL));
+#if 1
+ /* after loading all level set information, clone the level directory tree
+ and remove all level sets without levels (these may still contain artwork
+ to be offered in the setup menu as "custom artwork", and are therefore
+ checked for existing artwork in the function "LoadLevelArtworkInfo()") */
+ leveldir_first_all = leveldir_first;
+ cloneTree(&leveldir_first, leveldir_first_all, TRUE);
+#endif
+
/* before sorting, the first entries will be from the user directory */
leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
{
char *directory_path = getPath2(base_directory, directory_name);
char *filename = getPath2(directory_path, ARTWORKINFO_FILENAME(type));
- struct SetupFileList *setup_file_list = NULL;
+ SetupFileHash *setup_file_hash = NULL;
TreeInfo *artwork_new = NULL;
int i;
- if (access(filename, F_OK) == 0) /* file exists */
- setup_file_list = loadSetupFileList(filename);
+ if (fileExists(filename))
+ setup_file_hash = loadSetupFileHash(filename);
- if (setup_file_list == NULL) /* no config file -- look for artwork files */
+ if (setup_file_hash == NULL) /* no config file -- look for artwork files */
{
DIR *dir;
struct dirent *dir_entry;
else
setTreeInfoToDefaults(artwork_new, type);
- artwork_new->filename = getStringCopy(directory_name);
+ artwork_new->subdir = getStringCopy(directory_name);
- if (setup_file_list) /* (before defining ".color" and ".class_desc") */
+ if (setup_file_hash) /* (before defining ".color" and ".class_desc") */
{
#if 0
- checkSetupFileListIdentifier(setup_file_list, getCookie("..."));
+ checkSetupFileHashIdentifier(setup_file_hash, filename, getCookie("..."));
#endif
/* set all structure fields according to the token/value pairs */
ldi = *artwork_new;
- for (i=0; i<NUM_LEVELINFO_TOKENS; i++)
+ for (i = 0; i < NUM_LEVELINFO_TOKENS; i++)
setSetupInfo(levelinfo_tokens, i,
- getTokenValue(setup_file_list, levelinfo_tokens[i].text));
+ getHashEntry(setup_file_hash, levelinfo_tokens[i].text));
*artwork_new = ldi;
if (strcmp(artwork_new->name, ANONYMOUS_NAME) == 0)
- {
- free(artwork_new->name);
- artwork_new->name = getStringCopy(artwork_new->filename);
- }
+ setString(&artwork_new->name, artwork_new->subdir);
#if 0
DrawInitText(artwork_new->name, 150, FC_YELLOW);
#endif
- if (artwork_new->name_short == NULL)
- artwork_new->name_short = getStringCopy(artwork_new->name);
+ if (artwork_new->identifier == NULL)
+ artwork_new->identifier = getStringCopy(artwork_new->subdir);
if (artwork_new->name_sorting == NULL)
artwork_new->name_sorting = getStringCopy(artwork_new->name);
if (node_parent == NULL) /* top level group */
{
artwork_new->basepath = getStringCopy(base_directory);
- artwork_new->fullpath = getStringCopy(artwork_new->filename);
+ artwork_new->fullpath = getStringCopy(artwork_new->subdir);
}
else /* sub level group */
{
artwork_new->fullpath = getPath2(node_parent->fullpath, directory_name);
}
- artwork_new->user_defined =
- (artwork_new->basepath == OPTIONS_ARTWORK_DIRECTORY(type) ? FALSE : TRUE);
+ artwork_new->in_user_dir =
+ (strcmp(artwork_new->basepath, OPTIONS_ARTWORK_DIRECTORY(type)) != 0);
- /* (may use ".sort_priority" from "setup_file_list" above) */
+ /* (may use ".sort_priority" from "setup_file_hash" above) */
artwork_new->color = ARTWORKCOLOR(artwork_new);
- artwork_new->class_desc = getLevelClassDescription(artwork_new);
- if (setup_file_list == NULL) /* (after determining ".user_defined") */
- {
- if (artwork_new->name != NULL)
- free(artwork_new->name);
+ setString(&artwork_new->class_desc, getLevelClassDescription(artwork_new));
- if (strcmp(artwork_new->filename, ".") == 0)
+ if (setup_file_hash == NULL) /* (after determining ".user_defined") */
+ {
+ if (strcmp(artwork_new->subdir, ".") == 0)
{
if (artwork_new->user_defined)
{
- artwork_new->name = getStringCopy("private");
- artwork_new->sort_priority = ARTWORKCLASS_USER;
+ setString(&artwork_new->identifier, "private");
+ artwork_new->sort_priority = ARTWORKCLASS_PRIVATE;
}
else
{
- artwork_new->name = getStringCopy("classic");
+ setString(&artwork_new->identifier, "classic");
artwork_new->sort_priority = ARTWORKCLASS_CLASSICS;
}
+ /* set to new values after changing ".sort_priority" */
artwork_new->color = ARTWORKCOLOR(artwork_new);
- artwork_new->class_desc = getLevelClassDescription(artwork_new);
+
+ setString(&artwork_new->class_desc,
+ getLevelClassDescription(artwork_new));
}
else
- artwork_new->name = getStringCopy(artwork_new->filename);
+ {
+ setString(&artwork_new->identifier, artwork_new->subdir);
+ }
- artwork_new->name_short = getStringCopy(artwork_new->name);
- artwork_new->name_sorting = getStringCopy(artwork_new->name);
+ setString(&artwork_new->name, artwork_new->identifier);
+ setString(&artwork_new->name_sorting, artwork_new->name);
}
DrawInitText(artwork_new->name, 150, FC_YELLOW);
pushTreeInfo(node_first, artwork_new);
- freeSetupFileList(setup_file_list);
+ freeSetupFileHash(setup_file_hash);
free(directory_path);
free(filename);
setTreeInfoToDefaults(artwork_new, type);
- artwork_new->filename = getStringCopy(NOT_AVAILABLE);
- artwork_new->fullpath = getStringCopy(NOT_AVAILABLE);
- artwork_new->basepath = getStringCopy(NOT_AVAILABLE);
+ setString(&artwork_new->subdir, UNDEFINED_FILENAME);
+ setString(&artwork_new->fullpath, UNDEFINED_FILENAME);
+ setString(&artwork_new->basepath, UNDEFINED_FILENAME);
- if (artwork_new->name != NULL)
- free(artwork_new->name);
-
- artwork_new->name = getStringCopy(NOT_AVAILABLE);
- artwork_new->name_short = getStringCopy(NOT_AVAILABLE);
- artwork_new->name_sorting = getStringCopy(NOT_AVAILABLE);
+ setString(&artwork_new->identifier, UNDEFINED_FILENAME);
+ setString(&artwork_new->name, UNDEFINED_FILENAME);
+ setString(&artwork_new->name_sorting, UNDEFINED_FILENAME);
return artwork_new;
}
/* before sorting, the first entries will be from the user directory */
artwork.gfx_current =
- getTreeInfoFromFilename(artwork.gfx_first, setup.graphics_set);
+ getTreeInfoFromIdentifier(artwork.gfx_first, setup.graphics_set);
+ if (artwork.gfx_current == NULL)
+ artwork.gfx_current =
+ getTreeInfoFromIdentifier(artwork.gfx_first, GFX_CLASSIC_SUBDIR);
if (artwork.gfx_current == NULL)
artwork.gfx_current = getFirstValidTreeInfoEntry(artwork.gfx_first);
artwork.snd_current =
- getTreeInfoFromFilename(artwork.snd_first, setup.sounds_set);
+ getTreeInfoFromIdentifier(artwork.snd_first, setup.sounds_set);
+ if (artwork.snd_current == NULL)
+ artwork.snd_current =
+ getTreeInfoFromIdentifier(artwork.snd_first, SND_CLASSIC_SUBDIR);
if (artwork.snd_current == NULL)
artwork.snd_current = getFirstValidTreeInfoEntry(artwork.snd_first);
artwork.mus_current =
- getTreeInfoFromFilename(artwork.mus_first, setup.music_set);
+ getTreeInfoFromIdentifier(artwork.mus_first, setup.music_set);
+ if (artwork.mus_current == NULL)
+ artwork.mus_current =
+ getTreeInfoFromIdentifier(artwork.mus_first, MUS_CLASSIC_SUBDIR);
if (artwork.mus_current == NULL)
artwork.mus_current = getFirstValidTreeInfoEntry(artwork.mus_first);
- artwork.graphics_set_current_name = artwork.gfx_current->name;
- artwork.sounds_set_current_name = artwork.snd_current->name;
- artwork.music_set_current_name = artwork.mus_current->name;
+ artwork.gfx_current_identifier = artwork.gfx_current->identifier;
+ artwork.snd_current_identifier = artwork.snd_current->identifier;
+ artwork.mus_current_identifier = artwork.mus_current->identifier;
#if 0
- printf("graphics set == %s\n\n", artwork.graphics_set_current_name);
- printf("sounds set == %s\n\n", artwork.sounds_set_current_name);
- printf("music set == %s\n\n", artwork.music_set_current_name);
+ printf("graphics set == %s\n\n", artwork.gfx_current_identifier);
+ printf("sounds set == %s\n\n", artwork.snd_current_identifier);
+ printf("music set == %s\n\n", artwork.mus_current_identifier);
#endif
sortTreeInfo(&artwork.gfx_first, compareTreeInfoEntries);
char *path = getPath2(getLevelDirFromTreeInfo(level_node),
ARTWORK_DIRECTORY((*artwork_node)->type));
-#if 0
- if (!level_node->parent_link)
- printf("CHECKING '%s' ['%s', '%s'] ...\n", path,
- level_node->filename, level_node->name);
-#endif
-
if (!level_node->parent_link)
{
TreeInfo *topnode_last = *artwork_node;
if (topnode_last != *artwork_node)
{
+ free((*artwork_node)->identifier);
free((*artwork_node)->name);
free((*artwork_node)->name_sorting);
- free((*artwork_node)->name_short);
+ (*artwork_node)->identifier = getStringCopy(level_node->subdir);
(*artwork_node)->name = getStringCopy(level_node->name);
(*artwork_node)->name_sorting = getStringCopy(level_node->name);
- (*artwork_node)->name_short = getStringCopy(level_node->filename);
(*artwork_node)->sort_priority = level_node->sort_priority;
(*artwork_node)->color = LEVELCOLOR((*artwork_node));
{
DrawInitText("Looking for custom level artwork:", 120, FC_GREEN);
- LoadArtworkInfoFromLevelInfo(&artwork.gfx_first, leveldir_first);
- LoadArtworkInfoFromLevelInfo(&artwork.snd_first, leveldir_first);
- LoadArtworkInfoFromLevelInfo(&artwork.mus_first, leveldir_first);
+ LoadArtworkInfoFromLevelInfo(&artwork.gfx_first, leveldir_first_all);
+ LoadArtworkInfoFromLevelInfo(&artwork.snd_first, leveldir_first_all);
+ LoadArtworkInfoFromLevelInfo(&artwork.mus_first, leveldir_first_all);
+
+ /* needed for reloading level artwork not known at ealier stage */
+
+ if (strcmp(artwork.gfx_current_identifier, setup.graphics_set) != 0)
+ {
+ artwork.gfx_current =
+ getTreeInfoFromIdentifier(artwork.gfx_first, setup.graphics_set);
+ if (artwork.gfx_current == NULL)
+ artwork.gfx_current =
+ getTreeInfoFromIdentifier(artwork.gfx_first, GFX_CLASSIC_SUBDIR);
+ if (artwork.gfx_current == NULL)
+ artwork.gfx_current = getFirstValidTreeInfoEntry(artwork.gfx_first);
+ }
+
+ if (strcmp(artwork.snd_current_identifier, setup.sounds_set) != 0)
+ {
+ artwork.snd_current =
+ getTreeInfoFromIdentifier(artwork.snd_first, setup.sounds_set);
+ if (artwork.snd_current == NULL)
+ artwork.snd_current =
+ getTreeInfoFromIdentifier(artwork.snd_first, SND_CLASSIC_SUBDIR);
+ if (artwork.snd_current == NULL)
+ artwork.snd_current = getFirstValidTreeInfoEntry(artwork.snd_first);
+ }
+
+ if (strcmp(artwork.mus_current_identifier, setup.music_set) != 0)
+ {
+ artwork.mus_current =
+ getTreeInfoFromIdentifier(artwork.mus_first, setup.music_set);
+ if (artwork.mus_current == NULL)
+ artwork.mus_current =
+ getTreeInfoFromIdentifier(artwork.mus_first, MUS_CLASSIC_SUBDIR);
+ if (artwork.mus_current == NULL)
+ artwork.mus_current = getFirstValidTreeInfoEntry(artwork.mus_first);
+ }
sortTreeInfo(&artwork.gfx_first, compareTreeInfoEntries);
sortTreeInfo(&artwork.snd_first, compareTreeInfoEntries);
static void SaveUserLevelInfo()
{
+ LevelDirTree *level_info;
char *filename;
FILE *file;
int i;
return;
}
+ level_info = newTreeInfo();
+
/* always start with reliable default values */
- setTreeInfoToDefaults(&ldi, TREE_TYPE_LEVEL_DIR);
+ setTreeInfoToDefaults(level_info, TREE_TYPE_LEVEL_DIR);
+
+ setString(&level_info->name, getLoginName());
+ setString(&level_info->author, getRealName());
+ level_info->levels = 100;
+ level_info->first_level = 1;
- ldi.name = getStringCopy(getLoginName());
- ldi.author = getStringCopy(getRealName());
- ldi.levels = 100;
- ldi.first_level = 1;
- ldi.sort_priority = LEVELCLASS_USER_START;
- ldi.readonly = FALSE;
+ token_value_position = TOKEN_VALUE_POSITION_SHORT;
fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
getCookie("LEVELINFO")));
- for (i=0; i<NUM_LEVELINFO_TOKENS; i++)
- if (i != LEVELINFO_TOKEN_NAME_SHORT &&
- i != LEVELINFO_TOKEN_NAME_SORTING &&
- i != LEVELINFO_TOKEN_IMPORTED_FROM)
+ ldi = *level_info;
+ for (i = 0; i < NUM_LEVELINFO_TOKENS; i++)
+ {
+ if (i == LEVELINFO_TOKEN_NAME ||
+ i == LEVELINFO_TOKEN_AUTHOR ||
+ i == LEVELINFO_TOKEN_LEVELS ||
+ i == LEVELINFO_TOKEN_FIRST_LEVEL)
fprintf(file, "%s\n", getSetupLine(levelinfo_tokens, "", i));
+ /* just to make things nicer :) */
+ if (i == LEVELINFO_TOKEN_AUTHOR)
+ fprintf(file, "\n");
+ }
+
+ token_value_position = TOKEN_VALUE_POSITION_DEFAULT;
+
fclose(file);
- free(filename);
SetFilePermissions(filename, PERMS_PRIVATE);
+
+ freeTreeInfo(level_info);
+ free(filename);
}
char *getSetupValue(int type, void *value)
break;
}
+ if (type & TYPE_GHOSTED)
+ strcpy(value_string, "n/a");
+
return value_string;
}
{
/* add at least one whitespace */
strcat(line, " ");
- for (i=strlen(line); i<TOKEN_COMMENT_POSITION; i++)
+ for (i = strlen(line); i < token_comment_position; i++)
strcat(line, " ");
strcat(line, "# ");
void LoadLevelSetup_LastSeries()
{
- char *filename;
- struct SetupFileList *level_setup_list = NULL;
-
- /* always start with reliable default values */
- leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
-
/* ----------------------------------------------------------------------- */
/* ~/.<program>/levelsetup.conf */
/* ----------------------------------------------------------------------- */
- filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME);
+ char *filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME);
+ SetupFileHash *level_setup_hash = NULL;
+
+ /* always start with reliable default values */
+ leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
- if ((level_setup_list = loadSetupFileList(filename)))
+ if ((level_setup_hash = loadSetupFileHash(filename)))
{
char *last_level_series =
- getTokenValue(level_setup_list, TOKEN_STR_LAST_LEVEL_SERIES);
+ getHashEntry(level_setup_hash, TOKEN_STR_LAST_LEVEL_SERIES);
- leveldir_current = getTreeInfoFromFilename(leveldir_first,
- last_level_series);
+ leveldir_current = getTreeInfoFromIdentifier(leveldir_first,
+ last_level_series);
if (leveldir_current == NULL)
leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
- checkSetupFileListIdentifier(level_setup_list, getCookie("LEVELSETUP"));
+ checkSetupFileHashIdentifier(level_setup_hash, filename,
+ getCookie("LEVELSETUP"));
- freeSetupFileList(level_setup_list);
+ freeSetupFileHash(level_setup_hash);
}
else
Error(ERR_WARN, "using default setup values");
void SaveLevelSetup_LastSeries()
{
- char *filename;
- char *level_subdir = leveldir_current->filename;
- FILE *file;
-
/* ----------------------------------------------------------------------- */
/* ~/.<program>/levelsetup.conf */
/* ----------------------------------------------------------------------- */
- InitUserDataDirectory();
+ char *filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME);
+ char *level_subdir = leveldir_current->subdir;
+ FILE *file;
- filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME);
+ InitUserDataDirectory();
if (!(file = fopen(filename, MODE_WRITE)))
{
level_subdir));
fclose(file);
- free(filename);
SetFilePermissions(filename, PERMS_PRIVATE);
+
+ free(filename);
}
static void checkSeriesInfo()
/* check for more levels besides the 'levels' field of 'levelinfo.conf' */
- level_directory = getPath2((leveldir_current->user_defined ?
+ level_directory = getPath2((leveldir_current->in_user_dir ?
getUserLevelDir(NULL) :
options.level_directory),
leveldir_current->fullpath);
levelnum_value = atoi(levelnum_str);
+#if 0
if (levelnum_value < leveldir_current->first_level)
{
Error(ERR_WARN, "additional level %d found", levelnum_value);
Error(ERR_WARN, "additional level %d found", levelnum_value);
leveldir_current->last_level = levelnum_value;
}
+#endif
}
}
void LoadLevelSetup_SeriesInfo()
{
char *filename;
- struct SetupFileList *level_setup_list = NULL;
- char *level_subdir = leveldir_current->filename;
+ SetupFileHash *level_setup_hash = NULL;
+ char *level_subdir = leveldir_current->subdir;
/* always start with reliable default values */
level_nr = leveldir_current->first_level;
/* ~/.<program>/levelsetup/<level series>/levelsetup.conf */
/* ----------------------------------------------------------------------- */
- level_subdir = leveldir_current->filename;
+ level_subdir = leveldir_current->subdir;
filename = getPath2(getLevelSetupDir(level_subdir), LEVELSETUP_FILENAME);
- if ((level_setup_list = loadSetupFileList(filename)))
+ if ((level_setup_hash = loadSetupFileHash(filename)))
{
char *token_value;
- token_value = getTokenValue(level_setup_list, TOKEN_STR_LAST_PLAYED_LEVEL);
+ token_value = getHashEntry(level_setup_hash, TOKEN_STR_LAST_PLAYED_LEVEL);
if (token_value)
{
level_nr = leveldir_current->last_level;
}
- token_value = getTokenValue(level_setup_list, TOKEN_STR_HANDICAP_LEVEL);
+ token_value = getHashEntry(level_setup_hash, TOKEN_STR_HANDICAP_LEVEL);
if (token_value)
{
if (level_nr > leveldir_current->last_level + 1)
level_nr = leveldir_current->last_level;
- if (leveldir_current->user_defined)
+ if (leveldir_current->user_defined || !leveldir_current->handicap)
level_nr = leveldir_current->last_level;
leveldir_current->handicap_level = level_nr;
}
- checkSetupFileListIdentifier(level_setup_list, getCookie("LEVELSETUP"));
+ checkSetupFileHashIdentifier(level_setup_hash, filename,
+ getCookie("LEVELSETUP"));
- freeSetupFileList(level_setup_list);
+ freeSetupFileHash(level_setup_hash);
}
else
Error(ERR_WARN, "using default setup values");
void SaveLevelSetup_SeriesInfo()
{
char *filename;
- char *level_subdir = leveldir_current->filename;
+ char *level_subdir = leveldir_current->subdir;
char *level_nr_str = int2str(level_nr, 0);
char *handicap_level_str = int2str(leveldir_current->handicap_level, 0);
FILE *file;
handicap_level_str));
fclose(file);
- free(filename);
SetFilePermissions(filename, PERMS_PRIVATE);
+
+ free(filename);
}