rnd-20100309-1-src
authorHolger Schemel <info@artsoft.org>
Tue, 9 Mar 2010 14:16:26 +0000 (15:16 +0100)
committerHolger Schemel <info@artsoft.org>
Sat, 30 Aug 2014 08:58:42 +0000 (10:58 +0200)
* added (hidden) function to save native Supaplex levels with tape as
  native *.sp file containing level with demo (saved with a file name
  similar to native R'n'D levels, but with ".sp" extension instead of
  ".level"); to use this functionality, enter ":save-native-level" or
  ":snl" from the main menu with the native Supaplex level loaded and
  the appropriate tape loaded to the tape recorder
* added updating of game values on the panel to Supaplex game engine

12 files changed:
ChangeLog
src/conftime.h
src/events.c
src/files.c
src/files.h
src/game_sp/export.h
src/game_sp/file.c
src/libgame/misc.c
src/libgame/misc.h
src/libgame/setup.c
src/tape.c
src/tape.h

index 7ce8c682fd9cbe3dc2ba3184939b16734017d18a..0d4ad4f787b10e111d000f3f6faae54f3a1ee2c4 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2010-03-09
+       * added (hidden) function to save native Supaplex levels with tape as
+         native *.sp file containing level with demo (saved with a file name
+         similar to native R'n'D levels, but with ".sp" extension instead of
+         ".level"); to use this functionality, enter ":save-native-level" or
+         ":snl" from the main menu with the native Supaplex level loaded and
+         the appropriate tape loaded to the tape recorder
+
+2010-03-03
+       * added updating of game values on the panel to Supaplex game engine
+
 2010-02-23
        * finished integrating R'n'D graphics engine into Supaplex game engine
          (although some animations do not support full customizability yet)
index 58e80c90e035d7152983e4db16ca65a58056e78c..303bcbd0dbaf02ebaba9cf015405597aac1a2bd7 100644 (file)
@@ -1 +1 @@
-#define COMPILE_DATE_STRING "2010-03-02 23:49"
+#define COMPILE_DATE_STRING "2010-03-09 14:59"
index 278704e6763f9924142f2a6cc4c74c00f055773a..2d9cbfcd159329dc24e59bf3e26092de59765c00 100644 (file)
@@ -577,6 +577,11 @@ static void HandleKeysSpecial(Key key)
     {
       DumpTape(&tape);
     }
+    else if (is_string_suffix(cheat_input, ":save-native-level") ||
+            is_string_suffix(cheat_input, ":snl"))
+    {
+      SaveNativeLevel(&level);
+    }
   }
   else if (game_status == GAME_MODE_PLAYING)
   {
index 01c1b1ac9a4bdb1c21d808d36e054efbe3331f21..6304da1f670e92fce336c84b8cde533349324820 100644 (file)
@@ -1877,18 +1877,23 @@ static boolean checkForPackageFromBasename(char *basename)
   return (getFileTypeFromBasename(basename) != LEVEL_FILE_TYPE_UNKNOWN);
 }
 
-static char *getSingleLevelBasename(int nr)
+static char *getSingleLevelBasenameExt(int nr, char *extension)
 {
   static char basename[MAX_FILENAME_LEN];
 
   if (nr < 0)
-    sprintf(basename, "template.%s", LEVELFILE_EXTENSION);
+    sprintf(basename, "template.%s", extension);
   else
-    sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION);
+    sprintf(basename, "%03d.%s", nr, extension);
 
   return basename;
 }
 
+static char *getSingleLevelBasename(int nr)
+{
+  return getSingleLevelBasenameExt(nr, LEVELFILE_EXTENSION);
+}
+
 static char *getPackedLevelBasename(int type)
 {
   static char basename[MAX_FILENAME_LEN];
@@ -4469,22 +4474,61 @@ void CopyNativeLevel_SP_to_RND(struct LevelInfo *level)
        level->yamyam_content[i].e[x][y] = EL_EMPTY;
 }
 
