rnd-20091101-2-src
authorHolger Schemel <info@artsoft.org>
Sun, 1 Nov 2009 16:38:05 +0000 (17:38 +0100)
committerHolger Schemel <info@artsoft.org>
Sat, 30 Aug 2014 08:57:55 +0000 (10:57 +0200)
* added support for loading Supaplex levels in MPX level file format

ChangeLog
src/conftime.h
src/files.c
src/game_sp/file.c
src/game_sp/vb_lib.c
src/libgame/misc.c
src/libgame/misc.h

index a839562702d1940a7798def94b2a4472a25b5ae2..e42c6d05e448025df1ab032528ac965e4d42c972 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,6 @@
+2009-11-01
+       * added support for loading Supaplex levels in MPX level file format
+
 2009-10-31
        * fixed SP engine to set "game over" not before lead out counter done
 
index 3cac76c22e44c65140bdbba952e2b442331b06ac..3a907a713967cf69fb56428beb92f96698e3c7d6 100644 (file)
@@ -1 +1 @@
-#define COMPILE_DATE_STRING "2009-10-31 23:44"
+#define COMPILE_DATE_STRING "2009-11-01 17:22"
index 05dfd5bd6e9dd1a05a0d2fa14838531e83181276..329e4e931187c1eb55abe3cf08d88708a5162c6c 100644 (file)
@@ -1770,19 +1770,26 @@ static char *getLevelFilenameFromBasename(char *basename)
 
 static int getFileTypeFromBasename(char *basename)
 {
+  /* !!! ALSO SEE COMMENT IN checkForPackageFromBasename() !!! */
+
   static char *filename = NULL;
   struct stat file_status;
 
   /* ---------- try to determine file type from filename ---------- */
 
   /* check for typical filename of a Supaplex level package file */
+#if 1
+  if (strlen(basename) == 10 && strPrefixLower(basename, "levels.d"))
+    return LEVEL_FILE_TYPE_SP;
+#else
   if (strlen(basename) == 10 && (strncmp(basename, "levels.d", 8) == 0 ||
                                 strncmp(basename, "LEVELS.D", 8) == 0))
     return LEVEL_FILE_TYPE_SP;
+#endif
 
   /* check for typical filename of a Diamond Caves II level package file */
-  if (strSuffix(basename, ".dc") ||
-      strSuffix(basename, ".dc2"))
+  if (strSuffixLower(basename, ".dc") ||
+      strSuffixLower(basename, ".dc2"))
     return LEVEL_FILE_TYPE_DC;
 
   /* ---------- try to determine file type from filesize ---------- */
@@ -1800,6 +1807,14 @@ static int getFileTypeFromBasename(char *basename)
   return LEVEL_FILE_TYPE_UNKNOWN;
 }
 
+static boolean checkForPackageFromBasename(char *basename)
+{
+  /* !!! WON'T WORK ANYMORE IF getFileTypeFromBasename() ALSO DETECTS !!!
+     !!! SINGLE LEVELS (CURRENTLY ONLY DETECTS LEVEL PACKAGES         !!! */
+
+  return (getFileTypeFromBasename(basename) != LEVEL_FILE_TYPE_UNKNOWN);
+}
+
 static char *getSingleLevelBasename(int nr)
 {
   static char basename[MAX_FILENAME_LEN];
@@ -1953,6 +1968,9 @@ static void determineLevelFileInfo_Filename(struct LevelFileInfo *lfi)
 
     setLevelFileInfo_FormatLevelFilename(lfi, filetype,
                                         leveldir_current->level_filename, nr);
+
+    lfi->packed = checkForPackageFromBasename(leveldir_current->level_filename);
+
     if (fileExists(lfi->filename))
       return;
   }
index 2a657fccc732077c0b7380d98a0f641fdd0ab1d9..0d09e22e37b098e07c5d67ac8750c7d0167ec062 100644 (file)
@@ -149,7 +149,8 @@ void copyInternalEngineVars_SP()
   LevelLoaded = True;
 }
 
