rnd-20041124-1-src
[rocksndiamonds.git] / src / files.c
index 3651ace4252b631058278db15b17c4a9ad544727..abcf15d20761100b5e14479b9a3acc7985349a7f 100644 (file)
 #define TAPE_COOKIE_TMPL       "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
 #define SCORE_COOKIE           "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
 
+static struct
+{
+  int filetype;
+  char *id;
+}
+filetype_id_list[] =
+{
+  { LEVEL_FILE_TYPE_RND,       "RND"   },
+  { LEVEL_FILE_TYPE_BD,                "BD"    },
+  { LEVEL_FILE_TYPE_EM,                "EM"    },
+  { LEVEL_FILE_TYPE_SP,                "SP"    },
+  { LEVEL_FILE_TYPE_DX,                "DX"    },
+  { LEVEL_FILE_TYPE_SB,                "SB"    },
+  { LEVEL_FILE_TYPE_DC,                "DC"    },
+  { -1,                                NULL    },
+};
+
 
 /* ========================================================================= */
 /* level file functions                                                      */
@@ -111,9 +128,10 @@ void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
 static void setLevelInfoToDefaults(struct LevelInfo *level)
 {
   static boolean clipboard_elements_initialized = FALSE;
-
   int i, j, x, y;
 
+  setLevelInfoToDefaults_EM();
+
   level->native_em_level = &native_em_level;
 
   level->game_engine_type = GAME_ENGINE_TYPE_RND;
@@ -410,34 +428,14 @@ static int getFileTypeFromBasename(char *basename)
   return LEVEL_FILE_TYPE_UNKNOWN;
 }
 
-static char *getSingleLevelBasename(int nr, int type)
+static char *getSingleLevelBasename(int nr)
 {
   static char basename[MAX_FILENAME_LEN];
-  char *level_filename = getStringCopy(leveldir_current->level_filename);
-
-  if (level_filename == NULL)
-    level_filename = getStringCat2("%03d.", LEVELFILE_EXTENSION);
-
-  switch (type)
-  {
-    case LEVEL_FILE_TYPE_RND:
-      if (nr < 0)
-       sprintf(basename, "template.%s", LEVELFILE_EXTENSION);
-      else
-       sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION);
-      break;
 
-    case LEVEL_FILE_TYPE_EM:
-      sprintf(basename, "%d", nr);
-      break;
-
-    case LEVEL_FILE_TYPE_UNKNOWN:
-    default:
-      sprintf(basename, level_filename, nr);
-      break;
-  }
-
-  free(level_filename);
+  if (nr < 0)
+    sprintf(basename, "template.%s", LEVELFILE_EXTENSION);
+  else
+    sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION);
 
   return basename;
 }
@@ -480,9 +478,9 @@ static char *getPackedLevelBasename(int type)
   return basename;
 }
 
-static char *getSingleLevelFilename(int nr, int type)
+static char *getSingleLevelFilename(int nr)
 {
-  return getLevelFilenameFromBasename(getSingleLevelBasename(nr, type));
+  return getLevelFilenameFromBasename(getSingleLevelBasename(nr));
 }
 
 #if 0
@@ -494,9 +492,10 @@ static char *getPackedLevelFilename(int type)
 
 char *getDefaultLevelFilename(int nr)
 {
-  return getSingleLevelFilename(nr, LEVEL_FILE_TYPE_RND);
+  return getSingleLevelFilename(nr);
 }
 