+static void CopyNativeTape_RND_to_SP(struct LevelInfo *level)
+{
+  struct LevelInfo_SP *level_sp = level->native_sp_level;
+  struct DemoInfo_SP *demo = &level_sp->demo;
+  int i, j;
+
+  /* always start with reliable default values */
+  demo->is_available = FALSE;
+  demo->length = 0;
+
+  if (TAPE_IS_EMPTY(tape))
+    return;
+
+  demo->level_nr = tape.level_nr;      /* (currently not used) */
+
+  level_sp->header.DemoRandomSeed = tape.random_seed;
+
+  demo->length = 0;
+  for (i = 0; i < tape.length; i++)
+  {
+    int demo_action = map_key_RND_to_SP(tape.pos[i].action[0]);
+    int demo_repeat = tape.pos[i].delay;
+
+    for (j = 0; j < demo_repeat / 16; j++)
+      demo->data[demo->length++] = 0xf0 | demo_action;
+
+    if (demo_repeat % 16)
+      demo->data[demo->length++] = ((demo_repeat % 16 - 1) << 4) | demo_action;
+  }
+
+  demo->data[demo->length++] = 0xff;
+
+  demo->is_available = TRUE;
+}
+
 static void setTapeInfoToDefaults();
 
 static void CopyNativeTape_SP_to_RND(struct LevelInfo *level)
 {
   struct LevelInfo_SP *level_sp = level->native_sp_level;
   struct DemoInfo_SP *demo = &level_sp->demo;
+  char *filename = level->file_info.filename;
   int i;
 
   /* always start with reliable default values */
   setTapeInfoToDefaults();
 
+  if (!demo->is_available)
+    return;
+
   tape.level_nr = demo->level_nr;      /* (currently not used) */
   tape.length = demo->length - 1;      /* without "end of demo" byte */
   tape.random_seed = level_sp->header.DemoRandomSeed;
 
-  // tape.date = <SET FROM FILE DATE OF *.SP FILE>
+  TapeSetDateFromEpochSeconds(getFileTimestampEpochSeconds(filename));
 
   for (i = 0; i < demo->length - 1; i++)
   {
@@ -6854,6 +6898,20 @@ void CopyNativeLevel_Native_to_RND(struct LevelInfo *level)
     CopyNativeLevel_SP_to_RND(level);
 }
 
+void SaveNativeLevel(struct LevelInfo *level)
+{
+  if (level->game_engine_type == GAME_ENGINE_TYPE_SP)
+  {
+    char *basename = getSingleLevelBasenameExt(level->file_info.nr, "sp");
+    char *filename = getLevelFilenameFromBasename(basename);
+
+    CopyNativeLevel_RND_to_SP(level);
+    CopyNativeTape_RND_to_SP(level);
+
+    SaveNativeLevel_SP(filename);
+  }
+}
+
 
 /* ------------------------------------------------------------------------- */
 /* functions for loading generic level                                       */
index 75dc34601e02e72b237e06b1f872f102aa1bb0ed..9edda3222fd68a5002d1768e6b637f3a70a39671 100644 (file)
@@ -38,6 +38,7 @@ void LoadLevel(int);
 void LoadLevelTemplate(int);
 void SaveLevel(int);
 void SaveLevelTemplate();
+void SaveNativeLevel(struct LevelInfo *);
 void DumpLevel(struct LevelInfo *);
 boolean SaveLevelChecked(int);
 
index 8abe983b6864621a7df930019b24b338eeb8bc5a..9e374dc52e752118fc3068b545105bea0ff75524 100644 (file)
@@ -179,6 +179,7 @@ extern unsigned int InitEngineRandom_SP(long);
 extern void setLevelInfoToDefaults_SP();
 extern void copyInternalEngineVars_SP();
 extern boolean LoadNativeLevel_SP(char *, int);
+extern void SaveNativeLevel_SP(char *);
 
 extern void BackToFront_SP(void);
 extern void BlitScreenToBitmap_SP(Bitmap *);
index 26f74167920efe9d835a4d154e378fe919b37270..f7b833c10474fd26003d51b86b67c49a8599ff20 100644 (file)
@@ -7,6 +7,12 @@
 /* functions for loading Supaplex level                                      */
 /* ------------------------------------------------------------------------- */
 
+void setTapeInfoToDefaults_SP()
+{
+  native_sp_level.demo.is_available = FALSE;
+  native_sp_level.demo.length = 0;
+}
+
 void setLevelInfoToDefaults_SP()
 {
   LevelInfoType *header = &native_sp_level.header;
@@ -49,8 +55,7 @@ void setLevelInfoToDefaults_SP()
   for (i = 0; i < SP_HEADER_SIZE; i++)
     native_sp_level.header_raw_bytes[i] = 0x20;
 
-  native_sp_level.demo.is_available = FALSE;
-  native_sp_level.demo.length = 0;
+  setTapeInfoToDefaults_SP();
 }
 
 void copyInternalEngineVars_SP()
@@ -659,3 +664,64 @@ boolean LoadNativeLevel_SP(char *filename, int level_pos)
 
   return TRUE;
 }