-static void LoadNativeLevelFromFileStream_SP(FILE *file, boolean demo_available)
+static void LoadNativeLevelFromFileStream_SP(FILE *file, int width, int height,
+                                            boolean demo_available)
 {
   LevelInfoType *header = &native_sp_level.header;
   int i, x, y;
@@ -157,8 +158,8 @@ static void LoadNativeLevelFromFileStream_SP(FILE *file, boolean demo_available)
   /* for details of the Supaplex level format, see Herman Perk's Supaplex
      documentation file "SPFIX63.DOC" from his Supaplex "SpeedFix" package */
 
-  native_sp_level.width  = SP_PLAYFIELD_WIDTH;
-  native_sp_level.height = SP_PLAYFIELD_HEIGHT;
+  native_sp_level.width  = width;
+  native_sp_level.height = height;
 
   /* read level playfield (width * height == 60 * 24 tiles == 1440 bytes) */
   for (y = 0; y < native_sp_level.height; y++)
@@ -259,7 +260,7 @@ static void LoadNativeLevelFromFileStream_SP(FILE *file, boolean demo_available)
   for (i = 0; i < SP_HEADER_SIZE; i++)
     native_sp_level.header_raw_bytes[i] = fgetc(file);
 
-  /* also load demo tape, if available */
+  /* also load demo tape, if available (only in single level files) */
 
   if (demo_available)
   {
@@ -288,7 +289,7 @@ static void LoadNativeLevelFromFileStream_SP(FILE *file, boolean demo_available)
   }
 }
 