+#if 0
 static void setLevelFileInfo_SingleLevelFilename(struct LevelFileInfo *lfi,
                                                 int type)
 {
@@ -505,6 +504,23 @@ static void setLevelFileInfo_SingleLevelFilename(struct LevelFileInfo *lfi,
   lfi->basename = getSingleLevelBasename(lfi->nr, lfi->type);
   lfi->filename = getLevelFilenameFromBasename(lfi->basename);
 }
+#endif
+
+static void setLevelFileInfo_FormatLevelFilename(struct LevelFileInfo *lfi,
+                                                int type, char *format, ...)
+{
+  static char basename[MAX_FILENAME_LEN];
+  va_list ap;
+
+  va_start(ap, format);
+  vsprintf(basename, format, ap);
+  va_end(ap);
+
+  lfi->type = type;
+  lfi->packed = FALSE;
+  lfi->basename = basename;
+  lfi->filename = getLevelFilenameFromBasename(lfi->basename);
+}
 
 static void setLevelFileInfo_PackedLevelFilename(struct LevelFileInfo *lfi,
                                                 int type)
@@ -515,7 +531,37 @@ static void setLevelFileInfo_PackedLevelFilename(struct LevelFileInfo *lfi,
   lfi->filename = getLevelFilenameFromBasename(lfi->basename);
 }
 
-static void determineLevelFileInfo_Filename(struct LevelFileInfo *lfi)
+static int getFiletypeFromID(char *filetype_id)
+{
+  char *filetype_id_lower;
+  int filetype = LEVEL_FILE_TYPE_UNKNOWN;
+  int i;
+
+  if (filetype_id == NULL)
+    return LEVEL_FILE_TYPE_UNKNOWN;
+
+  filetype_id_lower = getStringToLower(filetype_id);
+
+  for (i = 0; filetype_id_list[i].id != NULL; i++)
+  {
+    char *id_lower = getStringToLower(filetype_id_list[i].id);
+    
+    if (strcmp(filetype_id_lower, id_lower) == 0)
+      filetype = filetype_id_list[i].filetype;
+
+    free(id_lower);
+
+    if (filetype != LEVEL_FILE_TYPE_UNKNOWN)
+      break;
+  }
+
+  free(filetype_id_lower);
+
+  return filetype;
+}
+
+#if 0
+static void OLD_determineLevelFileInfo_Filename(struct LevelFileInfo *lfi)
 {
   /* special case: level number is negative => check for level template file */
   if (lfi->nr < 0)
@@ -527,8 +573,11 @@ static void determineLevelFileInfo_Filename(struct LevelFileInfo *lfi)
 
   if (leveldir_current->level_filename != NULL)
   {
+    int filetype = getFiletypeFromID(leveldir_current->level_filetype);
+
     /* check for file name/pattern specified in "levelinfo.conf" */
-    setLevelFileInfo_SingleLevelFilename(lfi, LEVEL_FILE_TYPE_UNKNOWN);
+    setLevelFileInfo_SingleLevelFilename(lfi, filetype);
+
     if (fileExists(lfi->filename))
       return;
   }
@@ -551,6 +600,79 @@ static void determineLevelFileInfo_Filename(struct LevelFileInfo *lfi)
   /* no known level file found -- try to use default values */
   setLevelFileInfo_SingleLevelFilename(lfi, LEVEL_FILE_TYPE_UNKNOWN);
 }
+#endif
+
+static void determineLevelFileInfo_Filename(struct LevelFileInfo *lfi)
+{
+  int nr = lfi->nr;
+
+  /* special case: level number is negative => check for level template file */
+  if (nr < 0)
+  {
+    setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
+                                        "template.%s", LEVELFILE_EXTENSION);
+
+    /* no fallback if template file not existing */
+    return;
+  }
+
+  /* special case: check for file name/pattern specified in "levelinfo.conf" */
+  if (leveldir_current->level_filename != NULL)
+  {
+    int filetype = getFiletypeFromID(leveldir_current->level_filetype);
+
+    setLevelFileInfo_FormatLevelFilename(lfi, filetype,
+                                        leveldir_current->level_filename, nr);
+    if (fileExists(lfi->filename))
+      return;
+  }
+
+  /* check for native Rocks'n'Diamonds level file */
+  setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
+                                      "%03d.%s", nr, LEVELFILE_EXTENSION);
+  if (fileExists(lfi->filename))
+    return;
+
+  /* check for Emerald Mine level file (V1) */
+  setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "a%c%c",
+                                      'a' + (nr / 10) % 26, '0' + nr % 10);
+  if (fileExists(lfi->filename))
+    return;
+  setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "A%c%c",
+                                      'A' + (nr / 10) % 26, '0' + nr % 10);
+  if (fileExists(lfi->filename))
+    return;
+
+  /* check for Emerald Mine level file (V2 to V5) */
+  setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%d", nr);
+  if (fileExists(lfi->filename))
+    return;
+
+  /* check for Emerald Mine level file (V6 / single mode) */
+  setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02ds", nr);
+  if (fileExists(lfi->filename))
+    return;
+  setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dS", nr);
+  if (fileExists(lfi->filename))
+    return;
+
+  /* check for Emerald Mine level file (V6 / teamwork mode) */
+  setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dt", nr);
+  if (fileExists(lfi->filename))
+    return;
+  setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dT", nr);
+  if (fileExists(lfi->filename))
+    return;
+
+  /* check for various packed level file formats */
+  setLevelFileInfo_PackedLevelFilename(lfi, LEVEL_FILE_TYPE_UNKNOWN);
+  if (fileExists(lfi->filename))
+    return;
+
+  /* no known level file found -- use default values (and fail later) */
+  setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
+                                      "%03d.%s", nr, LEVELFILE_EXTENSION);
+}
 
 static void determineLevelFileInfo_Filetype(struct LevelFileInfo *lfi)
 {
@@ -1808,7 +1930,7 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
   lev->width  = MIN(level->fieldx, EM_MAX_CAVE_WIDTH);
   lev->height = MIN(level->fieldy, EM_MAX_CAVE_HEIGHT);
 
-  lev->time_initial     = level->time;
+  lev->time_seconds     = level->time;
   lev->required_initial = level->gems_needed;
 
   lev->emerald_score   = level->score[SC_EMERALD];
@@ -1819,7 +1941,8 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
   lev->eater_score     = level->score[SC_YAMYAM];
   lev->nut_score       = level->score[SC_NUT];
   lev->dynamite_score  = level->score[SC_DYNAMITE];
-  lev->key_score       = level->score[SC_TIME_BONUS];  /* ??? CHECK THIS */
+  lev->key_score       = level->score[SC_KEY];
+  lev->exit_score      = level->score[SC_TIME_BONUS];
 
   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
     for (y = 0; y < 3; y++)
@@ -1836,9 +1959,11 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
   lev->ball_random             = level->ball_random;
   lev->ball_state_initial      = level->ball_state_initial;
   lev->ball_time               = level->ball_time;
+
   lev->lenses_score            = level->lenses_score;
   lev->magnify_score           = level->magnify_score;
   lev->slurp_score             = level->slurp_score;
+
   lev->lenses_time             = level->lenses_time;
   lev->magnify_time            = level->magnify_time;
   lev->wind_direction_initial  = level->wind_direction_initial;
@@ -1914,7 +2039,7 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
   level->fieldx = MIN(lev->width,  MAX_LEV_FIELDX);
   level->fieldy = MIN(lev->height, MAX_LEV_FIELDY);
 
-  level->time        = lev->time_initial;
+  level->time        = lev->time_seconds;
   level->gems_needed = lev->required_initial;
 
   sprintf(level->name, "Level %d", level->file_info.nr);
@@ -1927,7 +2052,8 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
   level->score[SC_YAMYAM]      = lev->eater_score;
   level->score[SC_NUT]         = lev->nut_score;
   level->score[SC_DYNAMITE]    = lev->dynamite_score;
-  level->score[SC_TIME_BONUS]  = lev->key_score;       /* ??? CHECK THIS */
+  level->score[SC_KEY]         = lev->key_score;
+  level->score[SC_TIME_BONUS]  = lev->exit_score;
 
   level->num_yamyam_contents = MAX_ELEMENT_CONTENTS;
 
@@ -1946,9 +2072,11 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
   level->ball_random           = lev->ball_random;
   level->ball_state_initial    = lev->ball_state_initial;
   level->ball_time             = lev->ball_time;
+
   level->lenses_score          = lev->lenses_score;
   level->magnify_score         = lev->magnify_score;
   level->slurp_score           = lev->slurp_score;
+
   level->lenses_time           = lev->lenses_time;
   level->magnify_time          = lev->magnify_time;
   level->wind_direction_initial        = lev->wind_direction_initial;
@@ -1975,6 +2103,10 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
   /* in case of both players set to the same field, use the first player */
   level->field[ply2->x_initial - 1][ply2->y_initial - 1] = EL_PLAYER_2;
   level->field[ply1->x_initial - 1][ply1->y_initial - 1] = EL_PLAYER_1;
+
+#if 0
+  printf("::: native Emerald Mine file version: %d\n", level_em->file_version);
+#endif
 }
 
 static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,