rnd-20051228-2-src
[rocksndiamonds.git] / src / files.c
index 0482ba8d65b1b6bcc33b59936a115d92b71f5d1b..890ca1ce2caad450c89f080b84496e5ed5297514 100644 (file)
 #define TAPE_HEADER_SIZE       20      /* size of tape file header   */
 #define TAPE_HEADER_UNUSED     3       /* unused tape header bytes   */
 
-#define LEVEL_CHUNK_CNT3_SIZE(x) (LEVEL_CHUNK_CNT3_HEADER + (x))
-#define LEVEL_CHUNK_CUS3_SIZE(x) (2 + (x) * LEVEL_CPART_CUS3_SIZE)
-#define LEVEL_CHUNK_CUS4_SIZE(x) (96 + (x) * 48)
+#define LEVEL_CHUNK_CNT3_SIZE(x)        (LEVEL_CHUNK_CNT3_HEADER + (x))
+#define LEVEL_CHUNK_CUS3_SIZE(x)        (2 + (x) * LEVEL_CPART_CUS3_SIZE)
+#define LEVEL_CHUNK_CUS4_SIZE(x)        (96 + (x) * 48)
 
 /* file identifier strings */
-#define LEVEL_COOKIE_TMPL      "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x"
-#define TAPE_COOKIE_TMPL       "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
-#define SCORE_COOKIE           "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
+#define LEVEL_COOKIE_TMPL              "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x"
+#define TAPE_COOKIE_TMPL               "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
+#define SCORE_COOKIE                   "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
 
 /* values for "CONF" chunk */
-#define CONF_MASK_1_BYTE       0x00
-#define CONF_MASK_2_BYTE       0x40
-#define CONF_MASK_4_BYTE       0x80
-#define CONF_MASK_MULTI_BYTES  0xc0
+#define CONF_MASK_1_BYTE               0x00
+#define CONF_MASK_2_BYTE               0x40
+#define CONF_MASK_4_BYTE               0x80
+#define CONF_MASK_MULTI_BYTES          0xc0
 
-#define CONF_MASK_BYTES                0xc0
-#define CONF_MASK_TOKEN                0x3f
+#define CONF_MASK_BYTES                        0xc0
+#define CONF_MASK_TOKEN                        0x3f
 
-#define CONF_LAST_ENTRY                (CONF_MASK_1_BYTE | 0)
+#define CONF_LAST_ENTRY                        (CONF_MASK_1_BYTE | 0)
 
-#define CONF_VALUE_INTEGER_1   (CONF_MASK_1_BYTE | 1)
-#define CONF_VALUE_INTEGER_2   (CONF_MASK_1_BYTE | 2)
-#define CONF_VALUE_INTEGER_3   (CONF_MASK_1_BYTE | 3)
-#define CONF_VALUE_INTEGER_4   (CONF_MASK_1_BYTE | 4)
-#define CONF_VALUE_BOOLEAN_1   (CONF_MASK_1_BYTE | 5)
-#define CONF_VALUE_BOOLEAN_2   (CONF_MASK_1_BYTE | 6)
-#define CONF_VALUE_BOOLEAN_3   (CONF_MASK_1_BYTE | 7)
-#define CONF_VALUE_BOOLEAN_4   (CONF_MASK_1_BYTE | 8)
+#define CONF_VALUE_INTEGER_1           (CONF_MASK_1_BYTE | 1)
+#define CONF_VALUE_INTEGER_2           (CONF_MASK_1_BYTE | 2)
+#define CONF_VALUE_INTEGER_3           (CONF_MASK_1_BYTE | 3)
+#define CONF_VALUE_INTEGER_4           (CONF_MASK_1_BYTE | 4)
+#define CONF_VALUE_BOOLEAN_1           (CONF_MASK_1_BYTE | 5)
+#define CONF_VALUE_BOOLEAN_2           (CONF_MASK_1_BYTE | 6)
+#define CONF_VALUE_BOOLEAN_3           (CONF_MASK_1_BYTE | 7)
+#define CONF_VALUE_BOOLEAN_4           (CONF_MASK_1_BYTE | 8)
 
-#define CONF_VALUE_ELEMENT_1   (CONF_MASK_2_BYTE | 1)
-#define CONF_VALUE_ELEMENT_2   (CONF_MASK_2_BYTE | 2)
-#define CONF_VALUE_ELEMENT_3   (CONF_MASK_2_BYTE | 3)
-#define CONF_VALUE_ELEMENT_4   (CONF_MASK_2_BYTE | 4)
+#define CONF_VALUE_ELEMENT_1           (CONF_MASK_2_BYTE | 1)
+#define CONF_VALUE_ELEMENT_2           (CONF_MASK_2_BYTE | 2)
+#define CONF_VALUE_ELEMENT_3           (CONF_MASK_2_BYTE | 3)
+#define CONF_VALUE_ELEMENT_4           (CONF_MASK_2_BYTE | 4)
 
