#include "tape.h"
#include "joystick.h"
-#define MAX_LINE_LEN 1000 /* file 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 18 /* 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 MAX_FILENAME_LEN 256 /* maximal filename length */
+#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 18 /* 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 */
+
+/* file identifier strings */
+#define LEVEL_COOKIE "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_1.2"
+#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"
+#define LEVELSETUP_COOKIE "ROCKSNDIAMONDS_LEVELSETUP_FILE_VERSION_1.2"
+#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 TAPE_COOKIE_10 "ROCKSNDIAMONDS_LEVELREC_FILE_VERSION_1.0"
+
+/* file names and filename extensions */
+#ifndef MSDOS
+#define USERDATA_DIRECTORY ".rocksndiamonds"
+#define SETUP_FILENAME "setup.conf"
+#define LEVELSETUP_FILENAME "levelsetup.conf"
+#define LEVELINFO_FILENAME "levelinfo.conf"
+#define LEVELFILE_EXTENSION "level"
+#define TAPEFILE_EXTENSION "tape"
+#define SCOREFILE_EXTENSION "score"
+#else
+#define USERDATA_DIRECTORY "userdata"
+#define SETUP_FILENAME "setup.cnf"
+#define LEVELSETUP_FILENAME "lvlsetup.cnf"
+#define LEVELINFO_FILENAME "lvlinfo.cnf"
+#define LEVELFILE_EXTENSION "lvl"
+#define TAPEFILE_EXTENSION "rec"
+#define SCOREFILE_EXTENSION "sco"
+#endif
+
+/* file permissions for newly written files */
+#define MODE_R_ALL (S_IRUSR | S_IRGRP | S_IROTH)
+#define MODE_W_ALL (S_IWUSR | S_IWGRP | S_IWOTH)
+#define MODE_X_ALL (S_IXUSR | S_IXGRP | S_IXOTH)
+#define USERDATA_DIR_MODE (MODE_R_ALL | MODE_X_ALL | S_IWUSR)
+#define LEVEL_PERMS (MODE_R_ALL | MODE_W_ALL)
+#define SCORE_PERMS LEVEL_PERMS
+#define TAPE_PERMS LEVEL_PERMS
+#define SETUP_PERMS LEVEL_PERMS
static void SaveUserLevelInfo(); /* for 'InitUserLevelDir()' */
static char *getSetupLine(char *, int); /* for 'SaveUserLevelInfo()' */
return score_dir;
}
+static char *getLevelFilename(int nr)
+{
+ static char *filename = NULL;
+ char basename[20 + strlen(LEVELFILE_EXTENSION)];
+
+ if (filename != NULL)
+ free(filename);
+
+ sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION);
+ filename = getPath3((leveldir[leveldir_nr].user_defined ?
+ getUserLevelDir("") :
+ options.level_directory),
+ leveldir[leveldir_nr].filename,
+ basename);
+
+ return filename;
+}
+
+static char *getTapeFilename(int nr)
+{
+ static char *filename = NULL;
+ char basename[20 + strlen(LEVELFILE_EXTENSION)];
+
+ if (filename != NULL)
+ free(filename);
+
+ sprintf(basename, "%03d.%s", nr, TAPEFILE_EXTENSION);
+ filename = getPath2(getTapeDir(leveldir[leveldir_nr].filename), basename);
+
+ return filename;
+}
+
+static char *getScoreFilename(int nr)
+{
+ static char *filename = NULL;
+ char basename[20 + strlen(LEVELFILE_EXTENSION)];
+
+ if (filename != NULL)
+ free(filename);
+
+ sprintf(basename, "%03d.%s", nr, SCOREFILE_EXTENSION);
+ filename = getPath2(getScoreDir(leveldir[leveldir_nr].filename), basename);
+
+ return filename;
+}
+
static void createDirectory(char *dir, char *text)
{
if (access(dir, F_OK) != 0)
static void InitTapeDirectory(char *level_subdir)
{
+ createDirectory(getUserDataDir(), "user data");
createDirectory(getTapeDir(""), "main tape");
createDirectory(getTapeDir(level_subdir), "level tape");
}
{
if (access(getUserLevelDir(level_subdir), F_OK) != 0)
{
+ createDirectory(getUserDataDir(), "user data");
createDirectory(getUserLevelDir(""), "main user level");
createDirectory(getUserLevelDir(level_subdir), "user level");
strcpy(level.name, "Nameless Level");
- for(i=0; i<MAX_LEVSCORE_ENTRIES; i++)
+ for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
level.score[i] = 10;
for(i=0; i<4; i++)
void LoadLevel(int level_nr)
{
int i, x, y;
- char filename[MAX_FILENAME_LEN];
+ 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 */
/* always start with reliable default values */
setLevelInfoToDefaults();
- if (leveldir[leveldir_nr].user_defined)
- sprintf(filename, "%s/%s/%d",
- getUserLevelDir(""), leveldir[leveldir_nr].filename, level_nr);
- else
- sprintf(filename, "%s/%s/%d",
- options.level_directory, leveldir[leveldir_nr].filename, level_nr);
-
if (!(file = fopen(filename, "r")))
{
Error(ERR_WARN, "cannot read level '%s' - creating new level", filename);
level.name[i] = fgetc(file);
level.name[MAX_LEVNAMLEN - 1] = 0;
- for(i=0; i<MAX_LEVSCORE_ENTRIES; i++)
+ for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
level.score[i] = fgetc(file);
for(i=0; i<4; i++)
void SaveLevel(int level_nr)
{
int i, x, y;
- char filename[MAX_FILENAME_LEN];
+ char *filename = getLevelFilename(level_nr);
FILE *file;
int chunk_length;
- if (leveldir[leveldir_nr].user_defined)
- sprintf(filename, "%s/%s/%d",
- getUserLevelDir(""), leveldir[leveldir_nr].filename, level_nr);
- else
- sprintf(filename, "%s/%s/%d",
- options.level_directory, leveldir[leveldir_nr].filename, level_nr);
-
if (!(file = fopen(filename, "w")))
{
Error(ERR_WARN, "cannot save level file '%s'", filename);
for(i=0; i<MAX_LEVNAMLEN; i++)
fputc(level.name[i], file);
- for(i=0; i<MAX_LEVSCORE_ENTRIES; i++)
+ for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
fputc(level.score[i], file);
for(i=0; i<4; i++)
for(y=0; y<3; y++)
void LoadTape(int level_nr)
{
int i, j;
- char filename[MAX_FILENAME_LEN];
+ char *filename = getTapeFilename(level_nr);
char cookie[MAX_LINE_LEN];
char chunk[CHUNK_ID_LEN + 1];
FILE *file;
- boolean player_participates[MAX_PLAYERS];
int num_participating_players;
int file_version = FILE_VERSION_1_2; /* last version of tape files */
int chunk_length;
- sprintf(filename, "%s/%d.%s",
- getTapeDir(leveldir[leveldir_nr].filename),
- level_nr, TAPEFILE_EXTENSION);
-
if (!(file = fopen(filename, "r")))
return;
num_participating_players = 0;
for(i=0; i<MAX_PLAYERS; i++)
{
- player_participates[i] = FALSE;
+ tape.player_participates[i] = FALSE;
if (store_participating_players & (1 << i))
{
- player_participates[i] = TRUE;
+ tape.player_participates[i] = TRUE;
num_participating_players++;
}
}
if (file_version == FILE_VERSION_1_0 && j > 0)
continue;
- if (player_participates[j])
+ if (tape.player_participates[j])
tape.pos[i].action[j] = fgetc(file);
}
void SaveTape(int level_nr)
{
- int i, j;
- char filename[MAX_FILENAME_LEN];
+ int i;
+ char *filename = getTapeFilename(level_nr);
FILE *file;
boolean new_tape = TRUE;
- boolean player_participates[MAX_PLAYERS];
byte store_participating_players;
int num_participating_players;
int chunk_length;
InitTapeDirectory(leveldir[leveldir_nr].filename);
- sprintf(filename, "%s/%d.%s",
- getTapeDir(leveldir[leveldir_nr].filename),
- level_nr, TAPEFILE_EXTENSION);
-
/* if a tape still exists, ask to overwrite it */
- if ((file = fopen(filename, "r")))
+ if (access(filename, F_OK) == 0)
{
new_tape = FALSE;
- fclose(file);
-
if (!Request("Replace old tape ?", REQ_ASK))
return;
}
- for(i=0; i<MAX_PLAYERS; i++)
- player_participates[i] = FALSE;
-
- /* check which players participate in this tape recording */
- for(i=0; i<tape.length; i++)
- for(j=0; j<MAX_PLAYERS; j++)
- if (tape.pos[i].action[j] != 0)
- player_participates[j] = TRUE;
-
/* count number of players and set corresponding bits for compact storage */
store_participating_players = 0;
num_participating_players = 0;
for(i=0; i<MAX_PLAYERS; i++)
{
- if (player_participates[i])
+ if (tape.player_participates[i])
{
num_participating_players++;
store_participating_players |= (1 << i);
int j;
for(j=0; j<MAX_PLAYERS; j++)
- if (player_participates[j])
+ if (tape.player_participates[j])
fputc(tape.pos[i].action[j], file);
fputc(tape.pos[i].delay, file);
fclose(file);
- chmod(filename, LEVREC_PERMS);
+ chmod(filename, TAPE_PERMS);
tape.changed = FALSE;
void LoadScore(int level_nr)
{
int i;
- char filename[MAX_FILENAME_LEN];
+ char *filename = getScoreFilename(level_nr);
char cookie[MAX_LINE_LEN];
char line[MAX_LINE_LEN];
char *line_ptr;
FILE *file;
- /* start with empty score table */
+ /* always start with reliable default values */
for(i=0; i<MAX_SCORE_ENTRIES; i++)
{
strcpy(highscore[i].Name, EMPTY_ALIAS);
highscore[i].Score = 0;
}
- sprintf(filename, "%s/%d.%s",
- getScoreDir(leveldir[leveldir_nr].filename),
- level_nr, SCOREFILE_EXTENSION);
-
if (!(file = fopen(filename, "r")))
return;
/* check file identifier */
fgets(cookie, MAX_LINE_LEN, file);
+ if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
+ cookie[strlen(cookie) - 1] = '\0';
if (strcmp(cookie, SCORE_COOKIE) != 0)
{
void SaveScore(int level_nr)
{
int i;
- char filename[MAX_FILENAME_LEN];
+ char *filename = getScoreFilename(level_nr);
FILE *file;
InitScoreDirectory(leveldir[leveldir_nr].filename);
- sprintf(filename, "%s/%d.%s",
- getScoreDir(leveldir[leveldir_nr].filename),
- level_nr, SCOREFILE_EXTENSION);
-
if (!(file = fopen(filename, "w")))
{
Error(ERR_WARN, "cannot save score for level %d", level_nr);
if (!(file = fopen(filename, "r")))
{
- Error(ERR_WARN, "cannot open setup/info file '%s'", filename);
+ Error(ERR_WARN, "cannot open configuration file '%s'", filename);
return NULL;
}
freeSetupFileList(setup_file_list);
if (first_valid_list_entry == NULL)
- Error(ERR_WARN, "setup/info file '%s' is empty", filename);
+ Error(ERR_WARN, "configuration file '%s' is empty", filename);
return first_valid_list_entry;
}
{
if (strcmp(setup_file_list->value, identifier) != 0)
{
- Error(ERR_WARN, "setup/info file has wrong version");
+ Error(ERR_WARN, "configuration file has wrong version");
return;
}
else
checkSetupFileListIdentifier(setup_file_list->next, identifier);
else
{
- Error(ERR_WARN, "setup/info file has no version information");
+ Error(ERR_WARN, "configuration file has no version information");
return;
}
}
int i, current_entry = start_entry;
if ((dir = opendir(level_directory)) == NULL)
- Error(ERR_EXIT, "cannot read level directory '%s'", level_directory);
+ {
+ Error(ERR_WARN, "cannot read level directory '%s'", level_directory);
+ return current_entry;
+ }
while (current_entry < MAX_LEVDIR_ENTRIES)
{
continue;
}
- if (strlen(dir_entry->d_name) >= MAX_LEVDIR_FILENAME)
- {
- Error(ERR_WARN, "filename of level directory '%s' too long -- ignoring",
- dir_entry->d_name);
- continue;
- }
-
filename = getPath2(directory, LEVELINFO_FILENAME);
setup_file_list = loadSetupFileList(filename);
closedir(dir);
- if (current_entry == start_entry && start_entry != -1)
- Error(ERR_EXIT, "cannot find any valid level series in directory '%s'",
+ if (current_entry == start_entry)
+ Error(ERR_WARN, "cannot find any valid level series in directory '%s'",
level_directory);
return current_entry;
num_leveldirs);
num_leveldirs = LoadLevelInfoFromLevelDir(getUserLevelDir(""),
num_leveldirs);
+
+ if (num_leveldirs == 0)
+ Error(ERR_EXIT, "cannot find any valid level series in any directory");
+
if (num_leveldirs > 1)
qsort(leveldir, num_leveldirs, sizeof(struct LevelDirInfo),
compareLevelDirInfoEntries);