X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Flibgame%2Fsetup.c;h=b7e34adf1b3d2ab8267102e7cb48731f9d9be03d;hb=f965a2a6e56dd5c1e91b306dfd52b38b1dd49537;hp=39165b06574461dbcfc22e8a97e709612c721c61;hpb=43d8239a719759a411bc31e0330e5e1cb353c32e;p=rocksndiamonds.git diff --git a/src/libgame/setup.c b/src/libgame/setup.c index 39165b06..b7e34adf 100644 --- a/src/libgame/setup.c +++ b/src/libgame/setup.c @@ -262,14 +262,14 @@ static char *getDefaultMusicDir(char *music_subdir) return music_dir; } -static char *getDefaultArtworkSet(int type) +static char *getClassicArtworkSet(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) +static char *getClassicArtworkDir(int type) { return (type == TREE_TYPE_GRAPHICS_DIR ? getDefaultGraphicsDir(GFX_CLASSIC_SUBDIR) : @@ -334,15 +334,23 @@ char *setLevelArtworkDir(TreeInfo *ti) 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. */ + /* + 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. + + Update: For "special" versions of R'n'D (like "R'n'D jue"), do not use + the "default" artwork (which would be "jue0" for "R'n'D jue"), but use + the real "classic" artwork from the original R'n'D (like "gfx_classic"). + */ char *dir = getPath2(getCurrentLevelDir(), ARTWORK_DIRECTORY(ti->type)); @@ -350,8 +358,8 @@ char *setLevelArtworkDir(TreeInfo *ti) if (fileExists(dir)) { - *artwork_path_ptr = getStringCopy(getDefaultArtworkDir(ti->type)); - *artwork_set_ptr = getStringCopy(getDefaultArtworkSet(ti->type)); + *artwork_path_ptr = getStringCopy(getClassicArtworkDir(ti->type)); + *artwork_set_ptr = getStringCopy(getClassicArtworkSet(ti->type)); } else { @@ -404,6 +412,19 @@ char *getSolutionTapeFilename(int nr) sprintf(basename, "%03d.%s", nr, TAPEFILE_EXTENSION); filename = getPath2(getSolutionTapeDir(), basename); + if (!fileExists(filename)) + { + static char *filename_sln = NULL; + + checked_free(filename_sln); + + sprintf(basename, "%03d.sln", nr); + filename_sln = getPath2(getSolutionTapeDir(), basename); + + if (fileExists(filename_sln)) + return filename_sln; + } + return filename; } @@ -498,38 +519,80 @@ char *getLevelSetInfoFilename() return NULL; } -char *getLevelSetTitleMessageFilename(int nr, boolean initial) +char *getLevelSetTitleMessageBasename(int nr, boolean initial) { - static char *filename = NULL; -#if 1 - char *filename_from_artwork; -#endif - char basename[32]; + static char basename[32]; sprintf(basename, "%s_%d.txt", (initial ? "titlemessage_initial" : "titlemessage"), nr + 1); -#if 1 - /* 1st try: look for message file in all relevant graphics directories */ - if ((filename_from_artwork = getCustomImageFilename(basename)) != NULL) - return filename_from_artwork; -#endif + return basename; +} -#if 1 - /* forced custom graphics also override messages in level set directory */ - if (!setup.override_level_graphics) -#endif +char *getLevelSetTitleMessageFilename(int nr, boolean initial) +{ + static char *filename = NULL; + char *basename; + boolean skip_setup_artwork = FALSE; + + checked_free(filename); + + basename = getLevelSetTitleMessageBasename(nr, initial); + + if (!gfx.override_level_graphics) { - checked_free(filename); + /* 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 message file in current level set directory */ filename = getPath2(getCurrentLevelDir(), 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) + { + /* 3rd 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) + { + /* 4th try: look for special artwork in configured artwork directory */ + filename = getPath2(getSetupArtworkDir(artwork.gfx_current), basename); if (fileExists(filename)) return filename; + + free(filename); } - return NULL; + /* 5th try: look for default artwork in new default artwork directory */ + filename = getPath2(getDefaultGraphicsDir(GFX_DEFAULT_SUBDIR), basename); + if (fileExists(filename)) + return filename; + + free(filename); + + /* 6th try: look for default artwork in old default artwork directory */ + filename = getPath2(options.graphics_directory, basename); + if (fileExists(filename)) + return filename; + + return NULL; /* cannot find specified artwork file anywhere */ } static char *getCorrectedArtworkBasename(char *basename) @@ -573,7 +636,7 @@ char *getCustomImageFilename(char *basename) basename = getCorrectedArtworkBasename(basename); - if (!setup.override_level_graphics) + if (!gfx.override_level_graphics) { /* 1st try: look for special artwork in current level series directory */ filename = getPath3(getCurrentLevelDir(), GRAPHICS_DIRECTORY, basename); @@ -608,7 +671,7 @@ char *getCustomImageFilename(char *basename) } /* 4th try: look for default artwork in new default artwork directory */ - filename = getPath2(getDefaultGraphicsDir(GFX_CLASSIC_SUBDIR), basename); + filename = getPath2(getDefaultGraphicsDir(GFX_DEFAULT_SUBDIR), basename); if (fileExists(filename)) return filename; @@ -619,10 +682,14 @@ char *getCustomImageFilename(char *basename) if (fileExists(filename)) return filename; -#if CREATE_SPECIAL_EDITION +#if defined(CREATE_SPECIAL_EDITION) free(filename); + if (options.debug) + Error(ERR_WARN, "cannot find artwork file '%s' (using fallback)", basename); + /* 6th try: look for fallback artwork in old default artwork directory */ + /* (needed to prevent errors when trying to access unused artwork files) */ filename = getPath2(options.graphics_directory, GFX_FALLBACK_FILENAME); if (fileExists(filename)) return filename; @@ -640,7 +707,7 @@ char *getCustomSoundFilename(char *basename) basename = getCorrectedArtworkBasename(basename); - if (!setup.override_level_sounds) + if (!gfx.override_level_sounds) { /* 1st try: look for special artwork in current level series directory */ filename = getPath3(getCurrentLevelDir(), SOUNDS_DIRECTORY, basename); @@ -675,7 +742,7 @@ char *getCustomSoundFilename(char *basename) } /* 4th try: look for default artwork in new default artwork directory */ - filename = getPath2(getDefaultSoundsDir(SND_CLASSIC_SUBDIR), basename); + filename = getPath2(getDefaultSoundsDir(SND_DEFAULT_SUBDIR), basename); if (fileExists(filename)) return filename; @@ -686,10 +753,14 @@ char *getCustomSoundFilename(char *basename) if (fileExists(filename)) return filename; -#if CREATE_SPECIAL_EDITION +#if defined(CREATE_SPECIAL_EDITION) free(filename); + if (options.debug) + Error(ERR_WARN, "cannot find artwork file '%s' (using fallback)", basename); + /* 6th try: look for fallback artwork in old default artwork directory */ + /* (needed to prevent errors when trying to access unused artwork files) */ filename = getPath2(options.sounds_directory, SND_FALLBACK_FILENAME); if (fileExists(filename)) return filename; @@ -707,7 +778,7 @@ char *getCustomMusicFilename(char *basename) basename = getCorrectedArtworkBasename(basename); - if (!setup.override_level_music) + if (!gfx.override_level_music) { /* 1st try: look for special artwork in current level series directory */ filename = getPath3(getCurrentLevelDir(), MUSIC_DIRECTORY, basename); @@ -742,7 +813,7 @@ char *getCustomMusicFilename(char *basename) } /* 4th try: look for default artwork in new default artwork directory */ - filename = getPath2(getDefaultMusicDir(MUS_CLASSIC_SUBDIR), basename); + filename = getPath2(getDefaultMusicDir(MUS_DEFAULT_SUBDIR), basename); if (fileExists(filename)) return filename; @@ -753,10 +824,14 @@ char *getCustomMusicFilename(char *basename) if (fileExists(filename)) return filename; -#if CREATE_SPECIAL_EDITION +#if defined(CREATE_SPECIAL_EDITION) free(filename); + if (options.debug) + Error(ERR_WARN, "cannot find artwork file '%s' (using fallback)", basename); + /* 6th try: look for fallback artwork in old default artwork directory */ + /* (needed to prevent errors when trying to access unused artwork files) */ filename = getPath2(options.music_directory, MUS_FALLBACK_FILENAME); if (fileExists(filename)) return filename; @@ -800,7 +875,7 @@ char *getCustomMusicDirectory(void) checked_free(directory); - if (!setup.override_level_music) + if (!gfx.override_level_music) { /* 1st try: look for special artwork in current level series directory */ directory = getPath2(getCurrentLevelDir(), MUSIC_DIRECTORY); @@ -835,7 +910,7 @@ char *getCustomMusicDirectory(void) } /* 4th try: look for default artwork in new default artwork directory */ - directory = getStringCopy(getDefaultMusicDir(MUS_CLASSIC_SUBDIR)); + directory = getStringCopy(getDefaultMusicDir(MUS_DEFAULT_SUBDIR)); if (fileExists(directory)) return directory; @@ -1348,21 +1423,41 @@ static int posix_mkdir(const char *pathname, mode_t mode) #endif } +static boolean posix_process_running_setgid() +{ +#if defined(PLATFORM_UNIX) + return (getgid() != getegid()); +#else + return FALSE; +#endif +} + void createDirectory(char *dir, char *text, int permission_class) { /* leave "other" permissions in umask untouched, but ensure group parts of USERDATA_DIR_MODE are not masked */ mode_t dir_mode = (permission_class == PERMS_PRIVATE ? DIR_PERMS_PRIVATE : DIR_PERMS_PUBLIC); - mode_t normal_umask = posix_umask(0); + mode_t last_umask = posix_umask(0); mode_t group_umask = ~(dir_mode & S_IRWXG); - posix_umask(normal_umask & group_umask); + int running_setgid = posix_process_running_setgid(); + + /* if we're setgid, protect files against "other" */ + /* else keep umask(0) to make the dir world-writable */ + + if (running_setgid) + posix_umask(last_umask & group_umask); + else + dir_mode |= MODE_W_ALL; if (!fileExists(dir)) if (posix_mkdir(dir, dir_mode) != 0) Error(ERR_WARN, "cannot create %s directory '%s'", text, dir); - posix_umask(normal_umask); /* reset normal umask */ + if (permission_class == PERMS_PUBLIC && !running_setgid) + chmod(dir, dir_mode); + + posix_umask(last_umask); /* restore previous umask */ } void InitUserDataDirectory() @@ -1372,8 +1467,14 @@ void InitUserDataDirectory() void SetFilePermissions(char *filename, int permission_class) { - chmod(filename, (permission_class == PERMS_PRIVATE ? - FILE_PERMS_PRIVATE : FILE_PERMS_PUBLIC)); + int running_setgid = posix_process_running_setgid(); + int perms = (permission_class == PERMS_PRIVATE ? + FILE_PERMS_PRIVATE : FILE_PERMS_PUBLIC); + + if (permission_class == PERMS_PUBLIC && !running_setgid) + perms |= MODE_W_ALL; + + chmod(filename, perms); } char *getCookie(char *file_type) @@ -1554,7 +1655,7 @@ DEFINE_HASHTABLE_REMOVE(remove_hash_entry, char, char); #define remove_hash_entry hashtable_remove #endif -static unsigned int get_hash_from_key(void *key) +unsigned int get_hash_from_key(void *key) { /* djb2 @@ -2313,10 +2414,11 @@ void checkSetupFileHashIdentifier(SetupFileHash *setup_file_hash, #define LEVELINFO_TOKEN_MUSIC_SET 18 #define LEVELINFO_TOKEN_FILENAME 19 #define LEVELINFO_TOKEN_FILETYPE 20 -#define LEVELINFO_TOKEN_HANDICAP 21 -#define LEVELINFO_TOKEN_SKIP_LEVELS 22 +#define LEVELINFO_TOKEN_SPECIAL_FLAGS 21 +#define LEVELINFO_TOKEN_HANDICAP 22 +#define LEVELINFO_TOKEN_SKIP_LEVELS 23 -#define NUM_LEVELINFO_TOKENS 23 +#define NUM_LEVELINFO_TOKENS 24 static LevelDirTree ldi; @@ -2344,6 +2446,7 @@ static struct TokenInfo levelinfo_tokens[] = { TYPE_STRING, &ldi.music_set, "music_set" }, { TYPE_STRING, &ldi.level_filename, "filename" }, { TYPE_STRING, &ldi.level_filetype, "filetype" }, + { TYPE_STRING, &ldi.special_flags, "special_flags" }, { TYPE_BOOLEAN, &ldi.handicap, "handicap" }, { TYPE_BOOLEAN, &ldi.skip_levels, "skip_levels" } }; @@ -2420,6 +2523,8 @@ static void setTreeInfoToDefaults(TreeInfo *ti, int type) ti->level_filename = NULL; ti->level_filetype = NULL; + ti->special_flags = NULL; + ti->levels = 0; ti->first_level = 0; ti->last_level = 0; @@ -2491,12 +2596,18 @@ static void setTreeInfoToDefaultsFromParent(TreeInfo *ti, TreeInfo *parent) ti->level_filename = NULL; ti->level_filetype = NULL; + ti->special_flags = getStringCopy(parent->special_flags); + ti->levels = 0; ti->first_level = 0; ti->last_level = 0; ti->level_group = FALSE; ti->handicap_level = 0; +#if 1 + ti->readonly = parent->readonly; +#else ti->readonly = TRUE; +#endif ti->handicap = TRUE; ti->skip_levels = FALSE; } @@ -2542,6 +2653,8 @@ static TreeInfo *getTreeInfoCopy(TreeInfo *ti) ti_copy->level_filename = getStringCopy(ti->level_filename); ti_copy->level_filetype = getStringCopy(ti->level_filetype); + ti_copy->special_flags = getStringCopy(ti->special_flags); + ti_copy->levels = ti->levels; ti_copy->first_level = ti->first_level; ti_copy->last_level = ti->last_level; @@ -2603,6 +2716,8 @@ static void freeTreeInfo(TreeInfo *ti) checked_free(ti->level_filename); checked_free(ti->level_filetype); + + checked_free(ti->special_flags); } checked_free(ti); @@ -2625,6 +2740,10 @@ void setSetupInfo(struct TokenInfo *token_info, *(boolean *)setup_value = get_boolean_from_string(token_value); break; + case TYPE_SWITCH3: + *(int *)setup_value = get_switch3_from_string(token_value); + break; + case TYPE_KEY: *(Key *)setup_value = getKeyFromKeyName(token_value); break; @@ -2774,14 +2893,18 @@ static char *getCacheToken(char *prefix, char *suffix) return token; } -static char *getFileTimestamp(char *filename) +static char *getFileTimestampString(char *filename) { +#if 1 + return getStringCopy(i_to_a(getFileTimestampEpochSeconds(filename))); +#else struct stat file_status; if (stat(filename, &file_status) != 0) /* cannot stat file */ return getStringCopy(i_to_a(0)); return getStringCopy(i_to_a(file_status.st_mtime)); +#endif } static boolean modifiedFileTimestamp(char *filename, char *timestamp_string) @@ -2898,8 +3021,8 @@ static void setArtworkInfoCacheEntry(TreeInfo *artwork_info, LEVELINFO_FILENAME); char *filename_artworkinfo = getPath2(getSetupArtworkDir(artwork_info), ARTWORKINFO_FILENAME(type)); - char *timestamp_levelinfo = getFileTimestamp(filename_levelinfo); - char *timestamp_artworkinfo = getFileTimestamp(filename_artworkinfo); + char *timestamp_levelinfo = getFileTimestampString(filename_levelinfo); + char *timestamp_artworkinfo = getFileTimestampString(filename_artworkinfo); token_main = getCacheToken(token_prefix, "TIMESTAMP_LEVELINFO"); setHashEntry(artworkinfo_cache_new, token_main, timestamp_levelinfo); @@ -3018,6 +3141,12 @@ static boolean LoadLevelInfoFromLevelConf(TreeInfo **node_first, leveldir_new->in_user_dir = (!strEqual(leveldir_new->basepath, options.level_directory)); +#if 0 + printf("::: '%s' -> %d\n", + leveldir_new->identifier, + leveldir_new->in_user_dir); +#endif + /* adjust some settings if user's private level directory was detected */ if (leveldir_new->sort_priority == LEVELCLASS_UNDEFINED && leveldir_new->in_user_dir && @@ -3451,7 +3580,7 @@ void LoadArtworkInfo() getTreeInfoFromIdentifier(artwork.gfx_first, setup.graphics_set); if (artwork.gfx_current == NULL) artwork.gfx_current = - getTreeInfoFromIdentifier(artwork.gfx_first, GFX_CLASSIC_SUBDIR); + getTreeInfoFromIdentifier(artwork.gfx_first, GFX_DEFAULT_SUBDIR); if (artwork.gfx_current == NULL) artwork.gfx_current = getFirstValidTreeInfoEntry(artwork.gfx_first); @@ -3459,7 +3588,7 @@ void LoadArtworkInfo() getTreeInfoFromIdentifier(artwork.snd_first, setup.sounds_set); if (artwork.snd_current == NULL) artwork.snd_current = - getTreeInfoFromIdentifier(artwork.snd_first, SND_CLASSIC_SUBDIR); + getTreeInfoFromIdentifier(artwork.snd_first, SND_DEFAULT_SUBDIR); if (artwork.snd_current == NULL) artwork.snd_current = getFirstValidTreeInfoEntry(artwork.snd_first); @@ -3467,7 +3596,7 @@ void LoadArtworkInfo() getTreeInfoFromIdentifier(artwork.mus_first, setup.music_set); if (artwork.mus_current == NULL) artwork.mus_current = - getTreeInfoFromIdentifier(artwork.mus_first, MUS_CLASSIC_SUBDIR); + getTreeInfoFromIdentifier(artwork.mus_first, MUS_DEFAULT_SUBDIR); if (artwork.mus_current == NULL) artwork.mus_current = getFirstValidTreeInfoEntry(artwork.mus_first); @@ -3577,7 +3706,7 @@ void LoadLevelArtworkInfo() getTreeInfoFromIdentifier(artwork.gfx_first, setup.graphics_set); if (artwork.gfx_current == NULL) artwork.gfx_current = - getTreeInfoFromIdentifier(artwork.gfx_first, GFX_CLASSIC_SUBDIR); + getTreeInfoFromIdentifier(artwork.gfx_first, GFX_DEFAULT_SUBDIR); if (artwork.gfx_current == NULL) artwork.gfx_current = getFirstValidTreeInfoEntry(artwork.gfx_first); } @@ -3588,7 +3717,7 @@ void LoadLevelArtworkInfo() getTreeInfoFromIdentifier(artwork.snd_first, setup.sounds_set); if (artwork.snd_current == NULL) artwork.snd_current = - getTreeInfoFromIdentifier(artwork.snd_first, SND_CLASSIC_SUBDIR); + getTreeInfoFromIdentifier(artwork.snd_first, SND_DEFAULT_SUBDIR); if (artwork.snd_current == NULL) artwork.snd_current = getFirstValidTreeInfoEntry(artwork.snd_first); } @@ -3599,7 +3728,7 @@ void LoadLevelArtworkInfo() getTreeInfoFromIdentifier(artwork.mus_first, setup.music_set); if (artwork.mus_current == NULL) artwork.mus_current = - getTreeInfoFromIdentifier(artwork.mus_first, MUS_CLASSIC_SUBDIR); + getTreeInfoFromIdentifier(artwork.mus_first, MUS_DEFAULT_SUBDIR); if (artwork.mus_current == NULL) artwork.mus_current = getFirstValidTreeInfoEntry(artwork.mus_first); } @@ -3687,10 +3816,20 @@ char *getSetupValue(int type, void *value) strcpy(value_string, (*(boolean *)value ? "on" : "off")); break; + case TYPE_SWITCH3: + strcpy(value_string, (*(int *)value == AUTO ? "auto" : + *(int *)value == FALSE ? "off" : "on")); + break; + case TYPE_YES_NO: strcpy(value_string, (*(boolean *)value ? "yes" : "no")); break; + case TYPE_YES_NO_AUTO: + strcpy(value_string, (*(int *)value == AUTO ? "auto" : + *(int *)value == FALSE ? "no" : "yes")); + break; + case TYPE_ECS_AGA: strcpy(value_string, (*(boolean *)value ? "AGA" : "ECS")); break; @@ -3775,6 +3914,13 @@ void LoadLevelSetup_LastSeries() /* always start with reliable default values */ leveldir_current = getFirstValidTreeInfoEntry(leveldir_first); +#if defined(CREATE_SPECIAL_EDITION_RND_JUE) + leveldir_current = getTreeInfoFromIdentifier(leveldir_first, + "jue_start"); + if (leveldir_current == NULL) + leveldir_current = getFirstValidTreeInfoEntry(leveldir_first); +#endif + if ((level_setup_hash = loadSetupFileHash(filename))) { char *last_level_series =