rnd-20040113-1-src
[rocksndiamonds.git] / src / files.c
index d718224291c97d83ac523f4eec376f276e46ea21..2f8ca7c166c3ff7ee57b65317efc0642ecb7dcf2 100644 (file)
 #define LEVEL_CHUNK_CNT3_UNUSED        10      /* unused CNT3 chunk bytes    */
 #define LEVEL_CPART_CUS3_SIZE  134     /* size of CUS3 chunk part    */
 #define LEVEL_CPART_CUS3_UNUSED        15      /* unused CUS3 bytes / part   */
+#define LEVEL_CHUNK_GRP1_SIZE  74      /* size of level GRP1 chunk   */
 #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) (48 + 48 + (x) * 48)
 
@@ -176,62 +178,81 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
 
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
-    setElementChangePages(&element_info[i], 1);
-    setElementChangeInfoToDefaults(element_info[i].change);
-  }
+    int element = i;
 
-  for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
-  {
-    int element = EL_CUSTOM_START + i;
+    setElementChangePages(&element_info[element], 1);
+    setElementChangeInfoToDefaults(element_info[element].change);
 
-    for (j = 0; j < MAX_ELEMENT_NAME_LEN + 1; j++)
-      element_info[element].description[j] = '\0';
-    if (element_info[element].custom_description != NULL)
-      strncpy(element_info[element].description,
-             element_info[element].custom_description, MAX_ELEMENT_NAME_LEN);
-    else
-      strcpy(element_info[element].description,
-            element_info[element].editor_description);
+    if (IS_CUSTOM_ELEMENT(element) || IS_GROUP_ELEMENT(element))
+    {
+      for (j = 0; j < MAX_ELEMENT_NAME_LEN + 1; j++)
+       element_info[element].description[j] = '\0';
+
+      if (element_info[element].custom_description != NULL)
+       strncpy(element_info[element].description,
+               element_info[element].custom_description,MAX_ELEMENT_NAME_LEN);
+      else
+       strcpy(element_info[element].description,
+              element_info[element].editor_description);
+
+      element_info[element].use_gfx_element = FALSE;
+      element_info[element].gfx_element = EL_EMPTY_SPACE;
+    }
 
-    element_info[element].use_gfx_element = FALSE;
-    element_info[element].gfx_element = EL_EMPTY_SPACE;
+    if (IS_CUSTOM_ELEMENT(element))
+    {
+      element_info[element].collect_score = 10;                /* special default */
+      element_info[element].collect_count = 1;         /* special default */
 
-    element_info[element].collect_score = 10;          /* special default */
-    element_info[element].collect_count = 1;           /* special default */
+      element_info[element].push_delay_fixed = -1;     /* initialize later */
+      element_info[element].push_delay_random = -1;    /* initialize later */
+      element_info[element].move_delay_fixed = 0;
+      element_info[element].move_delay_random = 0;
 
-    element_info[element].push_delay_fixed = -1;       /* initialize later */
-    element_info[element].push_delay_random = -1;      /* initialize later */
-    element_info[element].move_delay_fixed = 0;
-    element_info[element].move_delay_random = 0;
+      element_info[element].move_pattern = MV_ALL_DIRECTIONS;
+      element_info[element].move_direction_initial = MV_NO_MOVING;
+      element_info[element].move_stepsize = TILEX / 8;
+      element_info[element].move_enter_element = EL_EMPTY_SPACE;
+      element_info[element].move_leave_element = EL_EMPTY_SPACE;
 
-    element_info[element].move_pattern = MV_ALL_DIRECTIONS;
-    element_info[element].move_direction_initial = MV_NO_MOVING;
-    element_info[element].move_stepsize = TILEX / 8;
+      element_info[element].slippery_type = SLIPPERY_ANY_RANDOM;
 
-    element_info[element].slippery_type = SLIPPERY_ANY_RANDOM;
+      for (x = 0; x < 3; x++)
+       for (y = 0; y < 3; y++)
+         element_info[element].content[x][y] = EL_EMPTY_SPACE;
 
-    for (x = 0; x < 3; x++)
-      for (y = 0; y < 3; y++)
-       element_info[element].content[x][y] = EL_EMPTY_SPACE;
+      element_info[element].access_type = 0;
+      element_info[element].access_layer = 0;
+      element_info[element].walk_to_action = 0;
+      element_info[element].smash_targets = 0;
+      element_info[element].deadliness = 0;
+      element_info[element].consistency = 0;
 
-    element_info[element].access_type = 0;
-    element_info[element].access_layer = 0;
-    element_info[element].walk_to_action = 0;
-    element_info[element].smash_targets = 0;
-    element_info[element].deadliness = 0;
-    element_info[element].consistency = 0;
+      element_info[element].can_explode_by_fire = FALSE;
+      element_info[element].can_explode_smashed = FALSE;
+      element_info[element].can_explode_impact = FALSE;
 
-    element_info[element].can_explode_by_fire = FALSE;
-    element_info[element].can_explode_smashed = FALSE;
-    element_info[element].can_explode_impact = FALSE;
+      element_info[element].current_change_page = 0;
 
-    element_info[element].current_change_page = 0;
+      /* start with no properties at all */
+      for (j = 0; j < NUM_EP_BITFIELDS; j++)
+       Properties[element][j] = EP_BITMASK_DEFAULT;
 
-    /* start with no properties at all */
-    for (j = 0; j < NUM_EP_BITFIELDS; j++)
-      Properties[element][j] = EP_BITMASK_DEFAULT;
+      element_info[element].modified_settings = FALSE;
+    }
+    else if (IS_GROUP_ELEMENT(element))
+    {
+      /* initialize memory for list of elements in group */
+      if (element_info[element].group == NULL)
+       element_info[element].group =
+         checked_malloc(sizeof(struct ElementGroupInfo));
 
-    element_info[element].modified_settings = FALSE;
+      for (j = 0; j < MAX_ELEMENTS_IN_GROUP; j++)
+       element_info[element].group->element[j] = EL_EMPTY_SPACE;
+
+      /* default: only one element in group */
+      element_info[element].group->num_elements = 1;
+    }
   }
 
   BorderElement = EL_STEELWALL;
