X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Ffiles.c;h=67f0168c42fbf64e068c11cb09a53017662a500f;hb=d2587727d750fdf2aae4eb8f4acb487a5c211041;hp=7e1ad30bc6dafa99c5a9478dc6929c6a34b41678;hpb=48542a06103232c408ce6250f5bc2d9add00f233;p=rocksndiamonds.git diff --git a/src/files.c b/src/files.c index 7e1ad30b..67f0168c 100644 --- a/src/files.c +++ b/src/files.c @@ -26,14 +26,15 @@ #define MAX_LINE_LEN 1000 /* maximal input line length */ #define CHUNK_ID_LEN 4 /* IFF style chunk id length */ #define LEVEL_HEADER_SIZE 80 /* size of level file header */ -#define LEVEL_HEADER_UNUSED 16 /* unused level header bytes */ +#define LEVEL_HEADER_UNUSED 15 /* unused level header bytes */ #define TAPE_HEADER_SIZE 20 /* size of tape file header */ #define TAPE_HEADER_UNUSED 7 /* unused tape header bytes */ -#define FILE_VERSION_1_0 10 /* old 1.0 file version */ -#define FILE_VERSION_1_2 12 /* actual file version */ +#define FILE_VERSION_1_0 10 /* 1.0 file version (old) */ +#define FILE_VERSION_1_2 12 /* 1.2 file version (still in use) */ +#define FILE_VERSION_1_4 14 /* 1.4 file version (new) */ /* file identifier strings */ -#define LEVEL_COOKIE "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_1.2" +#define LEVEL_COOKIE "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_1.4" #define SCORE_COOKIE "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2" #define TAPE_COOKIE "ROCKSNDIAMONDS_TAPE_FILE_VERSION_1.2" #define SETUP_COOKIE "ROCKSNDIAMONDS_SETUP_FILE_VERSION_1.2" @@ -41,11 +42,13 @@ #define LEVELINFO_COOKIE "ROCKSNDIAMONDS_LEVELINFO_FILE_VERSION_1.2" /* old file identifiers for backward compatibility */ #define LEVEL_COOKIE_10 "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_1.0" +#define LEVEL_COOKIE_12 "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_1.2" #define TAPE_COOKIE_10 "ROCKSNDIAMONDS_LEVELREC_FILE_VERSION_1.0" /* file names and filename extensions */ #ifndef MSDOS #define USERDATA_DIRECTORY ".rocksndiamonds" +#define LEVELSETUP_DIRECTORY "levelsetup" #define SETUP_FILENAME "setup.conf" #define LEVELSETUP_FILENAME "levelsetup.conf" #define LEVELINFO_FILENAME "levelinfo.conf" @@ -54,6 +57,7 @@ #define SCOREFILE_EXTENSION "score" #else #define USERDATA_DIRECTORY "userdata" +#define LEVELSETUP_DIRECTORY "lvlsetup" #define SETUP_FILENAME "setup.cnf" #define LEVELSETUP_FILENAME "lvlsetup.cnf" #define LEVELINFO_FILENAME "lvlinfo.cnf" @@ -82,36 +86,103 @@ #define LEVELCLASS_CONTRIBUTION_END 299 #define LEVELCLASS_USER_START 300 #define LEVELCLASS_USER_END 399 +#define LEVELCLASS_BD_START 400 +#define LEVELCLASS_BD_END 499 +#define LEVELCLASS_EM_START 500 +#define LEVELCLASS_EM_END 599 +#define LEVELCLASS_SP_START 600 +#define LEVELCLASS_SP_END 699 +#define LEVELCLASS_DX_START 700 +#define LEVELCLASS_DX_END 799 #define LEVELCLASS_TUTORIAL LEVELCLASS_TUTORIAL_START #define LEVELCLASS_CLASSICS LEVELCLASS_CLASSICS_START #define LEVELCLASS_CONTRIBUTION LEVELCLASS_CONTRIBUTION_START #define LEVELCLASS_USER LEVELCLASS_USER_START +#define LEVELCLASS_BD LEVELCLASS_BD_START +#define LEVELCLASS_EM LEVELCLASS_EM_START +#define LEVELCLASS_SP LEVELCLASS_SP_START +#define LEVELCLASS_DX LEVELCLASS_DX_START + #define LEVELCLASS_UNDEFINED 999 -#define IS_LEVELCLASS_TUTORIAL(n) \ - (leveldir[n].sort_priority >= LEVELCLASS_TUTORIAL_START && \ - leveldir[n].sort_priority <= LEVELCLASS_TUTORIAL_END) -#define IS_LEVELCLASS_CLASSICS(n) \ - (leveldir[n].sort_priority >= LEVELCLASS_CLASSICS_START && \ - leveldir[n].sort_priority <= LEVELCLASS_CLASSICS_END) -#define IS_LEVELCLASS_CONTRIBUTION(n) \ - (leveldir[n].sort_priority >= LEVELCLASS_CONTRIBUTION_START && \ - leveldir[n].sort_priority <= LEVELCLASS_CONTRIBUTION_END) -#define IS_LEVELCLASS_USER(n) \ - (leveldir[n].sort_priority >= LEVELCLASS_USER_START && \ - leveldir[n].sort_priority <= LEVELCLASS_USER_END) +#define NUM_LEVELCLASS_DESC 8 +char *levelclass_desc[NUM_LEVELCLASS_DESC] = +{ + "Tutorial Levels", + "Classic Originals", + "Contributions", + "Private Levels", + "Boulderdash", + "Emerald Mine", + "Supaplex", + "DX Boulderdash" +}; + +#define IS_LEVELCLASS_TUTORIAL(p) \ + ((p)->sort_priority >= LEVELCLASS_TUTORIAL_START && \ + (p)->sort_priority <= LEVELCLASS_TUTORIAL_END) +#define IS_LEVELCLASS_CLASSICS(p) \ + ((p)->sort_priority >= LEVELCLASS_CLASSICS_START && \ + (p)->sort_priority <= LEVELCLASS_CLASSICS_END) +#define IS_LEVELCLASS_CONTRIBUTION(p) \ + ((p)->sort_priority >= LEVELCLASS_CONTRIBUTION_START && \ + (p)->sort_priority <= LEVELCLASS_CONTRIBUTION_END) +#define IS_LEVELCLASS_USER(p) \ + ((p)->sort_priority >= LEVELCLASS_USER_START && \ + (p)->sort_priority <= LEVELCLASS_USER_END) +#define IS_LEVELCLASS_BD(p) \ + ((p)->sort_priority >= LEVELCLASS_BD_START && \ + (p)->sort_priority <= LEVELCLASS_BD_END) +#define IS_LEVELCLASS_EM(p) \ + ((p)->sort_priority >= LEVELCLASS_EM_START && \ + (p)->sort_priority <= LEVELCLASS_EM_END) +#define IS_LEVELCLASS_SP(p) \ + ((p)->sort_priority >= LEVELCLASS_SP_START && \ + (p)->sort_priority <= LEVELCLASS_SP_END) +#define IS_LEVELCLASS_DX(p) \ + ((p)->sort_priority >= LEVELCLASS_DX_START && \ + (p)->sort_priority <= LEVELCLASS_DX_END) #define LEVELCLASS(n) (IS_LEVELCLASS_TUTORIAL(n) ? LEVELCLASS_TUTORIAL : \ IS_LEVELCLASS_CLASSICS(n) ? LEVELCLASS_CLASSICS : \ IS_LEVELCLASS_CONTRIBUTION(n) ? LEVELCLASS_CONTRIBUTION : \ IS_LEVELCLASS_USER(n) ? LEVELCLASS_USER : \ + IS_LEVELCLASS_BD(n) ? LEVELCLASS_BD : \ + IS_LEVELCLASS_EM(n) ? LEVELCLASS_EM : \ + IS_LEVELCLASS_SP(n) ? LEVELCLASS_SP : \ + IS_LEVELCLASS_DX(n) ? LEVELCLASS_DX : \ LEVELCLASS_UNDEFINED) -#define LEVELCOLOR(n) (IS_LEVELCLASS_TUTORIAL(n) ? FC_BLUE : \ - IS_LEVELCLASS_CLASSICS(n) ? FC_YELLOW : \ - IS_LEVELCLASS_CONTRIBUTION(n) ? FC_GREEN : \ - IS_LEVELCLASS_USER(n) ? FC_RED : FC_BLUE) +#define LEVELCOLOR(n) (IS_LEVELCLASS_TUTORIAL(n) ? FC_BLUE : \ + IS_LEVELCLASS_CLASSICS(n) ? FC_RED : \ + IS_LEVELCLASS_BD(n) ? FC_GREEN : \ + IS_LEVELCLASS_EM(n) ? FC_YELLOW : \ + IS_LEVELCLASS_SP(n) ? FC_GREEN : \ + IS_LEVELCLASS_DX(n) ? FC_YELLOW : \ + IS_LEVELCLASS_CONTRIBUTION(n) ? FC_GREEN : \ + IS_LEVELCLASS_USER(n) ? FC_RED : \ + FC_BLUE) + +#define LEVELSORTING(n) (IS_LEVELCLASS_TUTORIAL(n) ? 0 : \ + IS_LEVELCLASS_CLASSICS(n) ? 1 : \ + IS_LEVELCLASS_BD(n) ? 2 : \ + IS_LEVELCLASS_EM(n) ? 3 : \ + IS_LEVELCLASS_SP(n) ? 4 : \ + IS_LEVELCLASS_DX(n) ? 5 : \ + IS_LEVELCLASS_CONTRIBUTION(n) ? 6 : \ + IS_LEVELCLASS_USER(n) ? 7 : \ + 9) + +char *getLevelClassDescription(struct LevelDirInfo *ldi) +{ + int position = ldi->sort_priority / 100; + + if (position >= 0 && position < NUM_LEVELCLASS_DESC) + return levelclass_desc[position]; + else + return "Unknown Level Class"; +} static void SaveUserLevelInfo(); /* for 'InitUserLevelDir()' */ static char *getSetupLine(char *, int); /* for 'SaveUserLevelInfo()' */ @@ -187,6 +258,23 @@ static char *getScoreDir(char *level_subdir) return score_dir; } +static char *getLevelSetupDir(char *level_subdir) +{ + static char *levelsetup_dir = NULL; + char *data_dir = getUserDataDir(); + char *levelsetup_subdir = LEVELSETUP_DIRECTORY; + + if (levelsetup_dir) + free(levelsetup_dir); + + if (strlen(level_subdir) > 0) + levelsetup_dir = getPath3(data_dir, levelsetup_subdir, level_subdir); + else + levelsetup_dir = getPath2(data_dir, levelsetup_subdir); + + return levelsetup_dir; +} + static char *getLevelFilename(int nr) { static char *filename = NULL; @@ -270,6 +358,13 @@ static void InitUserLevelDirectory(char *level_subdir) } } +static void InitLevelSetupDirectory(char *level_subdir) +{ + createDirectory(getUserDataDir(), "user data"); + createDirectory(getLevelSetupDir(""), "main level setup"); + createDirectory(getLevelSetupDir(level_subdir), "level setup"); +} + static void setLevelInfoToDefaults() { int i, x, y; @@ -286,6 +381,8 @@ static void setLevelInfoToDefaults() level.amoeba_speed = 10; level.time_magic_wall = 10; level.time_wheel = 10; + level.time_light = 10; + level.time_timegate = 10; level.amoeba_content = EL_DIAMANT; level.double_speed = FALSE; level.gravity = FALSE; @@ -321,7 +418,7 @@ static void setLevelInfoToDefaults() } else { - switch (LEVELCLASS(leveldir_nr)) + switch (LEVELCLASS(&leveldir[leveldir_nr])) { case LEVELCLASS_TUTORIAL: strcpy(level.author, PROGRAM_AUTHOR_STRING); @@ -350,7 +447,8 @@ void LoadLevel(int level_nr) char *filename = getLevelFilename(level_nr); char cookie[MAX_LINE_LEN]; char chunk[CHUNK_ID_LEN + 1]; - int file_version = FILE_VERSION_1_2; /* last version of level files */ + boolean encoding_16bit = FALSE; /* default: maximal 256 elements */ + int file_version = FILE_VERSION_1_4; /* last version of level files */ int chunk_length; FILE *file; @@ -370,6 +468,8 @@ void LoadLevel(int level_nr) if (strcmp(cookie, LEVEL_COOKIE_10) == 0) /* old 1.0 level format */ file_version = FILE_VERSION_1_0; + else if (strcmp(cookie, LEVEL_COOKIE_12) == 0)/* 1.2 (8 bit) level format */ + file_version = FILE_VERSION_1_2; else if (strcmp(cookie, LEVEL_COOKIE) != 0) /* unknown level format */ { Error(ERR_WARN, "wrong file identifier of level file '%s'", filename); @@ -424,10 +524,11 @@ void LoadLevel(int level_nr) level.double_speed = (fgetc(file) == 1 ? TRUE : FALSE); level.gravity = (fgetc(file) == 1 ? TRUE : FALSE); + encoding_16bit = (fgetc(file) == 1 ? TRUE : FALSE); + for(i=0; i= FILE_VERSION_1_2) { getFileChunk(file, chunk, &chunk_length, BYTE_ORDER_BIG_ENDIAN); @@ -451,10 +552,23 @@ void LoadLevel(int level_nr) fgetc(file); fgetc(file); + if (level.num_yam_contents < 1 || + level.num_yam_contents > MAX_ELEMENT_CONTENTS) + { +#if DEBUG + printf("WARNING: num_yam_contents == %d (corrected)\n", + level.num_yam_contents); +#endif + level.num_yam_contents = STD_ELEMENT_CONTENTS; + } + for(i=0; i 255) + encoding_16bit = TRUE; + + /* check level field for 16-bit elements */ + for(y=0; y 255) + encoding_16bit = TRUE; + + oldest_possible_cookie = (encoding_16bit ? LEVEL_COOKIE : LEVEL_COOKIE_12); + + fputs(oldest_possible_cookie, file); /* file identifier */ fputc('\n', file); putFileChunk(file, "HEAD", LEVEL_HEADER_SIZE, BYTE_ORDER_BIG_ENDIAN); @@ -523,7 +657,7 @@ void SaveLevel(int level_nr) for(i=0; ifilename = NULL; ldi->name = getStringCopy(ANONYMOUS_NAME); ldi->name_short = NULL; ldi->author = getStringCopy(ANONYMOUS_NAME); + ldi->imported_from = NULL; ldi->levels = 0; ldi->first_level = 0; + ldi->last_level = 0; ldi->sort_priority = LEVELCLASS_UNDEFINED; /* default: least priority */ ldi->readonly = TRUE; + ldi->user_defined = FALSE; + ldi->color = 0; + ldi->class_desc = NULL; + ldi->handicap_level = 0; } static void setSetupInfoToDefaults(struct SetupInfo *si) @@ -1267,6 +1434,9 @@ static void setSetupInfoToDefaults(struct SetupInfo *si) si->fading = FALSE; si->autorecord = TRUE; si->quick_doors = FALSE; + si->team_mode = FALSE; + si->handicap = TRUE; + si->time_limit = TRUE; for (i=0; i leveldir[level_series_nr].last_level) - last_level_nr = leveldir[level_series_nr].last_level; - } - - return last_level_nr; -} - static int compareLevelDirInfoEntries(const void *object1, const void *object2) { const struct LevelDirInfo *entry1 = object1; const struct LevelDirInfo *entry2 = object2; int compare_result; - if (entry1->sort_priority != entry2->sort_priority) - compare_result = entry1->sort_priority - entry2->sort_priority; - else + if (entry1->sort_priority == entry2->sort_priority) { - char *name1 = getStringToLower(entry1->name); - char *name2 = getStringToLower(entry2->name); + char *name1 = getStringToLower(entry1->name_short); + char *name2 = getStringToLower(entry2->name_short); compare_result = strcmp(name1, name2); free(name1); free(name2); } + else if (LEVELSORTING(entry1) == LEVELSORTING(entry2)) + compare_result = entry1->sort_priority - entry2->sort_priority; + else + compare_result = LEVELSORTING(entry1) - LEVELSORTING(entry2); return compare_result; } @@ -1474,7 +1622,9 @@ static int LoadLevelInfoFromLevelDir(char *level_directory, int start_entry) leveldir[current_entry].levels - 1; leveldir[current_entry].user_defined = (level_directory == options.level_directory ? FALSE : TRUE); - leveldir[current_entry].color = LEVELCOLOR(current_entry); + leveldir[current_entry].color = LEVELCOLOR(&leveldir[current_entry]); + leveldir[current_entry].class_desc = + getLevelClassDescription(&leveldir[current_entry]); freeSetupFileList(setup_file_list); current_entry++; @@ -1538,7 +1688,6 @@ static void SaveUserLevelInfo() setLevelDirInfoToDefaults(&ldi); ldi.name = getLoginName(); - ldi.name_short = getLoginName(); ldi.author = getRealName(); ldi.levels = 100; ldi.first_level = 1; @@ -1549,7 +1698,8 @@ static void SaveUserLevelInfo() getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, LEVELINFO_COOKIE)); for (i=FIRST_LEVELINFO_TOKEN; i<=LAST_LEVELINFO_TOKEN; i++) - fprintf(file, "%s\n", getSetupLine("", i)); + if (i != LEVELINFO_TOKEN_NAME_SHORT && i != LEVELINFO_TOKEN_IMPORTED_FROM) + fprintf(file, "%s\n", getSetupLine("", i)); fclose(file); free(filename); @@ -1710,54 +1860,48 @@ void SaveSetup() chmod(filename, SETUP_PERMS); } -void LoadLevelSetup() +void LoadLevelSetup_LastSeries() { char *filename; + struct SetupFileList *level_setup_list = NULL; /* always start with reliable default values */ leveldir_nr = 0; - level_nr = 0; - filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME); + /* ----------------------------------------------------------------------- */ + /* ~/.rocksndiamonds/levelsetup.conf */ + /* ----------------------------------------------------------------------- */ - if (level_setup_list) - freeSetupFileList(level_setup_list); - - level_setup_list = loadSetupFileList(filename); + filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME); - if (level_setup_list) + if ((level_setup_list = loadSetupFileList(filename))) { char *last_level_series = getTokenValue(level_setup_list, TOKEN_STR_LAST_LEVEL_SERIES); leveldir_nr = getLevelSeriesNrFromLevelSeriesName(last_level_series); - level_nr = getLastPlayedLevelOfLevelSeries(last_level_series); checkSetupFileListIdentifier(level_setup_list, LEVELSETUP_COOKIE); + + freeSetupFileList(level_setup_list); } else - { - level_setup_list = newSetupFileList(TOKEN_STR_FILE_IDENTIFIER, - LEVELSETUP_COOKIE); Error(ERR_WARN, "using default setup values"); - } free(filename); } -void SaveLevelSetup() +void SaveLevelSetup_LastSeries() { char *filename; - struct SetupFileList *list_entry = level_setup_list; + char *level_subdir = leveldir[leveldir_nr].filename; FILE *file; - InitUserDataDirectory(); - - setTokenValue(level_setup_list, - TOKEN_STR_LAST_LEVEL_SERIES, leveldir[leveldir_nr].filename); + /* ----------------------------------------------------------------------- */ + /* ~/.rocksndiamonds/levelsetup.conf */ + /* ----------------------------------------------------------------------- */ - setTokenValue(level_setup_list, - leveldir[leveldir_nr].filename, int2str(level_nr, 0)); + InitUserDataDirectory(); filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME); @@ -1770,18 +1914,102 @@ void SaveLevelSetup() fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, LEVELSETUP_COOKIE)); - while (list_entry) + fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_LAST_LEVEL_SERIES, + level_subdir)); + + fclose(file); + free(filename); + + chmod(filename, SETUP_PERMS); +} + +void LoadLevelSetup_SeriesInfo(int leveldir_nr) +{ + char *filename; + struct SetupFileList *level_setup_list = NULL; + char *level_subdir = leveldir[leveldir_nr].filename; + + /* always start with reliable default values */ + level_nr = 0; + leveldir[leveldir_nr].handicap_level = 0; + + /* ----------------------------------------------------------------------- */ + /* ~/.rocksndiamonds/levelsetup//levelsetup.conf */ + /* ----------------------------------------------------------------------- */ + + level_subdir = leveldir[leveldir_nr].filename; + + filename = getPath2(getLevelSetupDir(level_subdir), LEVELSETUP_FILENAME); + + if ((level_setup_list = loadSetupFileList(filename))) { - if (strcmp(list_entry->token, TOKEN_STR_FILE_IDENTIFIER) != 0) - fprintf(file, "%s\n", - getFormattedSetupEntry(list_entry->token, list_entry->value)); + char *token_value; - /* just to make things nicer :) */ - if (strcmp(list_entry->token, TOKEN_STR_LAST_LEVEL_SERIES) == 0) - fprintf(file, "\n"); + token_value = getTokenValue(level_setup_list, TOKEN_STR_LAST_PLAYED_LEVEL); + + if (token_value) + { + level_nr = atoi(token_value); + + if (level_nr < leveldir[leveldir_nr].first_level) + level_nr = leveldir[leveldir_nr].first_level; + if (level_nr > leveldir[leveldir_nr].last_level) + level_nr = leveldir[leveldir_nr].last_level; + } - list_entry = list_entry->next; + token_value = getTokenValue(level_setup_list, TOKEN_STR_HANDICAP_LEVEL); + + if (token_value) + { + int level_nr = atoi(token_value); + + if (level_nr < leveldir[leveldir_nr].first_level) + level_nr = leveldir[leveldir_nr].first_level; + if (level_nr > leveldir[leveldir_nr].last_level + 1) + level_nr = leveldir[leveldir_nr].last_level; + + leveldir[leveldir_nr].handicap_level = level_nr; + } + + checkSetupFileListIdentifier(level_setup_list, LEVELSETUP_COOKIE); + + freeSetupFileList(level_setup_list); } + else + Error(ERR_WARN, "using default setup values"); + + free(filename); +} + +void SaveLevelSetup_SeriesInfo(int leveldir_nr) +{ + char *filename; + char *level_subdir = leveldir[leveldir_nr].filename; + char *level_nr_str = int2str(level_nr, 0); + char *handicap_level_str = int2str(leveldir[leveldir_nr].handicap_level, 0); + FILE *file; + + /* ----------------------------------------------------------------------- */ + /* ~/.rocksndiamonds/levelsetup//levelsetup.conf */ + /* ----------------------------------------------------------------------- */ + + InitLevelSetupDirectory(level_subdir); + + filename = getPath2(getLevelSetupDir(level_subdir), LEVELSETUP_FILENAME); + + if (!(file = fopen(filename, "w"))) + { + Error(ERR_WARN, "cannot write setup file '%s'", filename); + free(filename); + return; + } + + fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, + LEVELSETUP_COOKIE)); + fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_LAST_PLAYED_LEVEL, + level_nr_str)); + fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_HANDICAP_LEVEL, + handicap_level_str)); fclose(file); free(filename);