rnd-20051213-1-src
authorHolger Schemel <info@artsoft.org>
Tue, 13 Dec 2005 00:21:58 +0000 (01:21 +0100)
committerHolger Schemel <info@artsoft.org>
Sat, 30 Aug 2014 08:49:49 +0000 (10:49 +0200)
* added level file chunk "CONF" for generic level and element settings
* uploaded pre-release (test) version 3.2.0-4 binary and source code

ChangeLog
Makefile
src/conftime.h
src/editor.c
src/files.c
src/game.c
src/libgame/misc.c
src/libgame/misc.h
src/main.h

index bf34b62472d6b9aef877deae1833d02ee8d52552..e6e0dd629c3bbb78fee952303d1d98b57a1f2cd1 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2005-12-12
+       * added level file chunk "CONF" for generic level and element settings
+
+2005-12-11
+       * uploaded pre-release (test) version 3.2.0-4 binary and source code
+
 2005-12-11
        * skip empty level sets (with "levels: 0"; may be artwork base sets)
        * added sound action ".page[1]" to ".page[32]" for each CE change page
index 832269b0b1ba5341c20cce999bd1df8c69ef2c98..4a242ed022c7a4655e17a3e334bbd703eb9a54b1 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -135,6 +135,9 @@ backup_lev:
 backup_gfx:
        ./Scripts/make_backup.sh gfx
 
+# prerelease:
+#      ./Scripts/make_prerelease.sh
+
 dist-unix:
        ./Scripts/make_dist.sh unix .
 
index bfeeb185fb896d11b85487040ec04f47e9370a14..fa2b987c6f79bffe5f390be02ad82dfbc76414ae 100644 (file)
@@ -1 +1 @@
-#define COMPILE_DATE_STRING "[2005-12-11 03:16]"
+#define COMPILE_DATE_STRING "[2005-12-13 01:12]"
index d141e16a962ad3bc9112eb3d4ba598ca872148f5..8c68e5c1bb9353a11cb33be00534b0eb6d7c519d 100644 (file)
@@ -4170,7 +4170,7 @@ static void DrawDrawingArea(int id)
       for (x = 0; x < 3; x++)
        DrawMiniGraphicExt(drawto,
                           gi->x + x * MINI_TILEX, gi->y + y * MINI_TILEY,
-                          el2edimg(custom_element.content[x][y]));
+                          el2edimg(custom_element.content.e[x][y]));
   else if (id == ED_DRAWING_ID_CUSTOM_MOVE_ENTER)
     DrawMiniGraphicExt(drawto, gi->x, gi->y,
                       el2edimg(custom_element.move_enter_element));
@@ -4185,7 +4185,7 @@ static void DrawDrawingArea(int id)
       for (x = 0; x < 3; x++)
        DrawMiniGraphicExt(drawto,
                           gi->x + x * MINI_TILEX, gi->y + y * MINI_TILEY,
-                          el2edimg(custom_element_change.target_content[x][y]));
+                          el2edimg(custom_element_change.target_content.e[x][y]));
   else if (id == ED_DRAWING_ID_CUSTOM_CHANGE_TRIGGER)
     DrawMiniGraphicExt(drawto, gi->x, gi->y,
                       el2edimg(custom_element_change.trigger_element));
@@ -4202,7 +4202,7 @@ static void DrawDrawingArea(int id)
       for (x = 0; x < 3; x++)
        DrawMiniGraphicExt(drawto,
                           gi->x + x * MINI_TILEX, gi->y + y * MINI_TILEY,
-                          el2edimg(level.yamyam_content[nr][x][y]));
+                          el2edimg(level.yamyam_content[nr].e[x][y]));
   }
   else if (id >= ED_DRAWING_ID_MAGIC_BALL_CONTENT_0 &&
           id <= ED_DRAWING_ID_MAGIC_BALL_CONTENT_7)
@@ -4213,7 +4213,7 @@ static void DrawDrawingArea(int id)
       for (x = 0; x < 3; x++)
        DrawMiniGraphicExt(drawto,
                           gi->x + x * MINI_TILEX, gi->y + y * MINI_TILEY,
-                          el2edimg(level.ball_content[nr][x][y]));
+                          el2edimg(level.ball_content[nr].e[x][y]));
   }
 }
 
@@ -5737,7 +5737,7 @@ static void copy_custom_element_settings(int element_from, int element_to)
 
   for (y = 0; y < 3; y++)
     for (x = 0; x < 3; x++)
-      ei_to->content[x][y] = ei_from->content[x][y];
+      ei_to->content.e[x][y] = ei_from->content.e[x][y];
 
   ei_to->explosion_type = ei_from->explosion_type;
   ei_to->explosion_delay = ei_from->explosion_delay;
@@ -5772,8 +5772,8 @@ static void replace_custom_element_in_settings(int element_from,
 
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
-       if (ei->content[x][y] == element_from)
-         ei->content[x][y] = element_to;
+       if (ei->content.e[x][y] == element_from)
+         ei->content.e[x][y] = element_to;
 
     for (j = 0; j < ei->num_change_pages; j++)
     {
@@ -5787,8 +5787,8 @@ static void replace_custom_element_in_settings(int element_from,
 
       for (y = 0; y < 3; y++)
        for (x = 0; x < 3; x++)
-         if (change->target_content[x][y] == element_from)
-           change->target_content[x][y] = element_to;
+         if (change->target_content.e[x][y] == element_from)
+           change->target_content.e[x][y] = element_to;
     }
 
     if (ei->group != NULL)                             /* group or internal */
@@ -6558,7 +6558,7 @@ static void DrawMagicBallContentAreas()
   int y = SY + ED_AREA_MAGIC_BALL_CONTENT_YPOS(0) + ED_BORDER_AREA_YSIZE;
   int i;
 
-  for (i = 0; i < NUM_MAGIC_BALL_CONTENTS; i++)
+  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
     MapDrawingArea(ED_DRAWING_ID_MAGIC_BALL_CONTENT_0 + i);
 
   DrawText(x, y + 0 * MINI_TILEY, "generated", FONT_TEXT_1);
@@ -8124,7 +8124,7 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
        }
        else if (id == GADGET_ID_CUSTOM_CONTENT)
        {
-         custom_element.content[sx][sy] = new_element;
+         custom_element.content.e[sx][sy] = new_element;
 
          CopyCustomElementPropertiesToGame(properties_element);
        }
@@ -8148,7 +8148,7 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
        }
        else if (id == GADGET_ID_CUSTOM_CHANGE_CONTENT)
        {
-         custom_element_change.target_content[sx][sy] = new_element;
+         custom_element_change.target_content.e[sx][sy] = new_element;
 
          CopyCustomElementPropertiesToGame(properties_element);
        }
