1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
17 #include "libgame/libgame.h"
26 #define ENABLE_UNUSED_CODE 0 // currently unused functions
27 #define ENABLE_HISTORIC_CHUNKS 0 // only for historic reference
28 #define ENABLE_RESERVED_CODE 0 // reserved for later use
30 #define CHUNK_ID_LEN 4 // IFF style chunk id length
31 #define CHUNK_SIZE_UNDEFINED 0 // undefined chunk size == 0
32 #define CHUNK_SIZE_NONE -1 // do not write chunk size
34 #define LEVEL_CHUNK_NAME_SIZE MAX_LEVEL_NAME_LEN
35 #define LEVEL_CHUNK_AUTH_SIZE MAX_LEVEL_AUTHOR_LEN
37 #define LEVEL_CHUNK_VERS_SIZE 8 // size of file version chunk
38 #define LEVEL_CHUNK_DATE_SIZE 4 // size of file date chunk
39 #define LEVEL_CHUNK_HEAD_SIZE 80 // size of level file header
40 #define LEVEL_CHUNK_HEAD_UNUSED 0 // unused level header bytes
41 #define LEVEL_CHUNK_CNT2_SIZE 160 // size of level CNT2 chunk
42 #define LEVEL_CHUNK_CNT2_UNUSED 11 // unused CNT2 chunk bytes
43 #define LEVEL_CHUNK_CNT3_HEADER 16 // size of level CNT3 header
44 #define LEVEL_CHUNK_CNT3_UNUSED 10 // unused CNT3 chunk bytes
45 #define LEVEL_CPART_CUS3_SIZE 134 // size of CUS3 chunk part
46 #define LEVEL_CPART_CUS3_UNUSED 15 // unused CUS3 bytes / part
47 #define LEVEL_CHUNK_GRP1_SIZE 74 // size of level GRP1 chunk
49 // (element number, number of change pages, change page number)
50 #define LEVEL_CHUNK_CUSX_UNCHANGED (2 + (1 + 1) + (1 + 1))
52 // (element number only)
53 #define LEVEL_CHUNK_GRPX_UNCHANGED 2
54 #define LEVEL_CHUNK_NOTE_UNCHANGED 2
56 // (nothing at all if unchanged)
57 #define LEVEL_CHUNK_ELEM_UNCHANGED 0
59 #define TAPE_CHUNK_VERS_SIZE 8 // size of file version chunk
60 #define TAPE_CHUNK_HEAD_SIZE 20 // size of tape file header
61 #define TAPE_CHUNK_HEAD_UNUSED 2 // unused tape header bytes
63 #define LEVEL_CHUNK_CNT3_SIZE(x) (LEVEL_CHUNK_CNT3_HEADER + (x))
64 #define LEVEL_CHUNK_CUS3_SIZE(x) (2 + (x) * LEVEL_CPART_CUS3_SIZE)
65 #define LEVEL_CHUNK_CUS4_SIZE(x) (96 + (x) * 48)
67 // file identifier strings
68 #define LEVEL_COOKIE_TMPL "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x"
69 #define TAPE_COOKIE_TMPL "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
70 #define SCORE_COOKIE "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
72 // values for deciding when (not) to save configuration data
73 #define SAVE_CONF_NEVER 0
74 #define SAVE_CONF_ALWAYS 1
75 #define SAVE_CONF_WHEN_CHANGED -1
77 // values for chunks using micro chunks
78 #define CONF_MASK_1_BYTE 0x00
79 #define CONF_MASK_2_BYTE 0x40
80 #define CONF_MASK_4_BYTE 0x80
81 #define CONF_MASK_MULTI_BYTES 0xc0
83 #define CONF_MASK_BYTES 0xc0
84 #define CONF_MASK_TOKEN 0x3f
86 #define CONF_VALUE_1_BYTE(x) (CONF_MASK_1_BYTE | (x))
87 #define CONF_VALUE_2_BYTE(x) (CONF_MASK_2_BYTE | (x))
88 #define CONF_VALUE_4_BYTE(x) (CONF_MASK_4_BYTE | (x))
89 #define CONF_VALUE_MULTI_BYTES(x) (CONF_MASK_MULTI_BYTES | (x))
91 // these definitions are just for convenience of use and readability
92 #define CONF_VALUE_8_BIT(x) CONF_VALUE_1_BYTE(x)
93 #define CONF_VALUE_16_BIT(x) CONF_VALUE_2_BYTE(x)
94 #define CONF_VALUE_32_BIT(x) CONF_VALUE_4_BYTE(x)
95 #define CONF_VALUE_BYTES(x) CONF_VALUE_MULTI_BYTES(x)
97 #define CONF_VALUE_NUM_BYTES(x) ((x) == CONF_MASK_1_BYTE ? 1 : \
98 (x) == CONF_MASK_2_BYTE ? 2 : \
99 (x) == CONF_MASK_4_BYTE ? 4 : 0)
101 #define CONF_CONTENT_NUM_ELEMENTS (3 * 3)
102 #define CONF_CONTENT_NUM_BYTES (CONF_CONTENT_NUM_ELEMENTS * 2)
103 #define CONF_ELEMENT_NUM_BYTES (2)
105 #define CONF_ENTITY_NUM_BYTES(t) ((t) == TYPE_ELEMENT || \
106 (t) == TYPE_ELEMENT_LIST ? \
107 CONF_ELEMENT_NUM_BYTES : \
108 (t) == TYPE_CONTENT || \
109 (t) == TYPE_CONTENT_LIST ? \
110 CONF_CONTENT_NUM_BYTES : 1)
112 #define CONF_ELEMENT_BYTE_POS(i) ((i) * CONF_ELEMENT_NUM_BYTES)
113 #define CONF_ELEMENTS_ELEMENT(b,i) ((b[CONF_ELEMENT_BYTE_POS(i)] << 8) | \
114 (b[CONF_ELEMENT_BYTE_POS(i) + 1]))
116 #define CONF_CONTENT_ELEMENT_POS(c,x,y) ((c) * CONF_CONTENT_NUM_ELEMENTS + \
118 #define CONF_CONTENT_BYTE_POS(c,x,y) (CONF_CONTENT_ELEMENT_POS(c,x,y) * \
119 CONF_ELEMENT_NUM_BYTES)
120 #define CONF_CONTENTS_ELEMENT(b,c,x,y) ((b[CONF_CONTENT_BYTE_POS(c,x,y)]<< 8)|\
121 (b[CONF_CONTENT_BYTE_POS(c,x,y) + 1]))
123 // temporary variables used to store pointers to structure members
124 static struct LevelInfo li;
125 static struct ElementInfo xx_ei, yy_ei;
126 static struct ElementChangeInfo xx_change;
127 static struct ElementGroupInfo xx_group;
128 static struct EnvelopeInfo xx_envelope;
129 static unsigned int xx_event_bits[NUM_CE_BITFIELDS];
130 static char xx_default_description[MAX_ELEMENT_NAME_LEN + 1];
131 static int xx_num_contents;
132 static int xx_current_change_page;
133 static char xx_default_string_empty[1] = "";
134 static int xx_string_length_unused;
136 struct LevelFileConfigInfo
138 int element; // element for which data is to be stored
139 int save_type; // save data always, never or when changed
140 int data_type; // data type (used internally, not stored)
141 int conf_type; // micro chunk identifier (stored in file)
144 void *value; // variable that holds the data to be stored
145 int default_value; // initial default value for this variable
148 void *value_copy; // variable that holds the data to be copied
149 void *num_entities; // number of entities for multi-byte data
150 int default_num_entities; // default number of entities for this data
151 int max_num_entities; // maximal number of entities for this data
152 char *default_string; // optional default string for string data
155 static struct LevelFileConfigInfo chunk_config_INFO[] =
157 // ---------- values not related to single elements -------------------------
160 -1, SAVE_CONF_ALWAYS,
161 TYPE_INTEGER, CONF_VALUE_8_BIT(1),
162 &li.game_engine_type, GAME_ENGINE_TYPE_RND
166 -1, SAVE_CONF_ALWAYS,
167 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
168 &li.fieldx, STD_LEV_FIELDX
171 -1, SAVE_CONF_ALWAYS,
172 TYPE_INTEGER, CONF_VALUE_16_BIT(2),
173 &li.fieldy, STD_LEV_FIELDY
177 -1, SAVE_CONF_ALWAYS,
178 TYPE_INTEGER, CONF_VALUE_16_BIT(3),
183 -1, SAVE_CONF_ALWAYS,
184 TYPE_INTEGER, CONF_VALUE_16_BIT(4),
190 TYPE_INTEGER, CONF_VALUE_32_BIT(2),
196 TYPE_BOOLEAN, CONF_VALUE_8_BIT(2),
197 &li.use_step_counter, FALSE
202 TYPE_BITFIELD, CONF_VALUE_8_BIT(4),
203 &li.wind_direction_initial, MV_NONE
208 TYPE_BOOLEAN, CONF_VALUE_8_BIT(5),
209 &li.em_slippery_gems, FALSE
214 TYPE_BOOLEAN, CONF_VALUE_8_BIT(6),
215 &li.use_custom_template, FALSE
220 TYPE_BITFIELD, CONF_VALUE_32_BIT(1),
221 &li.can_move_into_acid_bits, ~0 // default: everything can
226 TYPE_BITFIELD, CONF_VALUE_8_BIT(7),
227 &li.dont_collide_with_bits, ~0 // default: always deadly
232 TYPE_BOOLEAN, CONF_VALUE_8_BIT(8),
233 &li.em_explodes_by_fire, FALSE
238 TYPE_INTEGER, CONF_VALUE_16_BIT(5),
239 &li.score[SC_TIME_BONUS], 1
244 TYPE_BOOLEAN, CONF_VALUE_8_BIT(9),
245 &li.auto_exit_sokoban, FALSE
250 TYPE_BOOLEAN, CONF_VALUE_8_BIT(10),
251 &li.auto_count_gems, FALSE
256 TYPE_BOOLEAN, CONF_VALUE_8_BIT(11),
257 &li.solved_by_one_player, FALSE
267 static struct LevelFileConfigInfo chunk_config_ELEM[] =
269 // (these values are the same for each player)
272 TYPE_BOOLEAN, CONF_VALUE_8_BIT(1),
273 &li.block_last_field, FALSE // default case for EM levels
277 TYPE_BOOLEAN, CONF_VALUE_8_BIT(2),
278 &li.sp_block_last_field, TRUE // default case for SP levels
282 TYPE_BOOLEAN, CONF_VALUE_8_BIT(3),
283 &li.instant_relocation, FALSE
287 TYPE_BOOLEAN, CONF_VALUE_8_BIT(4),
288 &li.can_pass_to_walkable, FALSE
292 TYPE_BOOLEAN, CONF_VALUE_8_BIT(5),
293 &li.block_snap_field, TRUE
297 TYPE_BOOLEAN, CONF_VALUE_8_BIT(6),
298 &li.continuous_snapping, TRUE
302 TYPE_BOOLEAN, CONF_VALUE_8_BIT(12),
303 &li.shifted_relocation, FALSE
307 TYPE_BOOLEAN, CONF_VALUE_8_BIT(15),
308 &li.lazy_relocation, FALSE
311 // (these values are different for each player)
314 TYPE_INTEGER, CONF_VALUE_8_BIT(7),
315 &li.initial_player_stepsize[0], STEPSIZE_NORMAL
319 TYPE_BOOLEAN, CONF_VALUE_8_BIT(8),
320 &li.initial_player_gravity[0], FALSE
324 TYPE_BOOLEAN, CONF_VALUE_8_BIT(9),
325 &li.use_start_element[0], FALSE
329 TYPE_ELEMENT, CONF_VALUE_16_BIT(1),
330 &li.start_element[0], EL_PLAYER_1
334 TYPE_BOOLEAN, CONF_VALUE_8_BIT(10),
335 &li.use_artwork_element[0], FALSE
339 TYPE_ELEMENT, CONF_VALUE_16_BIT(2),
340 &li.artwork_element[0], EL_PLAYER_1
344 TYPE_BOOLEAN, CONF_VALUE_8_BIT(11),
345 &li.use_explosion_element[0], FALSE
349 TYPE_ELEMENT, CONF_VALUE_16_BIT(3),
350 &li.explosion_element[0], EL_PLAYER_1
354 TYPE_BOOLEAN, CONF_VALUE_8_BIT(13),
355 &li.use_initial_inventory[0], FALSE
359 TYPE_BOOLEAN, CONF_VALUE_8_BIT(14),
360 &li.initial_inventory_size[0], 1
364 TYPE_ELEMENT_LIST, CONF_VALUE_BYTES(1),
365 &li.initial_inventory_content[0][0],EL_EMPTY, NULL,
366 &li.initial_inventory_size[0], 1, MAX_INITIAL_INVENTORY_SIZE
371 TYPE_INTEGER, CONF_VALUE_8_BIT(7),
372 &li.initial_player_stepsize[1], STEPSIZE_NORMAL
376 TYPE_BOOLEAN, CONF_VALUE_8_BIT(8),
377 &li.initial_player_gravity[1], FALSE
381 TYPE_BOOLEAN, CONF_VALUE_8_BIT(9),
382 &li.use_start_element[1], FALSE
386 TYPE_ELEMENT, CONF_VALUE_16_BIT(1),
387 &li.start_element[1], EL_PLAYER_2
391 TYPE_BOOLEAN, CONF_VALUE_8_BIT(10),
392 &li.use_artwork_element[1], FALSE
396 TYPE_ELEMENT, CONF_VALUE_16_BIT(2),
397 &li.artwork_element[1], EL_PLAYER_2
401 TYPE_BOOLEAN, CONF_VALUE_8_BIT(11),
402 &li.use_explosion_element[1], FALSE
406 TYPE_ELEMENT, CONF_VALUE_16_BIT(3),
407 &li.explosion_element[1], EL_PLAYER_2
411 TYPE_BOOLEAN, CONF_VALUE_8_BIT(13),
412 &li.use_initial_inventory[1], FALSE
416 TYPE_BOOLEAN, CONF_VALUE_8_BIT(14),
417 &li.initial_inventory_size[1], 1
421 TYPE_ELEMENT_LIST, CONF_VALUE_BYTES(1),
422 &li.initial_inventory_content[1][0],EL_EMPTY, NULL,
423 &li.initial_inventory_size[1], 1, MAX_INITIAL_INVENTORY_SIZE
428 TYPE_INTEGER, CONF_VALUE_8_BIT(7),
429 &li.initial_player_stepsize[2], STEPSIZE_NORMAL
433 TYPE_BOOLEAN, CONF_VALUE_8_BIT(8),
434 &li.initial_player_gravity[2], FALSE
438 TYPE_BOOLEAN, CONF_VALUE_8_BIT(9),
439 &li.use_start_element[2], FALSE
443 TYPE_ELEMENT, CONF_VALUE_16_BIT(1),
444 &li.start_element[2], EL_PLAYER_3
448 TYPE_BOOLEAN, CONF_VALUE_8_BIT(10),
449 &li.use_artwork_element[2], FALSE
453 TYPE_ELEMENT, CONF_VALUE_16_BIT(2),
454 &li.artwork_element[2], EL_PLAYER_3
458 TYPE_BOOLEAN, CONF_VALUE_8_BIT(11),
459 &li.use_explosion_element[2], FALSE
463 TYPE_ELEMENT, CONF_VALUE_16_BIT(3),
464 &li.explosion_element[2], EL_PLAYER_3
468 TYPE_BOOLEAN, CONF_VALUE_8_BIT(13),
469 &li.use_initial_inventory[2], FALSE
473 TYPE_BOOLEAN, CONF_VALUE_8_BIT(14),
474 &li.initial_inventory_size[2], 1
478 TYPE_ELEMENT_LIST, CONF_VALUE_BYTES(1),
479 &li.initial_inventory_content[2][0],EL_EMPTY, NULL,
480 &li.initial_inventory_size[2], 1, MAX_INITIAL_INVENTORY_SIZE
485 TYPE_INTEGER, CONF_VALUE_8_BIT(7),
486 &li.initial_player_stepsize[3], STEPSIZE_NORMAL
490 TYPE_BOOLEAN, CONF_VALUE_8_BIT(8),
491 &li.initial_player_gravity[3], FALSE
495 TYPE_BOOLEAN, CONF_VALUE_8_BIT(9),
496 &li.use_start_element[3], FALSE
500 TYPE_ELEMENT, CONF_VALUE_16_BIT(1),
501 &li.start_element[3], EL_PLAYER_4
505 TYPE_BOOLEAN, CONF_VALUE_8_BIT(10),
506 &li.use_artwork_element[3], FALSE
510 TYPE_ELEMENT, CONF_VALUE_16_BIT(2),
511 &li.artwork_element[3], EL_PLAYER_4
515 TYPE_BOOLEAN, CONF_VALUE_8_BIT(11),
516 &li.use_explosion_element[3], FALSE
520 TYPE_ELEMENT, CONF_VALUE_16_BIT(3),
521 &li.explosion_element[3], EL_PLAYER_4
525 TYPE_BOOLEAN, CONF_VALUE_8_BIT(13),
526 &li.use_initial_inventory[3], FALSE
530 TYPE_BOOLEAN, CONF_VALUE_8_BIT(14),
531 &li.initial_inventory_size[3], 1
535 TYPE_ELEMENT_LIST, CONF_VALUE_BYTES(1),
536 &li.initial_inventory_content[3][0],EL_EMPTY, NULL,
537 &li.initial_inventory_size[3], 1, MAX_INITIAL_INVENTORY_SIZE
542 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
543 &li.score[SC_EMERALD], 10
548 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
549 &li.score[SC_DIAMOND], 10
554 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
555 &li.score[SC_BUG], 10
560 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
561 &li.score[SC_SPACESHIP], 10
566 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
567 &li.score[SC_PACMAN], 10
572 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
573 &li.score[SC_NUT], 10
578 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
579 &li.score[SC_DYNAMITE], 10
584 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
585 &li.score[SC_KEY], 10
590 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
591 &li.score[SC_PEARL], 10
596 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
597 &li.score[SC_CRYSTAL], 10
602 TYPE_ELEMENT, CONF_VALUE_16_BIT(1),
603 &li.amoeba_content, EL_DIAMOND
607 TYPE_INTEGER, CONF_VALUE_16_BIT(2),
612 TYPE_BOOLEAN, CONF_VALUE_8_BIT(1),
613 &li.grow_into_diggable, TRUE
618 TYPE_CONTENT_LIST, CONF_VALUE_BYTES(1),
619 &li.yamyam_content, EL_ROCK, NULL,
620 &li.num_yamyam_contents, 4, MAX_ELEMENT_CONTENTS
624 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
625 &li.score[SC_YAMYAM], 10
630 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
631 &li.score[SC_ROBOT], 10
635 TYPE_INTEGER, CONF_VALUE_16_BIT(2),
641 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
647 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
648 &li.time_magic_wall, 10
653 TYPE_INTEGER, CONF_VALUE_8_BIT(1),
654 &li.game_of_life[0], 2
658 TYPE_INTEGER, CONF_VALUE_8_BIT(2),
659 &li.game_of_life[1], 3
663 TYPE_INTEGER, CONF_VALUE_8_BIT(3),
664 &li.game_of_life[2], 3
668 TYPE_INTEGER, CONF_VALUE_8_BIT(4),
669 &li.game_of_life[3], 3
673 TYPE_BOOLEAN, CONF_VALUE_8_BIT(5),
674 &li.use_life_bugs, FALSE
679 TYPE_INTEGER, CONF_VALUE_8_BIT(1),
684 TYPE_INTEGER, CONF_VALUE_8_BIT(2),
689 TYPE_INTEGER, CONF_VALUE_8_BIT(3),
694 TYPE_INTEGER, CONF_VALUE_8_BIT(4),
699 EL_TIMEGATE_SWITCH, -1,
700 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
701 &li.time_timegate, 10
705 EL_LIGHT_SWITCH_ACTIVE, -1,
706 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
711 EL_SHIELD_NORMAL, -1,
712 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
713 &li.shield_normal_time, 10
716 EL_SHIELD_NORMAL, -1,
717 TYPE_INTEGER, CONF_VALUE_16_BIT(2),
718 &li.score[SC_SHIELD], 10
722 EL_SHIELD_DEADLY, -1,
723 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
724 &li.shield_deadly_time, 10
727 EL_SHIELD_DEADLY, -1,
728 TYPE_INTEGER, CONF_VALUE_16_BIT(2),
729 &li.score[SC_SHIELD], 10
734 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
739 TYPE_INTEGER, CONF_VALUE_16_BIT(2),
740 &li.extra_time_score, 10
744 EL_TIME_ORB_FULL, -1,
745 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
746 &li.time_orb_time, 10
749 EL_TIME_ORB_FULL, -1,
750 TYPE_BOOLEAN, CONF_VALUE_8_BIT(1),
751 &li.use_time_orb_bug, FALSE
756 TYPE_BOOLEAN, CONF_VALUE_8_BIT(1),
757 &li.use_spring_bug, FALSE
762 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
763 &li.android_move_time, 10
767 TYPE_INTEGER, CONF_VALUE_16_BIT(2),
768 &li.android_clone_time, 10
772 TYPE_ELEMENT_LIST, CONF_VALUE_BYTES(1),
773 &li.android_clone_element[0], EL_EMPTY, NULL,
774 &li.num_android_clone_elements, 1, MAX_ANDROID_ELEMENTS
779 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
784 TYPE_INTEGER, CONF_VALUE_16_BIT(2),
789 EL_EMC_MAGNIFIER, -1,
790 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
791 &li.magnify_score, 10
794 EL_EMC_MAGNIFIER, -1,
795 TYPE_INTEGER, CONF_VALUE_16_BIT(2),
800 EL_EMC_MAGIC_BALL, -1,
801 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
805 EL_EMC_MAGIC_BALL, -1,
806 TYPE_BOOLEAN, CONF_VALUE_8_BIT(1),
807 &li.ball_random, FALSE
810 EL_EMC_MAGIC_BALL, -1,
811 TYPE_BOOLEAN, CONF_VALUE_8_BIT(2),
812 &li.ball_state_initial, FALSE
815 EL_EMC_MAGIC_BALL, -1,
816 TYPE_CONTENT_LIST, CONF_VALUE_BYTES(1),
817 &li.ball_content, EL_EMPTY, NULL,
818 &li.num_ball_contents, 4, MAX_ELEMENT_CONTENTS
823 TYPE_BOOLEAN, CONF_VALUE_8_BIT(1),
824 &li.mm_laser_red, FALSE
828 TYPE_BOOLEAN, CONF_VALUE_8_BIT(2),
829 &li.mm_laser_green, FALSE
833 TYPE_BOOLEAN, CONF_VALUE_8_BIT(3),
834 &li.mm_laser_blue, TRUE
839 TYPE_BOOLEAN, CONF_VALUE_8_BIT(1),
840 &li.df_laser_red, TRUE
844 TYPE_BOOLEAN, CONF_VALUE_8_BIT(2),
845 &li.df_laser_green, TRUE
849 TYPE_BOOLEAN, CONF_VALUE_8_BIT(3),
850 &li.df_laser_blue, FALSE
854 EL_MM_FUSE_ACTIVE, -1,
855 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
860 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
865 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
869 EL_MM_STEEL_BLOCK, -1,
870 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
871 &li.mm_time_block, 75
875 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
876 &li.score[SC_ELEM_BONUS], 10
879 // ---------- unused values -------------------------------------------------
882 EL_UNKNOWN, SAVE_CONF_NEVER,
883 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
884 &li.score[SC_UNKNOWN_15], 10
894 static struct LevelFileConfigInfo chunk_config_NOTE[] =
898 TYPE_INTEGER, CONF_VALUE_8_BIT(1),
899 &xx_envelope.xsize, MAX_ENVELOPE_XSIZE,
903 TYPE_INTEGER, CONF_VALUE_8_BIT(2),
904 &xx_envelope.ysize, MAX_ENVELOPE_YSIZE,
909 TYPE_BOOLEAN, CONF_VALUE_8_BIT(3),
910 &xx_envelope.autowrap, FALSE
914 TYPE_BOOLEAN, CONF_VALUE_8_BIT(4),
915 &xx_envelope.centered, FALSE
920 TYPE_STRING, CONF_VALUE_BYTES(1),
921 &xx_envelope.text, -1, NULL,
922 &xx_string_length_unused, -1, MAX_ENVELOPE_TEXT_LEN,
923 &xx_default_string_empty[0]
933 static struct LevelFileConfigInfo chunk_config_CUSX_base[] =
937 TYPE_STRING, CONF_VALUE_BYTES(1),
938 &xx_ei.description[0], -1,
939 &yy_ei.description[0],
940 &xx_string_length_unused, -1, MAX_ELEMENT_NAME_LEN,
941 &xx_default_description[0]
946 TYPE_BITFIELD, CONF_VALUE_32_BIT(1),
947 &xx_ei.properties[EP_BITFIELD_BASE_NR], EP_BITMASK_BASE_DEFAULT,
948 &yy_ei.properties[EP_BITFIELD_BASE_NR]
950 #if ENABLE_RESERVED_CODE
951 // (reserved for later use)
954 TYPE_BITFIELD, CONF_VALUE_32_BIT(2),
955 &xx_ei.properties[EP_BITFIELD_BASE_NR + 1], EP_BITMASK_DEFAULT,
956 &yy_ei.properties[EP_BITFIELD_BASE_NR + 1]
962 TYPE_BOOLEAN, CONF_VALUE_8_BIT(1),
963 &xx_ei.use_gfx_element, FALSE,
964 &yy_ei.use_gfx_element
968 TYPE_ELEMENT, CONF_VALUE_16_BIT(1),
969 &xx_ei.gfx_element_initial, EL_EMPTY_SPACE,
970 &yy_ei.gfx_element_initial
975 TYPE_BITFIELD, CONF_VALUE_8_BIT(2),
976 &xx_ei.access_direction, MV_ALL_DIRECTIONS,
977 &yy_ei.access_direction
982 TYPE_INTEGER, CONF_VALUE_16_BIT(2),
983 &xx_ei.collect_score_initial, 10,
984 &yy_ei.collect_score_initial
988 TYPE_INTEGER, CONF_VALUE_16_BIT(3),
989 &xx_ei.collect_count_initial, 1,
990 &yy_ei.collect_count_initial
995 TYPE_INTEGER, CONF_VALUE_16_BIT(4),
996 &xx_ei.ce_value_fixed_initial, 0,
997 &yy_ei.ce_value_fixed_initial
1001 TYPE_INTEGER, CONF_VALUE_16_BIT(5),
1002 &xx_ei.ce_value_random_initial, 0,
1003 &yy_ei.ce_value_random_initial
1007 TYPE_BOOLEAN, CONF_VALUE_8_BIT(3),
1008 &xx_ei.use_last_ce_value, FALSE,
1009 &yy_ei.use_last_ce_value
1014 TYPE_INTEGER, CONF_VALUE_16_BIT(6),
1015 &xx_ei.push_delay_fixed, 8,
1016 &yy_ei.push_delay_fixed
1020 TYPE_INTEGER, CONF_VALUE_16_BIT(7),
1021 &xx_ei.push_delay_random, 8,
1022 &yy_ei.push_delay_random
1026 TYPE_INTEGER, CONF_VALUE_16_BIT(8),
1027 &xx_ei.drop_delay_fixed, 0,
1028 &yy_ei.drop_delay_fixed
1032 TYPE_INTEGER, CONF_VALUE_16_BIT(9),
1033 &xx_ei.drop_delay_random, 0,
1034 &yy_ei.drop_delay_random
1038 TYPE_INTEGER, CONF_VALUE_16_BIT(10),
1039 &xx_ei.move_delay_fixed, 0,
1040 &yy_ei.move_delay_fixed
1044 TYPE_INTEGER, CONF_VALUE_16_BIT(11),
1045 &xx_ei.move_delay_random, 0,
1046 &yy_ei.move_delay_random
1051 TYPE_BITFIELD, CONF_VALUE_32_BIT(3),
1052 &xx_ei.move_pattern, MV_ALL_DIRECTIONS,
1057 TYPE_BITFIELD, CONF_VALUE_8_BIT(4),
1058 &xx_ei.move_direction_initial, MV_START_AUTOMATIC,
1059 &yy_ei.move_direction_initial
1063 TYPE_INTEGER, CONF_VALUE_8_BIT(5),
1064 &xx_ei.move_stepsize, TILEX / 8,
1065 &yy_ei.move_stepsize
1070 TYPE_ELEMENT, CONF_VALUE_16_BIT(12),
1071 &xx_ei.move_enter_element, EL_EMPTY_SPACE,
1072 &yy_ei.move_enter_element
1076 TYPE_ELEMENT, CONF_VALUE_16_BIT(13),
1077 &xx_ei.move_leave_element, EL_EMPTY_SPACE,
1078 &yy_ei.move_leave_element
1082 TYPE_INTEGER, CONF_VALUE_8_BIT(6),
1083 &xx_ei.move_leave_type, LEAVE_TYPE_UNLIMITED,
1084 &yy_ei.move_leave_type
1089 TYPE_INTEGER, CONF_VALUE_8_BIT(7),
1090 &xx_ei.slippery_type, SLIPPERY_ANY_RANDOM,
1091 &yy_ei.slippery_type
1096 TYPE_INTEGER, CONF_VALUE_8_BIT(8),
1097 &xx_ei.explosion_type, EXPLODES_3X3,
1098 &yy_ei.explosion_type
1102 TYPE_INTEGER, CONF_VALUE_16_BIT(14),
1103 &xx_ei.explosion_delay, 16,
1104 &yy_ei.explosion_delay
1108 TYPE_INTEGER, CONF_VALUE_16_BIT(15),
1109 &xx_ei.ignition_delay, 8,
1110 &yy_ei.ignition_delay
1115 TYPE_CONTENT_LIST, CONF_VALUE_BYTES(2),
1116 &xx_ei.content, EL_EMPTY_SPACE,
1118 &xx_num_contents, 1, 1
1121 // ---------- "num_change_pages" must be the last entry ---------------------
1124 -1, SAVE_CONF_ALWAYS,
1125 TYPE_INTEGER, CONF_VALUE_8_BIT(9),
1126 &xx_ei.num_change_pages, 1,
1127 &yy_ei.num_change_pages
1138 static struct LevelFileConfigInfo chunk_config_CUSX_change[] =
1140 // ---------- "current_change_page" must be the first entry -----------------
1143 -1, SAVE_CONF_ALWAYS,
1144 TYPE_INTEGER, CONF_VALUE_8_BIT(1),
1145 &xx_current_change_page, -1
1148 // ---------- (the remaining entries can be in any order) -------------------
1152 TYPE_BOOLEAN, CONF_VALUE_8_BIT(2),
1153 &xx_change.can_change, FALSE
1158 TYPE_BITFIELD, CONF_VALUE_32_BIT(1),
1159 &xx_event_bits[0], 0
1163 TYPE_BITFIELD, CONF_VALUE_32_BIT(2),
1164 &xx_event_bits[1], 0
1169 TYPE_BITFIELD, CONF_VALUE_8_BIT(3),
1170 &xx_change.trigger_player, CH_PLAYER_ANY
1174 TYPE_BITFIELD, CONF_VALUE_8_BIT(4),
1175 &xx_change.trigger_side, CH_SIDE_ANY
1179 TYPE_BITFIELD, CONF_VALUE_32_BIT(3),
1180 &xx_change.trigger_page, CH_PAGE_ANY
1185 TYPE_ELEMENT, CONF_VALUE_16_BIT(1),
1186 &xx_change.target_element, EL_EMPTY_SPACE
1191 TYPE_INTEGER, CONF_VALUE_16_BIT(2),
1192 &xx_change.delay_fixed, 0
1196 TYPE_INTEGER, CONF_VALUE_16_BIT(3),
1197 &xx_change.delay_random, 0
1201 TYPE_INTEGER, CONF_VALUE_16_BIT(4),
1202 &xx_change.delay_frames, FRAMES_PER_SECOND
1207 TYPE_ELEMENT, CONF_VALUE_16_BIT(5),
1208 &xx_change.initial_trigger_element, EL_EMPTY_SPACE
1213 TYPE_BOOLEAN, CONF_VALUE_8_BIT(6),
1214 &xx_change.explode, FALSE
1218 TYPE_BOOLEAN, CONF_VALUE_8_BIT(7),
1219 &xx_change.use_target_content, FALSE
1223 TYPE_BOOLEAN, CONF_VALUE_8_BIT(8),
1224 &xx_change.only_if_complete, FALSE
1228 TYPE_BOOLEAN, CONF_VALUE_8_BIT(9),
1229 &xx_change.use_random_replace, FALSE
1233 TYPE_INTEGER, CONF_VALUE_8_BIT(10),
1234 &xx_change.random_percentage, 100
1238 TYPE_INTEGER, CONF_VALUE_8_BIT(11),
1239 &xx_change.replace_when, CP_WHEN_EMPTY
1244 TYPE_BOOLEAN, CONF_VALUE_8_BIT(12),
1245 &xx_change.has_action, FALSE
1249 TYPE_INTEGER, CONF_VALUE_8_BIT(13),
1250 &xx_change.action_type, CA_NO_ACTION
1254 TYPE_INTEGER, CONF_VALUE_8_BIT(14),
1255 &xx_change.action_mode, CA_MODE_UNDEFINED
1259 TYPE_INTEGER, CONF_VALUE_16_BIT(6),
1260 &xx_change.action_arg, CA_ARG_UNDEFINED
1265 TYPE_ELEMENT, CONF_VALUE_16_BIT(7),
1266 &xx_change.action_element, EL_EMPTY_SPACE
1271 TYPE_CONTENT_LIST, CONF_VALUE_BYTES(1),
1272 &xx_change.target_content, EL_EMPTY_SPACE, NULL,
1273 &xx_num_contents, 1, 1
1283 static struct LevelFileConfigInfo chunk_config_GRPX[] =
1287 TYPE_STRING, CONF_VALUE_BYTES(1),
1288 &xx_ei.description[0], -1, NULL,
1289 &xx_string_length_unused, -1, MAX_ELEMENT_NAME_LEN,
1290 &xx_default_description[0]
1295 TYPE_BOOLEAN, CONF_VALUE_8_BIT(1),
1296 &xx_ei.use_gfx_element, FALSE
1300 TYPE_ELEMENT, CONF_VALUE_16_BIT(1),
1301 &xx_ei.gfx_element_initial, EL_EMPTY_SPACE
1306 TYPE_INTEGER, CONF_VALUE_8_BIT(2),
1307 &xx_group.choice_mode, ANIM_RANDOM
1312 TYPE_ELEMENT_LIST, CONF_VALUE_BYTES(2),
1313 &xx_group.element[0], EL_EMPTY_SPACE, NULL,
1314 &xx_group.num_elements, 1, MAX_ELEMENTS_IN_GROUP
1324 static struct LevelFileConfigInfo chunk_config_CONF[] = // (OBSOLETE)
1328 TYPE_BOOLEAN, CONF_VALUE_8_BIT(9),
1329 &li.block_snap_field, TRUE
1333 TYPE_BOOLEAN, CONF_VALUE_8_BIT(13),
1334 &li.continuous_snapping, TRUE
1338 TYPE_INTEGER, CONF_VALUE_8_BIT(1),
1339 &li.initial_player_stepsize[0], STEPSIZE_NORMAL
1343 TYPE_BOOLEAN, CONF_VALUE_8_BIT(10),
1344 &li.use_start_element[0], FALSE
1348 TYPE_ELEMENT, CONF_VALUE_16_BIT(1),
1349 &li.start_element[0], EL_PLAYER_1
1353 TYPE_BOOLEAN, CONF_VALUE_8_BIT(11),
1354 &li.use_artwork_element[0], FALSE
1358 TYPE_ELEMENT, CONF_VALUE_16_BIT(2),
1359 &li.artwork_element[0], EL_PLAYER_1
1363 TYPE_BOOLEAN, CONF_VALUE_8_BIT(12),
1364 &li.use_explosion_element[0], FALSE
1368 TYPE_ELEMENT, CONF_VALUE_16_BIT(3),
1369 &li.explosion_element[0], EL_PLAYER_1
1384 filetype_id_list[] =
1386 { LEVEL_FILE_TYPE_RND, "RND" },
1387 { LEVEL_FILE_TYPE_BD, "BD" },
1388 { LEVEL_FILE_TYPE_EM, "EM" },
1389 { LEVEL_FILE_TYPE_SP, "SP" },
1390 { LEVEL_FILE_TYPE_DX, "DX" },
1391 { LEVEL_FILE_TYPE_SB, "SB" },
1392 { LEVEL_FILE_TYPE_DC, "DC" },
1393 { LEVEL_FILE_TYPE_MM, "MM" },
1394 { LEVEL_FILE_TYPE_MM, "DF" },
1399 // ============================================================================
1400 // level file functions
1401 // ============================================================================
1403 static boolean check_special_flags(char *flag)
1405 if (strEqual(options.special_flags, flag) ||
1406 strEqual(leveldir_current->special_flags, flag))
1412 static struct DateInfo getCurrentDate(void)
1414 time_t epoch_seconds = time(NULL);
1415 struct tm *now = localtime(&epoch_seconds);
1416 struct DateInfo date;
1418 date.year = now->tm_year + 1900;
1419 date.month = now->tm_mon + 1;
1420 date.day = now->tm_mday;
1422 date.src = DATE_SRC_CLOCK;
1427 static void resetEventFlags(struct ElementChangeInfo *change)
1431 for (i = 0; i < NUM_CHANGE_EVENTS; i++)
1432 change->has_event[i] = FALSE;
1435 static void resetEventBits(void)
1439 for (i = 0; i < NUM_CE_BITFIELDS; i++)
1440 xx_event_bits[i] = 0;
1443 static void setEventFlagsFromEventBits(struct ElementChangeInfo *change)
1447 /* important: only change event flag if corresponding event bit is set
1448 (this is because all xx_event_bits[] values are loaded separately,
1449 and all xx_event_bits[] values are set back to zero before loading
1450 another value xx_event_bits[x] (each value representing 32 flags)) */
1452 for (i = 0; i < NUM_CHANGE_EVENTS; i++)
1453 if (xx_event_bits[CH_EVENT_BITFIELD_NR(i)] & CH_EVENT_BIT(i))
1454 change->has_event[i] = TRUE;
1457 static void setEventBitsFromEventFlags(struct ElementChangeInfo *change)
1461 /* in contrast to the above function setEventFlagsFromEventBits(), it
1462 would also be possible to set all bits in xx_event_bits[] to 0 or 1
1463 depending on the corresponding change->has_event[i] values here, as
1464 all xx_event_bits[] values are reset in resetEventBits() before */
1466 for (i = 0; i < NUM_CHANGE_EVENTS; i++)
1467 if (change->has_event[i])
1468 xx_event_bits[CH_EVENT_BITFIELD_NR(i)] |= CH_EVENT_BIT(i);
1471 static char *getDefaultElementDescription(struct ElementInfo *ei)
1473 static char description[MAX_ELEMENT_NAME_LEN + 1];
1474 char *default_description = (ei->custom_description != NULL ?
1475 ei->custom_description :
1476 ei->editor_description);
1479 // always start with reliable default values
1480 for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++)
1481 description[i] = '\0';
1483 // truncate element description to MAX_ELEMENT_NAME_LEN bytes
1484 strncpy(description, default_description, MAX_ELEMENT_NAME_LEN);
1486 return &description[0];
1489 static void setElementDescriptionToDefault(struct ElementInfo *ei)
1491 char *default_description = getDefaultElementDescription(ei);
1494 for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++)
1495 ei->description[i] = default_description[i];
1498 static void setConfigToDefaultsFromConfigList(struct LevelFileConfigInfo *conf)
1502 for (i = 0; conf[i].data_type != -1; i++)
1504 int default_value = conf[i].default_value;
1505 int data_type = conf[i].data_type;
1506 int conf_type = conf[i].conf_type;
1507 int byte_mask = conf_type & CONF_MASK_BYTES;
1509 if (byte_mask == CONF_MASK_MULTI_BYTES)
1511 int default_num_entities = conf[i].default_num_entities;
1512 int max_num_entities = conf[i].max_num_entities;
1514 *(int *)(conf[i].num_entities) = default_num_entities;
1516 if (data_type == TYPE_STRING)
1518 char *default_string = conf[i].default_string;
1519 char *string = (char *)(conf[i].value);
1521 strncpy(string, default_string, max_num_entities);
1523 else if (data_type == TYPE_ELEMENT_LIST)
1525 int *element_array = (int *)(conf[i].value);
1528 for (j = 0; j < max_num_entities; j++)
1529 element_array[j] = default_value;
1531 else if (data_type == TYPE_CONTENT_LIST)
1533 struct Content *content = (struct Content *)(conf[i].value);
1536 for (c = 0; c < max_num_entities; c++)
1537 for (y = 0; y < 3; y++)
1538 for (x = 0; x < 3; x++)
1539 content[c].e[x][y] = default_value;
1542 else // constant size configuration data (1, 2 or 4 bytes)
1544 if (data_type == TYPE_BOOLEAN)
1545 *(boolean *)(conf[i].value) = default_value;
1547 *(int *) (conf[i].value) = default_value;
1552 static void copyConfigFromConfigList(struct LevelFileConfigInfo *conf)
1556 for (i = 0; conf[i].data_type != -1; i++)
1558 int data_type = conf[i].data_type;
1559 int conf_type = conf[i].conf_type;
1560 int byte_mask = conf_type & CONF_MASK_BYTES;
1562 if (byte_mask == CONF_MASK_MULTI_BYTES)
1564 int max_num_entities = conf[i].max_num_entities;
1566 if (data_type == TYPE_STRING)
1568 char *string = (char *)(conf[i].value);
1569 char *string_copy = (char *)(conf[i].value_copy);
1571 strncpy(string_copy, string, max_num_entities);
1573 else if (data_type == TYPE_ELEMENT_LIST)
1575 int *element_array = (int *)(conf[i].value);
1576 int *element_array_copy = (int *)(conf[i].value_copy);
1579 for (j = 0; j < max_num_entities; j++)
1580 element_array_copy[j] = element_array[j];
1582 else if (data_type == TYPE_CONTENT_LIST)
1584 struct Content *content = (struct Content *)(conf[i].value);
1585 struct Content *content_copy = (struct Content *)(conf[i].value_copy);
1588 for (c = 0; c < max_num_entities; c++)
1589 for (y = 0; y < 3; y++)
1590 for (x = 0; x < 3; x++)
1591 content_copy[c].e[x][y] = content[c].e[x][y];
1594 else // constant size configuration data (1, 2 or 4 bytes)
1596 if (data_type == TYPE_BOOLEAN)
1597 *(boolean *)(conf[i].value_copy) = *(boolean *)(conf[i].value);
1599 *(int *) (conf[i].value_copy) = *(int *) (conf[i].value);
1604 void copyElementInfo(struct ElementInfo *ei_from, struct ElementInfo *ei_to)
1608 xx_ei = *ei_from; // copy element data into temporary buffer
1609 yy_ei = *ei_to; // copy element data into temporary buffer
1611 copyConfigFromConfigList(chunk_config_CUSX_base);
1616 // ---------- reinitialize and copy change pages ----------
1618 ei_to->num_change_pages = ei_from->num_change_pages;
1619 ei_to->current_change_page = ei_from->current_change_page;
1621 setElementChangePages(ei_to, ei_to->num_change_pages);
1623 for (i = 0; i < ei_to->num_change_pages; i++)
1624 ei_to->change_page[i] = ei_from->change_page[i];
1626 // ---------- copy group element info ----------
1627 if (ei_from->group != NULL && ei_to->group != NULL) // group or internal
1628 *ei_to->group = *ei_from->group;
1630 // mark this custom element as modified
1631 ei_to->modified_settings = TRUE;
1634 void setElementChangePages(struct ElementInfo *ei, int change_pages)
1636 int change_page_size = sizeof(struct ElementChangeInfo);
1638 ei->num_change_pages = MAX(1, change_pages);
1641 checked_realloc(ei->change_page, ei->num_change_pages * change_page_size);
1643 if (ei->current_change_page >= ei->num_change_pages)
1644 ei->current_change_page = ei->num_change_pages - 1;
1646 ei->change = &ei->change_page[ei->current_change_page];
1649 void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
1651 xx_change = *change; // copy change data into temporary buffer
1653 setConfigToDefaultsFromConfigList(chunk_config_CUSX_change);
1655 *change = xx_change;
1657 resetEventFlags(change);
1659 change->direct_action = 0;
1660 change->other_action = 0;
1662 change->pre_change_function = NULL;
1663 change->change_function = NULL;
1664 change->post_change_function = NULL;
1667 static void setLevelInfoToDefaults_Level(struct LevelInfo *level)
1671 li = *level; // copy level data into temporary buffer
1672 setConfigToDefaultsFromConfigList(chunk_config_INFO);
1673 *level = li; // copy temporary buffer back to level data
1675 setLevelInfoToDefaults_EM();
1676 setLevelInfoToDefaults_SP();
1677 setLevelInfoToDefaults_MM();
1679 level->native_em_level = &native_em_level;
1680 level->native_sp_level = &native_sp_level;
1681 level->native_mm_level = &native_mm_level;
1683 level->file_version = FILE_VERSION_ACTUAL;
1684 level->game_version = GAME_VERSION_ACTUAL;
1686 level->creation_date = getCurrentDate();
1688 level->encoding_16bit_field = TRUE;
1689 level->encoding_16bit_yamyam = TRUE;
1690 level->encoding_16bit_amoeba = TRUE;
1692 // clear level name and level author string buffers
1693 for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
1694 level->name[i] = '\0';
1695 for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
1696 level->author[i] = '\0';
1698 // set level name and level author to default values
1699 strcpy(level->name, NAMELESS_LEVEL_NAME);
1700 strcpy(level->author, ANONYMOUS_NAME);
1702 // set level playfield to playable default level with player and exit
1703 for (x = 0; x < MAX_LEV_FIELDX; x++)
1704 for (y = 0; y < MAX_LEV_FIELDY; y++)
1705 level->field[x][y] = EL_SAND;
1707 level->field[0][0] = EL_PLAYER_1;
1708 level->field[STD_LEV_FIELDX - 1][STD_LEV_FIELDY - 1] = EL_EXIT_CLOSED;
1710 BorderElement = EL_STEELWALL;
1712 // detect custom elements when loading them
1713 level->file_has_custom_elements = FALSE;
1715 // set all bug compatibility flags to "false" => do not emulate this bug
1716 level->use_action_after_change_bug = FALSE;
1718 if (leveldir_current)
1720 // try to determine better author name than 'anonymous'
1721 if (!strEqual(leveldir_current->author, ANONYMOUS_NAME))
1723 strncpy(level->author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN);
1724 level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
1728 switch (LEVELCLASS(leveldir_current))
1730 case LEVELCLASS_TUTORIAL:
1731 strcpy(level->author, PROGRAM_AUTHOR_STRING);
1734 case LEVELCLASS_CONTRIB:
1735 strncpy(level->author, leveldir_current->name, MAX_LEVEL_AUTHOR_LEN);
1736 level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
1739 case LEVELCLASS_PRIVATE:
1740 strncpy(level->author, getRealName(), MAX_LEVEL_AUTHOR_LEN);
1741 level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
1745 // keep default value
1752 static void setLevelInfoToDefaults_Elements(struct LevelInfo *level)
1754 static boolean clipboard_elements_initialized = FALSE;
1757 InitElementPropertiesStatic();
1759 li = *level; // copy level data into temporary buffer
1760 setConfigToDefaultsFromConfigList(chunk_config_ELEM);
1761 *level = li; // copy temporary buffer back to level data
1763 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1766 struct ElementInfo *ei = &element_info[element];
1768 // never initialize clipboard elements after the very first time
1769 // (to be able to use clipboard elements between several levels)
1770 if (IS_CLIPBOARD_ELEMENT(element) && clipboard_elements_initialized)
1773 if (IS_ENVELOPE(element))
1775 int envelope_nr = element - EL_ENVELOPE_1;
1777 setConfigToDefaultsFromConfigList(chunk_config_NOTE);
1779 level->envelope[envelope_nr] = xx_envelope;
1782 if (IS_CUSTOM_ELEMENT(element) ||
1783 IS_GROUP_ELEMENT(element) ||
1784 IS_INTERNAL_ELEMENT(element))
1786 xx_ei = *ei; // copy element data into temporary buffer
1788 setConfigToDefaultsFromConfigList(chunk_config_CUSX_base);
1793 setElementChangePages(ei, 1);
1794 setElementChangeInfoToDefaults(ei->change);
1796 if (IS_CUSTOM_ELEMENT(element) ||
1797 IS_GROUP_ELEMENT(element) ||
1798 IS_INTERNAL_ELEMENT(element))
1800 setElementDescriptionToDefault(ei);
1802 ei->modified_settings = FALSE;
1805 if (IS_CUSTOM_ELEMENT(element) ||
1806 IS_INTERNAL_ELEMENT(element))
1808 // internal values used in level editor
1810 ei->access_type = 0;
1811 ei->access_layer = 0;
1812 ei->access_protected = 0;
1813 ei->walk_to_action = 0;
1814 ei->smash_targets = 0;
1817 ei->can_explode_by_fire = FALSE;
1818 ei->can_explode_smashed = FALSE;
1819 ei->can_explode_impact = FALSE;
1821 ei->current_change_page = 0;
1824 if (IS_GROUP_ELEMENT(element) ||
1825 IS_INTERNAL_ELEMENT(element))
1827 struct ElementGroupInfo *group;
1829 // initialize memory for list of elements in group
1830 if (ei->group == NULL)
1831 ei->group = checked_malloc(sizeof(struct ElementGroupInfo));
1835 xx_group = *group; // copy group data into temporary buffer
1837 setConfigToDefaultsFromConfigList(chunk_config_GRPX);
1843 clipboard_elements_initialized = TRUE;
1846 static void setLevelInfoToDefaults(struct LevelInfo *level,
1847 boolean level_info_only,
1848 boolean reset_file_status)
1850 setLevelInfoToDefaults_Level(level);
1852 if (!level_info_only)
1853 setLevelInfoToDefaults_Elements(level);
1855 if (reset_file_status)
1857 level->no_valid_file = FALSE;
1858 level->no_level_file = FALSE;
1861 level->changed = FALSE;
1864 static void setFileInfoToDefaults(struct LevelFileInfo *level_file_info)
1866 level_file_info->nr = 0;
1867 level_file_info->type = LEVEL_FILE_TYPE_UNKNOWN;
1868 level_file_info->packed = FALSE;
1870 setString(&level_file_info->basename, NULL);
1871 setString(&level_file_info->filename, NULL);
1874 int getMappedElement_SB(int, boolean);
1876 static void ActivateLevelTemplate(void)
1880 if (check_special_flags("load_xsb_to_ces"))
1882 // fill smaller playfields with padding "beyond border wall" elements
1883 if (level.fieldx < level_template.fieldx ||
1884 level.fieldy < level_template.fieldy)
1886 short field[level.fieldx][level.fieldy];
1887 int new_fieldx = MAX(level.fieldx, level_template.fieldx);
1888 int new_fieldy = MAX(level.fieldy, level_template.fieldy);
1889 int pos_fieldx = (new_fieldx - level.fieldx) / 2;
1890 int pos_fieldy = (new_fieldy - level.fieldy) / 2;
1892 // copy old playfield (which is smaller than the visible area)
1893 for (y = 0; y < level.fieldy; y++) for (x = 0; x < level.fieldx; x++)
1894 field[x][y] = level.field[x][y];
1896 // fill new, larger playfield with "beyond border wall" elements
1897 for (y = 0; y < new_fieldy; y++) for (x = 0; x < new_fieldx; x++)
1898 level.field[x][y] = getMappedElement_SB('_', TRUE);
1900 // copy the old playfield to the middle of the new playfield
1901 for (y = 0; y < level.fieldy; y++) for (x = 0; x < level.fieldx; x++)
1902 level.field[pos_fieldx + x][pos_fieldy + y] = field[x][y];
1904 level.fieldx = new_fieldx;
1905 level.fieldy = new_fieldy;
1909 // Currently there is no special action needed to activate the template
1910 // data, because 'element_info' property settings overwrite the original
1911 // level data, while all other variables do not change.
1913 // Exception: 'from_level_template' elements in the original level playfield
1914 // are overwritten with the corresponding elements at the same position in
1915 // playfield from the level template.
1917 for (x = 0; x < level.fieldx; x++)
1918 for (y = 0; y < level.fieldy; y++)
1919 if (level.field[x][y] == EL_FROM_LEVEL_TEMPLATE)
1920 level.field[x][y] = level_template.field[x][y];
1922 if (check_special_flags("load_xsb_to_ces"))
1924 struct LevelInfo level_backup = level;
1926 // overwrite all individual level settings from template level settings
1927 level = level_template;
1929 // restore level file info
1930 level.file_info = level_backup.file_info;
1932 // restore playfield size
1933 level.fieldx = level_backup.fieldx;
1934 level.fieldy = level_backup.fieldy;
1936 // restore playfield content
1937 for (x = 0; x < level.fieldx; x++)
1938 for (y = 0; y < level.fieldy; y++)
1939 level.field[x][y] = level_backup.field[x][y];
1941 // restore name and author from individual level
1942 strcpy(level.name, level_backup.name);
1943 strcpy(level.author, level_backup.author);
1945 // restore flag "use_custom_template"
1946 level.use_custom_template = level_backup.use_custom_template;
1950 static char *getLevelFilenameFromBasename(char *basename)
1952 static char *filename = NULL;
1954 checked_free(filename);
1956 filename = getPath2(getCurrentLevelDir(), basename);
1961 static int getFileTypeFromBasename(char *basename)
1963 // !!! ALSO SEE COMMENT IN checkForPackageFromBasename() !!!
1965 static char *filename = NULL;
1966 struct stat file_status;
1968 // ---------- try to determine file type from filename ----------
1970 // check for typical filename of a Supaplex level package file
1971 if (strlen(basename) == 10 && strPrefixLower(basename, "levels.d"))
1972 return LEVEL_FILE_TYPE_SP;
1974 // check for typical filename of a Diamond Caves II level package file
1975 if (strSuffixLower(basename, ".dc") ||
1976 strSuffixLower(basename, ".dc2"))
1977 return LEVEL_FILE_TYPE_DC;
1979 // check for typical filename of a Sokoban level package file
1980 if (strSuffixLower(basename, ".xsb") &&
1981 strchr(basename, '%') == NULL)
1982 return LEVEL_FILE_TYPE_SB;
1984 // ---------- try to determine file type from filesize ----------
1986 checked_free(filename);
1987 filename = getPath2(getCurrentLevelDir(), basename);
1989 if (stat(filename, &file_status) == 0)
1991 // check for typical filesize of a Supaplex level package file
1992 if (file_status.st_size == 170496)
1993 return LEVEL_FILE_TYPE_SP;
1996 return LEVEL_FILE_TYPE_UNKNOWN;
1999 static int getFileTypeFromMagicBytes(char *filename, int type)
2003 if ((file = openFile(filename, MODE_READ)))
2005 char chunk_name[CHUNK_ID_LEN + 1];
2007 getFileChunkBE(file, chunk_name, NULL);
2009 if (strEqual(chunk_name, "MMII") ||
2010 strEqual(chunk_name, "MIRR"))
2011 type = LEVEL_FILE_TYPE_MM;
2019 static boolean checkForPackageFromBasename(char *basename)
2021 // !!! WON'T WORK ANYMORE IF getFileTypeFromBasename() ALSO DETECTS !!!
2022 // !!! SINGLE LEVELS (CURRENTLY ONLY DETECTS LEVEL PACKAGES !!!
2024 return (getFileTypeFromBasename(basename) != LEVEL_FILE_TYPE_UNKNOWN);
2027 static char *getSingleLevelBasenameExt(int nr, char *extension)
2029 static char basename[MAX_FILENAME_LEN];
2032 sprintf(basename, "%s", LEVELTEMPLATE_FILENAME);
2034 sprintf(basename, "%03d.%s", nr, extension);
2039 static char *getSingleLevelBasename(int nr)
2041 return getSingleLevelBasenameExt(nr, LEVELFILE_EXTENSION);
2044 static char *getPackedLevelBasename(int type)
2046 static char basename[MAX_FILENAME_LEN];
2047 char *directory = getCurrentLevelDir();
2049 DirectoryEntry *dir_entry;
2051 strcpy(basename, UNDEFINED_FILENAME); // default: undefined file
2053 if ((dir = openDirectory(directory)) == NULL)
2055 Error(ERR_WARN, "cannot read current level directory '%s'", directory);
2060 while ((dir_entry = readDirectory(dir)) != NULL) // loop all entries
2062 char *entry_basename = dir_entry->basename;
2063 int entry_type = getFileTypeFromBasename(entry_basename);
2065 if (entry_type != LEVEL_FILE_TYPE_UNKNOWN) // found valid level package
2067 if (type == LEVEL_FILE_TYPE_UNKNOWN ||
2070 strcpy(basename, entry_basename);
2077 closeDirectory(dir);
2082 static char *getSingleLevelFilename(int nr)
2084 return getLevelFilenameFromBasename(getSingleLevelBasename(nr));
2087 #if ENABLE_UNUSED_CODE
2088 static char *getPackedLevelFilename(int type)
2090 return getLevelFilenameFromBasename(getPackedLevelBasename(type));
2094 char *getDefaultLevelFilename(int nr)
2096 return getSingleLevelFilename(nr);
2099 #if ENABLE_UNUSED_CODE
2100 static void setLevelFileInfo_SingleLevelFilename(struct LevelFileInfo *lfi,
2104 lfi->packed = FALSE;
2106 setString(&lfi->basename, getSingleLevelBasename(lfi->nr, lfi->type));
2107 setString(&lfi->filename, getLevelFilenameFromBasename(lfi->basename));
2111 static void setLevelFileInfo_FormatLevelFilename(struct LevelFileInfo *lfi,
2112 int type, char *format, ...)
2114 static char basename[MAX_FILENAME_LEN];
2117 va_start(ap, format);
2118 vsprintf(basename, format, ap);
2122 lfi->packed = FALSE;
2124 setString(&lfi->basename, basename);
2125 setString(&lfi->filename, getLevelFilenameFromBasename(lfi->basename));
2128 static void setLevelFileInfo_PackedLevelFilename(struct LevelFileInfo *lfi,
2134 setString(&lfi->basename, getPackedLevelBasename(lfi->type));
2135 setString(&lfi->filename, getLevelFilenameFromBasename(lfi->basename));
2138 static int getFiletypeFromID(char *filetype_id)
2140 char *filetype_id_lower;
2141 int filetype = LEVEL_FILE_TYPE_UNKNOWN;
2144 if (filetype_id == NULL)
2145 return LEVEL_FILE_TYPE_UNKNOWN;
2147 filetype_id_lower = getStringToLower(filetype_id);
2149 for (i = 0; filetype_id_list[i].id != NULL; i++)
2151 char *id_lower = getStringToLower(filetype_id_list[i].id);
2153 if (strEqual(filetype_id_lower, id_lower))
2154 filetype = filetype_id_list[i].filetype;
2158 if (filetype != LEVEL_FILE_TYPE_UNKNOWN)
2162 free(filetype_id_lower);
2167 char *getLocalLevelTemplateFilename(void)
2169 return getDefaultLevelFilename(-1);
2172 char *getGlobalLevelTemplateFilename(void)
2174 // global variable "leveldir_current" must be modified in the loop below
2175 LevelDirTree *leveldir_current_last = leveldir_current;
2176 char *filename = NULL;
2178 // check for template level in path from current to topmost tree node
2180 while (leveldir_current != NULL)
2182 filename = getDefaultLevelFilename(-1);
2184 if (fileExists(filename))
2187 leveldir_current = leveldir_current->node_parent;
2190 // restore global variable "leveldir_current" modified in above loop
2191 leveldir_current = leveldir_current_last;
2196 static void determineLevelFileInfo_Filename(struct LevelFileInfo *lfi)
2200 // special case: level number is negative => check for level template file
2203 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
2204 getSingleLevelBasename(-1));
2206 // replace local level template filename with global template filename
2207 setString(&lfi->filename, getGlobalLevelTemplateFilename());
2209 // no fallback if template file not existing
2213 // special case: check for file name/pattern specified in "levelinfo.conf"
2214 if (leveldir_current->level_filename != NULL)
2216 int filetype = getFiletypeFromID(leveldir_current->level_filetype);
2218 setLevelFileInfo_FormatLevelFilename(lfi, filetype,
2219 leveldir_current->level_filename, nr);
2221 lfi->packed = checkForPackageFromBasename(leveldir_current->level_filename);
2223 if (fileExists(lfi->filename))
2226 else if (leveldir_current->level_filetype != NULL)
2228 int filetype = getFiletypeFromID(leveldir_current->level_filetype);
2230 // check for specified native level file with standard file name
2231 setLevelFileInfo_FormatLevelFilename(lfi, filetype,
2232 "%03d.%s", nr, LEVELFILE_EXTENSION);
2233 if (fileExists(lfi->filename))
2237 // check for native Rocks'n'Diamonds level file
2238 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
2239 "%03d.%s", nr, LEVELFILE_EXTENSION);
2240 if (fileExists(lfi->filename))
2243 // check for Emerald Mine level file (V1)
2244 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "a%c%c",
2245 'a' + (nr / 10) % 26, '0' + nr % 10);
2246 if (fileExists(lfi->filename))
2248 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "A%c%c",
2249 'A' + (nr / 10) % 26, '0' + nr % 10);
2250 if (fileExists(lfi->filename))
2253 // check for Emerald Mine level file (V2 to V5)
2254 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%d", nr);
2255 if (fileExists(lfi->filename))
2258 // check for Emerald Mine level file (V6 / single mode)
2259 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02ds", nr);
2260 if (fileExists(lfi->filename))
2262 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dS", nr);
2263 if (fileExists(lfi->filename))
2266 // check for Emerald Mine level file (V6 / teamwork mode)
2267 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dt", nr);
2268 if (fileExists(lfi->filename))
2270 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dT", nr);
2271 if (fileExists(lfi->filename))
2274 // check for various packed level file formats
2275 setLevelFileInfo_PackedLevelFilename(lfi, LEVEL_FILE_TYPE_UNKNOWN);
2276 if (fileExists(lfi->filename))
2279 // no known level file found -- use default values (and fail later)
2280 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
2281 "%03d.%s", nr, LEVELFILE_EXTENSION);
2284 static void determineLevelFileInfo_Filetype(struct LevelFileInfo *lfi)
2286 if (lfi->type == LEVEL_FILE_TYPE_UNKNOWN)
2287 lfi->type = getFileTypeFromBasename(lfi->basename);
2289 if (lfi->type == LEVEL_FILE_TYPE_RND)
2290 lfi->type = getFileTypeFromMagicBytes(lfi->filename, lfi->type);
2293 static void setLevelFileInfo(struct LevelFileInfo *level_file_info, int nr)
2295 // always start with reliable default values
2296 setFileInfoToDefaults(level_file_info);
2298 level_file_info->nr = nr; // set requested level number
2300 determineLevelFileInfo_Filename(level_file_info);
2301 determineLevelFileInfo_Filetype(level_file_info);
2304 static void copyLevelFileInfo(struct LevelFileInfo *lfi_from,
2305 struct LevelFileInfo *lfi_to)
2307 lfi_to->nr = lfi_from->nr;
2308 lfi_to->type = lfi_from->type;
2309 lfi_to->packed = lfi_from->packed;
2311 setString(&lfi_to->basename, lfi_from->basename);
2312 setString(&lfi_to->filename, lfi_from->filename);
2315 // ----------------------------------------------------------------------------
2316 // functions for loading R'n'D level
2317 // ----------------------------------------------------------------------------
2319 static int getMappedElement(int element)
2321 // remap some (historic, now obsolete) elements
2325 case EL_PLAYER_OBSOLETE:
2326 element = EL_PLAYER_1;
2329 case EL_KEY_OBSOLETE:
2333 case EL_EM_KEY_1_FILE_OBSOLETE:
2334 element = EL_EM_KEY_1;
2337 case EL_EM_KEY_2_FILE_OBSOLETE:
2338 element = EL_EM_KEY_2;
2341 case EL_EM_KEY_3_FILE_OBSOLETE:
2342 element = EL_EM_KEY_3;
2345 case EL_EM_KEY_4_FILE_OBSOLETE:
2346 element = EL_EM_KEY_4;
2349 case EL_ENVELOPE_OBSOLETE:
2350 element = EL_ENVELOPE_1;
2358 if (element >= NUM_FILE_ELEMENTS)
2360 Error(ERR_WARN, "invalid level element %d", element);
2362 element = EL_UNKNOWN;
2370 static int getMappedElementByVersion(int element, int game_version)
2372 // remap some elements due to certain game version
2374 if (game_version <= VERSION_IDENT(2,2,0,0))
2376 // map game font elements
2377 element = (element == EL_CHAR('[') ? EL_CHAR_AUMLAUT :
2378 element == EL_CHAR('\\') ? EL_CHAR_OUMLAUT :
2379 element == EL_CHAR(']') ? EL_CHAR_UUMLAUT :
2380 element == EL_CHAR('^') ? EL_CHAR_COPYRIGHT : element);
2383 if (game_version < VERSION_IDENT(3,0,0,0))
2385 // map Supaplex gravity tube elements
2386 element = (element == EL_SP_GRAVITY_PORT_LEFT ? EL_SP_PORT_LEFT :
2387 element == EL_SP_GRAVITY_PORT_RIGHT ? EL_SP_PORT_RIGHT :
2388 element == EL_SP_GRAVITY_PORT_UP ? EL_SP_PORT_UP :
2389 element == EL_SP_GRAVITY_PORT_DOWN ? EL_SP_PORT_DOWN :
2396 static int LoadLevel_VERS(File *file, int chunk_size, struct LevelInfo *level)
2398 level->file_version = getFileVersion(file);
2399 level->game_version = getFileVersion(file);
2404 static int LoadLevel_DATE(File *file, int chunk_size, struct LevelInfo *level)
2406 level->creation_date.year = getFile16BitBE(file);
2407 level->creation_date.month = getFile8Bit(file);
2408 level->creation_date.day = getFile8Bit(file);
2410 level->creation_date.src = DATE_SRC_LEVELFILE;
2415 static int LoadLevel_HEAD(File *file, int chunk_size, struct LevelInfo *level)
2417 int initial_player_stepsize;
2418 int initial_player_gravity;
2421 level->fieldx = getFile8Bit(file);
2422 level->fieldy = getFile8Bit(file);
2424 level->time = getFile16BitBE(file);
2425 level->gems_needed = getFile16BitBE(file);
2427 for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
2428 level->name[i] = getFile8Bit(file);
2429 level->name[MAX_LEVEL_NAME_LEN] = 0;
2431 for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
2432 level->score[i] = getFile8Bit(file);
2434 level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
2435 for (i = 0; i < STD_ELEMENT_CONTENTS; i++)
2436 for (y = 0; y < 3; y++)
2437 for (x = 0; x < 3; x++)
2438 level->yamyam_content[i].e[x][y] = getMappedElement(getFile8Bit(file));
2440 level->amoeba_speed = getFile8Bit(file);
2441 level->time_magic_wall = getFile8Bit(file);
2442 level->time_wheel = getFile8Bit(file);
2443 level->amoeba_content = getMappedElement(getFile8Bit(file));
2445 initial_player_stepsize = (getFile8Bit(file) == 1 ? STEPSIZE_FAST :
2448 for (i = 0; i < MAX_PLAYERS; i++)
2449 level->initial_player_stepsize[i] = initial_player_stepsize;
2451 initial_player_gravity = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2453 for (i = 0; i < MAX_PLAYERS; i++)
2454 level->initial_player_gravity[i] = initial_player_gravity;
2456 level->encoding_16bit_field = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2457 level->em_slippery_gems = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2459 level->use_custom_template = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2461 level->block_last_field = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2462 level->sp_block_last_field = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2463 level->can_move_into_acid_bits = getFile32BitBE(file);
2464 level->dont_collide_with_bits = getFile8Bit(file);
2466 level->use_spring_bug = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2467 level->use_step_counter = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2469 level->instant_relocation = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2470 level->can_pass_to_walkable = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2471 level->grow_into_diggable = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2473 level->game_engine_type = getFile8Bit(file);
2475 ReadUnusedBytesFromFile(file, LEVEL_CHUNK_HEAD_UNUSED);
2480 static int LoadLevel_NAME(File *file, int chunk_size, struct LevelInfo *level)
2484 for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
2485 level->name[i] = getFile8Bit(file);
2486 level->name[MAX_LEVEL_NAME_LEN] = 0;
2491 static int LoadLevel_AUTH(File *file, int chunk_size, struct LevelInfo *level)
2495 for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
2496 level->author[i] = getFile8Bit(file);
2497 level->author[MAX_LEVEL_AUTHOR_LEN] = 0;
2502 static int LoadLevel_BODY(File *file, int chunk_size, struct LevelInfo *level)
2505 int chunk_size_expected = level->fieldx * level->fieldy;
2507 /* Note: "chunk_size" was wrong before version 2.0 when elements are
2508 stored with 16-bit encoding (and should be twice as big then).
2509 Even worse, playfield data was stored 16-bit when only yamyam content
2510 contained 16-bit elements and vice versa. */
2512 if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
2513 chunk_size_expected *= 2;
2515 if (chunk_size_expected != chunk_size)
2517 ReadUnusedBytesFromFile(file, chunk_size);
2518 return chunk_size_expected;
2521 for (y = 0; y < level->fieldy; y++)
2522 for (x = 0; x < level->fieldx; x++)
2523 level->field[x][y] =
2524 getMappedElement(level->encoding_16bit_field ? getFile16BitBE(file) :
2529 static int LoadLevel_CONT(File *file, int chunk_size, struct LevelInfo *level)
2532 int header_size = 4;
2533 int content_size = MAX_ELEMENT_CONTENTS * 3 * 3;
2534 int chunk_size_expected = header_size + content_size;
2536 /* Note: "chunk_size" was wrong before version 2.0 when elements are
2537 stored with 16-bit encoding (and should be twice as big then).
2538 Even worse, playfield data was stored 16-bit when only yamyam content
2539 contained 16-bit elements and vice versa. */
2541 if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
2542 chunk_size_expected += content_size;
2544 if (chunk_size_expected != chunk_size)
2546 ReadUnusedBytesFromFile(file, chunk_size);
2547 return chunk_size_expected;
2551 level->num_yamyam_contents = getFile8Bit(file);
2555 // correct invalid number of content fields -- should never happen
2556 if (level->num_yamyam_contents < 1 ||
2557 level->num_yamyam_contents > MAX_ELEMENT_CONTENTS)
2558 level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
2560 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
2561 for (y = 0; y < 3; y++)
2562 for (x = 0; x < 3; x++)
2563 level->yamyam_content[i].e[x][y] =
2564 getMappedElement(level->encoding_16bit_field ?
2565 getFile16BitBE(file) : getFile8Bit(file));
2569 static int LoadLevel_CNT2(File *file, int chunk_size, struct LevelInfo *level)
2574 int content_array[MAX_ELEMENT_CONTENTS][3][3];
2576 element = getMappedElement(getFile16BitBE(file));
2577 num_contents = getFile8Bit(file);
2579 getFile8Bit(file); // content x size (unused)
2580 getFile8Bit(file); // content y size (unused)
2582 ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED);
2584 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
2585 for (y = 0; y < 3; y++)
2586 for (x = 0; x < 3; x++)
2587 content_array[i][x][y] = getMappedElement(getFile16BitBE(file));
2589 // correct invalid number of content fields -- should never happen
2590 if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS)
2591 num_contents = STD_ELEMENT_CONTENTS;
2593 if (element == EL_YAMYAM)
2595 level->num_yamyam_contents = num_contents;
2597 for (i = 0; i < num_contents; i++)
2598 for (y = 0; y < 3; y++)
2599 for (x = 0; x < 3; x++)
2600 level->yamyam_content[i].e[x][y] = content_array[i][x][y];
2602 else if (element == EL_BD_AMOEBA)
2604 level->amoeba_content = content_array[0][0][0];
2608 Error(ERR_WARN, "cannot load content for element '%d'", element);
2614 static int LoadLevel_CNT3(File *file, int chunk_size, struct LevelInfo *level)
2620 int chunk_size_expected;
2622 element = getMappedElement(getFile16BitBE(file));
2623 if (!IS_ENVELOPE(element))
2624 element = EL_ENVELOPE_1;
2626 envelope_nr = element - EL_ENVELOPE_1;
2628 envelope_len = getFile16BitBE(file);
2630 level->envelope[envelope_nr].xsize = getFile8Bit(file);
2631 level->envelope[envelope_nr].ysize = getFile8Bit(file);
2633 ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT3_UNUSED);
2635 chunk_size_expected = LEVEL_CHUNK_CNT3_SIZE(envelope_len);
2636 if (chunk_size_expected != chunk_size)
2638 ReadUnusedBytesFromFile(file, chunk_size - LEVEL_CHUNK_CNT3_HEADER);
2639 return chunk_size_expected;
2642 for (i = 0; i < envelope_len; i++)
2643 level->envelope[envelope_nr].text[i] = getFile8Bit(file);
2648 static int LoadLevel_CUS1(File *file, int chunk_size, struct LevelInfo *level)
2650 int num_changed_custom_elements = getFile16BitBE(file);
2651 int chunk_size_expected = 2 + num_changed_custom_elements * 6;
2654 if (chunk_size_expected != chunk_size)
2656 ReadUnusedBytesFromFile(file, chunk_size - 2);
2657 return chunk_size_expected;
2660 for (i = 0; i < num_changed_custom_elements; i++)
2662 int element = getMappedElement(getFile16BitBE(file));
2663 int properties = getFile32BitBE(file);
2665 if (IS_CUSTOM_ELEMENT(element))
2666 element_info[element].properties[EP_BITFIELD_BASE_NR] = properties;
2668 Error(ERR_WARN, "invalid custom element number %d", element);
2670 // older game versions that wrote level files with CUS1 chunks used
2671 // different default push delay values (not yet stored in level file)
2672 element_info[element].push_delay_fixed = 2;
2673 element_info[element].push_delay_random = 8;
2676 level->file_has_custom_elements = TRUE;
2681 static int LoadLevel_CUS2(File *file, int chunk_size, struct LevelInfo *level)
2683 int num_changed_custom_elements = getFile16BitBE(file);
2684 int chunk_size_expected = 2 + num_changed_custom_elements * 4;
2687 if (chunk_size_expected != chunk_size)
2689 ReadUnusedBytesFromFile(file, chunk_size - 2);
2690 return chunk_size_expected;
2693 for (i = 0; i < num_changed_custom_elements; i++)
2695 int element = getMappedElement(getFile16BitBE(file));
2696 int custom_target_element = getMappedElement(getFile16BitBE(file));
2698 if (IS_CUSTOM_ELEMENT(element))
2699 element_info[element].change->target_element = custom_target_element;
2701 Error(ERR_WARN, "invalid custom element number %d", element);
2704 level->file_has_custom_elements = TRUE;
2709 static int LoadLevel_CUS3(File *file, int chunk_size, struct LevelInfo *level)
2711 int num_changed_custom_elements = getFile16BitBE(file);
2712 int chunk_size_expected = LEVEL_CHUNK_CUS3_SIZE(num_changed_custom_elements);
2715 if (chunk_size_expected != chunk_size)
2717 ReadUnusedBytesFromFile(file, chunk_size - 2);
2718 return chunk_size_expected;
2721 for (i = 0; i < num_changed_custom_elements; i++)
2723 int element = getMappedElement(getFile16BitBE(file));
2724 struct ElementInfo *ei = &element_info[element];
2725 unsigned int event_bits;
2727 if (!IS_CUSTOM_ELEMENT(element))
2729 Error(ERR_WARN, "invalid custom element number %d", element);
2731 element = EL_INTERNAL_DUMMY;
2734 for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++)
2735 ei->description[j] = getFile8Bit(file);
2736 ei->description[MAX_ELEMENT_NAME_LEN] = 0;
2738 ei->properties[EP_BITFIELD_BASE_NR] = getFile32BitBE(file);
2740 // some free bytes for future properties and padding
2741 ReadUnusedBytesFromFile(file, 7);
2743 ei->use_gfx_element = getFile8Bit(file);
2744 ei->gfx_element_initial = getMappedElement(getFile16BitBE(file));
2746 ei->collect_score_initial = getFile8Bit(file);
2747 ei->collect_count_initial = getFile8Bit(file);
2749 ei->push_delay_fixed = getFile16BitBE(file);
2750 ei->push_delay_random = getFile16BitBE(file);
2751 ei->move_delay_fixed = getFile16BitBE(file);
2752 ei->move_delay_random = getFile16BitBE(file);
2754 ei->move_pattern = getFile16BitBE(file);
2755 ei->move_direction_initial = getFile8Bit(file);
2756 ei->move_stepsize = getFile8Bit(file);
2758 for (y = 0; y < 3; y++)
2759 for (x = 0; x < 3; x++)
2760 ei->content.e[x][y] = getMappedElement(getFile16BitBE(file));
2762 event_bits = getFile32BitBE(file);
2763 for (j = 0; j < NUM_CHANGE_EVENTS; j++)
2764 if (event_bits & (1 << j))
2765 ei->change->has_event[j] = TRUE;
2767 ei->change->target_element = getMappedElement(getFile16BitBE(file));
2769 ei->change->delay_fixed = getFile16BitBE(file);
2770 ei->change->delay_random = getFile16BitBE(file);
2771 ei->change->delay_frames = getFile16BitBE(file);
2773 ei->change->initial_trigger_element= getMappedElement(getFile16BitBE(file));
2775 ei->change->explode = getFile8Bit(file);
2776 ei->change->use_target_content = getFile8Bit(file);
2777 ei->change->only_if_complete = getFile8Bit(file);
2778 ei->change->use_random_replace = getFile8Bit(file);
2780 ei->change->random_percentage = getFile8Bit(file);
2781 ei->change->replace_when = getFile8Bit(file);
2783 for (y = 0; y < 3; y++)
2784 for (x = 0; x < 3; x++)
2785 ei->change->target_content.e[x][y] =
2786 getMappedElement(getFile16BitBE(file));
2788 ei->slippery_type = getFile8Bit(file);
2790 // some free bytes for future properties and padding
2791 ReadUnusedBytesFromFile(file, LEVEL_CPART_CUS3_UNUSED);
2793 // mark that this custom element has been modified
2794 ei->modified_settings = TRUE;
2797 level->file_has_custom_elements = TRUE;
2802 static int LoadLevel_CUS4(File *file, int chunk_size, struct LevelInfo *level)
2804 struct ElementInfo *ei;
2805 int chunk_size_expected;
2809 // ---------- custom element base property values (96 bytes) ----------------
2811 element = getMappedElement(getFile16BitBE(file));
2813 if (!IS_CUSTOM_ELEMENT(element))
2815 Error(ERR_WARN, "invalid custom element number %d", element);
2817 ReadUnusedBytesFromFile(file, chunk_size - 2);
2821 ei = &element_info[element];
2823 for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
2824 ei->description[i] = getFile8Bit(file);
2825 ei->description[MAX_ELEMENT_NAME_LEN] = 0;
2827 ei->properties[EP_BITFIELD_BASE_NR] = getFile32BitBE(file);
2829 ReadUnusedBytesFromFile(file, 4); // reserved for more base properties
2831 ei->num_change_pages = getFile8Bit(file);
2833 chunk_size_expected = LEVEL_CHUNK_CUS4_SIZE(ei->num_change_pages);
2834 if (chunk_size_expected != chunk_size)
2836 ReadUnusedBytesFromFile(file, chunk_size - 43);
2837 return chunk_size_expected;
2840 ei->ce_value_fixed_initial = getFile16BitBE(file);
2841 ei->ce_value_random_initial = getFile16BitBE(file);
2842 ei->use_last_ce_value = getFile8Bit(file);
2844 ei->use_gfx_element = getFile8Bit(file);
2845 ei->gfx_element_initial = getMappedElement(getFile16BitBE(file));
2847 ei->collect_score_initial = getFile8Bit(file);
2848 ei->collect_count_initial = getFile8Bit(file);
2850 ei->drop_delay_fixed = getFile8Bit(file);
2851 ei->push_delay_fixed = getFile8Bit(file);
2852 ei->drop_delay_random = getFile8Bit(file);
2853 ei->push_delay_random = getFile8Bit(file);
2854 ei->move_delay_fixed = getFile16BitBE(file);
2855 ei->move_delay_random = getFile16BitBE(file);
2857 // bits 0 - 15 of "move_pattern" ...
2858 ei->move_pattern = getFile16BitBE(file);
2859 ei->move_direction_initial = getFile8Bit(file);
2860 ei->move_stepsize = getFile8Bit(file);
2862 ei->slippery_type = getFile8Bit(file);
2864 for (y = 0; y < 3; y++)
2865 for (x = 0; x < 3; x++)
2866 ei->content.e[x][y] = getMappedElement(getFile16BitBE(file));
2868 ei->move_enter_element = getMappedElement(getFile16BitBE(file));
2869 ei->move_leave_element = getMappedElement(getFile16BitBE(file));
2870 ei->move_leave_type = getFile8Bit(file);
2872 // ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible)
2873 ei->move_pattern |= (getFile16BitBE(file) << 16);
2875 ei->access_direction = getFile8Bit(file);
2877 ei->explosion_delay = getFile8Bit(file);
2878 ei->ignition_delay = getFile8Bit(file);
2879 ei->explosion_type = getFile8Bit(file);
2881 // some free bytes for future custom property values and padding
2882 ReadUnusedBytesFromFile(file, 1);
2884 // ---------- change page property values (48 bytes) ------------------------
2886 setElementChangePages(ei, ei->num_change_pages);
2888 for (i = 0; i < ei->num_change_pages; i++)
2890 struct ElementChangeInfo *change = &ei->change_page[i];
2891 unsigned int event_bits;
2893 // always start with reliable default values
2894 setElementChangeInfoToDefaults(change);
2896 // bits 0 - 31 of "has_event[]" ...
2897 event_bits = getFile32BitBE(file);
2898 for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
2899 if (event_bits & (1 << j))
2900 change->has_event[j] = TRUE;
2902 change->target_element = getMappedElement(getFile16BitBE(file));
2904 change->delay_fixed = getFile16BitBE(file);
2905 change->delay_random = getFile16BitBE(file);
2906 change->delay_frames = getFile16BitBE(file);
2908 change->initial_trigger_element = getMappedElement(getFile16BitBE(file));
2910 change->explode = getFile8Bit(file);
2911 change->use_target_content = getFile8Bit(file);
2912 change->only_if_complete = getFile8Bit(file);
2913 change->use_random_replace = getFile8Bit(file);
2915 change->random_percentage = getFile8Bit(file);
2916 change->replace_when = getFile8Bit(file);
2918 for (y = 0; y < 3; y++)
2919 for (x = 0; x < 3; x++)
2920 change->target_content.e[x][y]= getMappedElement(getFile16BitBE(file));
2922 change->can_change = getFile8Bit(file);
2924 change->trigger_side = getFile8Bit(file);
2926 change->trigger_player = getFile8Bit(file);
2927 change->trigger_page = getFile8Bit(file);
2929 change->trigger_page = (change->trigger_page == CH_PAGE_ANY_FILE ?
2930 CH_PAGE_ANY : (1 << change->trigger_page));
2932 change->has_action = getFile8Bit(file);
2933 change->action_type = getFile8Bit(file);
2934 change->action_mode = getFile8Bit(file);
2935 change->action_arg = getFile16BitBE(file);
2937 // ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible)
2938 event_bits = getFile8Bit(file);
2939 for (j = 32; j < NUM_CHANGE_EVENTS; j++)
2940 if (event_bits & (1 << (j - 32)))
2941 change->has_event[j] = TRUE;
2944 // mark this custom element as modified
2945 ei->modified_settings = TRUE;
2947 level->file_has_custom_elements = TRUE;
2952 static int LoadLevel_GRP1(File *file, int chunk_size, struct LevelInfo *level)
2954 struct ElementInfo *ei;
2955 struct ElementGroupInfo *group;
2959 element = getMappedElement(getFile16BitBE(file));
2961 if (!IS_GROUP_ELEMENT(element))
2963 Error(ERR_WARN, "invalid group element number %d", element);
2965 ReadUnusedBytesFromFile(file, chunk_size - 2);
2969 ei = &element_info[element];
2971 for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
2972 ei->description[i] = getFile8Bit(file);
2973 ei->description[MAX_ELEMENT_NAME_LEN] = 0;
2975 group = element_info[element].group;
2977 group->num_elements = getFile8Bit(file);
2979 ei->use_gfx_element = getFile8Bit(file);
2980 ei->gfx_element_initial = getMappedElement(getFile16BitBE(file));
2982 group->choice_mode = getFile8Bit(file);
2984 // some free bytes for future values and padding
2985 ReadUnusedBytesFromFile(file, 3);
2987 for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
2988 group->element[i] = getMappedElement(getFile16BitBE(file));
2990 // mark this group element as modified
2991 element_info[element].modified_settings = TRUE;
2993 level->file_has_custom_elements = TRUE;
2998 static int LoadLevel_MicroChunk(File *file, struct LevelFileConfigInfo *conf,
2999 int element, int real_element)
3001 int micro_chunk_size = 0;
3002 int conf_type = getFile8Bit(file);
3003 int byte_mask = conf_type & CONF_MASK_BYTES;
3004 boolean element_found = FALSE;
3007 micro_chunk_size += 1;
3009 if (byte_mask == CONF_MASK_MULTI_BYTES)
3011 int num_bytes = getFile16BitBE(file);
3012 byte *buffer = checked_malloc(num_bytes);
3014 ReadBytesFromFile(file, buffer, num_bytes);
3016 for (i = 0; conf[i].data_type != -1; i++)
3018 if (conf[i].element == element &&
3019 conf[i].conf_type == conf_type)
3021 int data_type = conf[i].data_type;
3022 int num_entities = num_bytes / CONF_ENTITY_NUM_BYTES(data_type);
3023 int max_num_entities = conf[i].max_num_entities;
3025 if (num_entities > max_num_entities)
3028 "truncating number of entities for element %d from %d to %d",
3029 element, num_entities, max_num_entities);
3031 num_entities = max_num_entities;
3034 if (num_entities == 0 && (data_type == TYPE_ELEMENT_LIST ||
3035 data_type == TYPE_CONTENT_LIST))
3037 // for element and content lists, zero entities are not allowed
3038 Error(ERR_WARN, "found empty list of entities for element %d",
3041 // do not set "num_entities" here to prevent reading behind buffer
3043 *(int *)(conf[i].num_entities) = 1; // at least one is required
3047 *(int *)(conf[i].num_entities) = num_entities;
3050 element_found = TRUE;
3052 if (data_type == TYPE_STRING)
3054 char *string = (char *)(conf[i].value);
3057 for (j = 0; j < max_num_entities; j++)
3058 string[j] = (j < num_entities ? buffer[j] : '\0');
3060 else if (data_type == TYPE_ELEMENT_LIST)
3062 int *element_array = (int *)(conf[i].value);
3065 for (j = 0; j < num_entities; j++)
3067 getMappedElement(CONF_ELEMENTS_ELEMENT(buffer, j));
3069 else if (data_type == TYPE_CONTENT_LIST)
3071 struct Content *content= (struct Content *)(conf[i].value);
3074 for (c = 0; c < num_entities; c++)
3075 for (y = 0; y < 3; y++)
3076 for (x = 0; x < 3; x++)
3077 content[c].e[x][y] =
3078 getMappedElement(CONF_CONTENTS_ELEMENT(buffer, c, x, y));
3081 element_found = FALSE;
3087 checked_free(buffer);
3089 micro_chunk_size += 2 + num_bytes;
3091 else // constant size configuration data (1, 2 or 4 bytes)
3093 int value = (byte_mask == CONF_MASK_1_BYTE ? getFile8Bit (file) :
3094 byte_mask == CONF_MASK_2_BYTE ? getFile16BitBE(file) :
3095 byte_mask == CONF_MASK_4_BYTE ? getFile32BitBE(file) : 0);
3097 for (i = 0; conf[i].data_type != -1; i++)
3099 if (conf[i].element == element &&
3100 conf[i].conf_type == conf_type)
3102 int data_type = conf[i].data_type;
3104 if (data_type == TYPE_ELEMENT)
3105 value = getMappedElement(value);
3107 if (data_type == TYPE_BOOLEAN)
3108 *(boolean *)(conf[i].value) = value;
3110 *(int *) (conf[i].value) = value;
3112 element_found = TRUE;
3118 micro_chunk_size += CONF_VALUE_NUM_BYTES(byte_mask);
3123 char *error_conf_chunk_bytes =
3124 (byte_mask == CONF_MASK_1_BYTE ? "CONF_VALUE_8_BIT" :
3125 byte_mask == CONF_MASK_2_BYTE ? "CONF_VALUE_16_BIT" :
3126 byte_mask == CONF_MASK_4_BYTE ? "CONF_VALUE_32_BIT" :"CONF_VALUE_BYTES");
3127 int error_conf_chunk_token = conf_type & CONF_MASK_TOKEN;
3128 int error_element = real_element;
3130 Error(ERR_WARN, "cannot load micro chunk '%s(%d)' value for element %d ['%s']",
3131 error_conf_chunk_bytes, error_conf_chunk_token,
3132 error_element, EL_NAME(error_element));
3135 return micro_chunk_size;
3138 static int LoadLevel_INFO(File *file, int chunk_size, struct LevelInfo *level)
3140 int real_chunk_size = 0;
3142 li = *level; // copy level data into temporary buffer
3144 while (!checkEndOfFile(file))
3146 real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_INFO, -1, -1);
3148 if (real_chunk_size >= chunk_size)
3152 *level = li; // copy temporary buffer back to level data
3154 return real_chunk_size;
3157 static int LoadLevel_CONF(File *file, int chunk_size, struct LevelInfo *level)
3159 int real_chunk_size = 0;
3161 li = *level; // copy level data into temporary buffer
3163 while (!checkEndOfFile(file))
3165 int element = getMappedElement(getFile16BitBE(file));
3167 real_chunk_size += 2;
3168 real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CONF,
3170 if (real_chunk_size >= chunk_size)
3174 *level = li; // copy temporary buffer back to level data
3176 return real_chunk_size;
3179 static int LoadLevel_ELEM(File *file, int chunk_size, struct LevelInfo *level)
3181 int real_chunk_size = 0;
3183 li = *level; // copy level data into temporary buffer
3185 while (!checkEndOfFile(file))
3187 int element = getMappedElement(getFile16BitBE(file));
3189 real_chunk_size += 2;
3190 real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_ELEM,
3192 if (real_chunk_size >= chunk_size)
3196 *level = li; // copy temporary buffer back to level data
3198 return real_chunk_size;
3201 static int LoadLevel_NOTE(File *file, int chunk_size, struct LevelInfo *level)
3203 int element = getMappedElement(getFile16BitBE(file));
3204 int envelope_nr = element - EL_ENVELOPE_1;
3205 int real_chunk_size = 2;
3207 xx_envelope = level->envelope[envelope_nr]; // copy into temporary buffer
3209 while (!checkEndOfFile(file))
3211 real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_NOTE,
3214 if (real_chunk_size >= chunk_size)
3218 level->envelope[envelope_nr] = xx_envelope; // copy from temporary buffer
3220 return real_chunk_size;
3223 static int LoadLevel_CUSX(File *file, int chunk_size, struct LevelInfo *level)
3225 int element = getMappedElement(getFile16BitBE(file));
3226 int real_chunk_size = 2;
3227 struct ElementInfo *ei = &element_info[element];
3230 xx_ei = *ei; // copy element data into temporary buffer
3232 xx_ei.num_change_pages = -1;
3234 while (!checkEndOfFile(file))
3236 real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CUSX_base,
3238 if (xx_ei.num_change_pages != -1)
3241 if (real_chunk_size >= chunk_size)
3247 if (ei->num_change_pages == -1)
3249 Error(ERR_WARN, "LoadLevel_CUSX(): missing 'num_change_pages' for '%s'",
3252 ei->num_change_pages = 1;
3254 setElementChangePages(ei, 1);
3255 setElementChangeInfoToDefaults(ei->change);
3257 return real_chunk_size;
3260 // initialize number of change pages stored for this custom element
3261 setElementChangePages(ei, ei->num_change_pages);
3262 for (i = 0; i < ei->num_change_pages; i++)
3263 setElementChangeInfoToDefaults(&ei->change_page[i]);
3265 // start with reading properties for the first change page
3266 xx_current_change_page = 0;
3268 while (!checkEndOfFile(file))
3270 struct ElementChangeInfo *change = &ei->change_page[xx_current_change_page];
3272 xx_change = *change; // copy change data into temporary buffer
3274 resetEventBits(); // reset bits; change page might have changed
3276 real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CUSX_change,
3279 *change = xx_change;
3281 setEventFlagsFromEventBits(change);
3283 if (real_chunk_size >= chunk_size)
3287 level->file_has_custom_elements = TRUE;
3289 return real_chunk_size;
3292 static int LoadLevel_GRPX(File *file, int chunk_size, struct LevelInfo *level)
3294 int element = getMappedElement(getFile16BitBE(file));
3295 int real_chunk_size = 2;
3296 struct ElementInfo *ei = &element_info[element];
3297 struct ElementGroupInfo *group = ei->group;
3299 xx_ei = *ei; // copy element data into temporary buffer
3300 xx_group = *group; // copy group data into temporary buffer
3302 while (!checkEndOfFile(file))
3304 real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_GRPX,
3307 if (real_chunk_size >= chunk_size)
3314 level->file_has_custom_elements = TRUE;
3316 return real_chunk_size;
3319 static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
3320 struct LevelFileInfo *level_file_info,
3321 boolean level_info_only)
3323 char *filename = level_file_info->filename;
3324 char cookie[MAX_LINE_LEN];
3325 char chunk_name[CHUNK_ID_LEN + 1];
3329 if (!(file = openFile(filename, MODE_READ)))
3331 level->no_valid_file = TRUE;
3332 level->no_level_file = TRUE;
3334 if (level_info_only)
3337 Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
3339 if (!setup.editor.use_template_for_new_levels)
3342 // if level file not found, try to initialize level data from template
3343 filename = getGlobalLevelTemplateFilename();
3345 if (!(file = openFile(filename, MODE_READ)))
3348 // default: for empty levels, use level template for custom elements
3349 level->use_custom_template = TRUE;
3351 level->no_valid_file = FALSE;
3354 getFileChunkBE(file, chunk_name, NULL);
3355 if (strEqual(chunk_name, "RND1"))
3357 getFile32BitBE(file); // not used
3359 getFileChunkBE(file, chunk_name, NULL);
3360 if (!strEqual(chunk_name, "CAVE"))
3362 level->no_valid_file = TRUE;
3364 Error(ERR_WARN, "unknown format of level file '%s'", filename);
3371 else // check for pre-2.0 file format with cookie string
3373 strcpy(cookie, chunk_name);
3374 if (getStringFromFile(file, &cookie[4], MAX_LINE_LEN - 4) == NULL)
3376 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
3377 cookie[strlen(cookie) - 1] = '\0';
3379 if (!checkCookieString(cookie, LEVEL_COOKIE_TMPL))
3381 level->no_valid_file = TRUE;
3383 Error(ERR_WARN, "unknown format of level file '%s'", filename);
3390 if ((level->file_version = getFileVersionFromCookieString(cookie)) == -1)
3392 level->no_valid_file = TRUE;
3394 Error(ERR_WARN, "unsupported version of level file '%s'", filename);
3401 // pre-2.0 level files have no game version, so use file version here
3402 level->game_version = level->file_version;
3405 if (level->file_version < FILE_VERSION_1_2)
3407 // level files from versions before 1.2.0 without chunk structure
3408 LoadLevel_HEAD(file, LEVEL_CHUNK_HEAD_SIZE, level);
3409 LoadLevel_BODY(file, level->fieldx * level->fieldy, level);
3417 int (*loader)(File *, int, struct LevelInfo *);
3421 { "VERS", LEVEL_CHUNK_VERS_SIZE, LoadLevel_VERS },
3422 { "DATE", LEVEL_CHUNK_DATE_SIZE, LoadLevel_DATE },
3423 { "HEAD", LEVEL_CHUNK_HEAD_SIZE, LoadLevel_HEAD },
3424 { "NAME", LEVEL_CHUNK_NAME_SIZE, LoadLevel_NAME },
3425 { "AUTH", LEVEL_CHUNK_AUTH_SIZE, LoadLevel_AUTH },
3426 { "INFO", -1, LoadLevel_INFO },
3427 { "BODY", -1, LoadLevel_BODY },
3428 { "CONT", -1, LoadLevel_CONT },
3429 { "CNT2", LEVEL_CHUNK_CNT2_SIZE, LoadLevel_CNT2 },
3430 { "CNT3", -1, LoadLevel_CNT3 },
3431 { "CUS1", -1, LoadLevel_CUS1 },
3432 { "CUS2", -1, LoadLevel_CUS2 },
3433 { "CUS3", -1, LoadLevel_CUS3 },
3434 { "CUS4", -1, LoadLevel_CUS4 },
3435 { "GRP1", -1, LoadLevel_GRP1 },
3436 { "CONF", -1, LoadLevel_CONF },
3437 { "ELEM", -1, LoadLevel_ELEM },
3438 { "NOTE", -1, LoadLevel_NOTE },
3439 { "CUSX", -1, LoadLevel_CUSX },
3440 { "GRPX", -1, LoadLevel_GRPX },
3445 while (getFileChunkBE(file, chunk_name, &chunk_size))
3449 while (chunk_info[i].name != NULL &&
3450 !strEqual(chunk_name, chunk_info[i].name))
3453 if (chunk_info[i].name == NULL)
3455 Error(ERR_WARN, "unknown chunk '%s' in level file '%s'",
3456 chunk_name, filename);
3457 ReadUnusedBytesFromFile(file, chunk_size);
3459 else if (chunk_info[i].size != -1 &&
3460 chunk_info[i].size != chunk_size)
3462 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
3463 chunk_size, chunk_name, filename);
3464 ReadUnusedBytesFromFile(file, chunk_size);
3468 // call function to load this level chunk
3469 int chunk_size_expected =
3470 (chunk_info[i].loader)(file, chunk_size, level);
3472 // the size of some chunks cannot be checked before reading other
3473 // chunks first (like "HEAD" and "BODY") that contain some header
3474 // information, so check them here
3475 if (chunk_size_expected != chunk_size)
3477 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
3478 chunk_size, chunk_name, filename);
3488 // ----------------------------------------------------------------------------
3489 // functions for loading EM level
3490 // ----------------------------------------------------------------------------
3492 static void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
3494 static int ball_xy[8][2] =
3505 struct LevelInfo_EM *level_em = level->native_em_level;
3506 struct LEVEL *lev = level_em->lev;
3507 struct PLAYER **ply = level_em->ply;
3510 lev->width = MIN(level->fieldx, EM_MAX_CAVE_WIDTH);
3511 lev->height = MIN(level->fieldy, EM_MAX_CAVE_HEIGHT);
3513 lev->time_seconds = level->time;
3514 lev->required_initial = level->gems_needed;
3516 lev->emerald_score = level->score[SC_EMERALD];
3517 lev->diamond_score = level->score[SC_DIAMOND];
3518 lev->alien_score = level->score[SC_ROBOT];
3519 lev->tank_score = level->score[SC_SPACESHIP];
3520 lev->bug_score = level->score[SC_BUG];
3521 lev->eater_score = level->score[SC_YAMYAM];
3522 lev->nut_score = level->score[SC_NUT];
3523 lev->dynamite_score = level->score[SC_DYNAMITE];
3524 lev->key_score = level->score[SC_KEY];
3525 lev->exit_score = level->score[SC_TIME_BONUS];
3527 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3528 for (y = 0; y < 3; y++)
3529 for (x = 0; x < 3; x++)
3530 lev->eater_array[i][y * 3 + x] =
3531 map_element_RND_to_EM(level->yamyam_content[i].e[x][y]);
3533 lev->amoeba_time = level->amoeba_speed;
3534 lev->wonderwall_time_initial = level->time_magic_wall;
3535 lev->wheel_time = level->time_wheel;
3537 lev->android_move_time = level->android_move_time;
3538 lev->android_clone_time = level->android_clone_time;
3539 lev->ball_random = level->ball_random;
3540 lev->ball_state_initial = level->ball_state_initial;
3541 lev->ball_time = level->ball_time;
3542 lev->num_ball_arrays = level->num_ball_contents;
3544 lev->lenses_score = level->lenses_score;
3545 lev->magnify_score = level->magnify_score;
3546 lev->slurp_score = level->slurp_score;
3548 lev->lenses_time = level->lenses_time;
3549 lev->magnify_time = level->magnify_time;
3551 lev->wind_direction_initial =
3552 map_direction_RND_to_EM(level->wind_direction_initial);
3553 lev->wind_cnt_initial = (level->wind_direction_initial != MV_NONE ?
3554 lev->wind_time : 0);
3556 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3557 for (j = 0; j < 8; j++)
3558 lev->ball_array[i][j] =
3559 map_element_RND_to_EM(level->
3560 ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
3562 map_android_clone_elements_RND_to_EM(level);
3564 // first fill the complete playfield with the default border element
3565 for (y = 0; y < EM_MAX_CAVE_HEIGHT; y++)
3566 for (x = 0; x < EM_MAX_CAVE_WIDTH; x++)
3567 level_em->cave[x][y] = ZBORDER;
3569 if (BorderElement == EL_STEELWALL)
3571 for (y = 0; y < lev->height + 2; y++)
3572 for (x = 0; x < lev->width + 2; x++)
3573 level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_STEELWALL);
3576 // then copy the real level contents from level file into the playfield
3577 for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
3579 int new_element = map_element_RND_to_EM(level->field[x][y]);
3580 int offset = (BorderElement == EL_STEELWALL ? 1 : 0);
3581 int xx = x + 1 + offset;
3582 int yy = y + 1 + offset;
3584 if (level->field[x][y] == EL_AMOEBA_DEAD)
3585 new_element = map_element_RND_to_EM(EL_AMOEBA_WET);
3587 level_em->cave[xx][yy] = new_element;
3590 for (i = 0; i < MAX_PLAYERS; i++)
3592 ply[i]->x_initial = 0;
3593 ply[i]->y_initial = 0;
3596 // initialize player positions and delete players from the playfield
3597 for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
3599 if (ELEM_IS_PLAYER(level->field[x][y]))
3601 int player_nr = GET_PLAYER_NR(level->field[x][y]);
3602 int offset = (BorderElement == EL_STEELWALL ? 1 : 0);
3603 int xx = x + 1 + offset;
3604 int yy = y + 1 + offset;
3606 ply[player_nr]->x_initial = xx;
3607 ply[player_nr]->y_initial = yy;
3609 level_em->cave[xx][yy] = map_element_RND_to_EM(EL_EMPTY);
3613 if (BorderElement == EL_STEELWALL)
3620 static void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
3622 static int ball_xy[8][2] =
3633 struct LevelInfo_EM *level_em = level->native_em_level;
3634 struct LEVEL *lev = level_em->lev;
3635 struct PLAYER **ply = level_em->ply;
3638 level->fieldx = MIN(lev->width, MAX_LEV_FIELDX);
3639 level->fieldy = MIN(lev->height, MAX_LEV_FIELDY);
3641 level->time = lev->time_seconds;
3642 level->gems_needed = lev->required_initial;
3644 sprintf(level->name, "Level %d", level->file_info.nr);
3646 level->score[SC_EMERALD] = lev->emerald_score;
3647 level->score[SC_DIAMOND] = lev->diamond_score;
3648 level->score[SC_ROBOT] = lev->alien_score;
3649 level->score[SC_SPACESHIP] = lev->tank_score;
3650 level->score[SC_BUG] = lev->bug_score;
3651 level->score[SC_YAMYAM] = lev->eater_score;
3652 level->score[SC_NUT] = lev->nut_score;
3653 level->score[SC_DYNAMITE] = lev->dynamite_score;
3654 level->score[SC_KEY] = lev->key_score;
3655 level->score[SC_TIME_BONUS] = lev->exit_score;
3657 level->num_yamyam_contents = MAX_ELEMENT_CONTENTS;
3659 for (i = 0; i < level->num_yamyam_contents; i++)
3660 for (y = 0; y < 3; y++)
3661 for (x = 0; x < 3; x++)
3662 level->yamyam_content[i].e[x][y] =
3663 map_element_EM_to_RND(lev->eater_array[i][y * 3 + x]);
3665 level->amoeba_speed = lev->amoeba_time;
3666 level->time_magic_wall = lev->wonderwall_time_initial;
3667 level->time_wheel = lev->wheel_time;
3669 level->android_move_time = lev->android_move_time;
3670 level->android_clone_time = lev->android_clone_time;
3671 level->ball_random = lev->ball_random;
3672 level->ball_state_initial = lev->ball_state_initial;
3673 level->ball_time = lev->ball_time;
3674 level->num_ball_contents = lev->num_ball_arrays;
3676 level->lenses_score = lev->lenses_score;
3677 level->magnify_score = lev->magnify_score;
3678 level->slurp_score = lev->slurp_score;
3680 level->lenses_time = lev->lenses_time;
3681 level->magnify_time = lev->magnify_time;
3683 level->wind_direction_initial =
3684 map_direction_EM_to_RND(lev->wind_direction_initial);
3686 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3687 for (j = 0; j < 8; j++)
3688 level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]] =
3689 map_element_EM_to_RND(lev->ball_array[i][j]);
3691 map_android_clone_elements_EM_to_RND(level);
3693 // convert the playfield (some elements need special treatment)
3694 for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
3696 int new_element = map_element_EM_to_RND(level_em->cave[x + 1][y + 1]);
3698 if (new_element == EL_AMOEBA_WET && level->amoeba_speed == 0)
3699 new_element = EL_AMOEBA_DEAD;
3701 level->field[x][y] = new_element;
3704 for (i = 0; i < MAX_PLAYERS; i++)
3706 // in case of all players set to the same field, use the first player
3707 int nr = MAX_PLAYERS - i - 1;
3708 int jx = ply[nr]->x_initial - 1;
3709 int jy = ply[nr]->y_initial - 1;
3711 if (jx != -1 && jy != -1)
3712 level->field[jx][jy] = EL_PLAYER_1 + nr;
3717 // ----------------------------------------------------------------------------
3718 // functions for loading SP level
3719 // ----------------------------------------------------------------------------
3721 static void CopyNativeLevel_RND_to_SP(struct LevelInfo *level)
3723 struct LevelInfo_SP *level_sp = level->native_sp_level;
3724 LevelInfoType *header = &level_sp->header;
3727 level_sp->width = level->fieldx;
3728 level_sp->height = level->fieldy;
3730 for (x = 0; x < level->fieldx; x++)
3731 for (y = 0; y < level->fieldy; y++)
3732 level_sp->playfield[x][y] = map_element_RND_to_SP(level->field[x][y]);
3734 header->InitialGravity = (level->initial_player_gravity[0] ? 1 : 0);