X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Flibgame%2Fsetup.c;h=2c7dcfd7c8742db7418d6da057c59b644dc1ba83;hb=a2c9a458aaa4ac568f07ecd25b19fbca3f766e6b;hp=7754e5e4ff42861a6d25f9c681610caca47bb7c8;hpb=a19647f4f265bb23bc249aa28a10d1d47a6179e1;p=rocksndiamonds.git diff --git a/src/libgame/setup.c b/src/libgame/setup.c index 7754e5e4..2c7dcfd7 100644 --- a/src/libgame/setup.c +++ b/src/libgame/setup.c @@ -21,33 +21,11 @@ #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", @@ -60,64 +38,44 @@ static char *levelclass_desc[NUM_LEVELCLASS_DESC] = "DX Boulderdash" }; -#define LEVELCOLOR(n) (IS_LEVELCLASS_TUTORIAL(n) ? FC_BLUE : \ - IS_LEVELCLASS_CLASSICS(n) ? FC_RED : \ - IS_LEVELCLASS_BD(n) ? FC_GREEN : \ - IS_LEVELCLASS_EM(n) ? FC_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 : \ + +#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_CONTRIB(n) ? FC_GREEN : \ + IS_LEVELCLASS_PRIVATE(n) ? FC_RED : \ FC_BLUE) -#define LEVELSORTING(n) (IS_LEVELCLASS_TUTORIAL(n) ? 0 : \ - IS_LEVELCLASS_CLASSICS(n) ? 1 : \ - IS_LEVELCLASS_BD(n) ? 2 : \ - IS_LEVELCLASS_EM(n) ? 3 : \ - IS_LEVELCLASS_SP(n) ? 4 : \ - IS_LEVELCLASS_DX(n) ? 5 : \ - IS_LEVELCLASS_CONTRIBUTION(n) ? 6 : \ - IS_LEVELCLASS_USER(n) ? 7 : \ +#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_CONTRIB(n) ? 6 : \ + IS_LEVELCLASS_PRIVATE(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 ARTWORKCOLOR(n) (IS_ARTWORKCLASS_CLASSICS(n) ? FC_RED : \ + IS_ARTWORKCLASS_CONTRIB(n) ? FC_YELLOW : \ + IS_ARTWORKCLASS_PRIVATE(n) ? FC_RED : \ + IS_ARTWORKCLASS_LEVEL(n) ? FC_GREEN : \ 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 : \ - 9) +#define ARTWORKSORTING(n) (IS_ARTWORKCLASS_CLASSICS(n) ? 0 : \ + IS_ARTWORKCLASS_LEVEL(n) ? 1 : \ + IS_ARTWORKCLASS_CONTRIB(n) ? 2 : \ + IS_ARTWORKCLASS_PRIVATE(n) ? 3 : \ + 9) #define TOKEN_VALUE_POSITION 40 #define TOKEN_COMMENT_POSITION 60 #define MAX_COOKIE_LEN 256 -#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 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 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 : "") - /* ------------------------------------------------------------------------- */ /* file functions */ @@ -170,7 +128,7 @@ static char *getTapeDir(char *level_subdir) 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) @@ -267,6 +225,23 @@ static char *getDefaultMusicDir(char *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; @@ -309,47 +284,67 @@ static char *getSetupArtworkDir(TreeInfo *ti) return artwork_dir; } -void setLevelArtworkDir(TreeInfo *ti) +char *setLevelArtworkDir(TreeInfo *ti) { - char **artwork_path_ptr, *artwork_set; + char **artwork_path_ptr, **artwork_set_ptr; TreeInfo *level_artwork; if (ti == NULL || leveldir_current == NULL) - return; - - artwork_path_ptr = - (ti->type == TREE_TYPE_GRAPHICS_DIR ? &leveldir_current->graphics_path : - ti->type == TREE_TYPE_SOUNDS_DIR ? &leveldir_current->sounds_path : - &leveldir_current->music_path); - - artwork_set = - (ti->type == TREE_TYPE_GRAPHICS_DIR ? leveldir_current->graphics_set : - ti->type == TREE_TYPE_SOUNDS_DIR ? leveldir_current->sounds_set : - leveldir_current->music_set); + return NULL; - if ((level_artwork = getTreeInfoFromIdentifier(ti, artwork_set)) == NULL) - return; + artwork_path_ptr = &(LEVELDIR_ARTWORK_PATH(leveldir_current, ti->type)); + artwork_set_ptr = &(LEVELDIR_ARTWORK_SET( leveldir_current, ti->type)); if (*artwork_path_ptr != NULL) free(*artwork_path_ptr); - *artwork_path_ptr = getStringCopy(getSetupArtworkDir(level_artwork)); + 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)); + + if (*artwork_set_ptr != NULL) + 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; } -static char *getLevelArtworkDir(int type) +inline static char *getLevelArtworkSet(int type) { - char *artwork_path; + 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; - artwork_path = - (type == TREE_TYPE_GRAPHICS_DIR ? leveldir_current->graphics_path : - type == TREE_TYPE_SOUNDS_DIR ? leveldir_current->sounds_path : - type == TREE_TYPE_MUSIC_DIR ? leveldir_current->music_path : - UNDEFINED_FILENAME); - - return artwork_path; + return LEVELDIR_ARTWORK_PATH(leveldir_current, type); } char *getLevelFilename(int nr) @@ -360,7 +355,11 @@ char *getLevelFilename(int nr) if (filename != NULL) free(filename); - sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION); + if (nr < 0) + sprintf(basename, "template.%s", LEVELFILE_EXTENSION); + else + sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION); + filename = getPath2(getCurrentLevelDir(), basename); return filename; @@ -406,7 +405,7 @@ char *getSetupFilename() return filename; } -static char *getCorrectedImageBasename(char *basename) +static char *getCorrectedArtworkBasename(char *basename) { char *basename_corrected = basename; @@ -421,15 +420,17 @@ static char *getCorrectedImageBasename(char *basename) /* 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) + if (strlen(basename_corrected) > 8 + 1 + 3) { static char *msdos_filename = NULL; - if (filename != NULL) - free(filename); + if (msdos_filename != NULL) + free(msdos_filename); - filename = getStringCopy(basename_corrected); - strncpy(&filename[8], &basename[strlen(basename) - 1+3], 1+3 + 1); + msdos_filename = getStringCopy(basename_corrected); + strncpy(&msdos_filename[8], &basename[strlen(basename) - (1+3)], 1+3 +1); + + basename_corrected = msdos_filename; } } #endif @@ -437,50 +438,52 @@ static char *getCorrectedImageBasename(char *basename) return basename_corrected; } -static boolean fileExists(char *filename) -{ -#if 0 - printf("checking file '%s'\n", filename); -#endif - - return (access(filename, F_OK) == 0); -} - char *getCustomImageFilename(char *basename) { static char *filename = NULL; + boolean skip_setup_artwork = FALSE; if (filename != NULL) free(filename); - basename = getCorrectedImageBasename(basename); + basename = getCorrectedArtworkBasename(basename); if (!setup.override_level_graphics) { - /* 1st try: look for special artwork configured in level series config */ - filename = getPath2(getLevelArtworkDir(TREE_TYPE_GRAPHICS_DIR), basename); + /* 1st try: look for special artwork in current level series directory */ + filename = getPath3(getCurrentLevelDir(), GRAPHICS_DIRECTORY, basename); if (fileExists(filename)) return filename; free(filename); - /* 2nd try: look for special artwork in current level series directory */ - filename = getPath3(getCurrentLevelDir(), GRAPHICS_DIRECTORY, basename); + /* 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; + } + } + + 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 special artwork in configured artwork directory */ - filename = getPath2(getSetupArtworkDir(artwork.gfx_current), basename); - if (fileExists(filename)) - return filename; - - free(filename); - /* 4th try: look for default artwork in new default artwork directory */ - filename = getPath2(getDefaultGraphicsDir(GRAPHICS_SUBDIR), basename); + filename = getPath2(getDefaultGraphicsDir(GFX_CLASSIC_SUBDIR), basename); if (fileExists(filename)) return filename; @@ -497,36 +500,49 @@ char *getCustomImageFilename(char *basename) char *getCustomSoundFilename(char *basename) { static char *filename = NULL; + boolean skip_setup_artwork = FALSE; if (filename != NULL) free(filename); + basename = getCorrectedArtworkBasename(basename); + if (!setup.override_level_sounds) { - /* 1st try: look for special artwork configured in level series config */ - filename = getPath2(getLevelArtworkDir(TREE_TYPE_SOUNDS_DIR), basename); + /* 1st try: look for special artwork in current level series directory */ + filename = getPath3(getCurrentLevelDir(), SOUNDS_DIRECTORY, basename); if (fileExists(filename)) return filename; free(filename); - /* 2nd try: look for special artwork in current level series directory */ - filename = getPath3(getCurrentLevelDir(), SOUNDS_DIRECTORY, basename); + /* 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); } - /* 3rd try: look for special artwork in configured artwork directory */ - filename = getPath2(getSetupArtworkDir(artwork.snd_current), basename); - if (fileExists(filename)) - return filename; - - free(filename); - /* 4th try: look for default artwork in new default artwork directory */ - filename = getPath2(getDefaultSoundsDir(SOUNDS_SUBDIR), basename); + filename = getPath2(getDefaultSoundsDir(SND_CLASSIC_SUBDIR), basename); if (fileExists(filename)) return filename; @@ -555,39 +571,62 @@ char *getCustomArtworkConfigFilename(int type) return getCustomArtworkFilename(ARTWORKINFO_FILENAME(type), type); } +char *getCustomArtworkLevelConfigFilename(int type) +{ + static char *filename = NULL; + + if (filename != NULL) + 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); if (!setup.override_level_music) { - /* 1st try: look for special artwork configured in level series config */ - directory = getStringCopy(getLevelArtworkDir(TREE_TYPE_MUSIC_DIR)); + /* 1st try: look for special artwork in current level series directory */ + directory = getPath2(getCurrentLevelDir(), MUSIC_DIRECTORY); if (fileExists(directory)) return directory; free(directory); - /* 2nd try: look for special artwork in current level series directory */ - directory = getPath2(getCurrentLevelDir(), MUSIC_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); } - /* 3rd try: look for special artwork in configured artwork directory */ - directory = getStringCopy(getSetupArtworkDir(artwork.mus_current)); - if (fileExists(directory)) - return directory; - - free(directory); - /* 4th try: look for default artwork in new default artwork directory */ - directory = getStringCopy(getDefaultMusicDir(MUSIC_SUBDIR)); + directory = getStringCopy(getDefaultMusicDir(MUS_CLASSIC_SUBDIR)); if (fileExists(directory)) return directory; @@ -610,6 +649,7 @@ void InitTapeDirectory(char *level_subdir) void InitScoreDirectory(char *level_subdir) { + createDirectory(getCommonDataDir(), "common data", PERMS_PUBLIC); createDirectory(getScoreDir(NULL), "main score", PERMS_PUBLIC); createDirectory(getScoreDir(level_subdir), "level score", PERMS_PUBLIC); } @@ -776,8 +816,13 @@ void dumpTreeInfo(TreeInfo *node, int depth) for (i=0; i<(depth + 1) * 3; i++) printf(" "); +#if 1 + printf("filename == '%s' ['%s', '%s'] [%d])\n", + node->filename, node->fullpath, node->basepath, node->user_defined); +#else printf("filename == '%s' (%s) [%s] (%d)\n", node->filename, node->name, node->identifier, node->sort_priority); +#endif if (node->node_group != NULL) dumpTreeInfo(node->node_group, depth + 1); @@ -885,15 +930,33 @@ char *getUserDataDir(void) { 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() @@ -1010,7 +1073,7 @@ boolean checkCookieString(const char *cookie, const char *template) } /* ------------------------------------------------------------------------- */ -/* setup file list handling functions */ +/* setup file list and hash handling functions */ /* ------------------------------------------------------------------------- */ char *getFormattedSetupEntry(char *token, char *value) @@ -1029,87 +1092,189 @@ char *getFormattedSetupEntry(char *token, char *value) return entry; } -void freeSetupFileList(struct SetupFileList *setup_file_list) +SetupFileList *newSetupFileList(char *token, char *value) { - if (!setup_file_list) - return; + SetupFileList *new = checked_malloc(sizeof(SetupFileList)); - 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); -} - -static struct SetupFileList *newSetupFileList(char *token, char *value) -{ - struct SetupFileList *new = checked_malloc(sizeof(struct SetupFileList)); - - new->token = checked_malloc(strlen(token) + 1); - strcpy(new->token, token); - - new->value = checked_malloc(strlen(value) + 1); - strcpy(new->value, value); + new->token = getStringCopy(token); + new->value = getStringCopy(value); new->next = NULL; return new; } -char *getTokenValue(struct SetupFileList *setup_file_list, char *token) +void freeSetupFileList(SetupFileList *list) +{ + if (list == NULL) + return; + + if (list->token) + free(list->token); + if (list->value) + free(list->value); + if (list->next) + freeSetupFileList(list->next); + free(list); +} + +char *getListEntry(SetupFileList *list, char *token) { - if (!setup_file_list) + if (list == NULL) return NULL; - if (strcmp(setup_file_list->token, token) == 0) - return setup_file_list->value; + if (strcmp(list->token, token) == 0) + return list->value; else - return getTokenValue(setup_file_list->next, token); + return getListEntry(list->next, token); } -void setTokenValue(struct SetupFileList *setup_file_list, - char *token, char *value) +SetupFileList *setListEntry(SetupFileList *list, char *token, char *value) { - if (!setup_file_list) - return; + if (list == NULL) + return NULL; - if (strcmp(setup_file_list->token, token) == 0) + if (strcmp(list->token, token) == 0) { - free(setup_file_list->value); - setup_file_list->value = checked_malloc(strlen(value) + 1); - strcpy(setup_file_list->value, value); + if (list->value) + free(list->value); + + list->value = getStringCopy(value); + + return list; } - else if (setup_file_list->next == NULL) - setup_file_list->next = newSetupFileList(token, value); + else if (list->next == NULL) + return (list->next = newSetupFileList(token, value)); else - setTokenValue(setup_file_list->next, token, value); + return setListEntry(list->next, token, value); } #ifdef DEBUG -static void printSetupFileList(struct SetupFileList *setup_file_list) +static void printSetupFileList(SetupFileList *list) { - if (!setup_file_list) + if (!list) return; - printf("token: '%s'\n", setup_file_list->token); - printf("value: '%s'\n", setup_file_list->value); + printf("token: '%s'\n", list->token); + printf("value: '%s'\n", list->value); - printSetupFileList(setup_file_list->next); + printSetupFileList(list->next); } #endif -struct SetupFileList *loadSetupFileList(char *filename) +#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) +{ + /* + djb2 + + 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. + + 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. + + 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; +} + +static int keys_are_equal(void *key1, void *key2) +{ + return (strcmp((char *)key1, (char *)key2) == 0); +} + +SetupFileHash *newSetupFileHash() +{ + SetupFileHash *new_hash = + create_hashtable(16, 0.75, get_hash_from_key, keys_are_equal); + + return new_hash; +} + +void freeSetupFileHash(SetupFileHash *hash) +{ + if (hash == NULL) + return; + + hashtable_destroy(hash, 1); /* 1 == also free values stored in hash */ +} + +char *getHashEntry(SetupFileHash *hash, char *token) +{ + if (hash == NULL) + return NULL; + + return search_hash_entry(hash, token); +} + +void setHashEntry(SetupFileHash *hash, char *token, char *value) +{ + char *value_copy; + + if (hash == NULL) + return; + + 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"); +} + +#if 0 +#ifdef DEBUG +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 +#endif + +static void *loadSetupFileData(char *filename, boolean use_hash) { int line_len; char 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; FILE *file; + if (use_hash) + setup_file_data = newSetupFileHash(); + else + insert_ptr = setup_file_data = newSetupFileList("", ""); + if (!(file = fopen(filename, MODE_READ))) { Error(ERR_WARN, "cannot open configuration file '%s'", filename); @@ -1169,47 +1334,57 @@ struct SetupFileList *loadSetupFileList(char *filename) break; if (*token && *value) - setTokenValue(setup_file_list, token, value); + { + if (use_hash) + setHashEntry((SetupFileHash *)setup_file_data, token, value); + else + insert_ptr = setListEntry((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); + setup_file_data = first_valid_list_entry; - /* free empty list header */ - setup_file_list->next = NULL; - freeSetupFileList(setup_file_list); + 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 setup_file_data; +} - return first_valid_list_entry; +SetupFileList *loadSetupFileList(char *filename) +{ + return (SetupFileList *)loadSetupFileData(filename, FALSE); } -void checkSetupFileListIdentifier(struct SetupFileList *setup_file_list, - char *identifier) +SetupFileHash *loadSetupFileHash(char *filename) { - if (!setup_file_list) - return; + return (SetupFileHash *)loadSetupFileData(filename, TRUE); +} - 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; - } +void checkSetupFileHashIdentifier(SetupFileHash *setup_file_hash, + char *identifier) +{ + char *value = getHashEntry(setup_file_hash, TOKEN_STR_FILE_IDENTIFIER); - if (setup_file_list->next) - checkSetupFileListIdentifier(setup_file_list->next, identifier); - else - { + if (value == NULL) Error(ERR_WARN, "configuration file has no file identifier"); - return; - } + else if (!checkCookieString(value, identifier)) + Error(ERR_WARN, "configuration file has wrong file identifier"); } @@ -1230,13 +1405,14 @@ void checkSetupFileListIdentifier(struct SetupFileList *setup_file_list, #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 LEVELINFO_TOKEN_GRAPHICS_SET 10 -#define LEVELINFO_TOKEN_SOUNDS_SET 11 -#define LEVELINFO_TOKEN_MUSIC_SET 12 +#define LEVELINFO_TOKEN_LATEST_ENGINE 8 +#define LEVELINFO_TOKEN_LEVEL_GROUP 9 +#define LEVELINFO_TOKEN_READONLY 10 +#define LEVELINFO_TOKEN_GRAPHICS_SET 11 +#define LEVELINFO_TOKEN_SOUNDS_SET 12 +#define LEVELINFO_TOKEN_MUSIC_SET 13 -#define NUM_LEVELINFO_TOKENS 13 +#define NUM_LEVELINFO_TOKENS 14 static LevelDirTree ldi; @@ -1251,6 +1427,7 @@ static struct TokenInfo levelinfo_tokens[] = { 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" }, @@ -1284,6 +1461,7 @@ static void setTreeInfoToDefaults(TreeInfo *ldi, int type) 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->user_defined = FALSE; ldi->color = 0; @@ -1292,12 +1470,14 @@ static void setTreeInfoToDefaults(TreeInfo *ldi, int type) if (ldi->type == TREE_TYPE_LEVEL_DIR) { ldi->imported_from = 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->levels = 0; ldi->first_level = 0; ldi->last_level = 0; @@ -1313,10 +1493,61 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ldi, TreeInfo *parent) { Error(ERR_WARN, "setTreeInfoToDefaultsFromParent(): parent == NULL"); - setTreeInfoToDefaults(ldi, TREE_TYPE_GENERIC); + setTreeInfoToDefaults(ldi, TREE_TYPE_UNDEFINED); + return; } +#if 1 + /* copy all values from the parent structure */ + + 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->fullpath = NULL; + ldi->basepath = NULL; + ldi->identifier = NULL; + ldi->name = getStringCopy(ANONYMOUS_NAME); + ldi->name_sorting = NULL; + ldi->author = getStringCopy(parent->author); + + ldi->sort_priority = parent->sort_priority; + ldi->latest_engine = parent->latest_engine; + ldi->parent_link = FALSE; + ldi->user_defined = parent->user_defined; + ldi->color = parent->color; + ldi->class_desc = getStringCopy(parent->class_desc); + + if (ldi->type == TREE_TYPE_LEVEL_DIR) + { + ldi->imported_from = getStringCopy(parent->imported_from); + + 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->levels = 0; + ldi->first_level = 0; + ldi->last_level = 0; + ldi->level_group = FALSE; + ldi->handicap_level = 0; + ldi->readonly = TRUE; + } + + +#else + /* first copy all values from the parent structure ... */ *ldi = *parent; @@ -1334,7 +1565,16 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ldi, TreeInfo *parent) ldi->name = getStringCopy(ANONYMOUS_NAME); ldi->name_sorting = NULL; ldi->author = getStringCopy(parent->author); + ldi->imported_from = getStringCopy(parent->imported_from); + ldi->class_desc = getStringCopy(parent->class_desc); + + ldi->graphics_set = NULL; + ldi->sounds_set = NULL; + ldi->music_set = NULL; + ldi->graphics_path = NULL; + ldi->sounds_path = NULL; + ldi->music_path = NULL; ldi->level_group = FALSE; ldi->parent_link = FALSE; @@ -1343,6 +1583,47 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ldi, TreeInfo *parent) ldi->node_parent = parent; ldi->node_group = NULL; ldi->next = NULL; + +#endif +} + +static void freeTreeInfo(TreeInfo *ldi) +{ + if (ldi->filename) + free(ldi->filename); + if (ldi->fullpath) + free(ldi->fullpath); + if (ldi->basepath) + free(ldi->basepath); + if (ldi->identifier) + free(ldi->identifier); + + if (ldi->name) + free(ldi->name); + if (ldi->name_sorting) + free(ldi->name_sorting); + if (ldi->author) + free(ldi->author); + + if (ldi->class_desc) + free(ldi->class_desc); + + if (ldi->type == TREE_TYPE_LEVEL_DIR) + { + if (ldi->graphics_set) + free(ldi->graphics_set); + if (ldi->sounds_set) + free(ldi->sounds_set); + if (ldi->music_set) + free(ldi->music_set); + + if (ldi->graphics_path) + free(ldi->graphics_path); + if (ldi->sounds_path) + free(ldi->sounds_path); + if (ldi->music_path) + free(ldi->music_path); + } } void setSetupInfo(struct TokenInfo *token_info, @@ -1436,6 +1717,19 @@ static void createParentTreeInfoNode(TreeInfo *node_parent) ti_new->node_parent = node_parent; ti_new->parent_link = TRUE; +#if 1 + setString(&ti_new->identifier, node_parent->identifier); + setString(&ti_new->name, ".. (parent directory)"); + setString(&ti_new->name_sorting, ti_new->name); + + setString(&ti_new->filename, ".."); + setString(&ti_new->fullpath, node_parent->fullpath); + + ti_new->sort_priority = node_parent->sort_priority; + ti_new->latest_engine = node_parent->latest_engine; + + setString(&ti_new->class_desc, getLevelClassDescription(ti_new)); +#else ti_new->identifier = getStringCopy(node_parent->identifier); ti_new->name = ".. (parent directory)"; ti_new->name_sorting = getStringCopy(ti_new->name); @@ -1444,7 +1738,10 @@ static void createParentTreeInfoNode(TreeInfo *node_parent) ti_new->fullpath = getStringCopy(node_parent->fullpath); ti_new->sort_priority = node_parent->sort_priority; + ti_new->latest_engine = node_parent->latest_engine; + ti_new->class_desc = getLevelClassDescription(ti_new); +#endif pushTreeInfo(&node_parent->node_group, ti_new); } @@ -1459,11 +1756,11 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first, { 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 = loadSetupFileHash(filename); LevelDirTree *leveldir_new = NULL; int i; - if (setup_file_list == NULL) + if (setup_file_hash == NULL) { Error(ERR_WARN, "ignoring level directory '%s'", directory_path); @@ -1482,20 +1779,25 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first, leveldir_new->filename = getStringCopy(directory_name); - checkSetupFileListIdentifier(setup_file_list, getCookie("LEVELINFO")); + checkSetupFileHashIdentifier(setup_file_hash, getCookie("LEVELINFO")); /* set all structure fields according to the token/value pairs */ ldi = *leveldir_new; for (i=0; iname, ANONYMOUS_NAME) == 0) + setString(&leveldir_new->name, leveldir_new->filename); +#else if (strcmp(leveldir_new->name, ANONYMOUS_NAME) == 0) { free(leveldir_new->name); leveldir_new->name = getStringCopy(leveldir_new->filename); } +#endif DrawInitText(leveldir_new->name, 150, FC_YELLOW); @@ -1507,12 +1809,12 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first, 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->filename); } 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); } @@ -1522,11 +1824,20 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first, leveldir_new->last_level = leveldir_new->first_level + leveldir_new->levels - 1; +#if 1 + leveldir_new->user_defined = + (strcmp(leveldir_new->basepath, options.level_directory) != 0); +#else leveldir_new->user_defined = (leveldir_new->basepath == options.level_directory ? FALSE : TRUE); +#endif leveldir_new->color = LEVELCOLOR(leveldir_new); +#if 1 + setString(&leveldir_new->class_desc, getLevelClassDescription(leveldir_new)); +#else leveldir_new->class_desc = getLevelClassDescription(leveldir_new); +#endif leveldir_new->handicap_level = /* set handicap to default value */ (leveldir_new->user_defined ? @@ -1535,7 +1846,7 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first, pushTreeInfo(node_first, leveldir_new); - freeSetupFileList(setup_file_list); + freeSetupFileHash(setup_file_hash); if (leveldir_new->level_group) { @@ -1644,14 +1955,14 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_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); + 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; @@ -1694,24 +2005,29 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first, artwork_new->filename = 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, getCookie("...")); #endif /* set all structure fields according to the token/value pairs */ ldi = *artwork_new; for (i=0; iname, ANONYMOUS_NAME) == 0) + setString(&artwork_new->name, artwork_new->filename); +#else if (strcmp(artwork_new->name, ANONYMOUS_NAME) == 0) { free(artwork_new->name); artwork_new->name = getStringCopy(artwork_new->filename); } +#endif #if 0 DrawInitText(artwork_new->name, 150, FC_YELLOW); @@ -1735,49 +2051,93 @@ static boolean LoadArtworkInfoFromArtworkConf(TreeInfo **node_first, artwork_new->fullpath = getPath2(node_parent->fullpath, directory_name); } +#if 1 + artwork_new->user_defined = + (strcmp(artwork_new->basepath, OPTIONS_ARTWORK_DIRECTORY(type)) != 0); +#else artwork_new->user_defined = (artwork_new->basepath == OPTIONS_ARTWORK_DIRECTORY(type) ? FALSE : TRUE); +#endif - /* (may use ".sort_priority" from "setup_file_list" above) */ + /* (may use ".sort_priority" from "setup_file_hash" above) */ artwork_new->color = ARTWORKCOLOR(artwork_new); +#if 1 + setString(&artwork_new->class_desc, getLevelClassDescription(artwork_new)); +#else artwork_new->class_desc = getLevelClassDescription(artwork_new); +#endif - if (setup_file_list == NULL) /* (after determining ".user_defined") */ + if (setup_file_hash == NULL) /* (after determining ".user_defined") */ { +#if 0 if (artwork_new->name != NULL) + { free(artwork_new->name); + artwork_new->name = NULL; + } +#endif + +#if 0 + if (artwork_new->identifier != NULL) + { + free(artwork_new->identifier); + artwork_new->identifier = NULL; + } +#endif if (strcmp(artwork_new->filename, ".") == 0) { if (artwork_new->user_defined) { +#if 1 + setString(&artwork_new->identifier, "private"); +#else artwork_new->identifier = getStringCopy("private"); - artwork_new->sort_priority = ARTWORKCLASS_USER; +#endif + artwork_new->sort_priority = ARTWORKCLASS_PRIVATE; } else { +#if 1 + setString(&artwork_new->identifier, "classic"); +#else artwork_new->identifier = getStringCopy("classic"); +#endif artwork_new->sort_priority = ARTWORKCLASS_CLASSICS; } /* set to new values after changing ".sort_priority" */ artwork_new->color = ARTWORKCOLOR(artwork_new); +#if 1 + setString(&artwork_new->class_desc, + getLevelClassDescription(artwork_new)); +#else artwork_new->class_desc = getLevelClassDescription(artwork_new); +#endif } else { +#if 1 + setString(&artwork_new->identifier, artwork_new->filename); +#else artwork_new->identifier = getStringCopy(artwork_new->filename); +#endif } +#if 1 + setString(&artwork_new->name, artwork_new->identifier); + setString(&artwork_new->name_sorting, artwork_new->name); +#else artwork_new->name = getStringCopy(artwork_new->identifier); artwork_new->name_sorting = getStringCopy(artwork_new->name); +#endif } 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); @@ -1848,6 +2208,15 @@ static TreeInfo *getDummyArtworkInfo(int type) setTreeInfoToDefaults(artwork_new, type); +#if 1 + setString(&artwork_new->filename, UNDEFINED_FILENAME); + setString(&artwork_new->fullpath, UNDEFINED_FILENAME); + setString(&artwork_new->basepath, UNDEFINED_FILENAME); + + setString(&artwork_new->identifier, UNDEFINED_FILENAME); + setString(&artwork_new->name, UNDEFINED_FILENAME); + setString(&artwork_new->name_sorting, UNDEFINED_FILENAME); +#else artwork_new->filename = getStringCopy(UNDEFINED_FILENAME); artwork_new->fullpath = getStringCopy(UNDEFINED_FILENAME); artwork_new->basepath = getStringCopy(UNDEFINED_FILENAME); @@ -1858,6 +2227,7 @@ static TreeInfo *getDummyArtworkInfo(int type) artwork_new->identifier = getStringCopy(UNDEFINED_FILENAME); artwork_new->name = getStringCopy(UNDEFINED_FILENAME); artwork_new->name_sorting = getStringCopy(UNDEFINED_FILENAME); +#endif return artwork_new; } @@ -1897,16 +2267,25 @@ void LoadArtworkInfo() /* before sorting, the first entries will be from the user directory */ 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); 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); 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); @@ -1987,10 +2366,14 @@ void LoadLevelArtworkInfo() LoadArtworkInfoFromLevelInfo(&artwork.mus_first, leveldir_first); /* 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); } @@ -1999,6 +2382,9 @@ void LoadLevelArtworkInfo() { 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); } @@ -2007,6 +2393,9 @@ void LoadLevelArtworkInfo() { 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); } @@ -2024,6 +2413,7 @@ void LoadLevelArtworkInfo() static void SaveUserLevelInfo() { + LevelDirTree *level_info; char *filename; FILE *file; int i; @@ -2037,22 +2427,37 @@ static void SaveUserLevelInfo() return; } - /* always start with reliable default values */ - setTreeInfoToDefaults(&ldi, TREE_TYPE_LEVEL_DIR); + level_info = newTreeInfo(); + /* always start with reliable default values */ + setTreeInfoToDefaults(level_info, TREE_TYPE_LEVEL_DIR); + +#if 1 + setString(&level_info->name, getLoginName()); + setString(&level_info->author, getRealName()); + level_info->levels = 100; + level_info->first_level = 1; + level_info->sort_priority = LEVELCLASS_PRIVATE_START; + level_info->readonly = FALSE; + setString(&level_info->graphics_set, GFX_CLASSIC_SUBDIR); + setString(&level_info->sounds_set, SND_CLASSIC_SUBDIR); + setString(&level_info->music_set, MUS_CLASSIC_SUBDIR); +#else ldi.name = getStringCopy(getLoginName()); ldi.author = getStringCopy(getRealName()); ldi.levels = 100; ldi.first_level = 1; - ldi.sort_priority = LEVELCLASS_USER_START; + ldi.sort_priority = LEVELCLASS_PRIVATE_START; ldi.readonly = FALSE; - ldi.graphics_set = getStringCopy(GRAPHICS_SUBDIR); - ldi.sounds_set = getStringCopy(SOUNDS_SUBDIR); - ldi.music_set = getStringCopy(MUSIC_SUBDIR); + ldi.graphics_set = getStringCopy(GFX_CLASSIC_SUBDIR); + ldi.sounds_set = getStringCopy(SND_CLASSIC_SUBDIR); + ldi.music_set = getStringCopy(MUS_CLASSIC_SUBDIR); +#endif fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, getCookie("LEVELINFO"))); + ldi = *level_info; for (i=0; ifirst_level) { Error(ERR_WARN, "additional level %d found", levelnum_value); @@ -2257,6 +2666,7 @@ static void checkSeriesInfo() Error(ERR_WARN, "additional level %d found", levelnum_value); leveldir_current->last_level = levelnum_value; } +#endif } } @@ -2266,7 +2676,7 @@ static void checkSeriesInfo() void LoadLevelSetup_SeriesInfo() { char *filename; - struct SetupFileList *level_setup_list = NULL; + SetupFileHash *level_setup_hash = NULL; char *level_subdir = leveldir_current->filename; /* always start with reliable default values */ @@ -2282,11 +2692,11 @@ void LoadLevelSetup_SeriesInfo() 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) { @@ -2298,7 +2708,7 @@ void LoadLevelSetup_SeriesInfo() 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) { @@ -2315,9 +2725,9 @@ void LoadLevelSetup_SeriesInfo() leveldir_current->handicap_level = level_nr; } - checkSetupFileListIdentifier(level_setup_list, getCookie("LEVELSETUP")); + checkSetupFileHashIdentifier(level_setup_hash, getCookie("LEVELSETUP")); - freeSetupFileList(level_setup_list); + freeSetupFileHash(level_setup_hash); } else Error(ERR_WARN, "using default setup values"); @@ -2356,7 +2766,8 @@ void SaveLevelSetup_SeriesInfo() handicap_level_str)); fclose(file); - free(filename); SetFilePermissions(filename, PERMS_PRIVATE); + + free(filename); }