@@ -8168,11 +8168,11 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
          random_placement_background_element = new_element;
        else if (id >= GADGET_ID_YAMYAM_CONTENT_0 &&
                 id <= GADGET_ID_YAMYAM_CONTENT_7)
-         level.yamyam_content[id - GADGET_ID_YAMYAM_CONTENT_0][sx][sy] =
+         level.yamyam_content[id - GADGET_ID_YAMYAM_CONTENT_0].e[sx][sy] =
            new_element;
        else if (id >= GADGET_ID_MAGIC_BALL_CONTENT_0 &&
                 id <= GADGET_ID_MAGIC_BALL_CONTENT_7)
-         level.ball_content[id - GADGET_ID_MAGIC_BALL_CONTENT_0][sx][sy] =
+         level.ball_content[id - GADGET_ID_MAGIC_BALL_CONTENT_0].e[sx][sy] =
            new_element;
       }
       break;
@@ -8277,7 +8277,7 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
       else if (id == GADGET_ID_CUSTOM_GRAPHIC)
        PickDrawingElement(button, custom_element.gfx_element);
       else if (id == GADGET_ID_CUSTOM_CONTENT)
-       PickDrawingElement(button, custom_element.content[sx][sy]);
+       PickDrawingElement(button, custom_element.content.e[sx][sy]);
       else if (id == GADGET_ID_CUSTOM_MOVE_ENTER)
        PickDrawingElement(button, custom_element.move_enter_element);
       else if (id == GADGET_ID_CUSTOM_MOVE_LEAVE)
@@ -8285,7 +8285,7 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
       else if (id == GADGET_ID_CUSTOM_CHANGE_TARGET)
        PickDrawingElement(button, custom_element_change.target_element);
       else if (id == GADGET_ID_CUSTOM_CHANGE_CONTENT)
-       PickDrawingElement(button, custom_element_change.target_content[sx][sy]);
+       PickDrawingElement(button, custom_element_change.target_content.e[sx][sy]);
       else if (id == GADGET_ID_CUSTOM_CHANGE_TRIGGER)
        PickDrawingElement(button, custom_element_change.trigger_element);
       else if (id == GADGET_ID_GROUP_CONTENT)
@@ -8297,14 +8297,14 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
       {
        int i = id - GADGET_ID_YAMYAM_CONTENT_0;
 
-       PickDrawingElement(button, level.yamyam_content[i][sx][sy]);
+       PickDrawingElement(button, level.yamyam_content[i].e[sx][sy]);
       }
       else if (id >= GADGET_ID_MAGIC_BALL_CONTENT_0 &&
               id <= GADGET_ID_MAGIC_BALL_CONTENT_7)
       {
        int i = id - GADGET_ID_MAGIC_BALL_CONTENT_0;
 
-       PickDrawingElement(button, level.ball_content[i][sx][sy]);
+       PickDrawingElement(button, level.ball_content[i].e[sx][sy]);
       }
 
       break;
@@ -9267,7 +9267,7 @@ static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
     else if (id == GADGET_ID_CUSTOM_GRAPHIC)
       element = custom_element.gfx_element;
     else if (id == GADGET_ID_CUSTOM_CONTENT)
-      element = custom_element.content[sx][sy];
+      element = custom_element.content.e[sx][sy];
     else if (id == GADGET_ID_CUSTOM_MOVE_ENTER)
       element = custom_element.move_enter_element;
     else if (id == GADGET_ID_CUSTOM_MOVE_LEAVE)
@@ -9275,7 +9275,7 @@ static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
     else if (id == GADGET_ID_CUSTOM_CHANGE_TARGET)
       element = custom_element_change.target_element;
     else if (id == GADGET_ID_CUSTOM_CHANGE_CONTENT)
-      element = custom_element_change.target_content[sx][sy];
+      element = custom_element_change.target_content.e[sx][sy];
     else if (id == GADGET_ID_CUSTOM_CHANGE_TRIGGER)
       element = custom_element_change.trigger_element;
     else if (id == GADGET_ID_GROUP_CONTENT)
@@ -9284,10 +9284,10 @@ static void HandleDrawingAreaInfo(struct GadgetInfo *gi)
       element = random_placement_background_element;
     else if (id >= GADGET_ID_YAMYAM_CONTENT_0 &&
             id <= GADGET_ID_YAMYAM_CONTENT_7)
-      element = level.yamyam_content[id - GADGET_ID_YAMYAM_CONTENT_0][sx][sy];
+      element = level.yamyam_content[id -GADGET_ID_YAMYAM_CONTENT_0].e[sx][sy];
     else if (id >= GADGET_ID_MAGIC_BALL_CONTENT_0 &&
             id <= GADGET_ID_MAGIC_BALL_CONTENT_7)
-      element = level.ball_content[id -GADGET_ID_MAGIC_BALL_CONTENT_0][sx][sy];
+      element =level.ball_content[id-GADGET_ID_MAGIC_BALL_CONTENT_0].e[sx][sy];
 
     strncpy(infotext, getElementInfoText(element), max_infotext_len);
   }