-#define CONF_VALUE_CONTENT_1   (CONF_MASK_MULTI_BYTES | 1)
-#define CONF_VALUE_CONTENT_8   (CONF_MASK_MULTI_BYTES | 2)
+#define CONF_VALUE_CONTENT_1           (CONF_MASK_MULTI_BYTES | 1)
+#define CONF_VALUE_CONTENT_8           (CONF_MASK_MULTI_BYTES | 2)
 
-#define CONF_VALUE_INTEGER(x)  ((x) >= CONF_VALUE_INTEGER_1 &&         \
-                                (x) <= CONF_VALUE_INTEGER_4)
+#define CONF_VALUE_INTEGER(x)          ((x) >= CONF_VALUE_INTEGER_1 && \
+                                        (x) <= CONF_VALUE_INTEGER_4)
 
-#define CONF_VALUE_BOOLEAN(x)  ((x) >= CONF_VALUE_BOOLEAN_1 &&         \
-                                (x) <= CONF_VALUE_BOOLEAN_4)
+#define CONF_VALUE_BOOLEAN(x)          ((x) >= CONF_VALUE_BOOLEAN_1 && \
+                                        (x) <= CONF_VALUE_BOOLEAN_4)
 
-#define CONF_VALUE_NUM_BYTES(x)        ((x) == CONF_MASK_1_BYTE ? 1 :          \
-                                (x) == CONF_MASK_2_BYTE ? 2 :          \
-                                (x) == CONF_MASK_4_BYTE ? 4 : 0)
+#define CONF_VALUE_NUM_BYTES(x)                ((x) == CONF_MASK_1_BYTE ? 1 :  \
+                                        (x) == CONF_MASK_2_BYTE ? 2 :  \
+                                        (x) == CONF_MASK_4_BYTE ? 4 : 0)
 
 #define CONF_CONTENT_NUM_ELEMENTS      (3 * 3)
 #define CONF_CONTENT_NUM_BYTES         (CONF_CONTENT_NUM_ELEMENTS * 2)
@@ -195,6 +195,10 @@ static struct
     EL_EXTRA_TIME,                     CONF_VALUE_INTEGER_1,
     &li.extra_time,                    10
   },
+  {
+    EL_EXTRA_TIME,                     CONF_VALUE_INTEGER_2,
+    &li.extra_time_score,              10
+  },
   {
     EL_TIME_ORB_FULL,                  CONF_VALUE_INTEGER_1,
     &li.time_orb_time,                 10
@@ -203,6 +207,44 @@ static struct
     EL_TIME_ORB_FULL,                  CONF_VALUE_BOOLEAN_1,
     &li.use_time_orb_bug,              FALSE
   },
+  {
+    EL_PLAYER_1,                       CONF_VALUE_BOOLEAN_1,
+    &li.block_snap_field,              TRUE
+  },
+  {
+    EL_PLAYER_1,                       CONF_VALUE_BOOLEAN_2,
+    &li.use_start_element[0],          FALSE
+  },
+  {
+    EL_PLAYER_2,                       CONF_VALUE_BOOLEAN_2,
+    &li.use_start_element[1],          FALSE
+  },
+  {
+    EL_PLAYER_3,                       CONF_VALUE_BOOLEAN_2,
+    &li.use_start_element[2],          FALSE
+  },
+  {
+    EL_PLAYER_4,                       CONF_VALUE_BOOLEAN_2,
+    &li.use_start_element[3],          FALSE
+  },
+
+  /* ---------- 2-byte values ---------------------------------------------- */
+  {
+    EL_PLAYER_1,                       CONF_VALUE_ELEMENT_1,
+    &li.start_element[0],              EL_PLAYER_1
+  },
+  {
+    EL_PLAYER_2,                       CONF_VALUE_ELEMENT_1,
+    &li.start_element[1],              EL_PLAYER_2
+  },
+  {
+    EL_PLAYER_3,                       CONF_VALUE_ELEMENT_1,
+    &li.start_element[2],              EL_PLAYER_3
+  },
+  {
+    EL_PLAYER_4,                       CONF_VALUE_ELEMENT_1,
+    &li.start_element[3],              EL_PLAYER_4
+  },
 
   /* ---------- multi-byte values ------------------------------------------ */
   {
@@ -304,7 +346,7 @@ void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
 
   change->delay_fixed = 0;
   change->delay_random = 0;
-  change->delay_frames = 1;
+  change->delay_frames = FRAMES_PER_SECOND;
 
   change->trigger_element = EL_EMPTY_SPACE;
 
@@ -443,7 +485,7 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
   }
 
   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