-boolean LoadNativeLevel_SP(char *filename, int pos)
+boolean LoadNativeLevel_SP(char *filename, int level_pos)
 {
   FILE *file;
   int i, l, x, y;
@@ -300,8 +301,13 @@ boolean LoadNativeLevel_SP(char *filename, int pos)
   boolean reading_multipart_level = FALSE;
   boolean use_empty_level = FALSE;
   LevelInfoType *header = &native_sp_level.header;
-  boolean demo_available = (strSuffix(filename, ".sp") ||
-                           strSuffix(filename, ".SP"));
+  boolean is_single_level_file = (strSuffixLower(filename, ".sp") ||
+                                 strSuffixLower(filename, ".mpx"));
+  boolean demo_available = is_single_level_file;
+  boolean is_mpx_file = strSuffixLower(filename, ".mpx");
+  int file_seek_pos = level_pos * SP_LEVEL_SIZE;
+  int level_width  = SP_PLAYFIELD_WIDTH;
+  int level_height = SP_PLAYFIELD_HEIGHT;
 
   /* always start with reliable default values */
   setLevelInfoToDefaults_SP();
@@ -309,13 +315,76 @@ boolean LoadNativeLevel_SP(char *filename, int pos)
 
   if (!(file = fopen(filename, MODE_READ)))
   {
-    Error(ERR_WARN, "cannot open level '%s' -- using empty level", filename);
+    Error(ERR_WARN, "cannot open file '%s' -- using empty level", filename);
 
     return FALSE;
   }
 
+  if (is_mpx_file)
+  {
+    char mpx_chunk_name[4 + 1];
+    int mpx_version;
+    int mpx_level_count;
+    LevelDescriptor *mpx_level_desc;
+
+    getFileChunkBE(file, mpx_chunk_name, NULL);
+
+    if (!strEqual(mpx_chunk_name, "MPX "))
+    {
+      Error(ERR_WARN, "cannot find MPX ID in file '%s' -- using empty level",
+           filename);
+
+      return FALSE;
+    }
+
+    mpx_version = getFile16BitLE(file);
+
+    if (mpx_version != 1)
+    {
+      Error(ERR_WARN, "unknown MPX version in file '%s' -- using empty level",
+           filename);
+
+      return FALSE;
+    }
+
+    mpx_level_count = getFile16BitLE(file);
+
+    if (mpx_level_count < 1)
+    {
+      Error(ERR_WARN, "no MPX levels found in file '%s' -- using empty level",
+           filename);
+
+      return FALSE;
+    }
+
+    if (level_pos >= mpx_level_count)
+    {
+      Error(ERR_WARN, "MPX level not found in file '%s' -- using empty level",
+           filename);
+
+      return FALSE;
+    }
+
+    mpx_level_desc = checked_calloc(mpx_level_count * sizeof(LevelDescriptor));
+
+    for (i = 0; i < mpx_level_count; i++)
+    {
+      LevelDescriptor *ldesc = &mpx_level_desc[i];
+
+      ldesc->Width  = getFile16BitLE(file);
+      ldesc->Height = getFile16BitLE(file);
+      ldesc->OffSet = getFile32BitLE(file);    /* starts with 1, not with 0 */
+      ldesc->Size   = getFile32BitLE(file);
+    }
+
+    level_width  = mpx_level_desc[level_pos].Width;
+    level_height = mpx_level_desc[level_pos].Height;
+
+    file_seek_pos = mpx_level_desc[level_pos].OffSet - 1;
+  }
+
   /* position file stream to the requested level (in case of level package) */
-  if (fseek(file, pos * SP_LEVEL_SIZE, SEEK_SET) != 0)
+  if (fseek(file, file_seek_pos, SEEK_SET) != 0)
   {
     Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level", filename);
 
@@ -330,12 +399,16 @@ boolean LoadNativeLevel_SP(char *filename, int pos)
      of the level name, the multi-part level consists of only horizontal or
      vertical parts */
 
-  for (l = pos; l < SP_NUM_LEVELS_PER_PACKAGE; l++)
+  for (l = level_pos; l < SP_NUM_LEVELS_PER_PACKAGE; l++)
   {
-    LoadNativeLevelFromFileStream_SP(file, demo_available);
+    LoadNativeLevelFromFileStream_SP(file, level_width, level_height,
+                                    demo_available);
 
     /* check if this level is a part of a bigger multi-part level */
 
+    if (is_single_level_file)
+      break;
+
     name_first = header->LevelTitle[0];
     name_last  = header->LevelTitle[SP_LEVEL_NAME_LEN - 1];
 
index 5c1dae75010089def694009c81b8c0c7162ed039..c2a9fceea2bd0ce0c68f109ec1abc6d18b26e622 100644 (file)
@@ -91,7 +91,8 @@ boolean STRING_IS_LIKE(char *a, char *b)
 
 void FILE_GET(FILE *file, int offset, void *buffer, int num_bytes)
 {
-  fseek(file, offset - 1, SEEK_SET);
+  if (offset != -1)
+    fseek(file, offset - 1, SEEK_SET);
 
   while (num_bytes--)
     *(byte *)buffer++ = fgetc(file);
index 5e4b9310bc4701f9921603fa1b353a94398462d9..7883f325e4de89b6f8a18ab459958c3fed342905 100644 (file)
@@ -637,6 +637,26 @@ boolean strSuffix(char *s, char *suffix)
          strncmp(&s[strlen(s) - strlen(suffix)], suffix, strlen(suffix)) == 0);
 }
 
+boolean strPrefixLower(char *s, char *prefix)
+{
+  char *s_lower = getStringToLower(s);
+  boolean match = strPrefix(s_lower, prefix);
+
+  free(s_lower);
+
+  return match;
+}
+
+boolean strSuffixLower(char *s, char *suffix)
+{
+  char *s_lower = getStringToLower(s);
+  boolean match = strSuffix(s_lower, suffix);
+
+  free(s_lower);
+
+  return match;
+}
+
 
 /* ------------------------------------------------------------------------- */
 /* command line option handling functions                                    */
index 56467dc1220255a11c51d9870a660b2dad4c6a75..6ac3d994c990a9fe74348168d3675b04b8b816bb 100644 (file)
@@ -110,6 +110,8 @@ boolean strEqual(char *, char *);
 boolean strEqualN(char *, char *, int);
 boolean strPrefix(char *, char *);
 boolean strSuffix(char *, char *);
+boolean strPrefixLower(char *, char *);
+boolean strSuffixLower(char *, char *);
 
 void GetOptions(char **, void (*print_usage_function)(void));