index f15e90700973941ab61fb78ed9dfed8464acd0ea..95268e5f5178963289297aa80551b8ac35be4302 100644 (file)
 #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_BYTES                0xc0
+#define CONF_MASK_TOKEN                0x3f
+
+#define CONF_LAST_ENTRY                (CONF_MASK_1_BYTE | 0)
+
+#define CONF_VALUE_SCORE_1     (CONF_MASK_1_BYTE | 1)
+#define CONF_VALUE_SCORE_2     (CONF_MASK_1_BYTE | 2)
+#define CONF_VALUE_SCORE_3     (CONF_MASK_1_BYTE | 3)
+#define CONF_VALUE_SCORE_4     (CONF_MASK_1_BYTE | 4)
+#define CONF_VALUE_TIME_1      (CONF_MASK_1_BYTE | 5)
+#define CONF_VALUE_TIME_2      (CONF_MASK_1_BYTE | 6)
+#define CONF_VALUE_TIME_3      (CONF_MASK_1_BYTE | 7)
+#define CONF_VALUE_TIME_4      (CONF_MASK_1_BYTE | 8)
+#define CONF_VALUE_SWITCH_1    (CONF_MASK_1_BYTE | 9)
+#define CONF_VALUE_SWITCH_2    (CONF_MASK_1_BYTE | 10)
+#define CONF_VALUE_SWITCH_3    (CONF_MASK_1_BYTE | 11)
+#define CONF_VALUE_SWITCH_4    (CONF_MASK_1_BYTE | 12)
+#define CONF_VALUE_USE_BUG_1   (CONF_MASK_1_BYTE | 13)
+#define CONF_VALUE_USE_BUG_2   (CONF_MASK_1_BYTE | 14)
+#define CONF_VALUE_USE_BUG_3   (CONF_MASK_1_BYTE | 15)
+#define CONF_VALUE_USE_BUG_4   (CONF_MASK_1_BYTE | 16)
+
+#define CONF_VALUE_ELEMENT_1   (CONF_MASK_2_BYTE | 1)
+#define CONF_VALUE_ELEMENT_2   (CONF_MASK_2_BYTE | 2)
+
+#define CONF_VALUE_CONTENT_1   (CONF_MASK_MULTI_BYTES | 1)
+#define CONF_VALUE_CONTENT_8   (CONF_MASK_MULTI_BYTES | 2)
+
+#define CONF_VALUE_BOOLEAN(x)  ((x) >= CONF_VALUE_SWITCH_1 &&          \
+                                (x) <= CONF_VALUE_USE_BUG_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_CONTENT_NUM_ELEMENTS      (3 * 3)
+#define CONF_CONTENT_NUM_BYTES         (CONF_CONTENT_NUM_ELEMENTS * 2)
+
+#define CONF_CONTENT_ELEMENT_POS(c,x,y)        ((c) * CONF_CONTENT_NUM_ELEMENTS +    \
+                                        (y) * 3 + (x))
+#define CONF_CONTENT_BYTE_POS(c,x,y)   (CONF_CONTENT_ELEMENT_POS(c,x,y) * 2)
+#define CONF_CONTENT_ELEMENT(b,c,x,y) ((b[CONF_CONTENT_BYTE_POS(c,x,y)] << 8)|\
+                                      (b[CONF_CONTENT_BYTE_POS(c,x,y) + 1]))
+
+static struct LevelInfo li;
+
+static struct
+{
+  int element;
+  int type;
+  void *value;
+} element_conf[] =
+{
+  /* 1-byte values */
+  { EL_EMC_ANDROID,    CONF_VALUE_TIME_1,      &li.android_move_time   },
+  { EL_EMC_ANDROID,    CONF_VALUE_TIME_2,      &li.android_clone_time  },
+  { EL_EMC_MAGIC_BALL, CONF_VALUE_TIME_1,      &li.ball_time           },
+  { EL_EMC_LENSES,     CONF_VALUE_SCORE_1,     &li.lenses_score        },
+  { EL_EMC_LENSES,     CONF_VALUE_TIME_1,      &li.lenses_time         },
+  { EL_EMC_MAGNIFIER,  CONF_VALUE_SCORE_1,     &li.magnify_score       },
+  { EL_EMC_MAGNIFIER,  CONF_VALUE_TIME_1,      &li.magnify_time        },
+  { EL_ROBOT,          CONF_VALUE_SCORE_2,     &li.slurp_score         },
+
+  /* multi-byte values */
+  { EL_EMC_MAGIC_BALL, CONF_VALUE_CONTENT_8,   &li.ball_content        },
+
+  { -1,                        -1,                     NULL                    },
+};
+
 static struct
 {
   int filetype;
@@ -121,7 +196,7 @@ void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
 
   for (x = 0; x < 3; x++)
     for (y = 0; y < 3; y++)
-      change->target_content[x][y] = EL_EMPTY_SPACE;
+      change->target_content.e[x][y] = EL_EMPTY_SPACE;
 
   change->direct_action = 0;
   change->other_action = 0;
@@ -196,10 +271,10 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
   level->lenses_time = 10;
   level->magnify_time = 10;
   level->wind_direction_initial = MV_NO_MOVING;
-  for (i = 0; i < NUM_MAGIC_BALL_CONTENTS; i++)
+  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
     for (x = 0; x < 3; x++)
       for (y = 0; y < 3; y++)
-       level->ball_content[i][x][y] = EL_EMPTY;
+       level->ball_content[i].e[x][y] = EL_EMPTY;
   for (i = 0; i < 16; i++)
     level->android_array[i] = FALSE;
 
@@ -227,7 +302,7 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
     for (x = 0; x < 3; x++)
       for (y = 0; y < 3; y++)
-       level->yamyam_content[i][x][y] =
+       level->yamyam_content[i].e[x][y] =
          (i < STD_ELEMENT_CONTENTS ? EL_ROCK : EL_EMPTY);
 
   level->field[0][0] = EL_PLAYER_1;
@@ -295,7 +370,7 @@ static void setLevelInfoToDefaults(struct LevelInfo *level)
 
       for (x = 0; x < 3; x++)
        for (y = 0; y < 3; y++)
-         element_info[element].content[x][y] = EL_EMPTY_SPACE;
+         element_info[element].content.e[x][y] = EL_EMPTY_SPACE;
 
       element_info[element].access_type = 0;
       element_info[element].access_layer = 0;
@@ -762,7 +837,7 @@ static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
   for (i = 0; i < STD_ELEMENT_CONTENTS; i++)
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
-       level->yamyam_content[i][x][y] = getMappedElement(getFile8Bit(file));
+       level->yamyam_content[i].e[x][y] = getMappedElement(getFile8Bit(file));
 
   level->amoeba_speed          = getFile8Bit(file);
   level->time_magic_wall       = getFile8Bit(file);
@@ -866,7 +941,7 @@ static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
-       level->yamyam_content[i][x][y] =
+       level->yamyam_content[i].e[x][y] =
          getMappedElement(level->encoding_16bit_field ?
                           getFile16BitBE(file) : getFile8Bit(file));
   return chunk_size;
@@ -902,7 +977,7 @@ static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
     for (i = 0; i < num_contents; i++)
       for (y = 0; y < 3; y++)
        for (x = 0; x < 3; x++)
-         level->yamyam_content[i][x][y] = content_array[i][x][y];
+         level->yamyam_content[i].e[x][y] = content_array[i][x][y];
   }
   else if (element == EL_BD_AMOEBA)
   {
@@ -1053,7 +1128,7 @@ static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level)
 
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
-       element_info[element].content[x][y] =
+       element_info[element].content.e[x][y] =
          getMappedElement(getFile16BitBE(file));
 
     event_bits = getFile32BitBE(file);