@@ -635,8 +656,7 @@ static int LoadLevel_CNT3(FILE *file, int chunk_size, struct LevelInfo *level)
 
   ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT3_UNUSED);
 
-  chunk_size_expected = LEVEL_CHUNK_CNT3_HEADER + envelope_len;
-
+  chunk_size_expected = LEVEL_CHUNK_CNT3_SIZE(envelope_len);
   if (chunk_size_expected != chunk_size)
   {
     ReadUnusedBytesFromFile(file, chunk_size - LEVEL_CHUNK_CNT3_HEADER);
@@ -804,7 +824,8 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
   {
     Error(ERR_WARN, "invalid custom element number %d", element);
 
-    element = EL_DUMMY;
+    ReadUnusedBytesFromFile(file, chunk_size - 2);
+    return chunk_size;
   }
 
   ei = &element_info[element];
@@ -851,8 +872,11 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
     for (x = 0; x < 3; x++)
       ei->content[x][y] = checkLevelElement(getFile16BitBE(file));
 
+  ei->move_enter_element = checkLevelElement(getFile16BitBE(file));
+  ei->move_leave_element = checkLevelElement(getFile16BitBE(file));
+
   /* some free bytes for future custom property values and padding */
-  ReadUnusedBytesFromFile(file, 12);
+  ReadUnusedBytesFromFile(file, 8);
 
   /* read change property values */
 
@@ -904,6 +928,48 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
   return chunk_size;
 }
 
