/***********************************************************
* Rocks'n'Diamonds -- McDuffin Strikes Back! *
*----------------------------------------------------------*
-* (c) 1995-2002 Artsoft Entertainment *
+* (c) 1995-2006 Artsoft Entertainment *
* Holger Schemel *
* Detmolder Strasse 189 *
* 33604 Bielefeld *
#define CHUNK_ID_LEN 4 /* IFF style chunk id length */
#define CHUNK_SIZE_UNDEFINED 0 /* undefined chunk size == 0 */
#define CHUNK_SIZE_NONE -1 /* do not write chunk size */
-#define FILE_VERS_CHUNK_SIZE 8 /* size of file version chunk */
-#define LEVEL_HEADER_SIZE 80 /* size of level file header */
-#define LEVEL_HEADER_UNUSED 0 /* unused level header bytes */
+
+#define LEVEL_CHUNK_NAME_SIZE MAX_LEVEL_NAME_LEN
+#define LEVEL_CHUNK_AUTH_SIZE MAX_LEVEL_AUTHOR_LEN
+
+#define LEVEL_CHUNK_VERS_SIZE 8 /* size of file version chunk */
+#define LEVEL_CHUNK_DATE_SIZE 4 /* size of file date chunk */
+#define LEVEL_CHUNK_HEAD_SIZE 80 /* size of level file header */
+#define LEVEL_CHUNK_HEAD_UNUSED 0 /* unused level header bytes */
#define LEVEL_CHUNK_CNT2_SIZE 160 /* size of level CNT2 chunk */
#define LEVEL_CHUNK_CNT2_UNUSED 11 /* unused CNT2 chunk bytes */
#define LEVEL_CHUNK_CNT3_HEADER 16 /* size of level CNT3 header */
#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 */
+
+/* (element number, number of change pages, change page number) */
+#define LEVEL_CHUNK_CUSX_UNCHANGED (2 + (1 + 1) + (1 + 1))
+
+/* (element number only) */
+#define LEVEL_CHUNK_GRPX_UNCHANGED 2
+#define LEVEL_CHUNK_NOTE_UNCHANGED 2
+
+/* (nothing at all if unchanged) */
+#define LEVEL_CHUNK_ELEM_UNCHANGED 0
+
+#define TAPE_CHUNK_VERS_SIZE 8 /* size of file version chunk */
+#define TAPE_CHUNK_HEAD_SIZE 20 /* size of tape file header */
+#define TAPE_CHUNK_HEAD_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 TAPE_COOKIE_TMPL "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
#define SCORE_COOKIE "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
-/* values for "CONF" chunk */
+/* values for deciding when (not) to save configuration data */
+#define SAVE_CONF_NEVER 0
+#define SAVE_CONF_ALWAYS 1
+#define SAVE_CONF_WHEN_CHANGED -1
+
+/* values for chunks using micro chunks */
#define CONF_MASK_1_BYTE 0x00
#define CONF_MASK_2_BYTE 0x40
#define CONF_MASK_4_BYTE 0x80
#define CONF_MASK_BYTES 0xc0
#define CONF_MASK_TOKEN 0x3f
-#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_INTEGER_5 (CONF_MASK_1_BYTE | 5)
-#define CONF_VALUE_INTEGER_6 (CONF_MASK_1_BYTE | 6)
-#define CONF_VALUE_INTEGER_7 (CONF_MASK_1_BYTE | 7)
-#define CONF_VALUE_INTEGER_8 (CONF_MASK_1_BYTE | 8)
-#define CONF_VALUE_BOOLEAN_1 (CONF_MASK_1_BYTE | 9)
-#define CONF_VALUE_BOOLEAN_2 (CONF_MASK_1_BYTE | 10)
-#define CONF_VALUE_BOOLEAN_3 (CONF_MASK_1_BYTE | 11)
-#define CONF_VALUE_BOOLEAN_4 (CONF_MASK_1_BYTE | 12)
-#define CONF_VALUE_BOOLEAN_5 (CONF_MASK_1_BYTE | 13)
-#define CONF_VALUE_BOOLEAN_6 (CONF_MASK_1_BYTE | 14)
-#define CONF_VALUE_BOOLEAN_7 (CONF_MASK_1_BYTE | 15)
-#define CONF_VALUE_BOOLEAN_8 (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_ELEMENT_3 (CONF_MASK_2_BYTE | 3)
-#define CONF_VALUE_ELEMENT_4 (CONF_MASK_2_BYTE | 4)
-#define CONF_VALUE_ELEMENT_5 (CONF_MASK_2_BYTE | 5)
-#define CONF_VALUE_ELEMENT_6 (CONF_MASK_2_BYTE | 6)
-#define CONF_VALUE_ELEMENT_7 (CONF_MASK_2_BYTE | 7)
-#define CONF_VALUE_ELEMENT_8 (CONF_MASK_2_BYTE | 8)
-
-#define CONF_VALUE_ELEMENTS (CONF_MASK_MULTI_BYTES | 1)
-#define CONF_VALUE_CONTENTS (CONF_MASK_MULTI_BYTES | 2)
-
-#define CONF_VALUE_INTEGER(x) ((x) >= CONF_VALUE_INTEGER_1 && \
- (x) <= CONF_VALUE_INTEGER_8)
-
-#define CONF_VALUE_BOOLEAN(x) ((x) >= CONF_VALUE_BOOLEAN_1 && \
- (x) <= CONF_VALUE_BOOLEAN_8)
+#define CONF_VALUE_1_BYTE(x) (CONF_MASK_1_BYTE | (x))
+#define CONF_VALUE_2_BYTE(x) (CONF_MASK_2_BYTE | (x))
+#define CONF_VALUE_4_BYTE(x) (CONF_MASK_4_BYTE | (x))
+#define CONF_VALUE_MULTI_BYTES(x) (CONF_MASK_MULTI_BYTES | (x))
+
+/* these definitions are just for convenience of use and readability */
+#define CONF_VALUE_8_BIT(x) CONF_VALUE_1_BYTE(x)
+#define CONF_VALUE_16_BIT(x) CONF_VALUE_2_BYTE(x)
+#define CONF_VALUE_32_BIT(x) CONF_VALUE_4_BYTE(x)
+#define CONF_VALUE_BYTES(x) CONF_VALUE_MULTI_BYTES(x)
#define CONF_VALUE_NUM_BYTES(x) ((x) == CONF_MASK_1_BYTE ? 1 : \
(x) == CONF_MASK_2_BYTE ? 2 : \
#define CONF_CONTENT_NUM_BYTES (CONF_CONTENT_NUM_ELEMENTS * 2)
#define CONF_ELEMENT_NUM_BYTES (2)
-#define CONF_ENTITY_NUM_BYTES(t) ((t) == CONF_VALUE_ELEMENTS ? \
+#define CONF_ENTITY_NUM_BYTES(t) ((t) == TYPE_ELEMENT || \
+ (t) == TYPE_ELEMENT_LIST ? \
CONF_ELEMENT_NUM_BYTES : \
- (t) == CONF_VALUE_CONTENTS ? \
+ (t) == TYPE_CONTENT || \
+ (t) == TYPE_CONTENT_LIST ? \
CONF_CONTENT_NUM_BYTES : 1)
#define CONF_ELEMENT_BYTE_POS(i) ((i) * CONF_ELEMENT_NUM_BYTES)
#define CONF_CONTENTS_ELEMENT(b,c,x,y) ((b[CONF_CONTENT_BYTE_POS(c,x,y)]<< 8)|\
(b[CONF_CONTENT_BYTE_POS(c,x,y) + 1]))
-#if 0
-static void LoadLevel_InitPlayfield(struct LevelInfo *, char *);
-#endif
-
+/* temporary variables used to store pointers to structure members */
static struct LevelInfo li;
-
-static struct
+static struct ElementInfo xx_ei, yy_ei;
+static struct ElementChangeInfo xx_change;
+static struct ElementGroupInfo xx_group;
+static struct EnvelopeInfo xx_envelope;
+static unsigned int xx_event_bits[NUM_CE_BITFIELDS];
+static char xx_default_description[MAX_ELEMENT_NAME_LEN + 1];
+static int xx_num_contents;
+static int xx_current_change_page;
+static char xx_default_string_empty[1] = "";
+static int xx_string_length_unused;
+
+struct LevelFileConfigInfo
{
int element; /* element for which data is to be stored */
- int type; /* type of data to be stored */
+ int save_type; /* save data always, never or when changed */
+ int data_type; /* data type (used internally, not stored) */
+ int conf_type; /* micro chunk identifier (stored in file) */
/* (mandatory) */
void *value; /* variable that holds the data to be stored */
int default_value; /* initial default value for this variable */
/* (optional) */
+ void *value_copy; /* variable that holds the data to be copied */
void *num_entities; /* number of entities for multi-byte data */
int default_num_entities; /* default number of entities for this data */
int max_num_entities; /* maximal number of entities for this data */
-} element_conf[] =
+ char *default_string; /* optional default string for string data */
+};
+
+static struct LevelFileConfigInfo chunk_config_INFO[] =
{
- /* ---------- 1-byte values ---------------------------------------------- */
+ /* ---------- values not related to single elements ----------------------- */
{
- EL_EMC_ANDROID, CONF_VALUE_INTEGER_1,
- &li.android_move_time, 10
+ -1, SAVE_CONF_ALWAYS,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(1),
+ &li.game_engine_type, GAME_ENGINE_TYPE_RND
},
+
{
- EL_EMC_ANDROID, CONF_VALUE_INTEGER_2,
- &li.android_clone_time, 10
+ -1, SAVE_CONF_ALWAYS,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(1),
+ &li.fieldx, STD_LEV_FIELDX
},
{
- EL_EMC_LENSES, CONF_VALUE_INTEGER_1,
- &li.lenses_score, 10
+ -1, SAVE_CONF_ALWAYS,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(2),
+ &li.fieldy, STD_LEV_FIELDY
},
+
{
- EL_EMC_LENSES, CONF_VALUE_INTEGER_2,
- &li.lenses_time, 10
+ -1, SAVE_CONF_ALWAYS,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(3),
+ &li.time, 100
},
+
{
- EL_EMC_MAGNIFIER, CONF_VALUE_INTEGER_1,
- &li.magnify_score, 10
+ -1, SAVE_CONF_ALWAYS,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(4),
+ &li.gems_needed, 0
},
+
{
- EL_EMC_MAGNIFIER, CONF_VALUE_INTEGER_2,
- &li.magnify_time, 10
+ -1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(2),
+ &li.use_step_counter, FALSE
},
+
{
- EL_ROBOT, CONF_VALUE_INTEGER_1,
- &li.slurp_score, 10
+ -1, -1,
+ TYPE_BITFIELD, CONF_VALUE_8_BIT(4),
+ &li.wind_direction_initial, MV_NONE
},
+
{
- EL_GAME_OF_LIFE, CONF_VALUE_INTEGER_1,
- &li.game_of_life[0], 2
+ -1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(5),
+ &li.em_slippery_gems, FALSE
},
+
{
- EL_GAME_OF_LIFE, CONF_VALUE_INTEGER_2,
- &li.game_of_life[1], 3
+ -1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(6),
+ &li.use_custom_template, FALSE
},
+
{
- EL_GAME_OF_LIFE, CONF_VALUE_INTEGER_3,
- &li.game_of_life[2], 3
+ -1, -1,
+ TYPE_BITFIELD, CONF_VALUE_32_BIT(1),
+ &li.can_move_into_acid_bits, ~0 /* default: everything can */
},
+
{
- EL_GAME_OF_LIFE, CONF_VALUE_INTEGER_4,
- &li.game_of_life[3], 3
+ -1, -1,
+ TYPE_BITFIELD, CONF_VALUE_8_BIT(7),
+ &li.dont_collide_with_bits, ~0 /* default: always deadly */
},
+
{
- EL_BIOMAZE, CONF_VALUE_INTEGER_1,
- &li.biomaze[0], 2
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(5),
+ &li.score[SC_TIME_BONUS], 1
},
+
{
- EL_BIOMAZE, CONF_VALUE_INTEGER_2,
- &li.biomaze[1], 3
+ -1, -1,
+ -1, -1,
+ NULL, -1
+ }
+};
+
+static struct LevelFileConfigInfo chunk_config_ELEM[] =
+{
+ /* (these values are the same for each player) */
+ {
+ EL_PLAYER_1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(1),
+ &li.block_last_field, FALSE /* default case for EM levels */
},
{
- EL_BIOMAZE, CONF_VALUE_INTEGER_3,
- &li.biomaze[2], 3
+ EL_PLAYER_1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(2),
+ &li.sp_block_last_field, TRUE /* default case for SP levels */
},
{
- EL_BIOMAZE, CONF_VALUE_INTEGER_4,
- &li.biomaze[3], 3
+ EL_PLAYER_1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(3),
+ &li.instant_relocation, FALSE
},
{
- EL_BALLOON, CONF_VALUE_INTEGER_1,
- &li.wind_direction_initial, MV_NONE
+ EL_PLAYER_1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(4),
+ &li.can_pass_to_walkable, FALSE
},
{
- EL_TIMEGATE_SWITCH, CONF_VALUE_INTEGER_1,
- &li.time_timegate, 10
+ EL_PLAYER_1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(5),
+ &li.block_snap_field, TRUE
},
{
- EL_LIGHT_SWITCH_ACTIVE, CONF_VALUE_INTEGER_1,
- &li.time_light, 10
+ EL_PLAYER_1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(6),
+ &li.continuous_snapping, TRUE
},
+
+ /* (these values are different for each player) */
{
- EL_SHIELD_NORMAL, CONF_VALUE_INTEGER_1,
- &li.shield_normal_time, 10
+ EL_PLAYER_1, -1,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(7),
+ &li.initial_player_stepsize[0], STEPSIZE_NORMAL
},
{
- EL_SHIELD_DEADLY, CONF_VALUE_INTEGER_1,
- &li.shield_deadly_time, 10
+ EL_PLAYER_1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(8),
+ &li.initial_player_gravity[0], FALSE
},
{
- EL_EXTRA_TIME, CONF_VALUE_INTEGER_1,
- &li.extra_time, 10
+ EL_PLAYER_1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(9),
+ &li.use_start_element[0], FALSE
},
{
- EL_EXTRA_TIME, CONF_VALUE_INTEGER_2,
- &li.extra_time_score, 10
+ EL_PLAYER_1, -1,
+ TYPE_ELEMENT, CONF_VALUE_16_BIT(1),
+ &li.start_element[0], EL_PLAYER_1
},
{
- EL_TIME_ORB_FULL, CONF_VALUE_INTEGER_1,
- &li.time_orb_time, 10
+ EL_PLAYER_1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(10),
+ &li.use_artwork_element[0], FALSE
},
{
- EL_TIME_ORB_FULL, CONF_VALUE_BOOLEAN_1,
- &li.use_time_orb_bug, FALSE
+ EL_PLAYER_1, -1,
+ TYPE_ELEMENT, CONF_VALUE_16_BIT(2),
+ &li.artwork_element[0], EL_PLAYER_1
},
{
- EL_PLAYER_1, CONF_VALUE_BOOLEAN_1,
- &li.block_snap_field, TRUE
+ EL_PLAYER_1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(11),
+ &li.use_explosion_element[0], FALSE
},
{
- EL_PLAYER_1, CONF_VALUE_BOOLEAN_2,
- &li.use_start_element[0], FALSE
+ EL_PLAYER_1, -1,
+ TYPE_ELEMENT, CONF_VALUE_16_BIT(3),
+ &li.explosion_element[0], EL_PLAYER_1
},
+
{
- EL_PLAYER_2, CONF_VALUE_BOOLEAN_2,
- &li.use_start_element[1], FALSE
+ EL_PLAYER_2, -1,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(7),
+ &li.initial_player_stepsize[1], STEPSIZE_NORMAL
},
{
- EL_PLAYER_3, CONF_VALUE_BOOLEAN_2,
- &li.use_start_element[2], FALSE
+ EL_PLAYER_2, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(8),
+ &li.initial_player_gravity[1], FALSE
},
{
- EL_PLAYER_4, CONF_VALUE_BOOLEAN_2,
- &li.use_start_element[3], FALSE
+ EL_PLAYER_2, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(9),
+ &li.use_start_element[1], FALSE
},
{
- EL_PLAYER_1, CONF_VALUE_BOOLEAN_3,
- &li.use_artwork_element[0], FALSE
+ EL_PLAYER_2, -1,
+ TYPE_ELEMENT, CONF_VALUE_16_BIT(1),
+ &li.start_element[1], EL_PLAYER_2
},
{
- EL_PLAYER_2, CONF_VALUE_BOOLEAN_3,
+ EL_PLAYER_2, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(10),
&li.use_artwork_element[1], FALSE
},
{
- EL_PLAYER_3, CONF_VALUE_BOOLEAN_3,
- &li.use_artwork_element[2], FALSE
+ EL_PLAYER_2, -1,
+ TYPE_ELEMENT, CONF_VALUE_16_BIT(2),
+ &li.artwork_element[1], EL_PLAYER_2
},
{
- EL_PLAYER_4, CONF_VALUE_BOOLEAN_3,
- &li.use_artwork_element[3], FALSE
+ EL_PLAYER_2, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(11),
+ &li.use_explosion_element[1], FALSE
},
{
- EL_PLAYER_1, CONF_VALUE_BOOLEAN_4,
- &li.use_explosion_element[0], FALSE
+ EL_PLAYER_2, -1,
+ TYPE_ELEMENT, CONF_VALUE_16_BIT(3),
+ &li.explosion_element[1], EL_PLAYER_2
},
+
{
- EL_PLAYER_2, CONF_VALUE_BOOLEAN_4,
- &li.use_explosion_element[1], FALSE
+ EL_PLAYER_3, -1,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(7),
+ &li.initial_player_stepsize[2], STEPSIZE_NORMAL
},
{
- EL_PLAYER_3, CONF_VALUE_BOOLEAN_4,
- &li.use_explosion_element[2], FALSE
+ EL_PLAYER_3, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(8),
+ &li.initial_player_gravity[2], FALSE
},
{
- EL_PLAYER_4, CONF_VALUE_BOOLEAN_4,
- &li.use_explosion_element[3], FALSE
+ EL_PLAYER_3, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(9),
+ &li.use_start_element[2], FALSE
},
{
- EL_PLAYER_1, CONF_VALUE_BOOLEAN_5,
- &li.continuous_snapping, TRUE
+ EL_PLAYER_3, -1,
+ TYPE_ELEMENT, CONF_VALUE_16_BIT(1),
+ &li.start_element[2], EL_PLAYER_3
},
{
- EL_PLAYER_1, CONF_VALUE_INTEGER_1,
- &li.initial_player_stepsize, STEPSIZE_NORMAL
+ EL_PLAYER_3, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(10),
+ &li.use_artwork_element[2], FALSE
},
{
- EL_EMC_MAGIC_BALL, CONF_VALUE_INTEGER_1,
- &li.ball_time, 10
+ EL_PLAYER_3, -1,
+ TYPE_ELEMENT, CONF_VALUE_16_BIT(2),
+ &li.artwork_element[2], EL_PLAYER_3
},
{
- EL_EMC_MAGIC_BALL, CONF_VALUE_BOOLEAN_1,
- &li.ball_random, FALSE
+ EL_PLAYER_3, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(11),
+ &li.use_explosion_element[2], FALSE
},
{
- EL_EMC_MAGIC_BALL, CONF_VALUE_BOOLEAN_2,
- &li.ball_state_initial, FALSE
+ EL_PLAYER_3, -1,
+ TYPE_ELEMENT, CONF_VALUE_16_BIT(3),
+ &li.explosion_element[2], EL_PLAYER_3
},
- /* ---------- 2-byte values ---------------------------------------------- */
-
{
- EL_PLAYER_1, CONF_VALUE_ELEMENT_1,
- &li.start_element[0], EL_PLAYER_1
+ EL_PLAYER_4, -1,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(7),
+ &li.initial_player_stepsize[3], STEPSIZE_NORMAL
},
{
- EL_PLAYER_2, CONF_VALUE_ELEMENT_1,
- &li.start_element[1], EL_PLAYER_2
+ EL_PLAYER_4, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(8),
+ &li.initial_player_gravity[3], FALSE
},
{
- EL_PLAYER_3, CONF_VALUE_ELEMENT_1,
- &li.start_element[2], EL_PLAYER_3
+ EL_PLAYER_4, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(9),
+ &li.use_start_element[3], FALSE
},
{
- EL_PLAYER_4, CONF_VALUE_ELEMENT_1,
+ EL_PLAYER_4, -1,
+ TYPE_ELEMENT, CONF_VALUE_16_BIT(1),
&li.start_element[3], EL_PLAYER_4
},
{
- EL_PLAYER_1, CONF_VALUE_ELEMENT_2,
- &li.artwork_element[0], EL_PLAYER_1
+ EL_PLAYER_4, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(10),
+ &li.use_artwork_element[3], FALSE
},
{
- EL_PLAYER_2, CONF_VALUE_ELEMENT_2,
- &li.artwork_element[1], EL_PLAYER_2
+ EL_PLAYER_4, -1,
+ TYPE_ELEMENT, CONF_VALUE_16_BIT(2),
+ &li.artwork_element[3], EL_PLAYER_4
},
{
- EL_PLAYER_3, CONF_VALUE_ELEMENT_2,
- &li.artwork_element[2], EL_PLAYER_3
+ EL_PLAYER_4, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(11),
+ &li.use_explosion_element[3], FALSE
},
{
- EL_PLAYER_4, CONF_VALUE_ELEMENT_2,
- &li.artwork_element[3], EL_PLAYER_4
+ EL_PLAYER_4, -1,
+ TYPE_ELEMENT, CONF_VALUE_16_BIT(3),
+ &li.explosion_element[3], EL_PLAYER_4
},
+
{
- EL_PLAYER_1, CONF_VALUE_ELEMENT_3,
- &li.explosion_element[0], EL_PLAYER_1
+ EL_EMERALD, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(1),
+ &li.score[SC_EMERALD], 10
},
+
{
- EL_PLAYER_2, CONF_VALUE_ELEMENT_3,
- &li.explosion_element[1], EL_PLAYER_2
+ EL_DIAMOND, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(1),
+ &li.score[SC_DIAMOND], 10
},
+
{
- EL_PLAYER_3, CONF_VALUE_ELEMENT_3,
- &li.explosion_element[2], EL_PLAYER_3
+ EL_BUG, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(1),
+ &li.score[SC_BUG], 10
},
+
{
- EL_PLAYER_4, CONF_VALUE_ELEMENT_3,
- &li.explosion_element[3], EL_PLAYER_4
+ EL_SPACESHIP, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(1),
+ &li.score[SC_SPACESHIP], 10
},
- /* ---------- multi-byte values ------------------------------------------ */
-
{
- EL_EMC_MAGIC_BALL, CONF_VALUE_CONTENTS,
- &li.ball_content, EL_EMPTY,
- &li.num_ball_contents, 4, MAX_ELEMENT_CONTENTS
+ EL_PACMAN, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(1),
+ &li.score[SC_PACMAN], 10
},
+
{
- EL_EMC_ANDROID, CONF_VALUE_ELEMENTS,
- &li.android_clone_element[0], EL_EMPTY,
- &li.num_android_clone_elements, 1, MAX_ANDROID_ELEMENTS
+ EL_NUT, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(1),
+ &li.score[SC_NUT], 10
},
{
- -1, -1,
- NULL, -1,
+ EL_DYNAMITE, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(1),
+ &li.score[SC_DYNAMITE], 10
},
-};
-static struct
-{
- int filetype;
- char *id;
-}
-filetype_id_list[] =
-{
- { LEVEL_FILE_TYPE_RND, "RND" },
- { LEVEL_FILE_TYPE_BD, "BD" },
- { LEVEL_FILE_TYPE_EM, "EM" },
- { LEVEL_FILE_TYPE_SP, "SP" },
- { LEVEL_FILE_TYPE_DX, "DX" },
- { LEVEL_FILE_TYPE_SB, "SB" },
- { LEVEL_FILE_TYPE_DC, "DC" },
- { -1, NULL },
-};
+ {
+ EL_KEY_1, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(1),
+ &li.score[SC_KEY], 10
+ },
+ {
+ EL_PEARL, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(1),
+ &li.score[SC_PEARL], 10
+ },
-/* ========================================================================= */
-/* level file functions */
-/* ========================================================================= */
+ {
+ EL_CRYSTAL, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(1),
+ &li.score[SC_CRYSTAL], 10
+ },
-static void setLevelInfoToDefaultsFromConfigList(struct LevelInfo *level)
-{
- int i;
+ {
+ EL_BD_AMOEBA, -1,
+ TYPE_ELEMENT, CONF_VALUE_16_BIT(1),
+ &li.amoeba_content, EL_DIAMOND
+ },
+ {
+ EL_BD_AMOEBA, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(2),
+ &li.amoeba_speed, 10
+ },
+ {
+ EL_BD_AMOEBA, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(1),
+ &li.grow_into_diggable, TRUE
+ },
- li = *level; /* copy level information into temporary buffer */
+ {
+ EL_YAMYAM, -1,
+ TYPE_CONTENT_LIST, CONF_VALUE_BYTES(1),
+ &li.yamyam_content, EL_ROCK, NULL,
+ &li.num_yamyam_contents, 4, MAX_ELEMENT_CONTENTS
+ },
+ {
+ EL_YAMYAM, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(1),
+ &li.score[SC_YAMYAM], 10
+ },
- for (i = 0; element_conf[i].element != -1; i++)
{
- int default_value = element_conf[i].default_value;
- int type = element_conf[i].type;
- int bytes = type & CONF_MASK_BYTES;
+ EL_ROBOT, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(1),
+ &li.score[SC_ROBOT], 10
+ },
+ {
+ EL_ROBOT, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(2),
+ &li.slurp_score, 10
+ },
- if (bytes == CONF_MASK_MULTI_BYTES)
- {
- int default_num_entities = element_conf[i].default_num_entities;
- int max_num_entities = element_conf[i].max_num_entities;
+ {
+ EL_ROBOT_WHEEL, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(1),
+ &li.time_wheel, 10
+ },
- *(int *)(element_conf[i].num_entities) = default_num_entities;
+ {
+ EL_MAGIC_WALL, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(1),
+ &li.time_magic_wall, 10
+ },
- if (type == CONF_VALUE_ELEMENTS)
- {
- int *element_array = (int *)(element_conf[i].value);
- int j;
+ {
+ EL_GAME_OF_LIFE, -1,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(1),
+ &li.game_of_life[0], 2
+ },
+ {
+ EL_GAME_OF_LIFE, -1,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(2),
+ &li.game_of_life[1], 3
+ },
+ {
+ EL_GAME_OF_LIFE, -1,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(3),
+ &li.game_of_life[2], 3
+ },
+ {
+ EL_GAME_OF_LIFE, -1,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(4),
+ &li.game_of_life[3], 3
+ },
- for (j = 0; j < max_num_entities; j++)
- element_array[j] = default_value;
- }
- else if (type == CONF_VALUE_CONTENTS)
- {
- struct Content *content = (struct Content *)(element_conf[i].value);
- int c, x, y;
+ {
+ EL_BIOMAZE, -1,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(1),
+ &li.biomaze[0], 2
+ },
+ {
+ EL_BIOMAZE, -1,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(2),
+ &li.biomaze[1], 3
+ },
+ {
+ EL_BIOMAZE, -1,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(3),
+ &li.biomaze[2], 3
+ },
+ {
+ EL_BIOMAZE, -1,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(4),
+ &li.biomaze[3], 3
+ },
- for (c = 0; c < max_num_entities; c++)
- for (y = 0; y < 3; y++)
- for (x = 0; x < 3; x++)
- content[c].e[x][y] = default_value;
- }
- }
- else /* constant size configuration data (1, 2 or 4 bytes) */
- {
- if (CONF_VALUE_BOOLEAN(type))
- *(boolean *)(element_conf[i].value) = default_value;
- else
- *(int *) (element_conf[i].value) = default_value;
- }
- }
+ {
+ EL_TIMEGATE_SWITCH, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(1),
+ &li.time_timegate, 10
+ },
- *level = li; /* copy temporary buffer back to level information */
-}
+ {
+ EL_LIGHT_SWITCH_ACTIVE, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(1),
+ &li.time_light, 10
+ },
-void setElementChangePages(struct ElementInfo *ei, int change_pages)
-{
- int change_page_size = sizeof(struct ElementChangeInfo);
+ {
+ EL_SHIELD_NORMAL, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(1),
+ &li.shield_normal_time, 10
+ },
+ {
+ EL_SHIELD_NORMAL, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(2),
+ &li.score[SC_SHIELD], 10
+ },
- ei->num_change_pages = MAX(1, change_pages);
+ {
+ EL_SHIELD_DEADLY, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(1),
+ &li.shield_deadly_time, 10
+ },
+ {
+ EL_SHIELD_DEADLY, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(2),
+ &li.score[SC_SHIELD], 10
+ },
- ei->change_page =
- checked_realloc(ei->change_page, ei->num_change_pages * change_page_size);
+ {
+ EL_EXTRA_TIME, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(1),
+ &li.extra_time, 10
+ },
+ {
+ EL_EXTRA_TIME, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(2),
+ &li.extra_time_score, 10
+ },
- if (ei->current_change_page >= ei->num_change_pages)
- ei->current_change_page = ei->num_change_pages - 1;
+ {
+ EL_TIME_ORB_FULL, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(1),
+ &li.time_orb_time, 10
+ },
+ {
+ EL_TIME_ORB_FULL, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(1),
+ &li.use_time_orb_bug, FALSE
+ },
- ei->change = &ei->change_page[ei->current_change_page];
+ {
+ EL_SPRING, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(1),
+ &li.use_spring_bug, FALSE
+ },
+
+ {
+ EL_EMC_ANDROID, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(1),
+ &li.android_move_time, 10
+ },
+ {
+ EL_EMC_ANDROID, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(2),
+ &li.android_clone_time, 10
+ },
+ {
+ EL_EMC_ANDROID, -1,
+ TYPE_ELEMENT_LIST, CONF_VALUE_BYTES(1),
+ &li.android_clone_element[0], EL_EMPTY, NULL,
+ &li.num_android_clone_elements, 1, MAX_ANDROID_ELEMENTS
+ },
+
+ {
+ EL_EMC_LENSES, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(1),
+ &li.lenses_score, 10
+ },
+ {
+ EL_EMC_LENSES, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(2),
+ &li.lenses_time, 10
+ },
+
+ {
+ EL_EMC_MAGNIFIER, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(1),
+ &li.magnify_score, 10
+ },
+ {
+ EL_EMC_MAGNIFIER, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(2),
+ &li.magnify_time, 10
+ },
+
+ {
+ EL_EMC_MAGIC_BALL, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(1),
+ &li.ball_time, 10
+ },
+ {
+ EL_EMC_MAGIC_BALL, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(1),
+ &li.ball_random, FALSE
+ },
+ {
+ EL_EMC_MAGIC_BALL, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(2),
+ &li.ball_state_initial, FALSE
+ },
+ {
+ EL_EMC_MAGIC_BALL, -1,
+ TYPE_CONTENT_LIST, CONF_VALUE_BYTES(1),
+ &li.ball_content, EL_EMPTY, NULL,
+ &li.num_ball_contents, 4, MAX_ELEMENT_CONTENTS
+ },
+
+ /* ---------- unused values ----------------------------------------------- */
+
+ {
+ EL_UNKNOWN, SAVE_CONF_NEVER,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(1),
+ &li.score[SC_UNKNOWN_14], 10
+ },
+ {
+ EL_UNKNOWN, SAVE_CONF_NEVER,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(2),
+ &li.score[SC_UNKNOWN_15], 10
+ },
+
+ {
+ -1, -1,
+ -1, -1,
+ NULL, -1
+ }
+};
+
+static struct LevelFileConfigInfo chunk_config_NOTE[] =
+{
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(1),
+ &xx_envelope.xsize, MAX_ENVELOPE_XSIZE,
+ },
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(2),
+ &xx_envelope.ysize, MAX_ENVELOPE_YSIZE,
+ },
+
+ {
+ -1, -1,
+ TYPE_STRING, CONF_VALUE_BYTES(1),
+ &xx_envelope.text, -1, NULL,
+ &xx_string_length_unused, -1, MAX_ENVELOPE_TEXT_LEN,
+ &xx_default_string_empty[0]
+ },
+
+ {
+ -1, -1,
+ -1, -1,
+ NULL, -1
+ }
+};
+
+static struct LevelFileConfigInfo chunk_config_CUSX_base[] =
+{
+ {
+ -1, -1,
+ TYPE_STRING, CONF_VALUE_BYTES(1),
+ &xx_ei.description[0], -1,
+ &yy_ei.description[0],
+ &xx_string_length_unused, -1, MAX_ELEMENT_NAME_LEN,
+ &xx_default_description[0]
+ },
+
+ {
+ -1, -1,
+ TYPE_BITFIELD, CONF_VALUE_32_BIT(1),
+ &xx_ei.properties[EP_BITFIELD_BASE_NR], EP_BITMASK_BASE_DEFAULT,
+ &yy_ei.properties[EP_BITFIELD_BASE_NR]
+ },
+#if 0
+ /* (reserved) */
+ {
+ -1, -1,
+ TYPE_BITFIELD, CONF_VALUE_32_BIT(2),
+ &xx_ei.properties[EP_BITFIELD_BASE_NR + 1], EP_BITMASK_DEFAULT,
+ &yy_ei.properties[EP_BITFIELD_BASE_NR + 1]
+ },
+#endif
+
+ {
+ -1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(1),
+ &xx_ei.use_gfx_element, FALSE,
+ &yy_ei.use_gfx_element
+ },
+ {
+ -1, -1,
+ TYPE_ELEMENT, CONF_VALUE_16_BIT(1),
+ &xx_ei.gfx_element, EL_EMPTY_SPACE,
+ &yy_ei.gfx_element
+ },
+
+ {
+ -1, -1,
+ TYPE_BITFIELD, CONF_VALUE_8_BIT(2),
+ &xx_ei.access_direction, MV_ALL_DIRECTIONS,
+ &yy_ei.access_direction
+ },
+
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(2),
+ &xx_ei.collect_score_initial, 10,
+ &yy_ei.collect_score_initial
+ },
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(3),
+ &xx_ei.collect_count_initial, 1,
+ &yy_ei.collect_count_initial
+ },
+
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(4),
+ &xx_ei.ce_value_fixed_initial, 0,
+ &yy_ei.ce_value_fixed_initial
+ },
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(5),
+ &xx_ei.ce_value_random_initial, 0,
+ &yy_ei.ce_value_random_initial
+ },
+ {
+ -1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(3),
+ &xx_ei.use_last_ce_value, FALSE,
+ &yy_ei.use_last_ce_value
+ },
+
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(6),
+ &xx_ei.push_delay_fixed, 8,
+ &yy_ei.push_delay_fixed
+ },
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(7),
+ &xx_ei.push_delay_random, 8,
+ &yy_ei.push_delay_random
+ },
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(8),
+ &xx_ei.drop_delay_fixed, 0,
+ &yy_ei.drop_delay_fixed
+ },
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(9),
+ &xx_ei.drop_delay_random, 0,
+ &yy_ei.drop_delay_random
+ },
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(10),
+ &xx_ei.move_delay_fixed, 0,
+ &yy_ei.move_delay_fixed
+ },
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(11),
+ &xx_ei.move_delay_random, 0,
+ &yy_ei.move_delay_random
+ },
+
+ {
+ -1, -1,
+ TYPE_BITFIELD, CONF_VALUE_32_BIT(3),
+ &xx_ei.move_pattern, MV_ALL_DIRECTIONS,
+ &yy_ei.move_pattern
+ },
+ {
+ -1, -1,
+ TYPE_BITFIELD, CONF_VALUE_8_BIT(4),
+ &xx_ei.move_direction_initial, MV_START_AUTOMATIC,
+ &yy_ei.move_direction_initial
+ },
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(5),
+ &xx_ei.move_stepsize, TILEX / 8,
+ &yy_ei.move_stepsize
+ },
+
+ {
+ -1, -1,
+ TYPE_ELEMENT, CONF_VALUE_16_BIT(12),
+ &xx_ei.move_enter_element, EL_EMPTY_SPACE,
+ &yy_ei.move_enter_element
+ },
+ {
+ -1, -1,
+ TYPE_ELEMENT, CONF_VALUE_16_BIT(13),
+ &xx_ei.move_leave_element, EL_EMPTY_SPACE,
+ &yy_ei.move_leave_element
+ },
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(6),
+ &xx_ei.move_leave_type, LEAVE_TYPE_UNLIMITED,
+ &yy_ei.move_leave_type
+ },
+
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(7),
+ &xx_ei.slippery_type, SLIPPERY_ANY_RANDOM,
+ &yy_ei.slippery_type
+ },
+
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(8),
+ &xx_ei.explosion_type, EXPLODES_3X3,
+ &yy_ei.explosion_type
+ },
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(14),
+ &xx_ei.explosion_delay, 16,
+ &yy_ei.explosion_delay
+ },
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(15),
+ &xx_ei.ignition_delay, 8,
+ &yy_ei.ignition_delay
+ },
+
+ {
+ -1, -1,
+ TYPE_CONTENT_LIST, CONF_VALUE_BYTES(2),
+ &xx_ei.content, EL_EMPTY_SPACE,
+ &yy_ei.content,
+ &xx_num_contents, 1, 1
+ },
+
+ /* ---------- "num_change_pages" must be the last entry ------------------- */
+
+ {
+ -1, SAVE_CONF_ALWAYS,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(9),
+ &xx_ei.num_change_pages, 1,
+ &yy_ei.num_change_pages
+ },
+
+ {
+ -1, -1,
+ -1, -1,
+ NULL, -1,
+ NULL
+ }
+};
+
+static struct LevelFileConfigInfo chunk_config_CUSX_change[] =
+{
+ /* ---------- "current_change_page" must be the first entry --------------- */
+
+ {
+ -1, SAVE_CONF_ALWAYS,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(1),
+ &xx_current_change_page, -1
+ },
+
+ /* ---------- (the remaining entries can be in any order) ----------------- */
+
+ {
+ -1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(2),
+ &xx_change.can_change, FALSE
+ },
+
+ {
+ -1, -1,
+ TYPE_BITFIELD, CONF_VALUE_32_BIT(1),
+ &xx_event_bits[0], 0
+ },
+ {
+ -1, -1,
+ TYPE_BITFIELD, CONF_VALUE_32_BIT(2),
+ &xx_event_bits[1], 0
+ },
+
+ {
+ -1, -1,
+ TYPE_BITFIELD, CONF_VALUE_8_BIT(3),
+ &xx_change.trigger_player, CH_PLAYER_ANY
+ },
+ {
+ -1, -1,
+ TYPE_BITFIELD, CONF_VALUE_8_BIT(4),
+ &xx_change.trigger_side, CH_SIDE_ANY
+ },
+ {
+ -1, -1,
+ TYPE_BITFIELD, CONF_VALUE_32_BIT(3),
+ &xx_change.trigger_page, CH_PAGE_ANY
+ },
+
+ {
+ -1, -1,
+ TYPE_ELEMENT, CONF_VALUE_16_BIT(1),
+ &xx_change.target_element, EL_EMPTY_SPACE
+ },
+
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(2),
+ &xx_change.delay_fixed, 0
+ },
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(3),
+ &xx_change.delay_random, 0
+ },
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(4),
+ &xx_change.delay_frames, FRAMES_PER_SECOND
+ },
+
+ {
+ -1, -1,
+ TYPE_ELEMENT, CONF_VALUE_16_BIT(5),
+ &xx_change.trigger_element, EL_EMPTY_SPACE
+ },
+
+ {
+ -1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(6),
+ &xx_change.explode, FALSE
+ },
+ {
+ -1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(7),
+ &xx_change.use_target_content, FALSE
+ },
+ {
+ -1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(8),
+ &xx_change.only_if_complete, FALSE
+ },
+ {
+ -1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(9),
+ &xx_change.use_random_replace, FALSE
+ },
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(10),
+ &xx_change.random_percentage, 100
+ },
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(11),
+ &xx_change.replace_when, CP_WHEN_EMPTY
+ },
+
+ {
+ -1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(12),
+ &xx_change.has_action, FALSE
+ },
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(13),
+ &xx_change.action_type, CA_NO_ACTION
+ },
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(14),
+ &xx_change.action_mode, CA_MODE_UNDEFINED
+ },
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_16_BIT(6),
+ &xx_change.action_arg, CA_ARG_UNDEFINED
+ },
+
+ {
+ -1, -1,
+ TYPE_CONTENT_LIST, CONF_VALUE_BYTES(1),
+ &xx_change.target_content, EL_EMPTY_SPACE, NULL,
+ &xx_num_contents, 1, 1
+ },
+
+ {
+ -1, -1,
+ -1, -1,
+ NULL, -1
+ }
+};
+
+static struct LevelFileConfigInfo chunk_config_GRPX[] =
+{
+ {
+ -1, -1,
+ TYPE_STRING, CONF_VALUE_BYTES(1),
+ &xx_ei.description[0], -1, NULL,
+ &xx_string_length_unused, -1, MAX_ELEMENT_NAME_LEN,
+ &xx_default_description[0]
+ },
+
+ {
+ -1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(1),
+ &xx_ei.use_gfx_element, FALSE
+ },
+ {
+ -1, -1,
+ TYPE_ELEMENT, CONF_VALUE_16_BIT(1),
+ &xx_ei.gfx_element, EL_EMPTY_SPACE
+ },
+
+ {
+ -1, -1,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(2),
+ &xx_group.choice_mode, ANIM_RANDOM
+ },
+
+ {
+ -1, -1,
+ TYPE_ELEMENT_LIST, CONF_VALUE_BYTES(2),
+ &xx_group.element[0], EL_EMPTY_SPACE, NULL,
+ &xx_group.num_elements, 1, MAX_ELEMENTS_IN_GROUP
+ },
+
+ {
+ -1, -1,
+ -1, -1,
+ NULL, -1
+ }
+};
+
+static struct LevelFileConfigInfo chunk_config_CONF[] = /* (OBSOLETE) */
+{
+ {
+ EL_PLAYER_1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(9),
+ &li.block_snap_field, TRUE
+ },
+ {
+ EL_PLAYER_1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(13),
+ &li.continuous_snapping, TRUE
+ },
+ {
+ EL_PLAYER_1, -1,
+ TYPE_INTEGER, CONF_VALUE_8_BIT(1),
+ &li.initial_player_stepsize[0], STEPSIZE_NORMAL
+ },
+ {
+ EL_PLAYER_1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(10),
+ &li.use_start_element[0], FALSE
+ },
+ {
+ EL_PLAYER_1, -1,
+ TYPE_ELEMENT, CONF_VALUE_16_BIT(1),
+ &li.start_element[0], EL_PLAYER_1
+ },
+ {
+ EL_PLAYER_1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(11),
+ &li.use_artwork_element[0], FALSE
+ },
+ {
+ EL_PLAYER_1, -1,
+ TYPE_ELEMENT, CONF_VALUE_16_BIT(2),
+ &li.artwork_element[0], EL_PLAYER_1
+ },
+ {
+ EL_PLAYER_1, -1,
+ TYPE_BOOLEAN, CONF_VALUE_8_BIT(12),
+ &li.use_explosion_element[0], FALSE
+ },
+ {
+ EL_PLAYER_1, -1,
+ TYPE_ELEMENT, CONF_VALUE_16_BIT(3),
+ &li.explosion_element[0], EL_PLAYER_1
+ },
+
+ {
+ -1, -1,
+ -1, -1,
+ NULL, -1
+ }
+};
+
+static struct
+{
+ int filetype;
+ char *id;
}
+filetype_id_list[] =
+{
+ { LEVEL_FILE_TYPE_RND, "RND" },
+ { LEVEL_FILE_TYPE_BD, "BD" },
+ { LEVEL_FILE_TYPE_EM, "EM" },
+ { LEVEL_FILE_TYPE_SP, "SP" },
+ { LEVEL_FILE_TYPE_DX, "DX" },
+ { LEVEL_FILE_TYPE_SB, "SB" },
+ { LEVEL_FILE_TYPE_DC, "DC" },
+ { -1, NULL },
+};
-void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
+
+/* ========================================================================= */
+/* level file functions */
+/* ========================================================================= */
+
+static struct DateInfo getCurrentDate()
{
- int i, x, y;
+ time_t epoch_seconds = time(NULL);
+ struct tm *now = localtime(&epoch_seconds);
+ struct DateInfo date;
+
+ date.year = now->tm_year + 1900;
+ date.month = now->tm_mon + 1;
+ date.day = now->tm_mday;
- change->can_change = FALSE;
+ return date;
+}
+
+static void resetEventFlags(struct ElementChangeInfo *change)
+{
+ int i;
for (i = 0; i < NUM_CHANGE_EVENTS; i++)
change->has_event[i] = FALSE;
+}
+
+static void resetEventBits()
+{
+ int i;
+
+ for (i = 0; i < NUM_CE_BITFIELDS; i++)
+ xx_event_bits[i] = 0;
+}
+
+static void setEventFlagsFromEventBits(struct ElementChangeInfo *change)
+{
+ int i;
+
+ /* important: only change event flag if corresponding event bit is set
+ (this is because all xx_event_bits[] values are loaded separately,
+ and all xx_event_bits[] values are set back to zero before loading
+ another value xx_event_bits[x] (each value representing 32 flags)) */
+
+ for (i = 0; i < NUM_CHANGE_EVENTS; i++)
+ if (xx_event_bits[CH_EVENT_BITFIELD_NR(i)] & CH_EVENT_BIT(i))
+ change->has_event[i] = TRUE;
+}
+
+static void setEventBitsFromEventFlags(struct ElementChangeInfo *change)
+{
+ int i;
+
+ /* in contrast to the above function setEventFlagsFromEventBits(), it
+ would also be possible to set all bits in xx_event_bits[] to 0 or 1
+ depending on the corresponding change->has_event[i] values here, as
+ all xx_event_bits[] values are reset in resetEventBits() before */
+
+ for (i = 0; i < NUM_CHANGE_EVENTS; i++)
+ if (change->has_event[i])
+ xx_event_bits[CH_EVENT_BITFIELD_NR(i)] |= CH_EVENT_BIT(i);
+}
+
+static char *getDefaultElementDescription(struct ElementInfo *ei)
+{
+ static char description[MAX_ELEMENT_NAME_LEN + 1];
+ char *default_description = (ei->custom_description != NULL ?
+ ei->custom_description :
+ ei->editor_description);
+ int i;
+
+ /* always start with reliable default values */
+ for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++)
+ description[i] = '\0';
+
+ /* truncate element description to MAX_ELEMENT_NAME_LEN bytes */
+ strncpy(description, default_description, MAX_ELEMENT_NAME_LEN);
+
+ return &description[0];
+}
+
+static void setElementDescriptionToDefault(struct ElementInfo *ei)
+{
+ char *default_description = getDefaultElementDescription(ei);
+ int i;
+
+ for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++)
+ ei->description[i] = default_description[i];
+}
+
+static void setConfigToDefaultsFromConfigList(struct LevelFileConfigInfo *conf)
+{
+ int i;
+
+ for (i = 0; conf[i].data_type != -1; i++)
+ {
+ int default_value = conf[i].default_value;
+ int data_type = conf[i].data_type;
+ int conf_type = conf[i].conf_type;
+ int byte_mask = conf_type & CONF_MASK_BYTES;
+
+ if (byte_mask == CONF_MASK_MULTI_BYTES)
+ {
+ int default_num_entities = conf[i].default_num_entities;
+ int max_num_entities = conf[i].max_num_entities;
+
+ *(int *)(conf[i].num_entities) = default_num_entities;
+
+ if (data_type == TYPE_STRING)
+ {
+ char *default_string = conf[i].default_string;
+ char *string = (char *)(conf[i].value);
+
+ strncpy(string, default_string, max_num_entities);
+ }
+ else if (data_type == TYPE_ELEMENT_LIST)
+ {
+ int *element_array = (int *)(conf[i].value);
+ int j;
+
+ for (j = 0; j < max_num_entities; j++)
+ element_array[j] = default_value;
+ }
+ else if (data_type == TYPE_CONTENT_LIST)
+ {
+ struct Content *content = (struct Content *)(conf[i].value);
+ int c, x, y;
+
+ for (c = 0; c < max_num_entities; c++)
+ for (y = 0; y < 3; y++)
+ for (x = 0; x < 3; x++)
+ content[c].e[x][y] = default_value;
+ }
+ }
+ else /* constant size configuration data (1, 2 or 4 bytes) */
+ {
+ if (data_type == TYPE_BOOLEAN)
+ *(boolean *)(conf[i].value) = default_value;
+ else
+ *(int *) (conf[i].value) = default_value;
+ }
+ }
+}
+
+static void copyConfigFromConfigList(struct LevelFileConfigInfo *conf)
+{
+ int i;
+
+ for (i = 0; conf[i].data_type != -1; i++)
+ {
+ int data_type = conf[i].data_type;
+ int conf_type = conf[i].conf_type;
+ int byte_mask = conf_type & CONF_MASK_BYTES;
+
+ if (byte_mask == CONF_MASK_MULTI_BYTES)
+ {
+ int max_num_entities = conf[i].max_num_entities;
+
+ if (data_type == TYPE_STRING)
+ {
+ char *string = (char *)(conf[i].value);
+ char *string_copy = (char *)(conf[i].value_copy);
+
+ strncpy(string_copy, string, max_num_entities);
+ }
+ else if (data_type == TYPE_ELEMENT_LIST)
+ {
+ int *element_array = (int *)(conf[i].value);
+ int *element_array_copy = (int *)(conf[i].value_copy);
+ int j;
+
+ for (j = 0; j < max_num_entities; j++)
+ element_array_copy[j] = element_array[j];
+ }
+ else if (data_type == TYPE_CONTENT_LIST)
+ {
+ struct Content *content = (struct Content *)(conf[i].value);
+ struct Content *content_copy = (struct Content *)(conf[i].value_copy);
+ int c, x, y;
+
+ for (c = 0; c < max_num_entities; c++)
+ for (y = 0; y < 3; y++)
+ for (x = 0; x < 3; x++)
+ content_copy[c].e[x][y] = content[c].e[x][y];
+ }
+ }
+ else /* constant size configuration data (1, 2 or 4 bytes) */
+ {
+ if (data_type == TYPE_BOOLEAN)
+ *(boolean *)(conf[i].value_copy) = *(boolean *)(conf[i].value);
+ else
+ *(int *) (conf[i].value_copy) = *(int *) (conf[i].value);
+ }
+ }
+}
+
+void copyElementInfo(struct ElementInfo *ei_from, struct ElementInfo *ei_to)
+{
+ int i;
+
+ xx_ei = *ei_from; /* copy element data into temporary buffer */
+ yy_ei = *ei_to; /* copy element data into temporary buffer */
+
+ copyConfigFromConfigList(chunk_config_CUSX_base);
+
+ *ei_from = xx_ei;
+ *ei_to = yy_ei;
+
+ /* ---------- reinitialize and copy change pages ---------- */
+
+ ei_to->num_change_pages = ei_from->num_change_pages;
+ ei_to->current_change_page = ei_from->current_change_page;
+
+ setElementChangePages(ei_to, ei_to->num_change_pages);
+
+ for (i = 0; i < ei_to->num_change_pages; i++)
+ ei_to->change_page[i] = ei_from->change_page[i];
+
+ /* ---------- copy group element info ---------- */
+ if (ei_from->group != NULL && ei_to->group != NULL) /* group or internal */
+ *ei_to->group = *ei_from->group;
+
+ /* mark this custom element as modified */
+ ei_to->modified_settings = TRUE;
+}
+
+void setElementChangePages(struct ElementInfo *ei, int change_pages)
+{
+ int change_page_size = sizeof(struct ElementChangeInfo);
+
+ ei->num_change_pages = MAX(1, change_pages);
+
+ ei->change_page =
+ checked_realloc(ei->change_page, ei->num_change_pages * change_page_size);
- change->trigger_player = CH_PLAYER_ANY;
- change->trigger_side = CH_SIDE_ANY;
- change->trigger_page = CH_PAGE_ANY;
+ if (ei->current_change_page >= ei->num_change_pages)
+ ei->current_change_page = ei->num_change_pages - 1;
- change->target_element = EL_EMPTY_SPACE;
+ ei->change = &ei->change_page[ei->current_change_page];
+}
- change->delay_fixed = 0;
- change->delay_random = 0;
- change->delay_frames = FRAMES_PER_SECOND;
+void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
+{
+ xx_change = *change; /* copy change data into temporary buffer */
- change->trigger_element = EL_EMPTY_SPACE;
+#if 0
+ /* (not needed; set by setConfigToDefaultsFromConfigList()) */
+ xx_num_contents = 1;
+#endif
- change->explode = FALSE;
- change->use_target_content = FALSE;
- change->only_if_complete = FALSE;
- change->use_random_replace = FALSE;
- change->random_percentage = 100;
- change->replace_when = CP_WHEN_EMPTY;
+ setConfigToDefaultsFromConfigList(chunk_config_CUSX_change);
- change->has_action = FALSE;
- change->action_type = CA_NO_ACTION;
- change->action_mode = CA_MODE_UNDEFINED;
- change->action_arg = CA_ARG_UNDEFINED;
+ *change = xx_change;
- for (x = 0; x < 3; x++)
- for (y = 0; y < 3; y++)
- change->target_content.e[x][y] = EL_EMPTY_SPACE;
+ resetEventFlags(change);
change->direct_action = 0;
change->other_action = 0;
static void setLevelInfoToDefaults(struct LevelInfo *level)
{
static boolean clipboard_elements_initialized = FALSE;
- int i, j, x, y;
+ int i, x, y;
-#if 1
InitElementPropertiesStatic();
-#endif
- setLevelInfoToDefaultsFromConfigList(level);
+ li = *level; /* copy level data into temporary buffer */
+
+ setConfigToDefaultsFromConfigList(chunk_config_INFO);
+ setConfigToDefaultsFromConfigList(chunk_config_ELEM);
+
+ *level = li; /* copy temporary buffer back to level data */
+
setLevelInfoToDefaults_EM();
level->native_em_level = &native_em_level;
- level->game_engine_type = GAME_ENGINE_TYPE_RND;
-
level->file_version = FILE_VERSION_ACTUAL;
level->game_version = GAME_VERSION_ACTUAL;
- level->encoding_16bit_field = FALSE; /* default: only 8-bit elements */
- level->encoding_16bit_yamyam = FALSE; /* default: only 8-bit elements */
- level->encoding_16bit_amoeba = FALSE; /* default: only 8-bit elements */
+ level->creation_date = getCurrentDate();
- level->fieldx = STD_LEV_FIELDX;
- level->fieldy = STD_LEV_FIELDY;
+ level->encoding_16bit_field = TRUE;
+ level->encoding_16bit_yamyam = TRUE;
+ level->encoding_16bit_amoeba = TRUE;
for (x = 0; x < MAX_LEV_FIELDX; x++)
for (y = 0; y < MAX_LEV_FIELDY; y++)
level->field[x][y] = EL_SAND;
- level->time = 100;
- level->gems_needed = 0;
-
- level->amoeba_speed = 10;
-
- level->time_magic_wall = 10;
- level->time_wheel = 10;
-#if 0
- level->time_light = 10;
- level->time_timegate = 10;
-#endif
-
- level->amoeba_content = EL_DIAMOND;
-
- level->game_of_life[0] = 2;
- level->game_of_life[1] = 3;
- level->game_of_life[2] = 3;
- level->game_of_life[3] = 3;
-
- level->biomaze[0] = 2;
- level->biomaze[1] = 3;
- level->biomaze[2] = 3;
- level->biomaze[3] = 3;
-
-#if 0
- level->double_speed = FALSE;
-#endif
- level->initial_gravity = FALSE;
- level->em_slippery_gems = FALSE;
- level->instant_relocation = FALSE;
- level->can_pass_to_walkable = FALSE;
- level->grow_into_diggable = TRUE;
-
-#if 0
- level->block_snap_field = TRUE;
-#endif
-
- level->block_last_field = FALSE; /* EM does not block by default */
- level->sp_block_last_field = TRUE; /* SP blocks the last field */
-
- level->can_move_into_acid_bits = ~0; /* everything can move into acid */
- level->dont_collide_with_bits = ~0; /* always deadly when colliding */
-
- level->use_spring_bug = FALSE;
- level->use_time_orb_bug = FALSE;
-
- level->use_step_counter = FALSE;
-
- /* values for the new EMC elements */
-#if 0
- level->android_move_time = 10;
- level->android_clone_time = 10;
- level->ball_time = 10;
- level->lenses_score = 10;
- level->lenses_time = 10;
- level->magnify_score = 10;
- level->magnify_time = 10;
- level->slurp_score = 10;
- level->wind_direction_initial = MV_NONE;
- level->ball_random = FALSE;
- level->ball_state_initial = FALSE;
- for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
- for (x = 0; x < 3; x++)
- for (y = 0; y < 3; y++)
- level->ball_content[i].e[x][y] = EL_EMPTY;
-#endif
-#if 0
- for (i = 0; i < 16; i++)
- level->android_array[i] = FALSE;
-#endif
-
- level->use_custom_template = FALSE;
-
for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
level->name[i] = '\0';
for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
strcpy(level->name, NAMELESS_LEVEL_NAME);
strcpy(level->author, ANONYMOUS_NAME);
- for (i = 0; i < 4; i++)
- {
- level->envelope_text[i][0] = '\0';
- level->envelope_xsize[i] = MAX_ENVELOPE_XSIZE;
- level->envelope_ysize[i] = MAX_ENVELOPE_YSIZE;
- }
-
- for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
- level->score[i] = (i == SC_TIME_BONUS ? 1 : 10);
-
- level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
- for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
- for (x = 0; x < 3; x++)
- for (y = 0; y < 3; y++)
- level->yamyam_content[i].e[x][y] =
- (i < STD_ELEMENT_CONTENTS ? EL_ROCK : EL_EMPTY);
-
level->field[0][0] = EL_PLAYER_1;
level->field[STD_LEV_FIELDX - 1][STD_LEV_FIELDY - 1] = EL_EXIT_CLOSED;
struct ElementInfo *ei = &element_info[element];
/* never initialize clipboard elements after the very first time */
+ /* (to be able to use clipboard elements between several levels) */
if (IS_CLIPBOARD_ELEMENT(element) && clipboard_elements_initialized)
continue;
- setElementChangePages(ei, 1);
- setElementChangeInfoToDefaults(ei->change);
-
- if (IS_CUSTOM_ELEMENT(element) ||
- IS_GROUP_ELEMENT(element) ||
- IS_INTERNAL_ELEMENT(element))
+ if (IS_ENVELOPE(element))
{
- for (j = 0; j < MAX_ELEMENT_NAME_LEN + 1; j++)
- ei->description[j] = '\0';
-
- if (ei->custom_description != NULL)
- strncpy(ei->description, ei->custom_description,MAX_ELEMENT_NAME_LEN);
- else
- strcpy(ei->description, ei->editor_description);
+ int envelope_nr = element - EL_ENVELOPE_1;
- ei->use_gfx_element = FALSE;
- ei->gfx_element = EL_EMPTY_SPACE;
+ setConfigToDefaultsFromConfigList(chunk_config_NOTE);
- ei->modified_settings = FALSE;
+ level->envelope[envelope_nr] = xx_envelope;
}
if (IS_CUSTOM_ELEMENT(element) ||
+ IS_GROUP_ELEMENT(element) ||
IS_INTERNAL_ELEMENT(element))
{
- ei->access_direction = MV_ALL_DIRECTIONS;
-
- ei->collect_score_initial = 10; /* special default */
- ei->collect_count_initial = 1; /* special default */
+ xx_ei = *ei; /* copy element data into temporary buffer */
- ei->ce_value_fixed_initial = 0;
- ei->ce_value_random_initial = 0;
- ei->use_last_ce_value = FALSE;
+ setConfigToDefaultsFromConfigList(chunk_config_CUSX_base);
- ei->push_delay_fixed = -1; /* initialize later */
- ei->push_delay_random = -1; /* initialize later */
- ei->drop_delay_fixed = 0;
- ei->drop_delay_random = 0;
- ei->move_delay_fixed = 0;
- ei->move_delay_random = 0;
-
- ei->move_pattern = MV_ALL_DIRECTIONS;
- ei->move_direction_initial = MV_START_AUTOMATIC;
- ei->move_stepsize = TILEX / 8;
+ *ei = xx_ei;
+ }
- ei->move_enter_element = EL_EMPTY_SPACE;
- ei->move_leave_element = EL_EMPTY_SPACE;
- ei->move_leave_type = LEAVE_TYPE_UNLIMITED;
+ setElementChangePages(ei, 1);
+ setElementChangeInfoToDefaults(ei->change);
- ei->slippery_type = SLIPPERY_ANY_RANDOM;
+ if (IS_CUSTOM_ELEMENT(element) ||
+ IS_GROUP_ELEMENT(element) ||
+ IS_INTERNAL_ELEMENT(element))
+ {
+ setElementDescriptionToDefault(ei);
- ei->explosion_type = EXPLODES_3X3;
- ei->explosion_delay = 16;
- ei->ignition_delay = 8;
+ ei->modified_settings = FALSE;
+ }
- for (x = 0; x < 3; x++)
- for (y = 0; y < 3; y++)
- ei->content.e[x][y] = EL_EMPTY_SPACE;
+ if (IS_CUSTOM_ELEMENT(element) ||
+ IS_INTERNAL_ELEMENT(element))
+ {
+ /* internal values used in level editor */
ei->access_type = 0;
ei->access_layer = 0;
ei->can_explode_impact = FALSE;
ei->current_change_page = 0;
-
-#if 0
- /* !!! now done in InitElementPropertiesStatic() (see above) !!! */
- /* !!! (else properties set there will be overwritten here) !!! */
- /* start with no properties at all */
-#if 1
- for (j = 0; j < NUM_EP_BITFIELDS; j++)
- ei->properties[j] = EP_BITMASK_DEFAULT;
-#else
- for (j = 0; j < NUM_EP_BITFIELDS; j++)
- Properties[element][j] = EP_BITMASK_DEFAULT;
-#endif
-#endif
-
- /* now set default properties */
- SET_PROPERTY(element, EP_CAN_MOVE_INTO_ACID, TRUE);
}
if (IS_GROUP_ELEMENT(element) ||
group = ei->group;
- for (j = 0; j < MAX_ELEMENTS_IN_GROUP; j++)
- group->element[j] = EL_EMPTY_SPACE;
+ xx_group = *group; /* copy group data into temporary buffer */
- /* default: only one element in group */
- group->num_elements = 1;
+ setConfigToDefaultsFromConfigList(chunk_config_GRPX);
- group->choice_mode = ANIM_RANDOM;
+ *group = xx_group;
}
}
static void ActivateLevelTemplate()
{
-#if 1
/* Currently there is no special action needed to activate the template
data, because 'element_info' property settings overwrite the original
level data, while all other variables do not change. */
-#else
- /* Currently there is no special action needed to activate the template
- data, because 'element_info' and 'Properties' overwrite the original
- level data, while all other variables do not change. */
-#endif
}
static char *getLevelFilenameFromBasename(char *basename)
return chunk_size;
}
+static int LoadLevel_DATE(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+ level->creation_date.year = getFile16BitBE(file);
+ level->creation_date.month = getFile8Bit(file);
+ level->creation_date.day = getFile8Bit(file);
+
+ return chunk_size;
+}
+
static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
{
+ int initial_player_stepsize;
+ int initial_player_gravity;
int i, x, y;
level->fieldx = getFile8Bit(file);
level->time_wheel = getFile8Bit(file);
level->amoeba_content = getMappedElement(getFile8Bit(file));
- level->initial_player_stepsize = (getFile8Bit(file) == 1 ? STEPSIZE_FAST :
- STEPSIZE_NORMAL);
+ initial_player_stepsize = (getFile8Bit(file) == 1 ? STEPSIZE_FAST :
+ STEPSIZE_NORMAL);
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ level->initial_player_stepsize[i] = initial_player_stepsize;
+
+ initial_player_gravity = (getFile8Bit(file) == 1 ? TRUE : FALSE);
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ level->initial_player_gravity[i] = initial_player_gravity;
- level->initial_gravity = (getFile8Bit(file) == 1 ? TRUE : FALSE);
level->encoding_16bit_field = (getFile8Bit(file) == 1 ? TRUE : FALSE);
level->em_slippery_gems = (getFile8Bit(file) == 1 ? TRUE : FALSE);
level->game_engine_type = getFile8Bit(file);
- ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED);
+ ReadUnusedBytesFromFile(file, LEVEL_CHUNK_HEAD_UNUSED);
+
+ return chunk_size;
+}
+
+static int LoadLevel_NAME(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+ int i;
+
+ for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
+ level->name[i] = getFile8Bit(file);
+ level->name[MAX_LEVEL_NAME_LEN] = 0;
return chunk_size;
}
for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
level->author[i] = getFile8Bit(file);
- level->author[MAX_LEVEL_NAME_LEN] = 0;
+ level->author[MAX_LEVEL_AUTHOR_LEN] = 0;
return chunk_size;
}
envelope_len = getFile16BitBE(file);
- level->envelope_xsize[envelope_nr] = getFile8Bit(file);
- level->envelope_ysize[envelope_nr] = getFile8Bit(file);
+ level->envelope[envelope_nr].xsize = getFile8Bit(file);
+ level->envelope[envelope_nr].ysize = getFile8Bit(file);
ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT3_UNUSED);
}
for (i = 0; i < envelope_len; i++)
- level->envelope_text[envelope_nr][i] = getFile8Bit(file);
+ level->envelope[envelope_nr].text[i] = getFile8Bit(file);
return chunk_size;
}
for (i = 0; i < num_changed_custom_elements; i++)
{
- int element = getFile16BitBE(file);
+ int element = getMappedElement(getFile16BitBE(file));
int properties = getFile32BitBE(file);
-#if 1
- if (IS_CUSTOM_ELEMENT(element))
- element_info[element].properties[EP_BITFIELD_BASE] = properties;
- else
- Error(ERR_WARN, "invalid custom element number %d", element);
-#else
if (IS_CUSTOM_ELEMENT(element))
- Properties[element][EP_BITFIELD_BASE] = properties;
+ element_info[element].properties[EP_BITFIELD_BASE_NR] = properties;
else
Error(ERR_WARN, "invalid custom element number %d", element);
-#endif
+
+ /* older game versions that wrote level files with CUS1 chunks used
+ different default push delay values (not yet stored in level file) */
+ element_info[element].push_delay_fixed = 2;
+ element_info[element].push_delay_random = 8;
}
return chunk_size;
for (i = 0; i < num_changed_custom_elements; i++)
{
- int element = getFile16BitBE(file);
- int custom_target_element = getFile16BitBE(file);
+ int element = getMappedElement(getFile16BitBE(file));
+ int custom_target_element = getMappedElement(getFile16BitBE(file));
if (IS_CUSTOM_ELEMENT(element))
element_info[element].change->target_element = custom_target_element;
for (i = 0; i < num_changed_custom_elements; i++)
{
- int element = getFile16BitBE(file);
+ int element = getMappedElement(getFile16BitBE(file));
struct ElementInfo *ei = &element_info[element];
- unsigned long event_bits;
+ unsigned int event_bits;
if (!IS_CUSTOM_ELEMENT(element))
{
ei->description[j] = getFile8Bit(file);
ei->description[MAX_ELEMENT_NAME_LEN] = 0;
-#if 1
- ei->properties[EP_BITFIELD_BASE] = getFile32BitBE(file);
-#else
- Properties[element][EP_BITFIELD_BASE] = getFile32BitBE(file);
-#endif
+ ei->properties[EP_BITFIELD_BASE_NR] = getFile32BitBE(file);
/* some free bytes for future properties and padding */
ReadUnusedBytesFromFile(file, 7);
/* ---------- custom element base property values (96 bytes) ------------- */
- element = getFile16BitBE(file);
+ element = getMappedElement(getFile16BitBE(file));
if (!IS_CUSTOM_ELEMENT(element))
{
ei->description[i] = getFile8Bit(file);
ei->description[MAX_ELEMENT_NAME_LEN] = 0;
-#if 1
- ei->properties[EP_BITFIELD_BASE] = getFile32BitBE(file);
-#else
- Properties[element][EP_BITFIELD_BASE] = getFile32BitBE(file);
-#endif
+ ei->properties[EP_BITFIELD_BASE_NR] = getFile32BitBE(file);
+
ReadUnusedBytesFromFile(file, 4); /* reserved for more base properties */
ei->num_change_pages = getFile8Bit(file);
for (i = 0; i < ei->num_change_pages; i++)
{
struct ElementChangeInfo *change = &ei->change_page[i];
- unsigned long event_bits;
+ unsigned int event_bits;
/* always start with reliable default values */
setElementChangeInfoToDefaults(change);
change->only_if_complete = getFile8Bit(file);
change->use_random_replace = getFile8Bit(file);
- change->random_percentage = getFile8Bit(file);
- change->replace_when = getFile8Bit(file);
+ change->random_percentage = getFile8Bit(file);
+ change->replace_when = getFile8Bit(file);
+
+ for (y = 0; y < 3; y++)
+ for (x = 0; x < 3; x++)
+ change->target_content.e[x][y]= getMappedElement(getFile16BitBE(file));
+
+ change->can_change = getFile8Bit(file);
+
+ change->trigger_side = getFile8Bit(file);
+
+ change->trigger_player = getFile8Bit(file);
+ change->trigger_page = getFile8Bit(file);
+
+ change->trigger_page = (change->trigger_page == CH_PAGE_ANY_FILE ?
+ CH_PAGE_ANY : (1 << change->trigger_page));
+
+ change->has_action = getFile8Bit(file);
+ change->action_type = getFile8Bit(file);
+ change->action_mode = getFile8Bit(file);
+ change->action_arg = getFile16BitBE(file);
+
+ /* ... 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 */
+ ei->modified_settings = TRUE;
+
+ 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 = getMappedElement(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 = getMappedElement(getFile16BitBE(file));
+
+ group->choice_mode = getFile8Bit(file);
+
+ /* some free bytes for future values and padding */
+ ReadUnusedBytesFromFile(file, 3);
+
+ for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
+ group->element[i] = getMappedElement(getFile16BitBE(file));
+
+ /* mark this group element as modified */
+ element_info[element].modified_settings = TRUE;
+
+ return chunk_size;
+}
+
+static int LoadLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *conf,
+ int element, int real_element)
+{
+ int micro_chunk_size = 0;
+ int conf_type = getFile8Bit(file);
+ int byte_mask = conf_type & CONF_MASK_BYTES;
+ boolean element_found = FALSE;
+ int i;
+
+ micro_chunk_size += 1;
+
+ if (byte_mask == CONF_MASK_MULTI_BYTES)
+ {
+ int num_bytes = getFile16BitBE(file);
+ byte *buffer = checked_malloc(num_bytes);
+
+ ReadBytesFromFile(file, buffer, num_bytes);
+
+ for (i = 0; conf[i].data_type != -1; i++)
+ {
+ if (conf[i].element == element &&
+ conf[i].conf_type == conf_type)
+ {
+ int data_type = conf[i].data_type;
+ int num_entities = num_bytes / CONF_ENTITY_NUM_BYTES(data_type);
+ int max_num_entities = conf[i].max_num_entities;
+
+ if (num_entities > max_num_entities)
+ {
+ Error(ERR_WARN,
+ "truncating number of entities for element %d from %d to %d",
+ element, num_entities, max_num_entities);
+
+ num_entities = max_num_entities;
+ }
+
+ if (num_entities == 0 && (data_type == TYPE_ELEMENT_LIST ||
+ data_type == TYPE_CONTENT_LIST))
+ {
+ /* for element and content lists, zero entities are not allowed */
+ Error(ERR_WARN, "found empty list of entities for element %d",
+ element);
+
+ /* do not set "num_entities" here to prevent reading behind buffer */
+
+ *(int *)(conf[i].num_entities) = 1; /* at least one is required */
+ }
+ else
+ {
+ *(int *)(conf[i].num_entities) = num_entities;
+ }
+
+ element_found = TRUE;
+
+ if (data_type == TYPE_STRING)
+ {
+ char *string = (char *)(conf[i].value);
+ int j;
+
+ for (j = 0; j < max_num_entities; j++)
+ string[j] = (j < num_entities ? buffer[j] : '\0');
+ }
+ else if (data_type == TYPE_ELEMENT_LIST)
+ {
+ int *element_array = (int *)(conf[i].value);
+ int j;
+
+ for (j = 0; j < num_entities; j++)
+ element_array[j] =
+ getMappedElement(CONF_ELEMENTS_ELEMENT(buffer, j));
+ }
+ else if (data_type == TYPE_CONTENT_LIST)
+ {
+ struct Content *content= (struct Content *)(conf[i].value);
+ int c, x, y;
+
+ for (c = 0; c < num_entities; c++)
+ for (y = 0; y < 3; y++)
+ for (x = 0; x < 3; x++)
+ content[c].e[x][y] =
+ getMappedElement(CONF_CONTENTS_ELEMENT(buffer, c, x, y));
+ }
+ else
+ element_found = FALSE;
+
+ break;
+ }
+ }
+
+ checked_free(buffer);
+
+ micro_chunk_size += 2 + num_bytes;
+ }
+ else /* constant size configuration data (1, 2 or 4 bytes) */
+ {
+ int value = (byte_mask == CONF_MASK_1_BYTE ? getFile8Bit (file) :
+ byte_mask == CONF_MASK_2_BYTE ? getFile16BitBE(file) :
+ byte_mask == CONF_MASK_4_BYTE ? getFile32BitBE(file) : 0);
+
+ for (i = 0; conf[i].data_type != -1; i++)
+ {
+ if (conf[i].element == element &&
+ conf[i].conf_type == conf_type)
+ {
+ int data_type = conf[i].data_type;
+
+ if (data_type == TYPE_ELEMENT)
+ value = getMappedElement(value);
+
+ if (data_type == TYPE_BOOLEAN)
+ *(boolean *)(conf[i].value) = value;
+ else
+ *(int *) (conf[i].value) = value;
+
+ element_found = TRUE;
+
+ break;
+ }
+ }
+
+ micro_chunk_size += CONF_VALUE_NUM_BYTES(byte_mask);
+ }
- for (y = 0; y < 3; y++)
- for (x = 0; x < 3; x++)
- change->target_content.e[x][y]= getMappedElement(getFile16BitBE(file));
+ if (!element_found)
+ {
+ char *error_conf_chunk_bytes =
+ (byte_mask == CONF_MASK_1_BYTE ? "CONF_VALUE_8_BIT" :
+ byte_mask == CONF_MASK_2_BYTE ? "CONF_VALUE_16_BIT" :
+ byte_mask == CONF_MASK_4_BYTE ? "CONF_VALUE_32_BIT" :"CONF_VALUE_BYTES");
+ int error_conf_chunk_token = conf_type & CONF_MASK_TOKEN;
+ int error_element = real_element;
- change->can_change = getFile8Bit(file);
+ Error(ERR_WARN, "cannot load micro chunk '%s(%d)' value for element %d ['%s']",
+ error_conf_chunk_bytes, error_conf_chunk_token,
+ error_element, EL_NAME(error_element));
+ }
- change->trigger_side = getFile8Bit(file);
+ return micro_chunk_size;
+}
- change->trigger_player = getFile8Bit(file);
- change->trigger_page = getFile8Bit(file);
+static int LoadLevel_INFO(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+ int real_chunk_size = 0;
- change->trigger_page = (change->trigger_page == CH_PAGE_ANY_FILE ?
- CH_PAGE_ANY : (1 << change->trigger_page));
+ li = *level; /* copy level data into temporary buffer */
- change->has_action = getFile8Bit(file);
- change->action_type = getFile8Bit(file);
- change->action_mode = getFile8Bit(file);
- change->action_arg = getFile16BitBE(file);
+ while (!feof(file))
+ {
+ real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_INFO, -1, -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;
+ if (real_chunk_size >= chunk_size)
+ break;
}
- /* mark this custom element as modified */
- ei->modified_settings = TRUE;
+ *level = li; /* copy temporary buffer back to level data */
- return chunk_size;
+ return real_chunk_size;
}
-static int LoadLevel_GRP1(FILE *file, int chunk_size, struct LevelInfo *level)
+static int LoadLevel_CONF(FILE *file, int chunk_size, struct LevelInfo *level)
{
- struct ElementInfo *ei;
- struct ElementGroupInfo *group;
- int element;
- int i;
+ int real_chunk_size = 0;
- element = getFile16BitBE(file);
+ li = *level; /* copy level data into temporary buffer */
- if (!IS_GROUP_ELEMENT(element))
+ while (!feof(file))
{
- Error(ERR_WARN, "invalid group element number %d", element);
+ int element = getMappedElement(getFile16BitBE(file));
- ReadUnusedBytesFromFile(file, chunk_size - 2);
- return chunk_size;
+ real_chunk_size += 2;
+ real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CONF,
+ element, element);
+ if (real_chunk_size >= chunk_size)
+ break;
}
- ei = &element_info[element];
+ *level = li; /* copy temporary buffer back to level data */
- for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
- ei->description[i] = getFile8Bit(file);
- ei->description[MAX_ELEMENT_NAME_LEN] = 0;
+ return real_chunk_size;
+}
- group = element_info[element].group;
+static int LoadLevel_ELEM(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+ int real_chunk_size = 0;
- group->num_elements = getFile8Bit(file);
+ li = *level; /* copy level data into temporary buffer */
- ei->use_gfx_element = getFile8Bit(file);
- ei->gfx_element = getMappedElement(getFile16BitBE(file));
+ while (!feof(file))
+ {
+ int element = getMappedElement(getFile16BitBE(file));
- group->choice_mode = getFile8Bit(file);
+ real_chunk_size += 2;
+ real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_ELEM,
+ element, element);
+ if (real_chunk_size >= chunk_size)
+ break;
+ }
- /* some free bytes for future values and padding */
- ReadUnusedBytesFromFile(file, 3);
+ *level = li; /* copy temporary buffer back to level data */
- for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
- group->element[i] = getMappedElement(getFile16BitBE(file));
+ return real_chunk_size;
+}
- /* mark this group element as modified */
- element_info[element].modified_settings = TRUE;
+static int LoadLevel_NOTE(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+ int element = getMappedElement(getFile16BitBE(file));
+ int envelope_nr = element - EL_ENVELOPE_1;
+ int real_chunk_size = 2;
- return chunk_size;
+ while (!feof(file))
+ {
+ real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_NOTE,
+ -1, element);
+
+ if (real_chunk_size >= chunk_size)
+ break;
+ }
+
+ level->envelope[envelope_nr] = xx_envelope;
+
+ return real_chunk_size;
}
-static int LoadLevel_CONF(FILE *file, int chunk_size, struct LevelInfo *level)
+static int LoadLevel_CUSX(FILE *file, int chunk_size, struct LevelInfo *level)
{
- int real_chunk_size = 0;
+ int element = getMappedElement(getFile16BitBE(file));
+ int real_chunk_size = 2;
+ struct ElementInfo *ei = &element_info[element];
int i;
+ xx_ei = *ei; /* copy element data into temporary buffer */
+
+ xx_ei.num_change_pages = -1;
+
while (!feof(file))
{
- int element = getFile16BitBE(file);
- int type = getFile8Bit(file);
- int bytes = type & CONF_MASK_BYTES;
- boolean element_found = FALSE;
+ real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CUSX_base,
+ -1, element);
+ if (xx_ei.num_change_pages != -1)
+ break;
- real_chunk_size += 3;
+ if (real_chunk_size >= chunk_size)
+ break;
+ }
- li = *level; /* copy level information into temporary buffer */
+ *ei = xx_ei;
- if (bytes == CONF_MASK_MULTI_BYTES)
- {
- int num_bytes = getFile16BitBE(file);
- byte *buffer = checked_malloc(num_bytes);
+ if (ei->num_change_pages == -1)
+ {
+ Error(ERR_WARN, "LoadLevel_CUSX(): missing 'num_change_pages' for '%s'",
+ EL_NAME(element));
- ReadBytesFromFile(file, buffer, num_bytes);
+ ei->num_change_pages = 1;
- for (i = 0; element_conf[i].element != -1; i++)
- {
- if (element_conf[i].element == element &&
- element_conf[i].type == type)
- {
- int num_entities = num_bytes / CONF_ENTITY_NUM_BYTES(type);
- int max_num_entities = element_conf[i].max_num_entities;
-
- if (num_entities > max_num_entities)
- {
- Error(ERR_WARN,
- "truncating number of entities for element %d from %d to %d",
- element, num_entities, max_num_entities);
-
- num_entities = max_num_entities;
- }
-
- *(int *)(element_conf[i].num_entities) = num_entities;
-
- element_found = TRUE;
-
- if (type == CONF_VALUE_ELEMENTS)
- {
- int *element_array = (int *)(element_conf[i].value);
- int j;
-
- for (j = 0; j < num_entities; j++)
- element_array[j] =
- getMappedElement(CONF_ELEMENTS_ELEMENT(buffer, j));
- }
- else if (type == CONF_VALUE_CONTENTS)
- {
- struct Content *content= (struct Content *)(element_conf[i].value);
- int c, x, y;
-
- for (c = 0; c < num_entities; c++)
- for (y = 0; y < 3; y++)
- for (x = 0; x < 3; x++)
- content[c].e[x][y] =
- getMappedElement(CONF_CONTENTS_ELEMENT(buffer, c, x, y));
- }
- else
- element_found = FALSE;
-
- break;
- }
- }
+ setElementChangePages(ei, 1);
+ setElementChangeInfoToDefaults(ei->change);
- checked_free(buffer);
+ return real_chunk_size;
+ }
- real_chunk_size += 2 + num_bytes;
- }
- else /* constant size configuration data (1, 2 or 4 bytes) */
- {
- int value = (bytes == CONF_MASK_1_BYTE ? getFile8Bit (file) :
- bytes == CONF_MASK_2_BYTE ? getFile16BitBE(file) :
- bytes == CONF_MASK_4_BYTE ? getFile32BitBE(file) : 0);
+ /* initialize number of change pages stored for this custom element */
+ setElementChangePages(ei, ei->num_change_pages);
+ for (i = 0; i < ei->num_change_pages; i++)
+ setElementChangeInfoToDefaults(&ei->change_page[i]);
- 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;
+ /* start with reading properties for the first change page */
+ xx_current_change_page = 0;
- element_found = TRUE;
+ while (!feof(file))
+ {
+ struct ElementChangeInfo *change = &ei->change_page[xx_current_change_page];
- break;
- }
- }
+ xx_change = *change; /* copy change data into temporary buffer */
- real_chunk_size += CONF_VALUE_NUM_BYTES(bytes);
- }
+ resetEventBits(); /* reset bits; change page might have changed */
+
+ real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CUSX_change,
+ -1, element);
+
+ *change = xx_change;
+
+ setEventFlagsFromEventBits(change);
+
+ if (real_chunk_size >= chunk_size)
+ break;
+ }
- *level = li; /* copy temporary buffer back to level information */
+ return real_chunk_size;
+}
+
+static int LoadLevel_GRPX(FILE *file, int chunk_size, struct LevelInfo *level)
+{
+ int element = getMappedElement(getFile16BitBE(file));
+ int real_chunk_size = 2;
+ struct ElementInfo *ei = &element_info[element];
+ struct ElementGroupInfo *group = ei->group;
- if (!element_found)
- Error(ERR_WARN, "cannot load CONF value for element %d", element);
+ xx_ei = *ei; /* copy element data into temporary buffer */
+ xx_group = *group; /* copy group data into temporary buffer */
+
+ while (!feof(file))
+ {
+ real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_GRPX,
+ -1, element);
- if (type == CONF_LAST_ENTRY || real_chunk_size >= chunk_size)
+ if (real_chunk_size >= chunk_size)
break;
}
+ *ei = xx_ei;
+ *group = xx_group;
+
return real_chunk_size;
}
if (level->file_version < FILE_VERSION_1_2)
{
/* level files from versions before 1.2.0 without chunk structure */
- LoadLevel_HEAD(file, LEVEL_HEADER_SIZE, level);
+ LoadLevel_HEAD(file, LEVEL_CHUNK_HEAD_SIZE, level);
LoadLevel_BODY(file, level->fieldx * level->fieldy, level);
}
else
}
chunk_info[] =
{
- { "VERS", FILE_VERS_CHUNK_SIZE, LoadLevel_VERS },
- { "HEAD", LEVEL_HEADER_SIZE, LoadLevel_HEAD },
- { "AUTH", MAX_LEVEL_AUTHOR_LEN, LoadLevel_AUTH },
+ { "VERS", LEVEL_CHUNK_VERS_SIZE, LoadLevel_VERS },
+ { "DATE", LEVEL_CHUNK_DATE_SIZE, LoadLevel_DATE },
+ { "HEAD", LEVEL_CHUNK_HEAD_SIZE, LoadLevel_HEAD },
+ { "NAME", LEVEL_CHUNK_NAME_SIZE, LoadLevel_NAME },
+ { "AUTH", LEVEL_CHUNK_AUTH_SIZE, LoadLevel_AUTH },
+ { "INFO", -1, LoadLevel_INFO },
{ "BODY", -1, LoadLevel_BODY },
{ "CONT", -1, LoadLevel_CONT },
{ "CNT2", LEVEL_CHUNK_CNT2_SIZE, LoadLevel_CNT2 },
{ "CUS4", -1, LoadLevel_CUS4 },
{ "GRP1", -1, LoadLevel_GRP1 },
{ "CONF", -1, LoadLevel_CONF },
+ { "ELEM", -1, LoadLevel_ELEM },
+ { "NOTE", -1, LoadLevel_NOTE },
+ { "CUSX", -1, LoadLevel_CUSX },
+ { "GRPX", -1, LoadLevel_GRPX },
{ NULL, 0, NULL }
};
struct PLAYER **ply = level_em->ply;
int i, j, x, y;
-#if 0
- printf("::: A\n");
- for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
- for (j = 0; j < 8; j++)
- printf("::: ball %d, %d: %d\n", i, j,
- level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
-#endif
-
lev->width = MIN(level->fieldx, EM_MAX_CAVE_WIDTH);
lev->height = MIN(level->fieldy, EM_MAX_CAVE_HEIGHT);
map_element_RND_to_EM(level->
ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
-#if 0
- for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
- for (j = 0; j < 8; j++)
- printf("::: ball %d, %d: %d\n", i, j,
- level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
-#endif
-
map_android_clone_elements_RND_to_EM(level);
-#if 0
- for (i = 0; i < 16; i++)
- lev->android_array[i] = FALSE; /* !!! YET TO COME !!! */
-#endif
-
/* first fill the complete playfield with the default border element */
for (y = 0; y < EM_MAX_CAVE_HEIGHT; y++)
for (x = 0; x < EM_MAX_CAVE_WIDTH; x++)
level_em->cave[x][y] = ZBORDER;
-#if 1
-
-#if 0
-#if 1
- LoadLevel_InitPlayfield();
-#else
- lev_fieldx = lev->width; /* !!! also in LoadLevel_InitPlayfield() !!! */
- lev_fieldy = lev->height; /* !!! also in LoadLevel_InitPlayfield() !!! */
- SetBorderElement(); /* !!! also in LoadLevel_InitPlayfield() !!! */
-#endif
-#endif
-
-#if 0
- printf("::: BorderElement == %d\n", BorderElement);
-#endif
-
if (BorderElement == EL_STEELWALL)
{
for (y = 0; y < lev->height + 2; y++)
level_em->cave[xx][yy] = new_element;
}
-#else
-
- /* then copy the real level contents from level file into the playfield */
- for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
- {
- int new_element = map_element_RND_to_EM(level->field[x][y]);
-
- if (level->field[x][y] == EL_AMOEBA_DEAD)
- new_element = map_element_RND_to_EM(EL_AMOEBA_WET);
-
- level_em->cave[x + 1][y + 1] = new_element;
- }
-
-#endif
-
-#if 1
-
for (i = 0; i < MAX_PLAYERS; i++)
{
ply[i]->x_initial = 0;
ply[i]->y_initial = 0;
}
-#else
-
- ply1->x_initial = 0;
- ply1->y_initial = 0;
-
- ply2->x_initial = 0;
- ply2->y_initial = 0;
-
-#endif
-
/* initialize player positions and delete players from the playfield */
for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
{
-
-#if 1
if (ELEM_IS_PLAYER(level->field[x][y]))
{
int player_nr = GET_PLAYER_NR(level->field[x][y]);
level_em->cave[xx][yy] = map_element_RND_to_EM(EL_EMPTY);
}
-
-#else
-
-#if 1
- /* !!! CURRENTLY ONLY SUPPORT FOR ONE PLAYER !!! */
- if (ELEM_IS_PLAYER(level->field[x][y]))
- {
- ply1->x_initial = x + 1;
- ply1->y_initial = y + 1;
- level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_EMPTY);
- }
-#else
- /* !!! ADD SUPPORT FOR MORE THAN ONE PLAYER !!! */
- if (level->field[x][y] == EL_PLAYER_1)
- {
- ply1->x_initial = x + 1;
- ply1->y_initial = y + 1;
- level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_EMPTY);
- }
- else if (level->field[x][y] == EL_PLAYER_2)
- {
- ply2->x_initial = x + 1;
- ply2->y_initial = y + 1;
- level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_EMPTY);
- }
-#endif
-
-#endif
-
}
if (BorderElement == EL_STEELWALL)
{
-#if 1
lev->width += 2;
lev->height += 2;
-#endif
}
}
level->wind_direction_initial =
map_direction_EM_to_RND(lev->wind_direction_initial);
-#if 0
- printf("::: foo\n");
- for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
- for (j = 0; j < 8; j++)
- printf("::: ball %d, %d: %d\n", i, j,
- level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
-#endif
-
for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
for (j = 0; j < 8; j++)
level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]] =
map_element_EM_to_RND(lev->ball_array[i][j]);
-#if 0
- printf("::: bar\n");
- for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
- for (j = 0; j < 8; j++)
- printf("::: ball %d, %d: %d\n", i, j,
- level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
-#endif
-
map_android_clone_elements_EM_to_RND(level);
-#if 0
- for (i = 0; i < 16; i++)
- level->android_array[i] = FALSE; /* !!! YET TO COME !!! */
-#endif
-
/* convert the playfield (some elements need special treatment) */
for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
{
level->field[x][y] = new_element;
}
-#if 0
- printf("::: bar 0\n");
- for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
- for (j = 0; j < 8; j++)
- printf("::: ball %d, %d: %d\n", i, j,
- level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
-#endif
-
-#if 1
-
for (i = 0; i < MAX_PLAYERS; i++)
{
/* in case of all players set to the same field, use the first player */
int jx = ply[nr]->x_initial - 1;
int jy = ply[nr]->y_initial - 1;
-#if 0
- printf("::: player %d: %d, %d\n", nr, jx, jy);
-#endif
-
if (jx != -1 && jy != -1)
level->field[jx][jy] = EL_PLAYER_1 + nr;
}
-
-#else
-
- /* in case of both players set to the same field, use the first player */
- level->field[ply2->x_initial - 1][ply2->y_initial - 1] = EL_PLAYER_2;
- level->field[ply1->x_initial - 1][ply1->y_initial - 1] = EL_PLAYER_1;
-
-#endif
-
-#if 0
- printf("::: native Emerald Mine file version: %d\n", level_em->file_version);
-#endif
-
-#if 0
- printf("::: bar 2\n");
- for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
- for (j = 0; j < 8; j++)
- printf("::: ball %d, %d: %d\n", i, j,
- level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
-#endif
}
static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,
void CopyNativeLevel_Native_to_RND(struct LevelInfo *level)
{
-
-#if 0
- {
- static int ball_xy[8][2] =
- {
- { 0, 0 },
- { 1, 0 },
- { 2, 0 },
- { 0, 1 },
- { 2, 1 },
- { 0, 2 },
- { 1, 2 },
- { 2, 2 },
- };
- int i, j;
-
- printf("::: A6\n");
- for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
- for (j = 0; j < 8; j++)
- printf("::: ball %d, %d: %d\n", i, j,
- level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
- }
-#endif
-
if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
CopyNativeLevel_EM_to_RND(level);
}
static void LoadLevelFromFileStream_SP(FILE *file, struct LevelInfo *level,
int nr)
{
+ int initial_player_gravity;
int num_special_ports;
int i, x, y;
ReadUnusedBytesFromFile(file, 4); /* (not used by Supaplex engine) */
/* initial gravity: 1 == "on", anything else (0) == "off" */
- level->initial_gravity = (fgetc(file) == 1 ? TRUE : FALSE);
+ initial_player_gravity = (fgetc(file) == 1 ? TRUE : FALSE);
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ level->initial_player_gravity[i] = initial_player_gravity;
ReadUnusedBytesFromFile(file, 1); /* (not used by Supaplex engine) */
/* original Supaplex does not use score values -- use default values */
#else
for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
- level->score[i] = 0; /* !!! CORRECT THIS !!! */
+ level->score[i] = 0;
#endif
/* there are no yamyams in supaplex levels */
if (level->game_engine_type == GAME_ENGINE_TYPE_UNKNOWN)
level->game_engine_type = GAME_ENGINE_TYPE_RND;
-#if 1
if (level_file_info->type != LEVEL_FILE_TYPE_RND)
CopyNativeLevel_Native_to_RND(level);
-#else
- if (level_file_info->type == LEVEL_FILE_TYPE_RND)
- CopyNativeLevel_RND_to_Native(level);
- else
- CopyNativeLevel_Native_to_RND(level);
-#endif
}
void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
{
+ int i, j;
+
if (leveldir_current == NULL) /* only when dumping level */
return;
/* all engine modifications also valid for levels which use latest engine */
-#if 1
if (level->game_version < VERSION_IDENT(3,2,0,5))
{
/* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */
level->score[SC_TIME_BONUS] /= 10;
}
-#endif
#if 0
leveldir_current->latest_engine = TRUE; /* !!! TEST ONLY !!! */
/* player was faster than enemies in 1.0.0 and before */
if (level->file_version == FILE_VERSION_1_0)
- level->initial_player_stepsize = STEPSIZE_FAST;
+ for (i = 0; i < MAX_PLAYERS; i++)
+ level->initial_player_stepsize[i] = STEPSIZE_FAST;
/* default behaviour for EM style gems was "slippery" only in 2.0.1 */
if (level->game_version == VERSION_IDENT(2,0,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))
{
- int i, j;
-
/* correct "can move into acid" settings (all zero in old levels) */
level->can_move_into_acid_bits = 0; /* nothing can move into acid */
}
}
}
+
+ /* try to detect and fix "Snake Bite" levels, which are broken with 3.2.0 */
+ {
+ int element = EL_CUSTOM_START + 255;
+ struct ElementInfo *ei = &element_info[element];
+ struct ElementChangeInfo *change = &ei->change_page[0];
+
+ /* This is needed to fix a problem that was caused by a bugfix in function
+ game.c/CreateFieldExt() introduced with 3.2.0 that corrects the behaviour
+ when a custom element changes to EL_SOKOBAN_FIELD_PLAYER (before, it did
+ not replace walkable elements, but instead just placed the player on it,
+ without placing the Sokoban field under the player). Unfortunately, this
+ breaks "Snake Bite" style levels when the snake is halfway through a door
+ that just closes (the snake head is still alive and can be moved in this
+ case). This can be fixed by replacing the EL_SOKOBAN_FIELD_PLAYER by the
+ player (without Sokoban element) which then gets killed as designed). */
+
+ if ((strncmp(leveldir_current->identifier, "snake_bite", 10) == 0 ||
+ strncmp(ei->description, "pause b4 death", 14) == 0) &&
+ change->target_element == EL_SOKOBAN_FIELD_PLAYER)
+ change->target_element = EL_PLAYER_1;
+ }
}
static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
if (ei->access_direction == MV_NO_DIRECTION)
ei->access_direction = MV_ALL_DIRECTIONS;
-
-#if 0
- for (j = 0; j < ei->num_change_pages; j++)
- {
- struct ElementChangeInfo *change = &ei->change_page[j];
-
- if (change->trigger_side == CH_SIDE_NONE)
- change->trigger_side = CH_SIDE_ANY;
- }
-#endif
}
}
-#if 1
/* correct custom element values (fix invalid values for all versions) */
if (1)
{
}
}
}
-#endif
/* initialize "can_explode" field for old levels which did not store this */
/* !!! CHECK THIS -- "<= 3,1,0,0" IS PROBABLY WRONG !!! */
/* initialize element properties for level editor etc. */
InitElementPropertiesEngine(level->game_version);
+ InitElementPropertiesAfterLoading(level->game_version);
}
static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
{
struct LevelFileInfo *level_file_info = &level->file_info;
-#if 1
if (level_file_info->type == LEVEL_FILE_TYPE_RND)
CopyNativeLevel_RND_to_Native(level);
-#else
- if (level_file_info->type == LEVEL_FILE_TYPE_RND)
- CopyNativeLevel_RND_to_Native(level);
- else
- CopyNativeLevel_Native_to_RND(level);
-#endif
}
void LoadLevelTemplate(int nr)
LoadLevel_InitNativeEngines(&level, filename);
}
-static void SaveLevel_VERS(FILE *file, struct LevelInfo *level)
+static int SaveLevel_VERS(FILE *file, struct LevelInfo *level)
+{
+ int chunk_size = 0;
+
+ chunk_size += putFileVersion(file, level->file_version);
+ chunk_size += putFileVersion(file, level->game_version);
+
+ return chunk_size;
+}
+
+static int SaveLevel_DATE(FILE *file, struct LevelInfo *level)
{
- putFileVersion(file, level->file_version);
- putFileVersion(file, level->game_version);
+ int chunk_size = 0;
+
+ chunk_size += putFile16BitBE(file, level->creation_date.year);
+ chunk_size += putFile8Bit(file, level->creation_date.month);
+ chunk_size += putFile8Bit(file, level->creation_date.day);
+
+ return chunk_size;
}
+#if 0
static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
{
int i, x, y;
putFile8Bit(file, level->game_engine_type);
- WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
+ WriteUnusedBytesToFile(file, LEVEL_CHUNK_HEAD_UNUSED);
+}
+#endif
+
+static int SaveLevel_NAME(FILE *file, struct LevelInfo *level)
+{
+ int chunk_size = 0;
+ int i;
+
+ for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
+ chunk_size += putFile8Bit(file, level->name[i]);
+
+ return chunk_size;
}
-static void SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
+static int SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
{
+ int chunk_size = 0;
int i;
for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
- putFile8Bit(file, level->author[i]);
+ chunk_size += putFile8Bit(file, level->author[i]);
+
+ return chunk_size;
}
-static void SaveLevel_BODY(FILE *file, struct LevelInfo *level)
+#if 0
+static int SaveLevel_BODY(FILE *file, struct LevelInfo *level)
{
+ int chunk_size = 0;
int x, y;
for (y = 0; y < level->fieldy; y++)
for (x = 0; x < level->fieldx; x++)
if (level->encoding_16bit_field)
- putFile16BitBE(file, level->field[x][y]);
+ chunk_size += putFile16BitBE(file, level->field[x][y]);
else
- putFile8Bit(file, level->field[x][y]);
+ chunk_size += putFile8Bit(file, level->field[x][y]);
+
+ return chunk_size;
+}
+#endif
+
+static int SaveLevel_BODY(FILE *file, struct LevelInfo *level)
+{
+ int chunk_size = 0;
+ int x, y;
+
+ for (y = 0; y < level->fieldy; y++)
+ for (x = 0; x < level->fieldx; x++)
+ chunk_size += putFile16BitBE(file, level->field[x][y]);
+
+ return chunk_size;
}
#if 0
}
#endif
+#if 0
static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
{
int i, x, y;
for (x = 0; x < 3; x++)
putFile16BitBE(file, content_array[i][x][y]);
}
+#endif
-static void SaveLevel_CNT3(FILE *file, struct LevelInfo *level, int element)
+#if 0
+static int SaveLevel_CNT3(FILE *file, struct LevelInfo *level, int element)
{
- int i;
int envelope_nr = element - EL_ENVELOPE_1;
int envelope_len = strlen(level->envelope_text[envelope_nr]) + 1;
+ int chunk_size = 0;
+ int i;
- putFile16BitBE(file, element);
- putFile16BitBE(file, envelope_len);
- putFile8Bit(file, level->envelope_xsize[envelope_nr]);
- putFile8Bit(file, level->envelope_ysize[envelope_nr]);
+ chunk_size += putFile16BitBE(file, element);
+ chunk_size += putFile16BitBE(file, envelope_len);
+ chunk_size += putFile8Bit(file, level->envelope_xsize[envelope_nr]);
+ chunk_size += putFile8Bit(file, level->envelope_ysize[envelope_nr]);
WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT3_UNUSED);
+ chunk_size += LEVEL_CHUNK_CNT3_UNUSED;
for (i = 0; i < envelope_len; i++)
- putFile8Bit(file, level->envelope_text[envelope_nr][i]);
+ chunk_size += putFile8Bit(file, level->envelope_text[envelope_nr][i]);
+
+ return chunk_size;
}
+#endif
#if 0
static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level,
{
int element = EL_CUSTOM_START + i;
-#if 1
struct ElementInfo *ei = &element_info[element];
- if (ei->properties[EP_BITFIELD_BASE] != EP_BITMASK_DEFAULT)
- {
- if (check < num_changed_custom_elements)
- {
- putFile16BitBE(file, element);
- putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE]);
- }
-
- check++;
- }
-#else
- if (Properties[element][EP_BITFIELD_BASE] != EP_BITMASK_DEFAULT)
+ if (ei->properties[EP_BITFIELD_BASE_NR] != EP_BITMASK_DEFAULT)
{
if (check < num_changed_custom_elements)
{
putFile16BitBE(file, element);
- putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
+ putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
}
check++;
}
-#endif
}
if (check != num_changed_custom_elements) /* should not happen */
for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++)
putFile8Bit(file, ei->description[j]);
-#if 1
- putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE]);
-#else
- putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
-#endif
+ putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
/* some free bytes for future properties and padding */
WriteUnusedBytesToFile(file, 7);
}
#endif
+#if 0
static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
{
struct ElementInfo *ei = &element_info[element];
for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
putFile8Bit(file, ei->description[i]);
-#if 1
- putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE]);
-#else
- putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
-#endif
+ putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
+
WriteUnusedBytesToFile(file, 4); /* reserved for more base properties */
putFile8Bit(file, ei->num_change_pages);
for (i = 0; i < ei->num_change_pages; i++)
{
struct ElementChangeInfo *change = &ei->change_page[i];
- unsigned long event_bits;
+ unsigned int event_bits;
/* bits 0 - 31 of "has_event[]" ... */
event_bits = 0;
putFile8Bit(file, event_bits);
}
}
+#endif
+#if 0
static void SaveLevel_GRP1(FILE *file, struct LevelInfo *level, int element)
{
struct ElementInfo *ei = &element_info[element];
for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
putFile16BitBE(file, group->element[i]);
}
+#endif
-static int SaveLevel_CONF_Value(FILE *file, int pos)
+static int SaveLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *entry,
+ boolean write_element)
{
- int default_value = element_conf[pos].default_value;
- int element = element_conf[pos].element;
- int type = element_conf[pos].type;
- int bytes = type & CONF_MASK_BYTES;
- void *value_ptr = element_conf[pos].value;
- int value = (CONF_VALUE_BOOLEAN(type) ? *(boolean *)value_ptr :
- *(int *)value_ptr);
+ int save_type = entry->save_type;
+ int data_type = entry->data_type;
+ int conf_type = entry->conf_type;
+ int byte_mask = conf_type & CONF_MASK_BYTES;
+ int element = entry->element;
+ int default_value = entry->default_value;
int num_bytes = 0;
boolean modified = FALSE;
- /* check if any settings have been modified before saving them */
- if (value != default_value)
- modified = TRUE;
+ if (byte_mask != CONF_MASK_MULTI_BYTES)
+ {
+ void *value_ptr = entry->value;
+ int value = (data_type == TYPE_BOOLEAN ? *(boolean *)value_ptr :
+ *(int *)value_ptr);
+
+ /* check if any settings have been modified before saving them */
+ if (value != default_value)
+ modified = TRUE;
+
+ /* do not save if explicitly told or if unmodified default settings */
+ if ((save_type == SAVE_CONF_NEVER) ||
+ (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
+ return 0;
+
+ if (write_element)
+ num_bytes += putFile16BitBE(file, element);
+
+ num_bytes += putFile8Bit(file, conf_type);
+ num_bytes += (byte_mask == CONF_MASK_1_BYTE ? putFile8Bit (file, value) :
+ byte_mask == CONF_MASK_2_BYTE ? putFile16BitBE(file, value) :
+ byte_mask == CONF_MASK_4_BYTE ? putFile32BitBE(file, value) :
+ 0);
+ }
+ else if (data_type == TYPE_STRING)
+ {
+ char *default_string = entry->default_string;
+ char *string = (char *)(entry->value);
+ int string_length = strlen(string);
+ int i;
+
+ /* check if any settings have been modified before saving them */
+ if (!strEqual(string, default_string))
+ modified = TRUE;
+
+ /* do not save if explicitly told or if unmodified default settings */
+ if ((save_type == SAVE_CONF_NEVER) ||
+ (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
+ return 0;
+
+ if (write_element)
+ num_bytes += putFile16BitBE(file, element);
+
+ num_bytes += putFile8Bit(file, conf_type);
+ num_bytes += putFile16BitBE(file, string_length);
+
+ for (i = 0; i < string_length; i++)
+ num_bytes += putFile8Bit(file, string[i]);
+ }
+ else if (data_type == TYPE_ELEMENT_LIST)
+ {
+ int *element_array = (int *)(entry->value);
+ int num_elements = *(int *)(entry->num_entities);
+ int i;
- if (!modified) /* do not save unmodified default settings */
- return 0;
+ /* check if any settings have been modified before saving them */
+ for (i = 0; i < num_elements; i++)
+ if (element_array[i] != default_value)
+ modified = TRUE;
- if (bytes == CONF_MASK_MULTI_BYTES)
- Error(ERR_EXIT, "SaveLevel_CONF_Value: cannot save multi-byte values");
+ /* do not save if explicitly told or if unmodified default settings */
+ if ((save_type == SAVE_CONF_NEVER) ||
+ (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
+ return 0;
- 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);
+ if (write_element)
+ num_bytes += putFile16BitBE(file, element);
+
+ num_bytes += putFile8Bit(file, conf_type);
+ num_bytes += putFile16BitBE(file, num_elements * CONF_ELEMENT_NUM_BYTES);
+
+ for (i = 0; i < num_elements; i++)
+ num_bytes += putFile16BitBE(file, element_array[i]);
+ }
+ else if (data_type == TYPE_CONTENT_LIST)
+ {
+ struct Content *content = (struct Content *)(entry->value);
+ int num_contents = *(int *)(entry->num_entities);
+ int i, x, y;
+
+ /* check if any settings have been modified before saving them */
+ for (i = 0; i < num_contents; i++)
+ for (y = 0; y < 3; y++)
+ for (x = 0; x < 3; x++)
+ if (content[i].e[x][y] != default_value)
+ modified = TRUE;
+
+ /* do not save if explicitly told or if unmodified default settings */
+ if ((save_type == SAVE_CONF_NEVER) ||
+ (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
+ return 0;
+
+ if (write_element)
+ num_bytes += putFile16BitBE(file, element);
+
+ num_bytes += putFile8Bit(file, conf_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_Elements(FILE *file, int pos)
+static int SaveLevel_INFO(FILE *file, struct LevelInfo *level)
{
- int *element_array = (int *)(element_conf[pos].value);
- int num_elements = *(int *)element_conf[pos].num_entities;
- int default_value = element_conf[pos].default_value;
- int element = element_conf[pos].element;
- int type = element_conf[pos].type;
- int num_bytes = 0;
- boolean modified = FALSE;
+ int chunk_size = 0;
int i;
- /* check if any settings have been modified before saving them */
- for (i = 0; i < num_elements; i++)
- if (element_array[i] != default_value)
- modified = TRUE;
+ li = *level; /* copy level data into temporary buffer */
+
+ for (i = 0; chunk_config_INFO[i].data_type != -1; i++)
+ chunk_size += SaveLevel_MicroChunk(file, &chunk_config_INFO[i], FALSE);
+
+ return chunk_size;
+}
- if (!modified) /* do not save unmodified default settings */
- return 0;
+static int SaveLevel_ELEM(FILE *file, struct LevelInfo *level)
+{
+ int chunk_size = 0;
+ int i;
- num_bytes += putFile16BitBE(file, element);
- num_bytes += putFile8Bit(file, type);
- num_bytes += putFile16BitBE(file, num_elements * CONF_ELEMENT_NUM_BYTES);
+ li = *level; /* copy level data into temporary buffer */
- for (i = 0; i < num_elements; i++)
- num_bytes += putFile16BitBE(file, element_array[i]);
+ for (i = 0; chunk_config_ELEM[i].data_type != -1; i++)
+ chunk_size += SaveLevel_MicroChunk(file, &chunk_config_ELEM[i], TRUE);
- return num_bytes;
+ return chunk_size;
}
-static int SaveLevel_CONF_Contents(FILE *file, int pos)
+static int SaveLevel_NOTE(FILE *file, struct LevelInfo *level, int element)
{
- struct Content *content = (struct Content *)(element_conf[pos].value);
- int num_contents = *(int *)element_conf[pos].num_entities;
- int default_value = element_conf[pos].default_value;
- int element = element_conf[pos].element;
- int type = element_conf[pos].type;
- int num_bytes = 0;
- boolean modified = FALSE;
- int i, x, y;
-
- /* check if any settings have been modified before saving them */
- for (i = 0; i < num_contents; i++)
- for (y = 0; y < 3; y++)
- for (x = 0; x < 3; x++)
- if (content[i].e[x][y] != default_value)
- modified = TRUE;
+ int envelope_nr = element - EL_ENVELOPE_1;
+ int chunk_size = 0;
+ int i;
- if (!modified) /* do not save unmodified default settings */
- return 0;
+ chunk_size += putFile16BitBE(file, element);
- num_bytes += putFile16BitBE(file, element);
- num_bytes += putFile8Bit(file, type);
- num_bytes += putFile16BitBE(file, num_contents * CONF_CONTENT_NUM_BYTES);
+ /* copy envelope data into temporary buffer */
+ xx_envelope = level->envelope[envelope_nr];
- 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]);
+ for (i = 0; chunk_config_NOTE[i].data_type != -1; i++)
+ chunk_size += SaveLevel_MicroChunk(file, &chunk_config_NOTE[i], FALSE);
- return num_bytes;
+ return chunk_size;
}
-static int SaveLevel_CONF(FILE *file, struct LevelInfo *level)
+static int SaveLevel_CUSX(FILE *file, struct LevelInfo *level, int element)
{
+ struct ElementInfo *ei = &element_info[element];
int chunk_size = 0;
- int i;
+ int i, j;
+
+ chunk_size += putFile16BitBE(file, element);
+
+ xx_ei = *ei; /* copy element data into temporary buffer */
+
+ /* set default description string for this specific element */
+ strcpy(xx_default_description, getDefaultElementDescription(ei));
- li = *level; /* copy level information into temporary buffer */
+#if 0
+ /* set (fixed) number of content areas (may be wrong by broken level file) */
+ /* (this is now directly corrected for broken level files after loading) */
+ xx_num_contents = 1;
+#endif
- for (i = 0; element_conf[i].element != -1; i++)
+ for (i = 0; chunk_config_CUSX_base[i].data_type != -1; i++)
+ chunk_size += SaveLevel_MicroChunk(file, &chunk_config_CUSX_base[i], FALSE);
+
+ for (i = 0; i < ei->num_change_pages; i++)
{
- int type = element_conf[i].type;
- int bytes = type & CONF_MASK_BYTES;
+ struct ElementChangeInfo *change = &ei->change_page[i];
+
+ xx_current_change_page = i;
+
+ xx_change = *change; /* copy change data into temporary buffer */
+
+ resetEventBits();
+ setEventBitsFromEventFlags(change);
- if (bytes != CONF_MASK_MULTI_BYTES)
- chunk_size += SaveLevel_CONF_Value(file, i);
- else if (type == CONF_VALUE_ELEMENTS)
- chunk_size += SaveLevel_CONF_Elements(file, i);
- else if (type == CONF_VALUE_CONTENTS)
- chunk_size += SaveLevel_CONF_Contents(file, i);
+ for (j = 0; chunk_config_CUSX_change[j].data_type != -1; j++)
+ chunk_size += SaveLevel_MicroChunk(file, &chunk_config_CUSX_change[j],
+ FALSE);
}
return chunk_size;
}
+static int SaveLevel_GRPX(FILE *file, struct LevelInfo *level, int element)
+{
+ struct ElementInfo *ei = &element_info[element];
+ struct ElementGroupInfo *group = ei->group;
+ int chunk_size = 0;
+ int i;
+
+ chunk_size += putFile16BitBE(file, element);
+
+ xx_ei = *ei; /* copy element data into temporary buffer */
+ xx_group = *group; /* copy group data into temporary buffer */
+
+ /* set default description string for this specific element */
+ strcpy(xx_default_description, getDefaultElementDescription(ei));
+
+ for (i = 0; chunk_config_GRPX[i].data_type != -1; i++)
+ chunk_size += SaveLevel_MicroChunk(file, &chunk_config_GRPX[i], FALSE);
+
+ return chunk_size;
+}
+
static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
{
- int body_chunk_size, conf_chunk_size;
- int i, x, y;
+ int chunk_size;
+ int i;
FILE *file;
if (!(file = fopen(filename, MODE_WRITE)))
level->file_version = FILE_VERSION_ACTUAL;
level->game_version = GAME_VERSION_ACTUAL;
- /* check level field for 16-bit elements */
- level->encoding_16bit_field = FALSE;
- for (y = 0; y < level->fieldy; y++)
- for (x = 0; x < level->fieldx; x++)
- if (level->field[x][y] > 255)
- level->encoding_16bit_field = TRUE;
-
- /* check yamyam content for 16-bit elements */
- level->encoding_16bit_yamyam = FALSE;
- 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].e[x][y] > 255)
- level->encoding_16bit_yamyam = TRUE;
-
- /* check amoeba content for 16-bit elements */
- level->encoding_16bit_amoeba = FALSE;
- if (level->amoeba_content > 255)
- level->encoding_16bit_amoeba = TRUE;
-
- /* calculate size of "BODY" chunk */
- body_chunk_size =
- level->fieldx * level->fieldy * (level->encoding_16bit_field ? 2 : 1);
+ level->creation_date = getCurrentDate();
putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
- putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
+ chunk_size = SaveLevel_VERS(NULL, level);
+ putFileChunkBE(file, "VERS", chunk_size);
SaveLevel_VERS(file, level);
- putFileChunkBE(file, "HEAD", LEVEL_HEADER_SIZE);
- SaveLevel_HEAD(file, level);
+ chunk_size = SaveLevel_DATE(NULL, level);
+ putFileChunkBE(file, "DATE", chunk_size);
+ SaveLevel_DATE(file, level);
- putFileChunkBE(file, "AUTH", MAX_LEVEL_AUTHOR_LEN);
+ chunk_size = SaveLevel_NAME(NULL, level);
+ putFileChunkBE(file, "NAME", chunk_size);
+ SaveLevel_NAME(file, level);
+
+ chunk_size = SaveLevel_AUTH(NULL, level);
+ putFileChunkBE(file, "AUTH", chunk_size);
SaveLevel_AUTH(file, level);
- putFileChunkBE(file, "BODY", body_chunk_size);
+ chunk_size = SaveLevel_INFO(NULL, level);
+ putFileChunkBE(file, "INFO", chunk_size);
+ SaveLevel_INFO(file, level);
+
+ chunk_size = SaveLevel_BODY(NULL, level);
+ putFileChunkBE(file, "BODY", chunk_size);
SaveLevel_BODY(file, level);
- if (level->encoding_16bit_yamyam ||
- level->num_yamyam_contents != STD_ELEMENT_CONTENTS)
+ chunk_size = SaveLevel_ELEM(NULL, level);
+ if (chunk_size > LEVEL_CHUNK_ELEM_UNCHANGED) /* save if changed */
{
- putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
- SaveLevel_CNT2(file, level, EL_YAMYAM);
+ putFileChunkBE(file, "ELEM", chunk_size);
+ SaveLevel_ELEM(file, level);
}
- if (level->encoding_16bit_amoeba)
+ for (i = 0; i < NUM_ENVELOPES; i++)
{
- putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
- SaveLevel_CNT2(file, level, EL_BD_AMOEBA);
- }
+ int element = EL_ENVELOPE_1 + i;
- /* check for envelope content */
- for (i = 0; i < 4; i++)
- {
- if (strlen(level->envelope_text[i]) > 0)
+ chunk_size = SaveLevel_NOTE(NULL, level, element);
+ if (chunk_size > LEVEL_CHUNK_NOTE_UNCHANGED) /* save if changed */
{
- int envelope_len = strlen(level->envelope_text[i]) + 1;
-
- putFileChunkBE(file, "CNT3", LEVEL_CHUNK_CNT3_SIZE(envelope_len));
- SaveLevel_CNT3(file, level, EL_ENVELOPE_1 + i);
+ putFileChunkBE(file, "NOTE", chunk_size);
+ SaveLevel_NOTE(file, level, element);
}
}
- /* check for non-default custom elements (unless using template level) */
+ /* if not using template level, check for non-default custom/group elements */
if (!level->use_custom_template)
{
for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
{
int element = EL_CUSTOM_START + i;
- if (element_info[element].modified_settings)
+ chunk_size = SaveLevel_CUSX(NULL, level, element);
+ if (chunk_size > LEVEL_CHUNK_CUSX_UNCHANGED) /* save if changed */
{
- int num_change_pages = element_info[element].num_change_pages;
-
- putFileChunkBE(file, "CUS4", LEVEL_CHUNK_CUS4_SIZE(num_change_pages));
- SaveLevel_CUS4(file, level, element);
+ putFileChunkBE(file, "CUSX", chunk_size);
+ SaveLevel_CUSX(file, level, element);
}
}
- }
- /* 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)
+ chunk_size = SaveLevel_GRPX(NULL, level, element);
+ if (chunk_size > LEVEL_CHUNK_GRPX_UNCHANGED) /* save if changed */
{
- putFileChunkBE(file, "GRP1", LEVEL_CHUNK_GRP1_SIZE);
- SaveLevel_GRP1(file, level, element);
+ putFileChunkBE(file, "GRPX", chunk_size);
+ SaveLevel_GRPX(file, level, element);
}
}
}
- conf_chunk_size = SaveLevel_CONF(NULL, level); /* get chunk size */
-
- /* check for non-default configuration settings to be saved in CONF chunk */
- if (conf_chunk_size > 0)
- {
- putFileChunkBE(file, "CONF", conf_chunk_size);
- SaveLevel_CONF(file, level);
- }
-
fclose(file);
SetFilePermissions(filename, PERMS_PRIVATE);
SaveLevelFromFilename(&level, filename);
}
+boolean SaveLevelChecked(int nr)
+{
+ char *filename = getDefaultLevelFilename(nr);
+ boolean new_level = !fileExists(filename);
+ boolean level_saved = FALSE;
+
+ if (new_level || Request("Save this level and kill the old ?", REQ_ASK))
+ {
+ SaveLevel(nr);
+
+ if (new_level)
+ Request("Level saved !", REQ_CONFIRM);
+
+ level_saved = TRUE;
+ }
+
+ return level_saved;
+}
+
void DumpLevel(struct LevelInfo *level)
{
if (level->no_valid_file)
printf("\n");
printf("Amoeba speed: %d\n", level->amoeba_speed);
printf("\n");
- printf("Initial gravity: %s\n", (level->initial_gravity ? "yes" : "no"));
- printf("Initial player stepsize: %d\n", level->initial_player_stepsize);
+
printf("EM style slippery gems: %s\n", (level->em_slippery_gems ? "yes" : "no"));
printf("Player blocks last field: %s\n", (level->block_last_field ? "yes" : "no"));
printf("SP player blocks last field: %s\n", (level->sp_block_last_field ? "yes" : "no"));
}
}
- ReadUnusedBytesFromFile(file, TAPE_HEADER_UNUSED);
+ ReadUnusedBytesFromFile(file, TAPE_CHUNK_HEAD_UNUSED);
engine_version = getFileVersion(file);
if (engine_version > 0)
if (tape.file_version < FILE_VERSION_1_2)
{
/* tape files from versions before 1.2.0 without chunk structure */
- LoadTape_HEAD(file, TAPE_HEADER_SIZE, &tape);
- LoadTape_BODY(file, 2 * tape.length, &tape);
+ LoadTape_HEAD(file, TAPE_CHUNK_HEAD_SIZE, &tape);
+ LoadTape_BODY(file, 2 * tape.length, &tape);
}
else
{
}
chunk_info[] =
{
- { "VERS", FILE_VERS_CHUNK_SIZE, LoadTape_VERS },
- { "HEAD", TAPE_HEADER_SIZE, LoadTape_HEAD },
+ { "VERS", TAPE_CHUNK_VERS_SIZE, LoadTape_VERS },
+ { "HEAD", TAPE_CHUNK_HEAD_SIZE, LoadTape_HEAD },
{ "INFO", -1, LoadTape_INFO },
{ "BODY", -1, LoadTape_BODY },
{ NULL, 0, NULL }
tape.length_seconds = GetTapeLength();
#if 0
+ printf("::: tape file version: %d\n", tape.file_version);
printf("::: tape game version: %d\n", tape.game_version);
printf("::: tape engine version: %d\n", tape.engine_version);
#endif
putFile8Bit(file, store_participating_players);
/* unused bytes not at the end here for 4-byte alignment of engine_version */
- WriteUnusedBytesToFile(file, TAPE_HEADER_UNUSED);
+ WriteUnusedBytesToFile(file, TAPE_CHUNK_HEAD_UNUSED);
putFileVersion(file, tape->engine_version);
}
{
char *filename = getTapeFilename(nr);
FILE *file;
+#if 0
boolean new_tape = TRUE;
+#endif
int num_participating_players = 0;
int info_chunk_size;
int body_chunk_size;
InitTapeDirectory(leveldir_current->subdir);
+#if 0
/* if a tape still exists, ask to overwrite it */
if (fileExists(filename))
{
if (!Request("Replace old tape ?", REQ_ASK))
return;
}
+#endif
if (!(file = fopen(filename, MODE_WRITE)))
{
putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
- putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
+ putFileChunkBE(file, "VERS", TAPE_CHUNK_VERS_SIZE);
SaveTape_VERS(file, &tape);
- putFileChunkBE(file, "HEAD", TAPE_HEADER_SIZE);
+ putFileChunkBE(file, "HEAD", TAPE_CHUNK_HEAD_SIZE);
SaveTape_HEAD(file, &tape);
putFileChunkBE(file, "INFO", info_chunk_size);
tape.changed = FALSE;
+#if 0
if (new_tape)
Request("Tape saved !", REQ_CONFIRM);
+#endif
+}
+
+boolean SaveTapeChecked(int nr)
+{
+ char *filename = getTapeFilename(nr);
+ boolean new_tape = !fileExists(filename);
+ boolean tape_saved = FALSE;
+
+ if (new_tape || Request("Replace old tape ?", REQ_ASK))
+ {
+ SaveTape(nr);
+
+ if (new_tape)
+ Request("Tape saved !", REQ_CONFIRM);
+
+ tape_saved = TRUE;
+ }
+
+ return tape_saved;
}
void DumpTape(struct TapeInfo *tape)
#define SETUP_TOKEN_TOONS 5
#define SETUP_TOKEN_SCROLL_DELAY 6
#define SETUP_TOKEN_SOFT_SCROLLING 7
-#define SETUP_TOKEN_FADING 8
+#define SETUP_TOKEN_FADE_SCREENS 8
#define SETUP_TOKEN_AUTORECORD 9
#define SETUP_TOKEN_SHOW_TITLESCREEN 10
#define SETUP_TOKEN_QUICK_DOORS 11
#define SETUP_TOKEN_SKIP_LEVELS 14
#define SETUP_TOKEN_TIME_LIMIT 15
#define SETUP_TOKEN_FULLSCREEN 16
-#define SETUP_TOKEN_ASK_ON_ESCAPE 17
-#define SETUP_TOKEN_ASK_ON_ESCAPE_EDITOR 18
-#define SETUP_TOKEN_QUICK_SWITCH 19
-#define SETUP_TOKEN_INPUT_ON_FOCUS 20
-#define SETUP_TOKEN_PREFER_AGA_GRAPHICS 21
-#define SETUP_TOKEN_GRAPHICS_SET 22
-#define SETUP_TOKEN_SOUNDS_SET 23
-#define SETUP_TOKEN_MUSIC_SET 24
-#define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS 25
-#define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS 26
-#define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC 27
-
-#define NUM_GLOBAL_SETUP_TOKENS 28
+#define SETUP_TOKEN_FULLSCREEN_MODE 17
+#define SETUP_TOKEN_ASK_ON_ESCAPE 18
+#define SETUP_TOKEN_ASK_ON_ESCAPE_EDITOR 19
+#define SETUP_TOKEN_QUICK_SWITCH 20
+#define SETUP_TOKEN_INPUT_ON_FOCUS 21
+#define SETUP_TOKEN_PREFER_AGA_GRAPHICS 22
+#define SETUP_TOKEN_GRAPHICS_SET 23
+#define SETUP_TOKEN_SOUNDS_SET 24
+#define SETUP_TOKEN_MUSIC_SET 25
+#define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS 26
+#define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS 27
+#define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC 28
+
+#define NUM_GLOBAL_SETUP_TOKENS 29
/* editor setup */
#define SETUP_TOKEN_EDITOR_EL_BOULDERDASH 0
#define SETUP_TOKEN_EDITOR_EL_HEADLINES 10
#define SETUP_TOKEN_EDITOR_EL_USER_DEFINED 11
#define SETUP_TOKEN_EDITOR_EL_DYNAMIC 12
-#define SETUP_TOKEN_EDITOR_SHOW_ELEMENT_TOKEN 13
+#define SETUP_TOKEN_EDITOR_EL_BY_GAME 13
+#define SETUP_TOKEN_EDITOR_EL_BY_TYPE 14
+#define SETUP_TOKEN_EDITOR_SHOW_ELEMENT_TOKEN 15
-#define NUM_EDITOR_SETUP_TOKENS 14
+#define NUM_EDITOR_SETUP_TOKENS 16
/* editor cascade setup */
#define SETUP_TOKEN_EDITOR_CASCADE_BD 0
#define SETUP_TOKEN_EDITOR_CASCADE_TEXT 8
#define SETUP_TOKEN_EDITOR_CASCADE_CE 9
#define SETUP_TOKEN_EDITOR_CASCADE_GE 10
-#define SETUP_TOKEN_EDITOR_CASCADE_USER 11
-#define SETUP_TOKEN_EDITOR_CASCADE_GENERIC 12
+#define SETUP_TOKEN_EDITOR_CASCADE_REF 11
+#define SETUP_TOKEN_EDITOR_CASCADE_USER 12
#define SETUP_TOKEN_EDITOR_CASCADE_DYNAMIC 13
#define NUM_EDITOR_CASCADE_SETUP_TOKENS 14
{ TYPE_SWITCH, &si.toons, "toons" },
{ TYPE_SWITCH, &si.scroll_delay, "scroll_delay" },
{ TYPE_SWITCH, &si.soft_scrolling, "soft_scrolling" },
- { TYPE_SWITCH, &si.fading, "screen_fading" },
+ { TYPE_SWITCH, &si.fade_screens, "fade_screens" },
{ TYPE_SWITCH, &si.autorecord, "automatic_tape_recording" },
{ TYPE_SWITCH, &si.show_titlescreen, "show_titlescreen" },
{ TYPE_SWITCH, &si.quick_doors, "quick_doors" },
{ TYPE_SWITCH, &si.skip_levels, "skip_levels" },
{ TYPE_SWITCH, &si.time_limit, "time_limit" },
{ TYPE_SWITCH, &si.fullscreen, "fullscreen" },
+ { TYPE_STRING, &si.fullscreen_mode, "fullscreen_mode" },
{ TYPE_SWITCH, &si.ask_on_escape, "ask_on_escape" },
{ TYPE_SWITCH, &si.ask_on_escape_editor, "ask_on_escape_editor" },
{ TYPE_SWITCH, &si.quick_switch, "quick_player_switch" },
{ TYPE_SWITCH, &si.override_level_music, "override_level_music" },
};
+static boolean not_used = FALSE;
static struct TokenInfo editor_setup_tokens[] =
{
+#if 1
+ { TYPE_SWITCH, ¬_used, "editor.el_boulderdash" },
+ { TYPE_SWITCH, ¬_used, "editor.el_emerald_mine" },
+ { TYPE_SWITCH, ¬_used, "editor.el_emerald_mine_club" },
+ { TYPE_SWITCH, ¬_used, "editor.el_more" },
+ { TYPE_SWITCH, ¬_used, "editor.el_sokoban" },
+ { TYPE_SWITCH, ¬_used, "editor.el_supaplex" },
+ { TYPE_SWITCH, ¬_used, "editor.el_diamond_caves" },
+ { TYPE_SWITCH, ¬_used, "editor.el_dx_boulderdash" },
+#else
{ TYPE_SWITCH, &sei.el_boulderdash, "editor.el_boulderdash" },
{ TYPE_SWITCH, &sei.el_emerald_mine, "editor.el_emerald_mine" },
{ TYPE_SWITCH, &sei.el_emerald_mine_club,"editor.el_emerald_mine_club"},
{ TYPE_SWITCH, &sei.el_supaplex, "editor.el_supaplex" },
{ TYPE_SWITCH, &sei.el_diamond_caves, "editor.el_diamond_caves" },
{ TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash" },
+#endif
{ TYPE_SWITCH, &sei.el_chars, "editor.el_chars" },
{ TYPE_SWITCH, &sei.el_custom, "editor.el_custom" },
+#if 1
+ { TYPE_SWITCH, ¬_used, "editor.el_headlines" },
+#else
{ TYPE_SWITCH, &sei.el_headlines, "editor.el_headlines" },
+#endif
{ TYPE_SWITCH, &sei.el_user_defined, "editor.el_user_defined" },
{ TYPE_SWITCH, &sei.el_dynamic, "editor.el_dynamic" },
+ { TYPE_SWITCH, &sei.el_by_game, "editor.el_by_game" },
+ { TYPE_SWITCH, &sei.el_by_type, "editor.el_by_type" },
{ TYPE_SWITCH, &sei.show_element_token,"editor.show_element_token" },
};
{ TYPE_SWITCH, &seci.el_chars, "editor.cascade.el_chars" },
{ TYPE_SWITCH, &seci.el_ce, "editor.cascade.el_ce" },
{ TYPE_SWITCH, &seci.el_ge, "editor.cascade.el_ge" },
+ { TYPE_SWITCH, &seci.el_ref, "editor.cascade.el_ref" },
{ TYPE_SWITCH, &seci.el_user, "editor.cascade.el_user" },
{ TYPE_SWITCH, &seci.el_dynamic, "editor.cascade.el_dynamic" },
};
si->direct_draw = !si->double_buffering;
si->scroll_delay = TRUE;
si->soft_scrolling = TRUE;
- si->fading = FALSE;
+ si->fade_screens = TRUE;
si->autorecord = TRUE;
si->show_titlescreen = TRUE;
si->quick_doors = FALSE;
si->skip_levels = TRUE;
si->time_limit = TRUE;
si->fullscreen = FALSE;
+ si->fullscreen_mode = getStringCopy(DEFAULT_FULLSCREEN_MODE);
si->ask_on_escape = TRUE;
si->ask_on_escape_editor = TRUE;
si->quick_switch = FALSE;
si->editor_cascade.el_chars = FALSE;
si->editor_cascade.el_ce = FALSE;
si->editor_cascade.el_ge = FALSE;
+ si->editor_cascade.el_ref = FALSE;
si->editor_cascade.el_user = FALSE;
si->editor_cascade.el_dynamic = FALSE;
}
seci = setup.editor_cascade;
fprintf(file, "\n");
- for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
+ for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
fprintf(file, "%s\n", getSetupLine(editor_cascade_setup_tokens, "", i));
fclose(file);
menu.list_size[i] = get_integer_from_string(list_size);
}
+ /* special case: initialize with default values that may be overwritten */
+ for (i = 0; i < NUM_SPECIAL_GFX_INFO_ARGS; i++)
+ {
+ char *value_x = getHashEntry(setup_file_hash, "menu.draw_xoffset.INFO");
+ char *value_y = getHashEntry(setup_file_hash, "menu.draw_yoffset.INFO");
+
+ if (value_x != NULL)
+ menu.draw_xoffset_info[i] = get_integer_from_string(value_x);
+ if (value_y != NULL)
+ menu.draw_yoffset_info[i] = get_integer_from_string(value_y);
+ }
+
/* read (and overwrite with) values that may be specified in config file */
for (i = 0; image_config_vars[i].token != NULL; i++)
{
get_auto_parameter_value(image_config_vars[i].token,
image_config[j].value);
-#if 1
if (!SETUP_OVERRIDE_ARTWORK(setup, ARTWORK_TYPE_GRAPHICS))
{
/* first look for special settings configured in level series config */
if (filename_local != NULL && !strEqual(filename_base, filename_local))
LoadSpecialMenuDesignSettingsFromFilename(filename_local);
-
-#else
-
- filename_local = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
-
- LoadSpecialMenuDesignSettingsFromFilename(filename_local);
-#endif
}
void LoadUserDefinedEditorElementList(int **elements, int *num_elements)