@@ -1081,7 +1156,7 @@ static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level)
 
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
-       element_info[element].change->target_content[x][y] =
+       element_info[element].change->target_content.e[x][y] =
          getMappedElement(getFile16BitBE(file));
 
     element_info[element].slippery_type = getFile8Bit(file);
@@ -1158,7 +1233,7 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
 
   for (y = 0; y < 3; y++)
     for (x = 0; x < 3; x++)
-      ei->content[x][y] = getMappedElement(getFile16BitBE(file));
+      ei->content.e[x][y] = getMappedElement(getFile16BitBE(file));
 
   ei->move_enter_element = getMappedElement(getFile16BitBE(file));
   ei->move_leave_element = getMappedElement(getFile16BitBE(file));
@@ -1211,7 +1286,7 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
 
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
-       change->target_content[x][y] = getMappedElement(getFile16BitBE(file));
+       change->target_content.e[x][y]= getMappedElement(getFile16BitBE(file));
 
     change->can_change = getFile8Bit(file);
 
@@ -1282,6 +1357,96 @@ static int LoadLevel_GRP1(FILE *file, int chunk_size, struct LevelInfo *level)
   return chunk_size;
 }
 
+static int LoadLevel_CONF(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+  int real_chunk_size = 0;
+  int i;
+
+  while (!feof(file))
+  {
+    int element = getFile16BitBE(file);
+    int type = getFile8Bit(file);
+    int bytes = type & CONF_MASK_BYTES;
+    boolean element_found = FALSE;
+
+    real_chunk_size += 3;
+
+    li = *level;       /* copy level information into temporary buffer */
+
+    if (bytes == CONF_MASK_MULTI_BYTES)
+    {
+      int num_bytes = getFile16BitBE(file);
+      byte *buffer = checked_malloc(num_bytes);
+
+      ReadBytesFromFile(file, buffer, num_bytes);
+
+      for (i = 0; element_conf[i].element != -1; i++)
+      {
+       if (element_conf[i].element == element &&
+           element_conf[i].type    == type)
+       {
+         element_found = TRUE;
+
+         if (type == CONF_VALUE_CONTENT_8)
+         {
+           struct Content *content= (struct Content *)(element_conf[i].value);
+           int num_contents = num_bytes / CONF_CONTENT_NUM_BYTES;
+           int c, x, y;
+
+           for (c = 0; c < num_contents; c++)
+             for (y = 0; y < 3; y++)
+               for (x = 0; x < 3; x++)
+                 content[c].e[x][y] =
+                   getMappedElement(CONF_CONTENT_ELEMENT(buffer, c, x, y));
+         }
+         else
+           element_found = FALSE;
+
+         break;
+       }
+      }
+
+      checked_free(buffer);
+
+      real_chunk_size += 2 + num_bytes;
+    }
+    else
+    {
+      int value = (bytes == CONF_MASK_1_BYTE ? getFile8Bit   (file) :
+                  bytes == CONF_MASK_2_BYTE ? getFile16BitBE(file) :
+                  bytes == CONF_MASK_4_BYTE ? getFile32BitBE(file) : 0);
+
+      for (i = 0; element_conf[i].element != -1; i++)
+      {
+       if (element_conf[i].element == element &&
+           element_conf[i].type    == type)
+       {
+         if (CONF_VALUE_BOOLEAN(type))
+           *(boolean *)(element_conf[i].value) = value;
+         else
+           *(int *)    (element_conf[i].value) = value;
+
+         element_found = TRUE;
+
+         break;
+       }
+      }
+
+      real_chunk_size += CONF_VALUE_NUM_BYTES(bytes);
+    }
+
+    *level = li;       /* copy temporary buffer back to level information */
+
+    if (!element_found)
+      Error(ERR_WARN, "cannot load CONF value for element %d", element);
+
+    if (type == CONF_LAST_ENTRY || real_chunk_size >= chunk_size)
+      break;
+  }
+
+  return real_chunk_size;
+}
+
 static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
                                      struct LevelFileInfo *level_file_info)
 {
@@ -1373,6 +1538,8 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
       { "CUS3", -1,                    LoadLevel_CUS3 },
       { "CUS4", -1,                    LoadLevel_CUS4 },
       { "GRP1", -1,                    LoadLevel_GRP1 },
+      { "CONF", -1,                    LoadLevel_CONF },
+
       {  NULL,  0,                     NULL }
     };
 