+
+void SaveNativeLevel_SP(char *filename)
+{
+  LevelInfoType *header = &native_sp_level.header;
+  FILE *file;
+  int i, x, y;
+
+  if (!(file = fopen(filename, MODE_WRITE)))
+  {
+    Error(ERR_WARN, "cannot save native level file '%s'", filename);
+
+    return;
+  }
+
+  /* write level playfield (width * height == 60 * 24 tiles == 1440 bytes) */
+  for (y = 0; y < native_sp_level.height; y++)
+    for (x = 0; x < native_sp_level.width; x++)
+      putFile8Bit(file, native_sp_level.playfield[x][y]);
+
+  /* write level header (96 bytes) */
+
+  WriteUnusedBytesToFile(file, 4);
+
+  putFile8Bit(file, header->InitialGravity);
+  putFile8Bit(file, header->Version);
+
+  for (i = 0; i < SP_LEVEL_NAME_LEN; i++)
+    putFile8Bit(file, header->LevelTitle[i]);
+
+  putFile8Bit(file, header->InitialFreezeZonks);
+  putFile8Bit(file, header->InfotronsNeeded);
+  putFile8Bit(file, header->SpecialPortCount);
+
+  for (i = 0; i < SP_MAX_SPECIAL_PORTS; i++)
+  {
+    SpecialPortType *port = &header->SpecialPort[i];
+
+    putFile16BitBE(file, port->PortLocation);
+    putFile8Bit(file, port->Gravity);
+    putFile8Bit(file, port->FreezeZonks);
+    putFile8Bit(file, port->FreezeEnemies);
+
+    WriteUnusedBytesToFile(file, 1);
+  }
+
+  putFile8Bit(file, header->SpeedByte);
+  putFile8Bit(file, header->CheckSumByte);
+  putFile16BitLE(file, header->DemoRandomSeed);
+
+  /* also save demo tape, if available */
+
+  if (native_sp_level.demo.is_available)
+  {
+    putFile8Bit(file, native_sp_level.demo.level_nr);
+
+    for (i = 0; i < native_sp_level.demo.length; i++)
+      putFile8Bit(file, native_sp_level.demo.data[i]);
+  }
+
+  fclose(file);
+}
index d4ebcda7025599fbaa0ae685b558685d60ef2311..27cf37c6d2e48a655162471db25681b059084c59 100644 (file)
@@ -14,6 +14,7 @@
 #include <time.h>
 #include <sys/time.h>
 #include <sys/types.h>
+#include <sys/stat.h>
 #include <stdarg.h>
 #include <ctype.h>
 #include <string.h>
@@ -468,6 +469,16 @@ char *getRealName()
   return real_name;
 }
 
+time_t getFileTimestampEpochSeconds(char *filename)
+{
+  struct stat file_status;
+
+  if (stat(filename, &file_status) != 0)       /* cannot stat file */
+    return 0;
+
+  return file_status.st_mtime;
+}
+
 
 /* ------------------------------------------------------------------------- */
 /* path manipulation functions                                               */
index 6ac3d994c990a9fe74348168d3675b04b8b816bb..34499610e2633ea978a4b11553a32cceb9a34105 100644 (file)
@@ -92,6 +92,8 @@ unsigned int get_random_number(int, int);
 char *getLoginName(void);
 char *getRealName(void);
 
+time_t getFileTimestampEpochSeconds(char *);
+
 char *getBasePath(char *);
 char *getBaseName(char *);
 char *getBaseNamePtr(char *);
index 9e35b4dbe240b10e2ab93b8aaf7fc5b6c88429de..dbe124df27cea2ab7a0df8c39b025d81e5f05d41 100644 (file)
@@ -2850,14 +2850,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)
@@ -2974,8 +2978,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);
index 49f06aa32272c5f77c13e0de6584d78411a23561..88f0f5a0300e4e0799ff9abf40cda0e138d3fd51 100644 (file)
@@ -453,12 +453,16 @@ void TapeDeactivateDisplayOff(boolean redraw_display)
 /* tape control functions                                                    */
 /* ========================================================================= */
 
-static void TapeSetDate()
+void TapeSetDateFromEpochSeconds(time_t epoch_seconds)
 {
-  time_t epoch_seconds = time(NULL);
-  struct tm *now = localtime(&epoch_seconds);
+  struct tm *lt = localtime(&epoch_seconds);
 
-  tape.date = 10000 * (now->tm_year % 100) + 100 * now->tm_mon + now->tm_mday;
+  tape.date = 10000 * (lt->tm_year % 100) + 100 * lt->tm_mon + lt->tm_mday;
+}
+
+void TapeSetDateFromNow()
+{
+  TapeSetDateFromEpochSeconds(time(NULL));
 }
 
 void TapeErase()
@@ -481,7 +485,7 @@ void TapeErase()
   tape.game_version = GAME_VERSION_ACTUAL;
   tape.engine_version = level.game_version;
 
-  TapeSetDate();
+  TapeSetDateFromNow();
 
   for (i = 0; i < MAX_PLAYERS; i++)
     tape.player_participates[i] = FALSE;
@@ -562,7 +566,7 @@ static void TapeAppendRecording()
   tape.recording = TRUE;
   tape.changed = TRUE;
 
-  TapeSetDate();
+  TapeSetDateFromNow();
 
   DrawVideoDisplay(VIDEO_STATE_DATE_ON, tape.date);
   DrawVideoDisplay(VIDEO_STATE_PLAY_OFF | VIDEO_STATE_REC_ON, 0);
index fe636495df8b07380d58bb0fe4ce6c775ddb3023..5243f26845d1f7671b9419c61a1d53ce1eb3f24c 100644 (file)
@@ -138,6 +138,9 @@ void DrawCompleteVideoDisplay(void);
 void TapeDeactivateDisplayOn();
 void TapeDeactivateDisplayOff(boolean);
 
+void TapeSetDateFromEpochSeconds(time_t);
+void TapeSetDateFromNow();
+
 void TapeStartRecording(long);
 void TapeHaltRecording(void);
 void TapeStopRecording(void);