+static int LoadLevel_GRP1(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+  struct ElementInfo *ei;
+  struct ElementGroupInfo *group;
+  int element;
+  int i;
+
+  element = getFile16BitBE(file);
+
+  if (!IS_GROUP_ELEMENT(element))
+  {
+    Error(ERR_WARN, "invalid group element number %d", element);
+
+    ReadUnusedBytesFromFile(file, chunk_size - 2);
+    return chunk_size;
+  }
+
+  ei = &element_info[element];
+
+  for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
+    ei->description[i] = getFile8Bit(file);
+  ei->description[MAX_ELEMENT_NAME_LEN] = 0;
+
+  group = element_info[element].group;
+
+  group->num_elements = getFile8Bit(file);
+
+  ei->use_gfx_element = getFile8Bit(file);
+  ei->gfx_element = checkLevelElement(getFile16BitBE(file));
+
+  /* some free bytes for future values and padding */
+  ReadUnusedBytesFromFile(file, 4);
+
+  for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
+    group->element[i] = checkLevelElement(getFile16BitBE(file));
+
+  /* mark this group element as modified */
+  element_info[element].modified_settings = TRUE;
+
+  return chunk_size;
+}
+
 static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
                                      struct LevelFileInfo *level_file_info)
 {
@@ -991,6 +1057,7 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
       { "CUS2", -1,                    LoadLevel_CUS2 },
       { "CUS3", -1,                    LoadLevel_CUS3 },
       { "CUS4", -1,                    LoadLevel_CUS4 },
+      { "GRP1", -1,                    LoadLevel_GRP1 },
       {  NULL,  0,                     NULL }
     };
 
@@ -1972,8 +2039,11 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
     for (x = 0; x < 3; x++)
       putFile16BitBE(file, ei->content[x][y]);
 
+  putFile16BitBE(file, ei->move_enter_element);
+  putFile16BitBE(file, ei->move_leave_element);
+
   /* some free bytes for future custom property values and padding */
-  WriteUnusedBytesToFile(file, 12);
+  WriteUnusedBytesToFile(file, 8);
 
   /* write change property values */
 
@@ -2012,6 +2082,29 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
   }
 }
 
+static void SaveLevel_GRP1(FILE *file, struct LevelInfo *level, int element)
+{
+  struct ElementInfo *ei = &element_info[element];
+  struct ElementGroupInfo *group = ei->group;
+  int i;
+
+  putFile16BitBE(file, element);
+
+  for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
+    putFile8Bit(file, ei->description[i]);
+
+  putFile8Bit(file, group->num_elements);
+
+  putFile8Bit(file, ei->use_gfx_element);
+  putFile16BitBE(file, ei->gfx_element);
+
+  /* some free bytes for future values and padding */
+  WriteUnusedBytesToFile(file, 4);
+
+  for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
+    putFile16BitBE(file, group->element[i]);
+}
+
 static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
 {
   int body_chunk_size;
@@ -2086,7 +2179,7 @@ static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
     {
       int envelope_len = strlen(level->envelope_text[i]) + 1;
 
-      putFileChunkBE(file, "CNT3", LEVEL_CHUNK_CNT3_HEADER + envelope_len);
+      putFileChunkBE(file, "CNT3", LEVEL_CHUNK_CNT3_SIZE(envelope_len));
       SaveLevel_CNT3(file, level, EL_ENVELOPE_1 + i);
     }
   }
@@ -2108,6 +2201,21 @@ static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
     }
   }
 
+  /* check for non-default group elements (unless using template level) */
+  if (!level->use_custom_template)
+  {
+    for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
+    {
+      int element = EL_GROUP_START + i;
+
+      if (element_info[element].modified_settings)
+      {
+       putFileChunkBE(file, "GRP1", LEVEL_CHUNK_GRP1_SIZE);
+       SaveLevel_GRP1(file, level, element);
+      }
+    }
+  }
+
   fclose(file);
 
   SetFilePermissions(filename, PERMS_PRIVATE);