@@ -1815,7 +1982,7 @@ static void OLD_LoadLevelFromFileInfo_EM(struct LevelInfo *level,
   for (i = 0; i < level->num_yamyam_contents; i++)
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
-       level->yamyam_content[i][x][y] =
+       level->yamyam_content[i].e[x][y] =
          map_em_element_yam(header[i * 9 + y * 3 + x]);
 
   level->amoeba_speed          = (header[52] * 256 + header[53]) % 256;
@@ -1884,7 +2051,7 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
        lev->eater_array[i][y * 3 + x] =
-         map_element_RND_to_EM(level->yamyam_content[i][x][y]);
+         map_element_RND_to_EM(level->yamyam_content[i].e[x][y]);
 
   lev->amoeba_time             = level->amoeba_speed;
   lev->wonderwall_time_initial = level->time_magic_wall;
@@ -1904,11 +2071,11 @@ void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
   lev->magnify_time            = level->magnify_time;
   lev->wind_direction_initial  = level->wind_direction_initial;
 
-  for (i = 0; i < NUM_MAGIC_BALL_CONTENTS; i++)
+  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
     for (j = 0; j < 8; j++)
       lev->ball_array[i][j] =
        map_element_RND_to_EM(level->
-                             ball_content[i][ball_xy[j][0]][ball_xy[j][1]]);
+                             ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
 
   for (i = 0; i < 16; i++)
     lev->android_array[i] = FALSE;     /* !!! YET TO COME !!! */
@@ -1996,7 +2163,7 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
   for (i = 0; i < level->num_yamyam_contents; i++)
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
-       level->yamyam_content[i][x][y] =
+       level->yamyam_content[i].e[x][y] =
          map_element_EM_to_RND(lev->eater_array[i][y * 3 + x]);
 
   level->amoeba_speed          = lev->amoeba_time;
@@ -2017,9 +2184,9 @@ void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
   level->magnify_time          = lev->magnify_time;
   level->wind_direction_initial        = lev->wind_direction_initial;
 
-  for (i = 0; i < NUM_MAGIC_BALL_CONTENTS; i++)
+  for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
     for (j = 0; j < 8; j++)
-      level->ball_content[i][ball_xy[j][0]][ball_xy[j][1]] =
+      level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]] =
        map_element_EM_to_RND(lev->ball_array[i][j]);
 
   for (i = 0; i < 16; i++)
@@ -2223,7 +2390,7 @@ static void LoadLevelFromFileStream_SP(FILE *file, struct LevelInfo *level,
   for (i = 0; i < level->num_yamyam_contents; i++)
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
-       level->yamyam_content[i][x][y] = EL_EMPTY;
+       level->yamyam_content[i].e[x][y] = EL_EMPTY;
 }
 
 static void LoadLevelFromFileInfo_SP(struct LevelInfo *level,
@@ -2688,8 +2855,8 @@ static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
     for (x = 0; x < 3; x++)
       for (y = 0; y < 3; y++)
-       level->yamyam_content[i][x][y] =
-         getMappedElementByVersion(level->yamyam_content[i][x][y],
+       level->yamyam_content[i].e[x][y] =
+         getMappedElementByVersion(level->yamyam_content[i].e[x][y],
                                    level->game_version);
 
   /* initialize element properties for level editor etc. */
@@ -2777,7 +2944,7 @@ static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
        putFile8Bit(file, (level->encoding_16bit_yamyam ? EL_EMPTY :
-                          level->yamyam_content[i][x][y]));
+                          level->yamyam_content[i].e[x][y]));
   putFile8Bit(file, level->amoeba_speed);
   putFile8Bit(file, level->time_magic_wall);
   putFile8Bit(file, level->time_wheel);
@@ -2841,9 +3008,9 @@ static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
        if (level->encoding_16bit_field)
-         putFile16BitBE(file, level->yamyam_content[i][x][y]);
+         putFile16BitBE(file, level->yamyam_content[i].e[x][y]);
        else
-         putFile8Bit(file, level->yamyam_content[i][x][y]);
+         putFile8Bit(file, level->yamyam_content[i].e[x][y]);
 }
 #endif
 
@@ -2862,7 +3029,7 @@ static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
     for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
       for (y = 0; y < 3; y++)
        for (x = 0; x < 3; x++)
-         content_array[i][x][y] = level->yamyam_content[i][x][y];
+         content_array[i][x][y] = level->yamyam_content[i].e[x][y];
   }
   else if (element == EL_BD_AMOEBA)
   {
@@ -3016,7 +3183,7 @@ static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
 
        for (y = 0; y < 3; y++)
          for (x = 0; x < 3; x++)
-           putFile16BitBE(file, element_info[element].content[x][y]);
+           putFile16BitBE(file, element_info[element].content.e[x][y]);
 
        putFile32BitBE(file, element_info[element].change->events);
 
@@ -3038,7 +3205,7 @@ static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
 
        for (y = 0; y < 3; y++)
          for (x = 0; x < 3; x++)
-           putFile16BitBE(file, element_info[element].change->content[x][y]);
+           putFile16BitBE(file,element_info[element].change->content.e[x][y]);
 
        putFile8Bit(file, element_info[element].slippery_type);
 
@@ -3097,7 +3264,7 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
 
   for (y = 0; y < 3; y++)
     for (x = 0; x < 3; x++)
-      putFile16BitBE(file, ei->content[x][y]);
+      putFile16BitBE(file, ei->content.e[x][y]);
 
   putFile16BitBE(file, ei->move_enter_element);
   putFile16BitBE(file, ei->move_leave_element);
@@ -3146,7 +3313,7 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
 
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
-       putFile16BitBE(file, change->target_content[x][y]);
+       putFile16BitBE(file, change->target_content.e[x][y]);
 
     putFile8Bit(file, change->can_change);
 
@@ -3191,9 +3358,82 @@ static void SaveLevel_GRP1(FILE *file, struct LevelInfo *level, int element)
     putFile16BitBE(file, group->element[i]);
 }
 