-    level->score[i] = 10;
+    level->score[i] = (i == SC_TIME_BONUS ? 1 : 10);
 
   level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
@@ -1414,8 +1456,9 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
     /* always start with reliable default values */
     setElementChangeInfoToDefaults(change);
 
+    /* bits 0 - 31 of "has_event[]" ... */
     event_bits = getFile32BitBE(file);
-    for (j = 0; j < NUM_CHANGE_EVENTS; j++)
+    for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
       if (event_bits & (1 << j))
        change->has_event[j] = TRUE;
 
@@ -1454,8 +1497,11 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
     change->action_mode = getFile8Bit(file);
     change->action_arg = getFile16BitBE(file);
 
-    /* some free bytes for future change property values and padding */
-    ReadUnusedBytesFromFile(file, 1);
+    /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */
+    event_bits = getFile8Bit(file);
+    for (j = 32; j < NUM_CHANGE_EVENTS; j++)
+      if (event_bits & (1 << (j - 32)))
+       change->has_event[j] = TRUE;
   }
 
   /* mark this custom element as modified */
@@ -2220,7 +2266,11 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
 
   lev->lenses_time             = level->lenses_time;
   lev->magnify_time            = level->magnify_time;
-  lev->wind_direction_initial  = level->wind_direction_initial;
+
+  lev->wind_direction_initial =
+    map_direction_RND_to_EM(level->wind_direction_initial);
+  lev->wind_cnt_initial = (level->wind_direction_initial != MV_NONE ?
+                          lev->wind_time : 0);
 
   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
     for (j = 0; j < 8; j++)
@@ -2333,7 +2383,9 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
 
   level->lenses_time           = lev->lenses_time;
   level->magnify_time          = lev->magnify_time;
-  level->wind_direction_initial        = lev->wind_direction_initial;
+
+  level->wind_direction_initial =
+    map_direction_EM_to_RND(lev->wind_direction_initial);
 
   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
     for (j = 0; j < 8; j++)
@@ -2836,14 +2888,21 @@ static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
   if (level->game_version < VERSION_IDENT(2,2,0,0))
     level->use_spring_bug = TRUE;
 
-  /* time orb caused limited time in endless time levels before 3.1.2 */
-  if (level->game_version < VERSION_IDENT(3,1,2,0))
+  if (level->game_version < VERSION_IDENT(3,2,0,5))
+  {
+    /* time orb caused limited time in endless time levels before 3.2.0-5 */
     level->use_time_orb_bug = TRUE;
 
-  /* default behaviour for snapping was "no snap delay" before 3.1.2 */
-  if (level->game_version < VERSION_IDENT(3,1,2,0))
+    /* default behaviour for snapping was "no snap delay" before 3.2.0-5 */
     level->block_snap_field = FALSE;
 
+    /* extra time score was same value as time left score before 3.2.0-5 */
+    level->extra_time_score = level->score[SC_TIME_BONUS];
+
+    /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */
+    level->score[SC_TIME_BONUS] /= 10;
+  }
+
   /* only few elements were able to actively move into acid before 3.1.0 */
   /* trigger settings did not exist before 3.1.0; set to default "any" */
   if (level->game_version < VERSION_IDENT(3,1,0,0))
@@ -3447,12 +3506,13 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
   for (i = 0; i < ei->num_change_pages; i++)
   {
     struct ElementChangeInfo *change = &ei->change_page[i];
-    unsigned long event_bits = 0;
+    unsigned long event_bits;
 
-    for (j = 0; j < NUM_CHANGE_EVENTS; j++)
+    /* bits 0 - 31 of "has_event[]" ... */
+    event_bits = 0;
+    for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
       if (change->has_event[j])
        event_bits |= (1 << j);
-
     putFile32BitBE(file, event_bits);
 
     putFile16BitBE(file, change->target_element);
@@ -3488,8 +3548,12 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
     putFile8Bit(file, change->action_mode);
     putFile16BitBE(file, change->action_arg);
 
-    /* some free bytes for future change property values and padding */
-    WriteUnusedBytesToFile(file, 1);
+    /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */
+    event_bits = 0;
+    for (j = 32; j < NUM_CHANGE_EVENTS; j++)
+      if (change->has_event[j])
+       event_bits |= (1 << (j - 32));
+    putFile8Bit(file, event_bits);
   }
 }