#include "platform.h"
#include "setup.h"
+#include "sound.h"
#include "joystick.h"
#include "text.h"
#include "misc.h"
#define TOKEN_VALUE_POSITION_DEFAULT 40
#define TOKEN_COMMENT_POSITION_DEFAULT 60
-#define MAX_COOKIE_LEN 256
-
#define TREE_NODE_TYPE_DEFAULT 0
#define TREE_NODE_TYPE_PARENT 1
#define TREE_NODE_TYPE_GROUP 2
static SetupFileHash *artworkinfo_cache_old = NULL;
static SetupFileHash *artworkinfo_cache_new = NULL;
static SetupFileHash *optional_tokens_hash = NULL;
+static SetupFileHash *missing_file_hash = NULL;
static boolean use_artworkinfo_cache = TRUE;
static boolean update_artworkinfo_cache = FALSE;
// file functions
// ----------------------------------------------------------------------------
+static void WarnUsingFallback(char *filename)
+{
+ if (getHashEntry(missing_file_hash, filename) == NULL)
+ {
+ setHashEntry(missing_file_hash, filename, "");
+
+ Debug("setup", "cannot find artwork file '%s' (using fallback)", filename);
+ }
+}
+
static char *getLevelClassDescription(TreeInfo *ti)
{
int position = ti->sort_priority / 100;
return "Unknown Level Class";
}
+static char *getCacheDir(void)
+{
+ static char *cache_dir = NULL;
+
+ if (cache_dir == NULL)
+ cache_dir = getPath2(getMainUserGameDataDir(), CACHE_DIRECTORY);
+
+ return cache_dir;
+}
+
static char *getScoreDir(char *level_subdir)
{
static char *score_dir = NULL;
char *score_subdir = SCORES_DIRECTORY;
if (score_dir == NULL)
+ score_dir = getPath2(getMainUserGameDataDir(), score_subdir);
+
+ if (level_subdir != NULL)
{
- if (program.global_scores)
- score_dir = getPath2(getCommonDataDir(), score_subdir);
- else
- score_dir = getPath2(getMainUserGameDataDir(), score_subdir);
+ checked_free(score_level_dir);
+
+ score_level_dir = getPath2(score_dir, level_subdir);
+
+ return score_level_dir;
}
+ return score_dir;
+}
+
+static char *getScoreCacheDir(char *level_subdir)
+{
+ static char *score_dir = NULL;
+ static char *score_level_dir = NULL;
+ char *score_subdir = SCORES_DIRECTORY;
+
+ if (score_dir == NULL)
+ score_dir = getPath2(getCacheDir(), score_subdir);
+
if (level_subdir != NULL)
{
checked_free(score_level_dir);
return score_tape_dir;
}
+static char *getScoreCacheTapeDir(char *level_subdir, int nr)
+{
+ static char *score_cache_tape_dir = NULL;
+ char tape_subdir[MAX_FILENAME_LEN];
+
+ checked_free(score_cache_tape_dir);
+
+ sprintf(tape_subdir, "%03d", nr);
+ score_cache_tape_dir = getPath2(getScoreCacheDir(level_subdir), tape_subdir);
+
+ return score_cache_tape_dir;
+}
+
static char *getUserSubdir(int nr)
{
static char user_subdir[16] = { 0 };
return levelsetup_dir;
}
-static char *getCacheDir(void)
-{
- static char *cache_dir = NULL;
-
- if (cache_dir == NULL)
- cache_dir = getPath2(getMainUserGameDataDir(), CACHE_DIRECTORY);
-
- return cache_dir;
-}
-
static char *getNetworkDir(void)
{
static char *network_dir = NULL;
return new_level_subdir;
}
-static char *getTapeDir(char *level_subdir)
+char *getTapeDir(char *level_subdir)
{
static char *tape_dir = NULL;
char *data_dir = getUserGameDataDir();
set the current working directory to the program package directory) */
char *main_data_path = getBasePath(command_filename);
-#if defined(PLATFORM_MACOSX)
+#if defined(PLATFORM_MAC)
if (strSuffix(main_data_path, MAC_APP_BINARY_SUBDIR))
{
char *main_data_path_old = main_data_path;
if (strSuffix(command_filename_1, ".exe"))
command_filename_1[strlen(command_filename_1) - 4] = '\0';
- char *ro_base_path = getProgramMainDataPath(command_filename, RO_BASE_PATH);
- char *conf_directory = getPath2(ro_base_path, CONF_DIRECTORY);
+ char *base_path = getProgramMainDataPath(command_filename, BASE_PATH);
+ char *conf_directory = getPath2(base_path, CONF_DIRECTORY);
char *command_basepath = getBasePath(command_filename);
char *command_basename = getBaseNameNoSuffix(command_filename);
config_filename_2 = getStringCat2(command_filename_2, ".conf");
config_filename_3 = getPath2(conf_directory, SETUP_FILENAME);
- checked_free(ro_base_path);
+ checked_free(base_path);
checked_free(conf_directory);
checked_free(command_basepath);
return config_filename_3;
}
+static char *getPlatformConfigFilename(char *config_filename)
+{
+ static char *platform_config_filename = NULL;
+ static boolean initialized = FALSE;
+
+ if (!initialized)
+ {
+ char *config_basepath = getBasePath(config_filename);
+ char *config_basename = getBaseNameNoSuffix(config_filename);
+ char *config_filename_prefix = getPath2(config_basepath, config_basename);
+ char *platform_string_lower = getStringToLower(PLATFORM_STRING);
+ char *platform_suffix = getStringCat2("-", platform_string_lower);
+
+ platform_config_filename = getStringCat3(config_filename_prefix,
+ platform_suffix, ".conf");
+
+ checked_free(config_basepath);
+ checked_free(config_basename);
+ checked_free(config_filename_prefix);
+ checked_free(platform_string_lower);
+ checked_free(platform_suffix);
+
+ initialized = TRUE;
+ }
+
+ return platform_config_filename;
+}
+
char *getTapeFilename(int nr)
{
static char *filename = NULL;
return filename;
}
-char *getSolutionTapeFilename(int nr)
+char *getTemporaryTapeFilename(void)
+{
+ static char *filename = NULL;
+ char basename[MAX_FILENAME_LEN];
+
+ checked_free(filename);
+
+ sprintf(basename, "tmp.%s", TAPEFILE_EXTENSION);
+ filename = getPath2(getTapeDir(NULL), basename);
+
+ return filename;
+}
+
+char *getDefaultSolutionTapeFilename(int nr)
{
static char *filename = NULL;
char basename[MAX_FILENAME_LEN];
sprintf(basename, "%03d.%s", nr, TAPEFILE_EXTENSION);
filename = getPath2(getSolutionTapeDir(), basename);
- if (!fileExists(filename))
- {
- static char *filename_sln = NULL;
+ return filename;
+}
- checked_free(filename_sln);
+char *getSokobanSolutionTapeFilename(int nr)
+{
+ static char *filename = NULL;
+ char basename[MAX_FILENAME_LEN];
- sprintf(basename, "%03d.sln", nr);
- filename_sln = getPath2(getSolutionTapeDir(), basename);
+ checked_free(filename);
- if (fileExists(filename_sln))
- return filename_sln;
+ sprintf(basename, "%03d.sln", nr);
+ filename = getPath2(getSolutionTapeDir(), basename);
+
+ return filename;
+}
+
+char *getSolutionTapeFilename(int nr)
+{
+ char *filename = getDefaultSolutionTapeFilename(nr);
+
+ if (!fileExists(filename))
+ {
+ char *filename2 = getSokobanSolutionTapeFilename(nr);
+
+ if (fileExists(filename2))
+ return filename2;
}
return filename;
return filename;
}
+char *getScoreCacheFilename(int nr)
+{
+ static char *filename = NULL;
+ char basename[MAX_FILENAME_LEN];
+
+ checked_free(filename);
+
+ sprintf(basename, "%03d.%s", nr, SCOREFILE_EXTENSION);
+
+ // used instead of "leveldir_current->subdir" (for network games)
+ filename = getPath2(getScoreCacheDir(levelset.identifier), basename);
+
+ return filename;
+}
+
char *getScoreTapeBasename(char *name)
{
static char basename[MAX_FILENAME_LEN];
return filename;
}
+char *getScoreCacheTapeFilename(char *basename_no_ext, int nr)
+{
+ static char *filename = NULL;
+ char basename[MAX_FILENAME_LEN];
+
+ checked_free(filename);
+
+ sprintf(basename, "%s.%s", basename_no_ext, TAPEFILE_EXTENSION);
+
+ // used instead of "leveldir_current->subdir" (for network games)
+ filename = getPath2(getScoreCacheTapeDir(levelset.identifier, nr), basename);
+
+ return filename;
+}
+
char *getSetupFilename(void)
{
static char *filename = NULL;
return program.config_filename;
}
+char *getPlatformSetupFilename(void)
+{
+ return getPlatformConfigFilename(program.config_filename);
+}
+
char *getEditorSetupFilename(void)
{
static char *filename = NULL;
return filename;
}
-char *getLevelSetInfoFilename(void)
+static char *getLevelSetInfoBasename(int nr)
+{
+ static char basename[32];
+
+ sprintf(basename, "levelset_%d.txt", nr + 1);
+
+ return basename;
+}
+
+char *getLevelSetInfoFilename(int nr)
{
+ char *basename = getLevelSetInfoBasename(nr);
+ static char *info_subdir = NULL;
static char *filename = NULL;
+
+ if (info_subdir == NULL)
+ info_subdir = getPath2(DOCS_DIRECTORY, LEVELSET_INFO_DIRECTORY);
+
+ checked_free(filename);
+
+ // look for level set info file the current level set directory
+ filename = getPath3(getCurrentLevelDir(), info_subdir, basename);
+ if (fileExists(filename))
+ return filename;
+
+ if (nr > 0)
+ return NULL;
+
char *basenames[] =
{
"README",
return NULL; // cannot find specified artwork file anywhere
}
+static char *getCreditsBasename(int nr)
+{
+ static char basename[32];
+
+ sprintf(basename, "credits_%d.txt", nr + 1);
+
+ return basename;
+}
+
+char *getCreditsFilename(int nr, boolean global)
+{
+ char *basename = getCreditsBasename(nr);
+ char *basepath = NULL;
+ static char *credits_subdir = NULL;
+ static char *filename = NULL;
+
+ if (credits_subdir == NULL)
+ credits_subdir = getPath2(DOCS_DIRECTORY, CREDITS_DIRECTORY);
+
+ checked_free(filename);
+
+ // look for credits file in the game's base or current level set directory
+ basepath = (global ? options.base_directory : getCurrentLevelDir());
+
+ filename = getPath3(basepath, credits_subdir, basename);
+ if (fileExists(filename))
+ return filename;
+
+ return NULL; // cannot find credits file
+}
+
+static char *getProgramInfoBasename(int nr)
+{
+ static char basename[32];
+
+ sprintf(basename, "program_%d.txt", nr + 1);
+
+ return basename;
+}
+
+char *getProgramInfoFilename(int nr)
+{
+ char *basename = getProgramInfoBasename(nr);
+ static char *info_subdir = NULL;
+ static char *filename = NULL;
+
+ if (info_subdir == NULL)
+ info_subdir = getPath2(DOCS_DIRECTORY, PROGRAM_INFO_DIRECTORY);
+
+ checked_free(filename);
+
+ // look for program info file in the game's base directory
+ filename = getPath3(options.base_directory, info_subdir, basename);
+ if (fileExists(filename))
+ return filename;
+
+ return NULL; // cannot find program info file
+}
+
static char *getCorrectedArtworkBasename(char *basename)
{
return basename;
{
free(filename);
- Warn("cannot find artwork file '%s' (using fallback)", basename);
+ WarnUsingFallback(basename);
// 6th try: look for fallback artwork in old default artwork directory
// (needed to prevent errors when trying to access unused artwork files)
{
free(filename);
- Warn("cannot find artwork file '%s' (using fallback)", basename);
+ WarnUsingFallback(basename);
// 6th try: look for fallback artwork in old default artwork directory
// (needed to prevent errors when trying to access unused artwork files)
{
free(filename);
- Warn("cannot find artwork file '%s' (using fallback)", basename);
+ WarnUsingFallback(basename);
// 6th try: look for fallback artwork in old default artwork directory
// (needed to prevent errors when trying to access unused artwork files)
return filename;
}
-char *getCustomMusicDirectory(void)
+static boolean directoryExists_CheckMusic(char *directory, boolean check_music)
+{
+ if (!directoryExists(directory))
+ return FALSE;
+
+ if (!check_music)
+ return TRUE;
+
+ Directory *dir;
+ DirectoryEntry *dir_entry;
+ int num_music = getMusicListSize();
+ boolean music_found = FALSE;
+
+ if ((dir = openDirectory(directory)) == NULL)
+ return FALSE;
+
+ while ((dir_entry = readDirectory(dir)) != NULL) // loop all entries
+ {
+ char *basename = dir_entry->basename;
+ boolean music_already_used = FALSE;
+ int i;
+
+ // skip all music files that are configured in music config file
+ for (i = 0; i < num_music; i++)
+ {
+ struct FileInfo *music = getMusicListEntry(i);
+
+ if (strEqual(basename, music->filename))
+ {
+ music_already_used = TRUE;
+
+ break;
+ }
+ }
+
+ if (music_already_used)
+ continue;
+
+ if (FileIsMusic(dir_entry->filename))
+ {
+ music_found = TRUE;
+
+ break;
+ }
+ }
+
+ closeDirectory(dir);
+
+ return music_found;
+}
+
+static char *getCustomMusicDirectoryExt(boolean check_music)
{
static char *directory = NULL;
boolean skip_setup_artwork = FALSE;
{
// 1st try: look for special artwork in current level series directory
directory = getPath2(getCurrentLevelDir(), MUSIC_DIRECTORY);
- if (directoryExists(directory))
+ if (directoryExists_CheckMusic(directory, check_music))
return directory;
free(directory);
{
// 2nd try: look for special artwork configured in level series config
directory = getStringCopy(getLevelArtworkDir(TREE_TYPE_MUSIC_DIR));
- if (directoryExists(directory))
+
+ // directory also valid if no unconfigured music found (no game music)
+ if (directoryExists_CheckMusic(directory, FALSE))
return directory;
free(directory);
{
// 3rd try: look for special artwork in configured artwork directory
directory = getStringCopy(getSetupArtworkDir(artwork.mus_current));
- if (directoryExists(directory))
+
+ // directory also valid if no unconfigured music found (no game music)
+ if (directoryExists_CheckMusic(directory, FALSE))
return directory;
free(directory);
// 4th try: look for default artwork in new default artwork directory
directory = getStringCopy(getDefaultMusicDir(MUS_DEFAULT_SUBDIR));
- if (directoryExists(directory))
+ if (directoryExists_CheckMusic(directory, check_music))
return directory;
free(directory);
// 5th try: look for default artwork in old default artwork directory
directory = getStringCopy(options.music_directory);
- if (directoryExists(directory))
+ if (directoryExists_CheckMusic(directory, check_music))
return directory;
return NULL; // cannot find specified artwork file anywhere
}
+char *getCustomMusicDirectory(void)
+{
+ return getCustomMusicDirectoryExt(FALSE);
+}
+
+char *getCustomMusicDirectory_NoConf(void)
+{
+ return getCustomMusicDirectoryExt(TRUE);
+}
+
+void MarkTapeDirectoryUploadsAsComplete(char *level_subdir)
+{
+ char *filename = getPath2(getTapeDir(level_subdir), UPLOADED_FILENAME);
+
+ touchFile(filename);
+
+ checked_free(filename);
+}
+
+void MarkTapeDirectoryUploadsAsIncomplete(char *level_subdir)
+{
+ char *filename = getPath2(getTapeDir(level_subdir), UPLOADED_FILENAME);
+
+ unlink(filename);
+
+ checked_free(filename);
+}
+
+boolean CheckTapeDirectoryUploadsComplete(char *level_subdir)
+{
+ char *filename = getPath2(getTapeDir(level_subdir), UPLOADED_FILENAME);
+ boolean success = fileExists(filename);
+
+ checked_free(filename);
+
+ return success;
+}
+
+void InitMissingFileHash(void)
+{
+ if (missing_file_hash == NULL)
+ freeSetupFileHash(missing_file_hash);
+
+ missing_file_hash = newSetupFileHash();
+}
+
void InitTapeDirectory(char *level_subdir)
{
- createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE);
- createDirectory(getTapeDir(NULL), "main tape", PERMS_PRIVATE);
- createDirectory(getTapeDir(level_subdir), "level tape", PERMS_PRIVATE);
+ boolean new_tape_dir = !directoryExists(getTapeDir(level_subdir));
+
+ createDirectory(getUserGameDataDir(), "user data");
+ createDirectory(getTapeDir(NULL), "main tape");
+ createDirectory(getTapeDir(level_subdir), "level tape");
+
+ if (new_tape_dir)
+ MarkTapeDirectoryUploadsAsComplete(level_subdir);
}
void InitScoreDirectory(char *level_subdir)
{
- int permissions = (program.global_scores ? PERMS_PUBLIC : PERMS_PRIVATE);
-
- if (program.global_scores)
- createDirectory(getCommonDataDir(), "common data", permissions);
- else
- createDirectory(getMainUserGameDataDir(), "main user data", permissions);
+ createDirectory(getMainUserGameDataDir(), "main user data");
+ createDirectory(getScoreDir(NULL), "main score");
+ createDirectory(getScoreDir(level_subdir), "level score");
+}
- createDirectory(getScoreDir(NULL), "main score", permissions);
- createDirectory(getScoreDir(level_subdir), "level score", permissions);
+void InitScoreCacheDirectory(char *level_subdir)
+{
+ createDirectory(getMainUserGameDataDir(), "main user data");
+ createDirectory(getCacheDir(), "cache data");
+ createDirectory(getScoreCacheDir(NULL), "main score");
+ createDirectory(getScoreCacheDir(level_subdir), "level score");
}
void InitScoreTapeDirectory(char *level_subdir, int nr)
{
- int permissions = (program.global_scores ? PERMS_PUBLIC : PERMS_PRIVATE);
-
InitScoreDirectory(level_subdir);
- createDirectory(getScoreTapeDir(level_subdir, nr), "score tape", permissions);
+ createDirectory(getScoreTapeDir(level_subdir, nr), "score tape");
+}
+
+void InitScoreCacheTapeDirectory(char *level_subdir, int nr)
+{
+ InitScoreCacheDirectory(level_subdir);
+
+ createDirectory(getScoreCacheTapeDir(level_subdir, nr), "score tape");
}
static void SaveUserLevelInfo(void);
{
if (!directoryExists(getUserLevelDir(level_subdir)))
{
- createDirectory(getMainUserGameDataDir(), "main user data", PERMS_PRIVATE);
- createDirectory(getUserLevelDir(NULL), "main user level", PERMS_PRIVATE);
- createDirectory(getUserLevelDir(level_subdir), "user level", PERMS_PRIVATE);
+ createDirectory(getMainUserGameDataDir(), "main user data");
+ createDirectory(getUserLevelDir(NULL), "main user level");
if (setup.internal.create_user_levelset)
+ {
+ createDirectory(getUserLevelDir(level_subdir), "user level");
+
SaveUserLevelInfo();
+ }
}
}
{
if (!directoryExists(getNetworkLevelDir(level_subdir)))
{
- createDirectory(getMainUserGameDataDir(), "main user data", PERMS_PRIVATE);
- createDirectory(getNetworkDir(), "network data", PERMS_PRIVATE);
- createDirectory(getNetworkLevelDir(NULL), "main network level", PERMS_PRIVATE);
- createDirectory(getNetworkLevelDir(level_subdir), "network level", PERMS_PRIVATE);
+ createDirectory(getMainUserGameDataDir(), "main user data");
+ createDirectory(getNetworkDir(), "network data");
+ createDirectory(getNetworkLevelDir(NULL), "main network level");
+ createDirectory(getNetworkLevelDir(level_subdir), "network level");
}
}
void InitLevelSetupDirectory(char *level_subdir)
{
- createDirectory(getUserGameDataDir(), "user data", PERMS_PRIVATE);
- createDirectory(getLevelSetupDir(NULL), "main level setup", PERMS_PRIVATE);
- createDirectory(getLevelSetupDir(level_subdir), "level setup", PERMS_PRIVATE);
+ createDirectory(getUserGameDataDir(), "user data");
+ createDirectory(getLevelSetupDir(NULL), "main level setup");
+ createDirectory(getLevelSetupDir(level_subdir), "level setup");
}
static void InitCacheDirectory(void)
{
- createDirectory(getMainUserGameDataDir(), "main user data", PERMS_PRIVATE);
- createDirectory(getCacheDir(), "cache data", PERMS_PRIVATE);
+ createDirectory(getMainUserGameDataDir(), "main user data");
+ createDirectory(getCacheDir(), "cache data");
}
return getFirstValidTreeInfoEntry(default_node);
}
-TreeInfo *getFirstValidTreeInfoEntry(TreeInfo *node)
+static TreeInfo *getValidTreeInfoEntryExt(TreeInfo *node, boolean get_next_node)
{
if (node == NULL)
return NULL;
- if (node->node_group) // enter level group (step down into tree)
+ if (node->node_group) // enter node group (step down into tree)
return getFirstValidTreeInfoEntry(node->node_group);
- else if (node->parent_link) // skip start entry of level group
- {
- if (node->next) // get first real level series entry
- return getFirstValidTreeInfoEntry(node->next);
- else // leave empty level group and go on
- return getFirstValidTreeInfoEntry(node->node_parent->next);
- }
- else // this seems to be a regular level series
+
+ if (node->parent_link) // skip first node (back link) of node group
+ get_next_node = TRUE;
+
+ if (!get_next_node) // get current regular tree node
return node;
+
+ // get next regular tree node, or step up until one is found
+ while (node->next == NULL && node->node_parent != NULL)
+ node = node->node_parent;
+
+ return getFirstValidTreeInfoEntry(node->next);
+}
+
+TreeInfo *getFirstValidTreeInfoEntry(TreeInfo *node)
+{
+ return getValidTreeInfoEntryExt(node, FALSE);
+}
+
+TreeInfo *getNextValidTreeInfoEntry(TreeInfo *node)
+{
+ return getValidTreeInfoEntryExt(node, TRUE);
}
TreeInfo *getTreeInfoFirstGroupEntry(TreeInfo *node)
*ti_new = ti_cloned;
}
-static boolean adjustTreeGraphicsForEMC(TreeInfo *node)
+static boolean adjustTreeArtworkForEMC(char **artwork_set_1,
+ char **artwork_set_2,
+ char **artwork_set, boolean prefer_2)
{
- boolean settings_changed = FALSE;
+ // do nothing if neither special artwork set 1 nor 2 are defined
+ if (!*artwork_set_1 && !*artwork_set_2)
+ return FALSE;
- while (node)
+ boolean want_1 = (prefer_2 == FALSE);
+ boolean want_2 = (prefer_2 == TRUE);
+ boolean has_only_1 = (!*artwork_set && !*artwork_set_2);
+ boolean has_only_2 = (!*artwork_set && !*artwork_set_1);
+ char *artwork_set_new = NULL;
+
+ // replace missing special artwork 1 or 2 with (optional) standard artwork
+
+ if (!*artwork_set_1)
+ setString(artwork_set_1, *artwork_set);
+
+ if (!*artwork_set_2)
+ setString(artwork_set_2, *artwork_set);
+
+ // set standard artwork to either special artwork 1 or 2, as requested
+
+ if (*artwork_set_1 && (want_1 || has_only_1))
+ artwork_set_new = *artwork_set_1;
+
+ if (*artwork_set_2 && (want_2 || has_only_2))
+ artwork_set_new = *artwork_set_2;
+
+ if (artwork_set_new && !strEqual(*artwork_set, artwork_set_new))
{
- boolean want_ecs = (setup.prefer_aga_graphics == FALSE);
- boolean want_aga = (setup.prefer_aga_graphics == TRUE);
- boolean has_only_ecs = (!node->graphics_set && !node->graphics_set_aga);
- boolean has_only_aga = (!node->graphics_set && !node->graphics_set_ecs);
- char *graphics_set = NULL;
+ setString(artwork_set, artwork_set_new);
- if (node->graphics_set_ecs && (want_ecs || has_only_ecs))
- graphics_set = node->graphics_set_ecs;
+ return TRUE;
+ }
- if (node->graphics_set_aga && (want_aga || has_only_aga))
- graphics_set = node->graphics_set_aga;
+ return FALSE;
+}
- if (graphics_set && !strEqual(node->graphics_set, graphics_set))
- {
- setString(&node->graphics_set, graphics_set);
- settings_changed = TRUE;
- }
+static boolean adjustTreeGraphicsForEMC(TreeInfo *node)
+{
+ boolean settings_changed = FALSE;
+ while (node)
+ {
+ settings_changed |= adjustTreeArtworkForEMC(&node->graphics_set_ecs,
+ &node->graphics_set_aga,
+ &node->graphics_set,
+ setup.prefer_aga_graphics);
if (node->node_group != NULL)
settings_changed |= adjustTreeGraphicsForEMC(node->node_group);
while (node)
{
- boolean want_default = (setup.prefer_lowpass_sounds == FALSE);
- boolean want_lowpass = (setup.prefer_lowpass_sounds == TRUE);
- boolean has_only_default = (!node->sounds_set && !node->sounds_set_lowpass);
- boolean has_only_lowpass = (!node->sounds_set && !node->sounds_set_default);
- char *sounds_set = NULL;
-
- if (node->sounds_set_default && (want_default || has_only_default))
- sounds_set = node->sounds_set_default;
-
- if (node->sounds_set_lowpass && (want_lowpass || has_only_lowpass))
- sounds_set = node->sounds_set_lowpass;
-
- if (sounds_set && !strEqual(node->sounds_set, sounds_set))
- {
- setString(&node->sounds_set, sounds_set);
- settings_changed = TRUE;
- }
-
+ settings_changed |= adjustTreeArtworkForEMC(&node->sounds_set_default,
+ &node->sounds_set_lowpass,
+ &node->sounds_set,
+ setup.prefer_lowpass_sounds);
if (node->node_group != NULL)
settings_changed |= adjustTreeSoundsForEMC(node->node_group);
return settings_changed;
}
-void dumpTreeInfo(TreeInfo *node, int depth)
+int dumpTreeInfo(TreeInfo *node, int depth)
{
char bullet_list[] = { '-', '*', 'o' };
+ int num_leaf_nodes = 0;
int i;
if (depth == 0)
DebugContinued("tree", "%c '%s' ['%s] [PARENT: '%s'] %s\n",
bullet, node->name, node->identifier,
(node->node_parent ? node->node_parent->identifier : "-"),
- (node->node_group ? "[GROUP]" : ""));
+ (node->node_group ? "[GROUP]" :
+ node->is_copy ? "[COPY]" : ""));
+
+ if (!node->node_group && !node->parent_link)
+ num_leaf_nodes++;
/*
// use for dumping artwork info tree
*/
if (node->node_group != NULL)
- dumpTreeInfo(node->node_group, depth + 1);
+ num_leaf_nodes += dumpTreeInfo(node->node_group, depth + 1);
node = node->next;
}
+
+ if (depth == 0)
+ Debug("tree", "Summary: %d leaf nodes found", num_leaf_nodes);
+
+ return num_leaf_nodes;
}
void sortTreeInfoBySortFunction(TreeInfo **node_first,
// some stuff from "files.c"
// ============================================================================
-#if defined(PLATFORM_WIN32)
+#if defined(PLATFORM_WINDOWS)
#ifndef S_IRGRP
#define S_IRGRP S_IRUSR
#endif
#ifndef S_ISGID
#define S_ISGID 0
#endif
-#endif // PLATFORM_WIN32
+#endif // PLATFORM_WINDOWS
// file permissions for newly written files
#define MODE_R_ALL (S_IRUSR | S_IRGRP | S_IROTH)
{
static char *dir = NULL;
-#if defined(PLATFORM_WIN32)
+#if defined(PLATFORM_WINDOWS)
if (dir == NULL)
{
dir = checked_malloc(MAX_PATH + 1);
strcpy(dir, ".");
}
#elif defined(PLATFORM_EMSCRIPTEN)
- dir = "/persistent";
+ dir = PERSISTENT_DIRECTORY;
#elif defined(PLATFORM_UNIX)
if (dir == NULL)
{
return dir;
}
-char *getCommonDataDir(void)
-{
- static char *common_data_dir = NULL;
-
-#if defined(PLATFORM_WIN32)
- if (common_data_dir == NULL)
- {
- char *dir = checked_malloc(MAX_PATH + 1);
-
- if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_COMMON_DOCUMENTS, NULL, 0, dir))
- && !strEqual(dir, "")) // empty for Windows 95/98
- common_data_dir = getPath2(dir, program.userdata_subdir);
- else
- common_data_dir = options.rw_base_directory;
- }
-#else
- if (common_data_dir == NULL)
- common_data_dir = options.rw_base_directory;
-#endif
-
- return common_data_dir;
-}
-
char *getPersonalDataDir(void)
{
static char *personal_data_dir = NULL;
-#if defined(PLATFORM_MACOSX)
+#if defined(PLATFORM_MAC)
if (personal_data_dir == NULL)
personal_data_dir = getPath2(getHomeDir(), "Documents");
#else
static int posix_mkdir(const char *pathname, mode_t mode)
{
-#if defined(PLATFORM_WIN32)
+#if defined(PLATFORM_WINDOWS)
return mkdir(pathname);
#else
return mkdir(pathname, mode);
#endif
}
-void createDirectory(char *dir, char *text, int permission_class)
+void createDirectory(char *dir, char *text)
{
if (directoryExists(dir))
return;
// leave "other" permissions in umask untouched, but ensure group parts
// of USERDATA_DIR_MODE are not masked
+ int permission_class = PERMS_PRIVATE;
mode_t dir_mode = (permission_class == PERMS_PRIVATE ?
DIR_PERMS_PRIVATE : DIR_PERMS_PUBLIC);
mode_t last_umask = posix_umask(0);
void InitMainUserDataDirectory(void)
{
- createDirectory(getMainUserGameDataDir(), "main user data", PERMS_PRIVATE);
+ createDirectory(getMainUserGameDataDir(), "main user data");
}
void InitUserDataDirectory(void)
{
- createDirectory(getMainUserGameDataDir(), "main user data", PERMS_PRIVATE);
+ createDirectory(getMainUserGameDataDir(), "main user data");
if (user.nr != 0)
{
- createDirectory(getUserDir(-1), "users", PERMS_PRIVATE);
- createDirectory(getUserDir(user.nr), "user data", PERMS_PRIVATE);
+ createDirectory(getUserDir(-1), "users");
+ createDirectory(getUserDir(user.nr), "user data");
}
}
chmod(filename, perms);
}
-char *getCookie(char *file_type)
-{
- static char cookie[MAX_COOKIE_LEN + 1];
-
- if (strlen(program.cookie_prefix) + 1 +
- strlen(file_type) + strlen("_FILE_VERSION_x.x") > MAX_COOKIE_LEN)
- return "[COOKIE ERROR]"; // should never happen
-
- sprintf(cookie, "%s_%s_FILE_VERSION_%d.%d",
- program.cookie_prefix, file_type,
- program.version_super, program.version_major);
-
- return cookie;
-}
-
void fprintFileHeader(FILE *file, char *basename)
{
char *prefix = "# ";
return hash;
}
-static int keys_are_equal(void *key1, void *key2)
+int hash_keys_are_equal(void *key1, void *key2)
{
return (strEqual((char *)key1, (char *)key2));
}
SetupFileHash *newSetupFileHash(void)
{
SetupFileHash *new_hash =
- create_hashtable(16, 0.75, get_hash_from_key, keys_are_equal);
+ create_hashtable(16, 0.75, get_hash_from_key, hash_keys_are_equal);
if (new_hash == NULL)
Fail("create_hashtable() failed -- out of memory");
// ============================================================================
#define TOKEN_STR_LAST_LEVEL_SERIES "last_level_series"
+#define TOKEN_STR_LAST_PLAYED_MENU_USED "last_played_menu_used"
#define TOKEN_STR_LAST_PLAYED_LEVEL "last_played_level"
#define TOKEN_STR_HANDICAP_LEVEL "handicap_level"
#define TOKEN_STR_LAST_USER "last_user"
#define LEVELINFO_TOKEN_FILENAME 24
#define LEVELINFO_TOKEN_FILETYPE 25
#define LEVELINFO_TOKEN_SPECIAL_FLAGS 26
-#define LEVELINFO_TOKEN_HANDICAP 27
-#define LEVELINFO_TOKEN_SKIP_LEVELS 28
-#define LEVELINFO_TOKEN_USE_EMC_TILES 29
+#define LEVELINFO_TOKEN_EMPTY_LEVEL_NAME 27
+#define LEVELINFO_TOKEN_FORCE_LEVEL_NAME 28
+#define LEVELINFO_TOKEN_HANDICAP 29
+#define LEVELINFO_TOKEN_TIME_LIMIT 30
+#define LEVELINFO_TOKEN_SKIP_LEVELS 31
+#define LEVELINFO_TOKEN_USE_EMC_TILES 32
+#define LEVELINFO_TOKEN_INFO_SCREENS_FROM_MAIN 33
-#define NUM_LEVELINFO_TOKENS 30
+#define NUM_LEVELINFO_TOKENS 34
static LevelDirTree ldi;
{ TYPE_STRING, &ldi.level_filename, "filename" },
{ TYPE_STRING, &ldi.level_filetype, "filetype" },
{ TYPE_STRING, &ldi.special_flags, "special_flags" },
+ { TYPE_STRING, &ldi.empty_level_name, "empty_level_name" },
+ { TYPE_BOOLEAN, &ldi.force_level_name, "force_level_name" },
{ TYPE_BOOLEAN, &ldi.handicap, "handicap" },
+ { TYPE_BOOLEAN, &ldi.time_limit, "time_limit" },
{ TYPE_BOOLEAN, &ldi.skip_levels, "skip_levels" },
- { TYPE_BOOLEAN, &ldi.use_emc_tiles, "use_emc_tiles" }
+ { TYPE_BOOLEAN, &ldi.use_emc_tiles, "use_emc_tiles" },
+ { TYPE_BOOLEAN, &ldi.info_screens_from_main, "info_screens_from_main" }
};
static struct TokenInfo artworkinfo_tokens[] =
ti->special_flags = NULL;
+ ti->empty_level_name = NULL;
+ ti->force_level_name = FALSE;
+
ti->levels = 0;
ti->first_level = 0;
ti->last_level = 0;
ti->handicap_level = 0;
ti->readonly = TRUE;
ti->handicap = TRUE;
+ ti->time_limit = TRUE;
ti->skip_levels = FALSE;
ti->use_emc_tiles = FALSE;
+ ti->info_screens_from_main = FALSE;
}
}
ti->special_flags = getStringCopy(parent->special_flags);
+ ti->empty_level_name = getStringCopy(parent->empty_level_name);
+ ti->force_level_name = parent->force_level_name;
+
ti->levels = parent->levels;
ti->first_level = parent->first_level;
ti->last_level = parent->last_level;
ti->handicap_level = parent->handicap_level;
ti->readonly = parent->readonly;
ti->handicap = parent->handicap;
+ ti->time_limit = parent->time_limit;
ti->skip_levels = parent->skip_levels;
ti->use_emc_tiles = parent->use_emc_tiles;
+ ti->info_screens_from_main = parent->info_screens_from_main;
}
}
ti_copy->special_flags = getStringCopy(ti->special_flags);
+ ti_copy->empty_level_name = getStringCopy(ti->empty_level_name);
+ ti_copy->force_level_name = ti->force_level_name;
+
ti_copy->levels = ti->levels;
ti_copy->first_level = ti->first_level;
ti_copy->last_level = ti->last_level;
ti_copy->user_defined = ti->user_defined;
ti_copy->readonly = ti->readonly;
ti_copy->handicap = ti->handicap;
+ ti_copy->time_limit = ti->time_limit;
ti_copy->skip_levels = ti->skip_levels;
ti_copy->use_emc_tiles = ti->use_emc_tiles;
+ ti_copy->info_screens_from_main = ti->info_screens_from_main;
ti_copy->color = ti->color;
ti_copy->class_desc = getStringCopy(ti->class_desc);
}
}
+TreeInfo *addTopTreeInfoNode(TreeInfo *node_first)
+{
+ // add top tree node with back link node in previous tree
+ node_first = createTopTreeInfoNode(node_first);
+
+ // set all parent links (back links) in complete tree
+ setTreeInfoParentNodes(node_first, NULL);
+
+ return node_first;
+}
+
// ----------------------------------------------------------------------------
// functions for handling level and custom artwork info cache
(leveldir_new->user_defined || !leveldir_new->handicap ?
leveldir_new->last_level : leveldir_new->first_level);
- DrawInitText(leveldir_new->name, 150, FC_YELLOW);
+ DrawInitTextItem(leveldir_new->name);
pushTreeInfo(node_first, leveldir_new);
level_directory, ".");
}
- if (!valid_entry_found)
+ boolean valid_entry_expected =
+ (strEqual(level_directory, options.level_directory) ||
+ setup.internal.create_user_levelset);
+
+ if (valid_entry_expected && !valid_entry_found)
Warn("cannot find any valid level series in directory '%s'",
- level_directory);
+ level_directory);
}
boolean AdjustGraphicsForEMC(void)
{
InitUserLevelDirectory(getLoginName());
- DrawInitText("Loading level series", 120, FC_GREEN);
+ DrawInitTextHead("Loading level series");
LoadLevelInfoFromLevelDir(&leveldir_first, NULL, options.level_directory);
LoadLevelInfoFromLevelDir(&leveldir_first, NULL, getUserLevelDir(NULL));
{
LoadArtworkInfoCache();
- DrawInitText("Looking for custom artwork", 120, FC_GREEN);
+ DrawInitTextHead("Looking for custom artwork");
LoadArtworkInfoFromArtworkDir(&artwork.gfx_first, NULL,
options.graphics_directory,
setArtworkInfoCacheEntry(artwork_new, level_node, type);
}
- DrawInitText(level_node->name, 150, FC_YELLOW);
+ DrawInitTextItem(level_node->name);
if (level_node->node_group != NULL)
{
LoadArtworkInfoFromLevelInfoExt(artwork_node, NULL, leveldir_first_all, TRUE);
LoadArtworkInfoFromLevelInfoExt(artwork_node, NULL, leveldir_first_all, FALSE);
- // add top tree node over all three separate sub-trees
- *artwork_node = createTopTreeInfoNode(*artwork_node);
-
- // set all parent links (back links) in complete artwork tree
- setTreeInfoParentNodes(*artwork_node, NULL);
+ // add top tree node over all sub-trees and set parent links
+ *artwork_node = addTopTreeInfoNode(*artwork_node);
}
void LoadLevelArtworkInfo(void)
{
print_timestamp_init("LoadLevelArtworkInfo");
- DrawInitText("Looking for custom level artwork", 120, FC_GREEN);
+ DrawInitTextHead("Looking for custom level artwork");
print_timestamp_time("DrawTimeText");
int i;
// create user level sub-directory, if needed
- createDirectory(getUserLevelDir(level_subdir), "user level", PERMS_PRIVATE);
+ createDirectory(getUserLevelDir(level_subdir), "user level");
filename = getPath2(getUserLevelDir(level_subdir), LEVELINFO_FILENAME);
setString(&last_level_series[0], leveldir_current->identifier);
}
-static TreeInfo *StoreOrRestoreLastPlayedLevels(TreeInfo *node, boolean store)
+#define LAST_PLAYED_MODE_SET 1
+#define LAST_PLAYED_MODE_SET_FORCED 2
+#define LAST_PLAYED_MODE_GET 3
+
+static TreeInfo *StoreOrRestoreLastPlayedLevels(TreeInfo *node, int mode)
{
static char *identifier = NULL;
- if (store)
+ if (mode == LAST_PLAYED_MODE_SET)
{
setString(&identifier, (node && node->is_copy ? node->identifier : NULL));
-
- return NULL; // not used
}
- else
+ else if (mode == LAST_PLAYED_MODE_SET_FORCED)
+ {
+ setString(&identifier, (node ? node->identifier : NULL));
+ }
+ else if (mode == LAST_PLAYED_MODE_GET)
{
TreeInfo *node_new = getTreeInfoFromIdentifierExt(leveldir_first,
identifier,
TREE_NODE_TYPE_COPY);
return (node_new != NULL ? node_new : node);
}
+
+ return NULL; // not used
}
void StoreLastPlayedLevels(TreeInfo *node)
{
- StoreOrRestoreLastPlayedLevels(node, TRUE);
+ StoreOrRestoreLastPlayedLevels(node, LAST_PLAYED_MODE_SET);
+}
+
+void ForcedStoreLastPlayedLevels(TreeInfo *node)
+{
+ StoreOrRestoreLastPlayedLevels(node, LAST_PLAYED_MODE_SET_FORCED);
}
void RestoreLastPlayedLevels(TreeInfo **node)
{
- *node = StoreOrRestoreLastPlayedLevels(*node, FALSE);
+ *node = StoreOrRestoreLastPlayedLevels(*node, LAST_PLAYED_MODE_GET);
+}
+
+boolean CheckLastPlayedLevels(void)
+{
+ return (StoreOrRestoreLastPlayedLevels(NULL, LAST_PLAYED_MODE_GET) != NULL);
}
void LoadLevelSetup_LastSeries(void)
if (leveldir_current == NULL)
leveldir_current = getFirstValidTreeInfoEntry(leveldir_first);
+ char *last_played_menu_used =
+ getHashEntry(level_setup_hash, TOKEN_STR_LAST_PLAYED_MENU_USED);
+
+ // store if last level set was selected from "last played" menu
+ if (strEqual(last_played_menu_used, "true"))
+ ForcedStoreLastPlayedLevels(leveldir_current);
+
for (i = 0; i < MAX_LEVELDIR_HISTORY; i++)
{
char token[strlen(TOKEN_STR_LAST_LEVEL_SERIES) + 10];
fprintf(file, "# %s\n# ", "the following level set may have caused a problem and was deactivated");
fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_LAST_LEVEL_SERIES,
- leveldir_current->identifier));
+ leveldir_current->identifier));
+
+ // store if last level set was selected from "last played" menu
+ boolean last_played_menu_used = CheckLastPlayedLevels();
+ char *setup_value = getSetupValue(TYPE_BOOLEAN, &last_played_menu_used);
+
+ fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_LAST_PLAYED_MENU_USED,
+ setup_value));
for (i = 0; last_level_series[i] != NULL; i++)
{
- char token[strlen(TOKEN_STR_LAST_LEVEL_SERIES) + 10];
+ char token[strlen(TOKEN_STR_LAST_LEVEL_SERIES) + 1 + 10 + 1];
sprintf(token, "%s.%03d", TOKEN_STR_LAST_LEVEL_SERIES, i);