+static int SaveLevel_CONF_Value(FILE *file, int element, int type, int value)
+{
+  int bytes = type & CONF_MASK_BYTES;
+  int num_bytes = 0;
+
+  if (bytes == CONF_MASK_MULTI_BYTES)
+    Error(ERR_EXIT, "SaveLevel_CONF_INT: invalid type CONF_MASK_MULTI_BYTES");
+
+  num_bytes += putFile16BitBE(file, element);
+  num_bytes += putFile8Bit(file, type);
+  num_bytes += (bytes == CONF_MASK_1_BYTE ? putFile8Bit   (file, value) :
+               bytes == CONF_MASK_2_BYTE ? putFile16BitBE(file, value) :
+               bytes == CONF_MASK_4_BYTE ? putFile32BitBE(file, value) : 0);
+
+  return num_bytes;
+}
+
+static int SaveLevel_CONF_Content(FILE *file, int element, int type,
+                                 struct Content *content, int num_contents)
+{
+  int num_bytes = 0;
+  int i, x, y;
+
+  num_bytes += putFile16BitBE(file, element);
+  num_bytes += putFile8Bit(file, type);
+  num_bytes += putFile16BitBE(file, num_contents * CONF_CONTENT_NUM_BYTES);
+
+  for (i = 0; i < num_contents; i++)
+    for (y = 0; y < 3; y++)
+      for (x = 0; x < 3; x++)
+       num_bytes += putFile16BitBE(file, content[i].e[x][y]);
+
+  return num_bytes;
+}
+
+static int SaveLevel_CONF(FILE *file, struct LevelInfo *level)
+{
+  int chunk_size = 0;
+  int i;
+
+  li = *level;         /* copy level information into temporary buffer */
+
+  for (i = 0; element_conf[i].element != -1; i++)
+  {
+    int element = element_conf[i].element;
+    int type    = element_conf[i].type;
+    void *value = element_conf[i].value;
+    int bytes = type & CONF_MASK_BYTES;
+
+    if (bytes == CONF_MASK_MULTI_BYTES)
+    {
+      if (type == CONF_VALUE_CONTENT_8)
+      {
+       struct Content *content = (struct Content *)value;
+
+       chunk_size += SaveLevel_CONF_Content(file, element, type,
+                                            content, MAX_ELEMENT_CONTENTS);
+      }
+      else
+       Error(ERR_WARN, "cannot save CONF value for element %d", element);
+    }
+    else
+    {
+      int value_int = (CONF_VALUE_BOOLEAN(type) ? *(boolean *)value :
+                      *(int *)value);
+
+      chunk_size += SaveLevel_CONF_Value(file, element, type, value_int);
+    }
+  }
+
+  return chunk_size;
+}
+
 static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
 {
-  int body_chunk_size;
+  int body_chunk_size, conf_chunk_size;
   int i, x, y;
   FILE *file;
 
@@ -3218,7 +3458,7 @@ static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
   for (i = 0; i < level->num_yamyam_contents; i++)
     for (y = 0; y < 3; y++)
       for (x = 0; x < 3; x++)
-       if (level->yamyam_content[i][x][y] > 255)
+       if (level->yamyam_content[i].e[x][y] > 255)
          level->encoding_16bit_yamyam = TRUE;
 
   /* check amoeba content for 16-bit elements */
@@ -3302,6 +3542,11 @@ static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
     }
   }
 
+  conf_chunk_size = SaveLevel_CONF(NULL, level);       /* get chunk size */
+
+  putFileChunkBE(file, "CONF", conf_chunk_size);
+  SaveLevel_CONF(file, level);
+
   fclose(file);
 
   SetFilePermissions(filename, PERMS_PRIVATE);
index d67c64e6ce94128bc0ceeba421feb2da835124c3..c4cac805d0e078fa1ab23c344e913aa335443f4c 100644 (file)
@@ -25,7 +25,7 @@
 #define USE_NEW_AMOEBA_CODE    FALSE
 
 /* EXPERIMENTAL STUFF */
-#define USE_NEW_STUFF                  (                       * 1)
+#define USE_NEW_STUFF                  (                         1)
 
 #define USE_NEW_SP_SLIPPERY            (USE_NEW_STUFF          * 1)
 #define USE_NEW_COLLECT_COUNT          (USE_NEW_STUFF          * 1)
@@ -1933,7 +1933,7 @@ void InitGame()
 
       for (yy = 0; yy < 3; yy++) for (xx = 0; xx < 3; xx++)
       {
-       content = element_info[element].content[xx][yy];
+       content = element_info[element].content.e[xx][yy];
        is_player = ELEM_IS_PLAYER(content);
 
        if (is_player && (found_rating < 2 || element < found_element))
@@ -1950,7 +1950,9 @@ void InitGame()
 
        for (i = 0; i < element_info[element].num_change_pages; i++)
        {
-         content= element_info[element].change_page[i].target_content[xx][yy];
+         content =
+           element_info[element].change_page[i].target_content.e[xx][yy];
+
          is_player = ELEM_IS_PLAYER(content);
 
          if (is_player && (found_rating < 1 || element < found_element))
@@ -3066,10 +3068,10 @@ void Explode(int ex, int ey, int phase, int mode)
       else if (center_element == EL_AMOEBA_TO_DIAMOND)
        Store[x][y] = level.amoeba_content;
       else if (center_element == EL_YAMYAM)
-       Store[x][y] = level.yamyam_content[game.yamyam_content_nr][xx][yy];
+       Store[x][y] = level.yamyam_content[game.yamyam_content_nr].e[xx][yy];
       else if (IS_CUSTOM_ELEMENT(center_element) &&
-              element_info[center_element].content[xx][yy] != EL_EMPTY)
-       Store[x][y] = element_info[center_element].content[xx][yy];
+              element_info[center_element].content.e[xx][yy] != EL_EMPTY)
+       Store[x][y] = element_info[center_element].content.e[xx][yy];
       else if (element == EL_WALL_EMERALD)
        Store[x][y] = EL_EMERALD;
       else if (element == EL_WALL_DIAMOND)
@@ -3087,7 +3089,7 @@ void Explode(int ex, int ey, int phase, int mode)
       else if (element == EL_WALL_CRYSTAL)
        Store[x][y] = EL_CRYSTAL;
       else if (IS_CUSTOM_ELEMENT(element) && !CAN_EXPLODE(element))
-       Store[x][y] = element_info[element].content[1][1];
+       Store[x][y] = element_info[element].content.e[1][1];
       else
        Store[x][y] = EL_EMPTY;
 
@@ -6966,7 +6968,7 @@ static boolean ChangeElementNow(int x, int y, int element, int page)
       boolean is_destructible;
       int ex = x + xx - 1;
       int ey = y + yy - 1;
-      int content_element = change->target_content[xx][yy];
+      int content_element = change->target_content.e[xx][yy];
       int e;
 
       can_replace[xx][yy] = TRUE;
@@ -7038,7 +7040,7 @@ static boolean ChangeElementNow(int x, int y, int element, int page)
 
          ChangeEvent[ex][ey] = ChangeEvent[x][y];
 
-         content_element = change->target_content[xx][yy];
+         content_element = change->target_content.e[xx][yy];
          target_element = GET_TARGET_ELEMENT(content_element, change);
 
          ChangeElementNowExt(change, ex, ey, target_element);
index 20962f8b2b9b23f4c8cc41eec9ee003c4bdbd394..39eca58ac7d2cc9d2438d5600e84b9f3521c1072 100644 (file)
@@ -925,6 +925,25 @@ inline void swap_number_pairs(int *x1, int *y1, int *x2, int *y2)
   *y2 = help_y;
 }
 
+/* the "put" variants of the following file access functions check for the file
+   pointer being != NULL and return the number of bytes they have or would have
+   written; this allows for chunk writing functions to first determine the size
+   of the (not yet written) chunk, write the correct chunk size and finally
+   write the chunk itself */
+
+int getFile8BitInteger(FILE *file)
+{
+  return fgetc(file);
+}
+
+int putFile8BitInteger(FILE *file, int value)
+{
+  if (file != NULL)
+    fputc(value, file);
+
+  return 1;
+}
+
 int getFile16BitInteger(FILE *file, int byte_order)
 {
   if (byte_order == BYTE_ORDER_BIG_ENDIAN)
@@ -935,18 +954,23 @@ int getFile16BitInteger(FILE *file, int byte_order)
            (fgetc(file) << 8));
 }
 
-void putFile16BitInteger(FILE *file, int value, int byte_order)
+int putFile16BitInteger(FILE *file, int value, int byte_order)
 {
-  if (byte_order == BYTE_ORDER_BIG_ENDIAN)
+  if (file != NULL)
   {
-    fputc((value >> 8) & 0xff, file);
-    fputc((value >> 0) & 0xff, file);
-  }
-  else          /* BYTE_ORDER_LITTLE_ENDIAN */
-  {
-    fputc((value >> 0) & 0xff, file);
-    fputc((value >> 8) & 0xff, file);
+    if (byte_order == BYTE_ORDER_BIG_ENDIAN)
+    {
+      fputc((value >> 8) & 0xff, file);
+      fputc((value >> 0) & 0xff, file);
+    }
+    else          /* BYTE_ORDER_LITTLE_ENDIAN */
+    {
+      fputc((value >> 0) & 0xff, file);
+      fputc((value >> 8) & 0xff, file);
+    }
   }
+
+  return 2;
 }
 
 int getFile32BitInteger(FILE *file, int byte_order)
@@ -963,22 +987,27 @@ int getFile32BitInteger(FILE *file, int byte_order)
            (fgetc(file) << 24));
 }
 
-void putFile32BitInteger(FILE *file, int value, int byte_order)
+int putFile32BitInteger(FILE *file, int value, int byte_order)
 {
-  if (byte_order == BYTE_ORDER_BIG_ENDIAN)
+  if (file != NULL)
   {
-    fputc((value >> 24) & 0xff, file);
-    fputc((value >> 16) & 0xff, file);
-    fputc((value >>  8) & 0xff, file);
-    fputc((value >>  0) & 0xff, file);
-  }
-  else          /* BYTE_ORDER_LITTLE_ENDIAN */
-  {
-    fputc((value >>  0) & 0xff, file);
-    fputc((value >>  8) & 0xff, file);
-    fputc((value >> 16) & 0xff, file);
-    fputc((value >> 24) & 0xff, file);
+    if (byte_order == BYTE_ORDER_BIG_ENDIAN)
+    {
+      fputc((value >> 24) & 0xff, file);
+      fputc((value >> 16) & 0xff, file);
+      fputc((value >>  8) & 0xff, file);
+      fputc((value >>  0) & 0xff, file);
+    }
+    else          /* BYTE_ORDER_LITTLE_ENDIAN */
+    {
+      fputc((value >>  0) & 0xff, file);
+      fputc((value >>  8) & 0xff, file);
+      fputc((value >> 16) & 0xff, file);
+      fputc((value >> 24) & 0xff, file);
+    }
   }
+
+  return 4;
 }
 
 boolean getFileChunk(FILE *file, char *chunk_name, int *chunk_size,
@@ -1035,6 +1064,22 @@ void putFileVersion(FILE *file, int version)
   fputc(version_build, file);
 }
 
+void ReadBytesFromFile(FILE *file, byte *buffer, unsigned long bytes)
+{
+  int i;
+
+  for(i = 0; i < bytes && !feof(file); i++)
+    buffer[i] = fgetc(file);
+}
+
+void WriteBytesToFile(FILE *file, byte *buffer, unsigned long bytes)
+{
+  int i;
+
+  for(i = 0; i < bytes; i++)
+    fputc(buffer[i], file);
+}
+
 void ReadUnusedBytesFromFile(FILE *file, unsigned long bytes)
 {
   while (bytes-- && !feof(file))
index b89be4e87d6382ef19d4305f876d28364a97692f..caa57ea3d3bb799f995b094bc41da99bbb9739dc 100644 (file)
@@ -118,19 +118,26 @@ void checked_free(void *);
 inline void swap_numbers(int *, int *);
 inline void swap_number_pairs(int *, int *, int *, int *);
 
+int getFile8BitInteger(FILE *);
+int putFile8BitInteger(FILE *, int);
 int getFile16BitInteger(FILE *, int);
-void putFile16BitInteger(FILE *, int, int);
+int putFile16BitInteger(FILE *, int, int);
 int getFile32BitInteger(FILE *, int);
-void putFile32BitInteger(FILE *, int, int);
+int putFile32BitInteger(FILE *, int, int);
+
 boolean getFileChunk(FILE *, char *, int *, int);
 void putFileChunk(FILE *, char *, int, int);
 int getFileVersion(FILE *);
 void putFileVersion(FILE *, int);
+
+void ReadBytesFromFile(FILE *, byte *, unsigned long);
+void WriteBytesToFile(FILE *, byte *, unsigned long);
+
 void ReadUnusedBytesFromFile(FILE *, unsigned long);
 void WriteUnusedBytesToFile(FILE *, unsigned long);
 
-#define getFile8Bit(f)        fgetc(f)
-#define putFile8Bit(f,x)      fputc(x, f)
+#define getFile8Bit(f)        getFile8BitInteger(f)
+#define putFile8Bit(f,x)      putFile8BitInteger(f,x)
 #define getFile16BitBE(f)     getFile16BitInteger(f,BYTE_ORDER_BIG_ENDIAN)
 #define getFile16BitLE(f)     getFile16BitInteger(f,BYTE_ORDER_LITTLE_ENDIAN)
 #define putFile16BitBE(f,x)   putFile16BitInteger(f,x,BYTE_ORDER_BIG_ENDIAN)
@@ -139,6 +146,7 @@ void WriteUnusedBytesToFile(FILE *, unsigned long);
 #define getFile32BitLE(f)     getFile32BitInteger(f,BYTE_ORDER_LITTLE_ENDIAN)
 #define putFile32BitBE(f,x)   putFile32BitInteger(f,x,BYTE_ORDER_BIG_ENDIAN)
 #define putFile32BitLE(f,x)   putFile32BitInteger(f,x,BYTE_ORDER_LITTLE_ENDIAN)
+
 #define getFileChunkBE(f,s,x) getFileChunk(f,s,x,BYTE_ORDER_BIG_ENDIAN)
 #define getFileChunkLE(f,s,x) getFileChunk(f,s,x,BYTE_ORDER_LITTLE_ENDIAN)
 #define putFileChunkBE(f,s,x) putFileChunk(f,s,x,BYTE_ORDER_BIG_ENDIAN)
index b52a5e8fbc44b1d79622a1ce7edca94b1d1aa7ba..6e3a8293a7ac1ba942359dbe3a976a39f79f1aaa 100644 (file)
 #define MIN_ELEMENT_CONTENTS   1
 #define STD_ELEMENT_CONTENTS   4
 #define MAX_ELEMENT_CONTENTS   8
-#define NUM_MAGIC_BALL_CONTENTS        8
 
 #define LEVEL_SCORE_ELEMENTS   16      /* level elements with score */
 
 #define PROGRAM_VERSION_MAJOR          3
 #define PROGRAM_VERSION_MINOR          2
 #define PROGRAM_VERSION_PATCH          0
-#define PROGRAM_VERSION_BUILD          4
+#define PROGRAM_VERSION_BUILD          5
 #endif
 
 #define PROGRAM_TITLE_STRING           "Rocks'n'Diamonds"
@@ -1584,6 +1583,11 @@ struct HiScore
   int Score;
 };
 
+struct Content
+{
+  int e[3][3];
+};
+
 struct PlayerInfo
 {
   boolean present;             /* player present in level playfield */
@@ -1722,7 +1726,7 @@ struct LevelInfo
 
   int score[LEVEL_SCORE_ELEMENTS];
 
-  int yamyam_content[MAX_ELEMENT_CONTENTS][3][3];
+  struct Content yamyam_content[MAX_ELEMENT_CONTENTS];
   int num_yamyam_contents;
 
   int amoeba_speed;
@@ -1745,7 +1749,7 @@ struct LevelInfo
   int lenses_time;
   int magnify_time;
   int wind_direction_initial;
-  int ball_content[NUM_MAGIC_BALL_CONTENTS][3][3];
+  struct Content ball_content[MAX_ELEMENT_CONTENTS];
   boolean android_array[16];
 
   int can_move_into_acid_bits; /* bitfield to store property for elements */
@@ -1886,7 +1890,7 @@ struct ElementChangeInfo
 
   short trigger_element;       /* element triggering change */
 
-  int target_content[3][3];    /* elements for extended change target */
+  struct Content target_content;/* elements for extended change target */
   boolean use_target_content;  /* use extended change target */
   boolean only_if_complete;    /* only use complete target content */
   boolean use_random_replace;  /* use random value for replacing elements */
@@ -1997,7 +2001,7 @@ struct ElementInfo
 
   int slippery_type;           /* how/where other elements slip away */
 
-  int content[3][3];           /* new elements after explosion */
+  struct Content content;      /* new elements after explosion */
 
   int explosion_type;          /* type of explosion, like 3x3, 3+3 or 1x1 */
   int explosion_delay;         /* duration of explosion of this element */