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
822 EL_SOKOBAN_FIELD_EMPTY, -1,
823 TYPE_BOOLEAN, CONF_VALUE_8_BIT(1),
824 &li.sb_fields_needed, TRUE
828 EL_SOKOBAN_OBJECT, -1,
829 TYPE_BOOLEAN, CONF_VALUE_8_BIT(1),
830 &li.sb_objects_needed, TRUE
835 TYPE_BOOLEAN, CONF_VALUE_8_BIT(1),
836 &li.mm_laser_red, FALSE
840 TYPE_BOOLEAN, CONF_VALUE_8_BIT(2),
841 &li.mm_laser_green, FALSE
845 TYPE_BOOLEAN, CONF_VALUE_8_BIT(3),
846 &li.mm_laser_blue, TRUE
851 TYPE_BOOLEAN, CONF_VALUE_8_BIT(1),
852 &li.df_laser_red, TRUE
856 TYPE_BOOLEAN, CONF_VALUE_8_BIT(2),
857 &li.df_laser_green, TRUE
861 TYPE_BOOLEAN, CONF_VALUE_8_BIT(3),
862 &li.df_laser_blue, FALSE
866 EL_MM_FUSE_ACTIVE, -1,
867 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
872 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
877 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
881 EL_MM_STEEL_BLOCK, -1,
882 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
883 &li.mm_time_block, 75
887 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
888 &li.score[SC_ELEM_BONUS], 10
891 // ---------- unused values -------------------------------------------------
894 EL_UNKNOWN, SAVE_CONF_NEVER,
895 TYPE_INTEGER, CONF_VALUE_16_BIT(1),
896 &li.score[SC_UNKNOWN_15], 10
906 static struct LevelFileConfigInfo chunk_config_NOTE[] =
910 TYPE_INTEGER, CONF_VALUE_8_BIT(1),
911 &xx_envelope.xsize, MAX_ENVELOPE_XSIZE,
915 TYPE_INTEGER, CONF_VALUE_8_BIT(2),
916 &xx_envelope.ysize, MAX_ENVELOPE_YSIZE,
921 TYPE_BOOLEAN, CONF_VALUE_8_BIT(3),
922 &xx_envelope.autowrap, FALSE
926 TYPE_BOOLEAN, CONF_VALUE_8_BIT(4),
927 &xx_envelope.centered, FALSE
932 TYPE_STRING, CONF_VALUE_BYTES(1),
933 &xx_envelope.text, -1, NULL,
934 &xx_string_length_unused, -1, MAX_ENVELOPE_TEXT_LEN,
935 &xx_default_string_empty[0]
945 static struct LevelFileConfigInfo chunk_config_CUSX_base[] =
949 TYPE_STRING, CONF_VALUE_BYTES(1),
950 &xx_ei.description[0], -1,
951 &yy_ei.description[0],
952 &xx_string_length_unused, -1, MAX_ELEMENT_NAME_LEN,
953 &xx_default_description[0]
958 TYPE_BITFIELD, CONF_VALUE_32_BIT(1),
959 &xx_ei.properties[EP_BITFIELD_BASE_NR], EP_BITMASK_BASE_DEFAULT,
960 &yy_ei.properties[EP_BITFIELD_BASE_NR]
962 #if ENABLE_RESERVED_CODE
963 // (reserved for later use)
966 TYPE_BITFIELD, CONF_VALUE_32_BIT(2),
967 &xx_ei.properties[EP_BITFIELD_BASE_NR + 1], EP_BITMASK_DEFAULT,
968 &yy_ei.properties[EP_BITFIELD_BASE_NR + 1]
974 TYPE_BOOLEAN, CONF_VALUE_8_BIT(1),
975 &xx_ei.use_gfx_element, FALSE,
976 &yy_ei.use_gfx_element
980 TYPE_ELEMENT, CONF_VALUE_16_BIT(1),
981 &xx_ei.gfx_element_initial, EL_EMPTY_SPACE,
982 &yy_ei.gfx_element_initial
987 TYPE_BITFIELD, CONF_VALUE_8_BIT(2),
988 &xx_ei.access_direction, MV_ALL_DIRECTIONS,
989 &yy_ei.access_direction
994 TYPE_INTEGER, CONF_VALUE_16_BIT(2),
995 &xx_ei.collect_score_initial, 10,
996 &yy_ei.collect_score_initial
1000 TYPE_INTEGER, CONF_VALUE_16_BIT(3),
1001 &xx_ei.collect_count_initial, 1,
1002 &yy_ei.collect_count_initial
1007 TYPE_INTEGER, CONF_VALUE_16_BIT(4),
1008 &xx_ei.ce_value_fixed_initial, 0,
1009 &yy_ei.ce_value_fixed_initial
1013 TYPE_INTEGER, CONF_VALUE_16_BIT(5),
1014 &xx_ei.ce_value_random_initial, 0,
1015 &yy_ei.ce_value_random_initial
1019 TYPE_BOOLEAN, CONF_VALUE_8_BIT(3),
1020 &xx_ei.use_last_ce_value, FALSE,
1021 &yy_ei.use_last_ce_value
1026 TYPE_INTEGER, CONF_VALUE_16_BIT(6),
1027 &xx_ei.push_delay_fixed, 8,
1028 &yy_ei.push_delay_fixed
1032 TYPE_INTEGER, CONF_VALUE_16_BIT(7),
1033 &xx_ei.push_delay_random, 8,
1034 &yy_ei.push_delay_random
1038 TYPE_INTEGER, CONF_VALUE_16_BIT(8),
1039 &xx_ei.drop_delay_fixed, 0,
1040 &yy_ei.drop_delay_fixed
1044 TYPE_INTEGER, CONF_VALUE_16_BIT(9),
1045 &xx_ei.drop_delay_random, 0,
1046 &yy_ei.drop_delay_random
1050 TYPE_INTEGER, CONF_VALUE_16_BIT(10),
1051 &xx_ei.move_delay_fixed, 0,
1052 &yy_ei.move_delay_fixed
1056 TYPE_INTEGER, CONF_VALUE_16_BIT(11),
1057 &xx_ei.move_delay_random, 0,
1058 &yy_ei.move_delay_random
1063 TYPE_BITFIELD, CONF_VALUE_32_BIT(3),
1064 &xx_ei.move_pattern, MV_ALL_DIRECTIONS,
1069 TYPE_BITFIELD, CONF_VALUE_8_BIT(4),
1070 &xx_ei.move_direction_initial, MV_START_AUTOMATIC,
1071 &yy_ei.move_direction_initial
1075 TYPE_INTEGER, CONF_VALUE_8_BIT(5),
1076 &xx_ei.move_stepsize, TILEX / 8,
1077 &yy_ei.move_stepsize
1082 TYPE_ELEMENT, CONF_VALUE_16_BIT(12),
1083 &xx_ei.move_enter_element, EL_EMPTY_SPACE,
1084 &yy_ei.move_enter_element
1088 TYPE_ELEMENT, CONF_VALUE_16_BIT(13),
1089 &xx_ei.move_leave_element, EL_EMPTY_SPACE,
1090 &yy_ei.move_leave_element
1094 TYPE_INTEGER, CONF_VALUE_8_BIT(6),
1095 &xx_ei.move_leave_type, LEAVE_TYPE_UNLIMITED,
1096 &yy_ei.move_leave_type
1101 TYPE_INTEGER, CONF_VALUE_8_BIT(7),
1102 &xx_ei.slippery_type, SLIPPERY_ANY_RANDOM,
1103 &yy_ei.slippery_type
1108 TYPE_INTEGER, CONF_VALUE_8_BIT(8),
1109 &xx_ei.explosion_type, EXPLODES_3X3,
1110 &yy_ei.explosion_type
1114 TYPE_INTEGER, CONF_VALUE_16_BIT(14),
1115 &xx_ei.explosion_delay, 16,
1116 &yy_ei.explosion_delay
1120 TYPE_INTEGER, CONF_VALUE_16_BIT(15),
1121 &xx_ei.ignition_delay, 8,
1122 &yy_ei.ignition_delay
1127 TYPE_CONTENT_LIST, CONF_VALUE_BYTES(2),
1128 &xx_ei.content, EL_EMPTY_SPACE,
1130 &xx_num_contents, 1, 1
1133 // ---------- "num_change_pages" must be the last entry ---------------------
1136 -1, SAVE_CONF_ALWAYS,
1137 TYPE_INTEGER, CONF_VALUE_8_BIT(9),
1138 &xx_ei.num_change_pages, 1,
1139 &yy_ei.num_change_pages
1150 static struct LevelFileConfigInfo chunk_config_CUSX_change[] =
1152 // ---------- "current_change_page" must be the first entry -----------------
1155 -1, SAVE_CONF_ALWAYS,
1156 TYPE_INTEGER, CONF_VALUE_8_BIT(1),
1157 &xx_current_change_page, -1
1160 // ---------- (the remaining entries can be in any order) -------------------
1164 TYPE_BOOLEAN, CONF_VALUE_8_BIT(2),
1165 &xx_change.can_change, FALSE
1170 TYPE_BITFIELD, CONF_VALUE_32_BIT(1),
1171 &xx_event_bits[0], 0
1175 TYPE_BITFIELD, CONF_VALUE_32_BIT(2),
1176 &xx_event_bits[1], 0
1181 TYPE_BITFIELD, CONF_VALUE_8_BIT(3),
1182 &xx_change.trigger_player, CH_PLAYER_ANY
1186 TYPE_BITFIELD, CONF_VALUE_8_BIT(4),
1187 &xx_change.trigger_side, CH_SIDE_ANY
1191 TYPE_BITFIELD, CONF_VALUE_32_BIT(3),
1192 &xx_change.trigger_page, CH_PAGE_ANY
1197 TYPE_ELEMENT, CONF_VALUE_16_BIT(1),
1198 &xx_change.target_element, EL_EMPTY_SPACE
1203 TYPE_INTEGER, CONF_VALUE_16_BIT(2),
1204 &xx_change.delay_fixed, 0
1208 TYPE_INTEGER, CONF_VALUE_16_BIT(3),
1209 &xx_change.delay_random, 0
1213 TYPE_INTEGER, CONF_VALUE_16_BIT(4),
1214 &xx_change.delay_frames, FRAMES_PER_SECOND
1219 TYPE_ELEMENT, CONF_VALUE_16_BIT(5),
1220 &xx_change.initial_trigger_element, EL_EMPTY_SPACE
1225 TYPE_BOOLEAN, CONF_VALUE_8_BIT(6),
1226 &xx_change.explode, FALSE
1230 TYPE_BOOLEAN, CONF_VALUE_8_BIT(7),
1231 &xx_change.use_target_content, FALSE
1235 TYPE_BOOLEAN, CONF_VALUE_8_BIT(8),
1236 &xx_change.only_if_complete, FALSE
1240 TYPE_BOOLEAN, CONF_VALUE_8_BIT(9),
1241 &xx_change.use_random_replace, FALSE
1245 TYPE_INTEGER, CONF_VALUE_8_BIT(10),
1246 &xx_change.random_percentage, 100
1250 TYPE_INTEGER, CONF_VALUE_8_BIT(11),
1251 &xx_change.replace_when, CP_WHEN_EMPTY
1256 TYPE_BOOLEAN, CONF_VALUE_8_BIT(12),
1257 &xx_change.has_action, FALSE
1261 TYPE_INTEGER, CONF_VALUE_8_BIT(13),
1262 &xx_change.action_type, CA_NO_ACTION
1266 TYPE_INTEGER, CONF_VALUE_8_BIT(14),
1267 &xx_change.action_mode, CA_MODE_UNDEFINED
1271 TYPE_INTEGER, CONF_VALUE_16_BIT(6),
1272 &xx_change.action_arg, CA_ARG_UNDEFINED
1277 TYPE_ELEMENT, CONF_VALUE_16_BIT(7),
1278 &xx_change.action_element, EL_EMPTY_SPACE
1283 TYPE_CONTENT_LIST, CONF_VALUE_BYTES(1),
1284 &xx_change.target_content, EL_EMPTY_SPACE, NULL,
1285 &xx_num_contents, 1, 1
1295 static struct LevelFileConfigInfo chunk_config_GRPX[] =
1299 TYPE_STRING, CONF_VALUE_BYTES(1),
1300 &xx_ei.description[0], -1, NULL,
1301 &xx_string_length_unused, -1, MAX_ELEMENT_NAME_LEN,
1302 &xx_default_description[0]
1307 TYPE_BOOLEAN, CONF_VALUE_8_BIT(1),
1308 &xx_ei.use_gfx_element, FALSE
1312 TYPE_ELEMENT, CONF_VALUE_16_BIT(1),
1313 &xx_ei.gfx_element_initial, EL_EMPTY_SPACE
1318 TYPE_INTEGER, CONF_VALUE_8_BIT(2),
1319 &xx_group.choice_mode, ANIM_RANDOM
1324 TYPE_ELEMENT_LIST, CONF_VALUE_BYTES(2),
1325 &xx_group.element[0], EL_EMPTY_SPACE, NULL,
1326 &xx_group.num_elements, 1, MAX_ELEMENTS_IN_GROUP
1336 static struct LevelFileConfigInfo chunk_config_CONF[] = // (OBSOLETE)
1340 TYPE_BOOLEAN, CONF_VALUE_8_BIT(9),
1341 &li.block_snap_field, TRUE
1345 TYPE_BOOLEAN, CONF_VALUE_8_BIT(13),
1346 &li.continuous_snapping, TRUE
1350 TYPE_INTEGER, CONF_VALUE_8_BIT(1),
1351 &li.initial_player_stepsize[0], STEPSIZE_NORMAL
1355 TYPE_BOOLEAN, CONF_VALUE_8_BIT(10),
1356 &li.use_start_element[0], FALSE
1360 TYPE_ELEMENT, CONF_VALUE_16_BIT(1),
1361 &li.start_element[0], EL_PLAYER_1
1365 TYPE_BOOLEAN, CONF_VALUE_8_BIT(11),
1366 &li.use_artwork_element[0], FALSE
1370 TYPE_ELEMENT, CONF_VALUE_16_BIT(2),
1371 &li.artwork_element[0], EL_PLAYER_1
1375 TYPE_BOOLEAN, CONF_VALUE_8_BIT(12),
1376 &li.use_explosion_element[0], FALSE
1380 TYPE_ELEMENT, CONF_VALUE_16_BIT(3),
1381 &li.explosion_element[0], EL_PLAYER_1
1396 filetype_id_list[] =
1398 { LEVEL_FILE_TYPE_RND, "RND" },
1399 { LEVEL_FILE_TYPE_BD, "BD" },
1400 { LEVEL_FILE_TYPE_EM, "EM" },
1401 { LEVEL_FILE_TYPE_SP, "SP" },
1402 { LEVEL_FILE_TYPE_DX, "DX" },
1403 { LEVEL_FILE_TYPE_SB, "SB" },
1404 { LEVEL_FILE_TYPE_DC, "DC" },
1405 { LEVEL_FILE_TYPE_MM, "MM" },
1406 { LEVEL_FILE_TYPE_MM, "DF" },
1411 // ============================================================================
1412 // level file functions
1413 // ============================================================================
1415 static boolean check_special_flags(char *flag)
1417 if (strEqual(options.special_flags, flag) ||
1418 strEqual(leveldir_current->special_flags, flag))
1424 static struct DateInfo getCurrentDate(void)
1426 time_t epoch_seconds = time(NULL);
1427 struct tm *now = localtime(&epoch_seconds);
1428 struct DateInfo date;
1430 date.year = now->tm_year + 1900;
1431 date.month = now->tm_mon + 1;
1432 date.day = now->tm_mday;
1434 date.src = DATE_SRC_CLOCK;
1439 static void resetEventFlags(struct ElementChangeInfo *change)
1443 for (i = 0; i < NUM_CHANGE_EVENTS; i++)
1444 change->has_event[i] = FALSE;
1447 static void resetEventBits(void)
1451 for (i = 0; i < NUM_CE_BITFIELDS; i++)
1452 xx_event_bits[i] = 0;
1455 static void setEventFlagsFromEventBits(struct ElementChangeInfo *change)
1459 /* important: only change event flag if corresponding event bit is set
1460 (this is because all xx_event_bits[] values are loaded separately,
1461 and all xx_event_bits[] values are set back to zero before loading
1462 another value xx_event_bits[x] (each value representing 32 flags)) */
1464 for (i = 0; i < NUM_CHANGE_EVENTS; i++)
1465 if (xx_event_bits[CH_EVENT_BITFIELD_NR(i)] & CH_EVENT_BIT(i))
1466 change->has_event[i] = TRUE;
1469 static void setEventBitsFromEventFlags(struct ElementChangeInfo *change)
1473 /* in contrast to the above function setEventFlagsFromEventBits(), it
1474 would also be possible to set all bits in xx_event_bits[] to 0 or 1
1475 depending on the corresponding change->has_event[i] values here, as
1476 all xx_event_bits[] values are reset in resetEventBits() before */
1478 for (i = 0; i < NUM_CHANGE_EVENTS; i++)
1479 if (change->has_event[i])
1480 xx_event_bits[CH_EVENT_BITFIELD_NR(i)] |= CH_EVENT_BIT(i);
1483 static char *getDefaultElementDescription(struct ElementInfo *ei)
1485 static char description[MAX_ELEMENT_NAME_LEN + 1];
1486 char *default_description = (ei->custom_description != NULL ?
1487 ei->custom_description :
1488 ei->editor_description);
1491 // always start with reliable default values
1492 for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++)
1493 description[i] = '\0';
1495 // truncate element description to MAX_ELEMENT_NAME_LEN bytes
1496 strncpy(description, default_description, MAX_ELEMENT_NAME_LEN);
1498 return &description[0];
1501 static void setElementDescriptionToDefault(struct ElementInfo *ei)
1503 char *default_description = getDefaultElementDescription(ei);
1506 for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++)
1507 ei->description[i] = default_description[i];
1510 static void setConfigToDefaultsFromConfigList(struct LevelFileConfigInfo *conf)
1514 for (i = 0; conf[i].data_type != -1; i++)
1516 int default_value = conf[i].default_value;
1517 int data_type = conf[i].data_type;
1518 int conf_type = conf[i].conf_type;
1519 int byte_mask = conf_type & CONF_MASK_BYTES;
1521 if (byte_mask == CONF_MASK_MULTI_BYTES)
1523 int default_num_entities = conf[i].default_num_entities;
1524 int max_num_entities = conf[i].max_num_entities;
1526 *(int *)(conf[i].num_entities) = default_num_entities;
1528 if (data_type == TYPE_STRING)
1530 char *default_string = conf[i].default_string;
1531 char *string = (char *)(conf[i].value);
1533 strncpy(string, default_string, max_num_entities);
1535 else if (data_type == TYPE_ELEMENT_LIST)
1537 int *element_array = (int *)(conf[i].value);
1540 for (j = 0; j < max_num_entities; j++)
1541 element_array[j] = default_value;
1543 else if (data_type == TYPE_CONTENT_LIST)
1545 struct Content *content = (struct Content *)(conf[i].value);
1548 for (c = 0; c < max_num_entities; c++)
1549 for (y = 0; y < 3; y++)
1550 for (x = 0; x < 3; x++)
1551 content[c].e[x][y] = default_value;
1554 else // constant size configuration data (1, 2 or 4 bytes)
1556 if (data_type == TYPE_BOOLEAN)
1557 *(boolean *)(conf[i].value) = default_value;
1559 *(int *) (conf[i].value) = default_value;
1564 static void copyConfigFromConfigList(struct LevelFileConfigInfo *conf)
1568 for (i = 0; conf[i].data_type != -1; i++)
1570 int data_type = conf[i].data_type;
1571 int conf_type = conf[i].conf_type;
1572 int byte_mask = conf_type & CONF_MASK_BYTES;
1574 if (byte_mask == CONF_MASK_MULTI_BYTES)
1576 int max_num_entities = conf[i].max_num_entities;
1578 if (data_type == TYPE_STRING)
1580 char *string = (char *)(conf[i].value);
1581 char *string_copy = (char *)(conf[i].value_copy);
1583 strncpy(string_copy, string, max_num_entities);
1585 else if (data_type == TYPE_ELEMENT_LIST)
1587 int *element_array = (int *)(conf[i].value);
1588 int *element_array_copy = (int *)(conf[i].value_copy);
1591 for (j = 0; j < max_num_entities; j++)
1592 element_array_copy[j] = element_array[j];
1594 else if (data_type == TYPE_CONTENT_LIST)
1596 struct Content *content = (struct Content *)(conf[i].value);
1597 struct Content *content_copy = (struct Content *)(conf[i].value_copy);
1600 for (c = 0; c < max_num_entities; c++)
1601 for (y = 0; y < 3; y++)
1602 for (x = 0; x < 3; x++)
1603 content_copy[c].e[x][y] = content[c].e[x][y];
1606 else // constant size configuration data (1, 2 or 4 bytes)
1608 if (data_type == TYPE_BOOLEAN)
1609 *(boolean *)(conf[i].value_copy) = *(boolean *)(conf[i].value);
1611 *(int *) (conf[i].value_copy) = *(int *) (conf[i].value);
1616 void copyElementInfo(struct ElementInfo *ei_from, struct ElementInfo *ei_to)
1620 xx_ei = *ei_from; // copy element data into temporary buffer
1621 yy_ei = *ei_to; // copy element data into temporary buffer
1623 copyConfigFromConfigList(chunk_config_CUSX_base);
1628 // ---------- reinitialize and copy change pages ----------
1630 ei_to->num_change_pages = ei_from->num_change_pages;
1631 ei_to->current_change_page = ei_from->current_change_page;
1633 setElementChangePages(ei_to, ei_to->num_change_pages);
1635 for (i = 0; i < ei_to->num_change_pages; i++)
1636 ei_to->change_page[i] = ei_from->change_page[i];
1638 // ---------- copy group element info ----------
1639 if (ei_from->group != NULL && ei_to->group != NULL) // group or internal
1640 *ei_to->group = *ei_from->group;
1642 // mark this custom element as modified
1643 ei_to->modified_settings = TRUE;
1646 void setElementChangePages(struct ElementInfo *ei, int change_pages)
1648 int change_page_size = sizeof(struct ElementChangeInfo);
1650 ei->num_change_pages = MAX(1, change_pages);
1653 checked_realloc(ei->change_page, ei->num_change_pages * change_page_size);
1655 if (ei->current_change_page >= ei->num_change_pages)
1656 ei->current_change_page = ei->num_change_pages - 1;
1658 ei->change = &ei->change_page[ei->current_change_page];
1661 void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
1663 xx_change = *change; // copy change data into temporary buffer
1665 setConfigToDefaultsFromConfigList(chunk_config_CUSX_change);
1667 *change = xx_change;
1669 resetEventFlags(change);
1671 change->direct_action = 0;
1672 change->other_action = 0;
1674 change->pre_change_function = NULL;
1675 change->change_function = NULL;
1676 change->post_change_function = NULL;
1679 static void setLevelInfoToDefaults_Level(struct LevelInfo *level)
1683 li = *level; // copy level data into temporary buffer
1684 setConfigToDefaultsFromConfigList(chunk_config_INFO);
1685 *level = li; // copy temporary buffer back to level data
1687 setLevelInfoToDefaults_EM();
1688 setLevelInfoToDefaults_SP();
1689 setLevelInfoToDefaults_MM();
1691 level->native_em_level = &native_em_level;
1692 level->native_sp_level = &native_sp_level;
1693 level->native_mm_level = &native_mm_level;
1695 level->file_version = FILE_VERSION_ACTUAL;
1696 level->game_version = GAME_VERSION_ACTUAL;
1698 level->creation_date = getCurrentDate();
1700 level->encoding_16bit_field = TRUE;
1701 level->encoding_16bit_yamyam = TRUE;
1702 level->encoding_16bit_amoeba = TRUE;
1704 // clear level name and level author string buffers
1705 for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
1706 level->name[i] = '\0';
1707 for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
1708 level->author[i] = '\0';
1710 // set level name and level author to default values
1711 strcpy(level->name, NAMELESS_LEVEL_NAME);
1712 strcpy(level->author, ANONYMOUS_NAME);
1714 // set level playfield to playable default level with player and exit
1715 for (x = 0; x < MAX_LEV_FIELDX; x++)
1716 for (y = 0; y < MAX_LEV_FIELDY; y++)
1717 level->field[x][y] = EL_SAND;
1719 level->field[0][0] = EL_PLAYER_1;
1720 level->field[STD_LEV_FIELDX - 1][STD_LEV_FIELDY - 1] = EL_EXIT_CLOSED;
1722 BorderElement = EL_STEELWALL;
1724 // detect custom elements when loading them
1725 level->file_has_custom_elements = FALSE;
1727 // set all bug compatibility flags to "false" => do not emulate this bug
1728 level->use_action_after_change_bug = FALSE;
1730 if (leveldir_current)
1732 // try to determine better author name than 'anonymous'
1733 if (!strEqual(leveldir_current->author, ANONYMOUS_NAME))
1735 strncpy(level->author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN);
1736 level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
1740 switch (LEVELCLASS(leveldir_current))
1742 case LEVELCLASS_TUTORIAL:
1743 strcpy(level->author, PROGRAM_AUTHOR_STRING);
1746 case LEVELCLASS_CONTRIB:
1747 strncpy(level->author, leveldir_current->name, MAX_LEVEL_AUTHOR_LEN);
1748 level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
1751 case LEVELCLASS_PRIVATE:
1752 strncpy(level->author, getRealName(), MAX_LEVEL_AUTHOR_LEN);
1753 level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
1757 // keep default value
1764 static void setLevelInfoToDefaults_Elements(struct LevelInfo *level)
1766 static boolean clipboard_elements_initialized = FALSE;
1769 InitElementPropertiesStatic();
1771 li = *level; // copy level data into temporary buffer
1772 setConfigToDefaultsFromConfigList(chunk_config_ELEM);
1773 *level = li; // copy temporary buffer back to level data
1775 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1778 struct ElementInfo *ei = &element_info[element];
1780 // never initialize clipboard elements after the very first time
1781 // (to be able to use clipboard elements between several levels)
1782 if (IS_CLIPBOARD_ELEMENT(element) && clipboard_elements_initialized)
1785 if (IS_ENVELOPE(element))
1787 int envelope_nr = element - EL_ENVELOPE_1;
1789 setConfigToDefaultsFromConfigList(chunk_config_NOTE);
1791 level->envelope[envelope_nr] = xx_envelope;
1794 if (IS_CUSTOM_ELEMENT(element) ||
1795 IS_GROUP_ELEMENT(element) ||
1796 IS_INTERNAL_ELEMENT(element))
1798 xx_ei = *ei; // copy element data into temporary buffer
1800 setConfigToDefaultsFromConfigList(chunk_config_CUSX_base);
1805 setElementChangePages(ei, 1);
1806 setElementChangeInfoToDefaults(ei->change);
1808 if (IS_CUSTOM_ELEMENT(element) ||
1809 IS_GROUP_ELEMENT(element) ||
1810 IS_INTERNAL_ELEMENT(element))
1812 setElementDescriptionToDefault(ei);
1814 ei->modified_settings = FALSE;
1817 if (IS_CUSTOM_ELEMENT(element) ||
1818 IS_INTERNAL_ELEMENT(element))
1820 // internal values used in level editor
1822 ei->access_type = 0;
1823 ei->access_layer = 0;
1824 ei->access_protected = 0;
1825 ei->walk_to_action = 0;
1826 ei->smash_targets = 0;
1829 ei->can_explode_by_fire = FALSE;
1830 ei->can_explode_smashed = FALSE;
1831 ei->can_explode_impact = FALSE;
1833 ei->current_change_page = 0;
1836 if (IS_GROUP_ELEMENT(element) ||
1837 IS_INTERNAL_ELEMENT(element))
1839 struct ElementGroupInfo *group;
1841 // initialize memory for list of elements in group
1842 if (ei->group == NULL)
1843 ei->group = checked_malloc(sizeof(struct ElementGroupInfo));
1847 xx_group = *group; // copy group data into temporary buffer
1849 setConfigToDefaultsFromConfigList(chunk_config_GRPX);
1855 clipboard_elements_initialized = TRUE;
1858 static void setLevelInfoToDefaults(struct LevelInfo *level,
1859 boolean level_info_only,
1860 boolean reset_file_status)
1862 setLevelInfoToDefaults_Level(level);
1864 if (!level_info_only)
1865 setLevelInfoToDefaults_Elements(level);
1867 if (reset_file_status)
1869 level->no_valid_file = FALSE;
1870 level->no_level_file = FALSE;
1873 level->changed = FALSE;
1876 static void setFileInfoToDefaults(struct LevelFileInfo *level_file_info)
1878 level_file_info->nr = 0;
1879 level_file_info->type = LEVEL_FILE_TYPE_UNKNOWN;
1880 level_file_info->packed = FALSE;
1882 setString(&level_file_info->basename, NULL);
1883 setString(&level_file_info->filename, NULL);
1886 int getMappedElement_SB(int, boolean);
1888 static void ActivateLevelTemplate(void)
1892 if (check_special_flags("load_xsb_to_ces"))
1894 // fill smaller playfields with padding "beyond border wall" elements
1895 if (level.fieldx < level_template.fieldx ||
1896 level.fieldy < level_template.fieldy)
1898 short field[level.fieldx][level.fieldy];
1899 int new_fieldx = MAX(level.fieldx, level_template.fieldx);
1900 int new_fieldy = MAX(level.fieldy, level_template.fieldy);
1901 int pos_fieldx = (new_fieldx - level.fieldx) / 2;
1902 int pos_fieldy = (new_fieldy - level.fieldy) / 2;
1904 // copy old playfield (which is smaller than the visible area)
1905 for (y = 0; y < level.fieldy; y++) for (x = 0; x < level.fieldx; x++)
1906 field[x][y] = level.field[x][y];
1908 // fill new, larger playfield with "beyond border wall" elements
1909 for (y = 0; y < new_fieldy; y++) for (x = 0; x < new_fieldx; x++)
1910 level.field[x][y] = getMappedElement_SB('_', TRUE);
1912 // copy the old playfield to the middle of the new playfield
1913 for (y = 0; y < level.fieldy; y++) for (x = 0; x < level.fieldx; x++)
1914 level.field[pos_fieldx + x][pos_fieldy + y] = field[x][y];
1916 level.fieldx = new_fieldx;
1917 level.fieldy = new_fieldy;
1921 // Currently there is no special action needed to activate the template
1922 // data, because 'element_info' property settings overwrite the original
1923 // level data, while all other variables do not change.
1925 // Exception: 'from_level_template' elements in the original level playfield
1926 // are overwritten with the corresponding elements at the same position in
1927 // playfield from the level template.
1929 for (x = 0; x < level.fieldx; x++)
1930 for (y = 0; y < level.fieldy; y++)
1931 if (level.field[x][y] == EL_FROM_LEVEL_TEMPLATE)
1932 level.field[x][y] = level_template.field[x][y];
1934 if (check_special_flags("load_xsb_to_ces"))
1936 struct LevelInfo level_backup = level;
1938 // overwrite all individual level settings from template level settings
1939 level = level_template;
1941 // restore level file info
1942 level.file_info = level_backup.file_info;
1944 // restore playfield size
1945 level.fieldx = level_backup.fieldx;
1946 level.fieldy = level_backup.fieldy;
1948 // restore playfield content
1949 for (x = 0; x < level.fieldx; x++)
1950 for (y = 0; y < level.fieldy; y++)
1951 level.field[x][y] = level_backup.field[x][y];
1953 // restore name and author from individual level
1954 strcpy(level.name, level_backup.name);
1955 strcpy(level.author, level_backup.author);
1957 // restore flag "use_custom_template"
1958 level.use_custom_template = level_backup.use_custom_template;
1962 static char *getLevelFilenameFromBasename(char *basename)
1964 static char *filename = NULL;
1966 checked_free(filename);
1968 filename = getPath2(getCurrentLevelDir(), basename);
1973 static int getFileTypeFromBasename(char *basename)
1975 // !!! ALSO SEE COMMENT IN checkForPackageFromBasename() !!!
1977 static char *filename = NULL;
1978 struct stat file_status;
1980 // ---------- try to determine file type from filename ----------
1982 // check for typical filename of a Supaplex level package file
1983 if (strlen(basename) == 10 && strPrefixLower(basename, "levels.d"))
1984 return LEVEL_FILE_TYPE_SP;
1986 // check for typical filename of a Diamond Caves II level package file
1987 if (strSuffixLower(basename, ".dc") ||
1988 strSuffixLower(basename, ".dc2"))
1989 return LEVEL_FILE_TYPE_DC;
1991 // check for typical filename of a Sokoban level package file
1992 if (strSuffixLower(basename, ".xsb") &&
1993 strchr(basename, '%') == NULL)
1994 return LEVEL_FILE_TYPE_SB;
1996 // ---------- try to determine file type from filesize ----------
1998 checked_free(filename);
1999 filename = getPath2(getCurrentLevelDir(), basename);
2001 if (stat(filename, &file_status) == 0)
2003 // check for typical filesize of a Supaplex level package file
2004 if (file_status.st_size == 170496)
2005 return LEVEL_FILE_TYPE_SP;
2008 return LEVEL_FILE_TYPE_UNKNOWN;
2011 static int getFileTypeFromMagicBytes(char *filename, int type)
2015 if ((file = openFile(filename, MODE_READ)))
2017 char chunk_name[CHUNK_ID_LEN + 1];
2019 getFileChunkBE(file, chunk_name, NULL);
2021 if (strEqual(chunk_name, "MMII") ||
2022 strEqual(chunk_name, "MIRR"))
2023 type = LEVEL_FILE_TYPE_MM;
2031 static boolean checkForPackageFromBasename(char *basename)
2033 // !!! WON'T WORK ANYMORE IF getFileTypeFromBasename() ALSO DETECTS !!!
2034 // !!! SINGLE LEVELS (CURRENTLY ONLY DETECTS LEVEL PACKAGES !!!
2036 return (getFileTypeFromBasename(basename) != LEVEL_FILE_TYPE_UNKNOWN);
2039 static char *getSingleLevelBasenameExt(int nr, char *extension)
2041 static char basename[MAX_FILENAME_LEN];
2044 sprintf(basename, "%s", LEVELTEMPLATE_FILENAME);
2046 sprintf(basename, "%03d.%s", nr, extension);
2051 static char *getSingleLevelBasename(int nr)
2053 return getSingleLevelBasenameExt(nr, LEVELFILE_EXTENSION);
2056 static char *getPackedLevelBasename(int type)
2058 static char basename[MAX_FILENAME_LEN];
2059 char *directory = getCurrentLevelDir();
2061 DirectoryEntry *dir_entry;
2063 strcpy(basename, UNDEFINED_FILENAME); // default: undefined file
2065 if ((dir = openDirectory(directory)) == NULL)
2067 Error(ERR_WARN, "cannot read current level directory '%s'", directory);
2072 while ((dir_entry = readDirectory(dir)) != NULL) // loop all entries
2074 char *entry_basename = dir_entry->basename;
2075 int entry_type = getFileTypeFromBasename(entry_basename);
2077 if (entry_type != LEVEL_FILE_TYPE_UNKNOWN) // found valid level package
2079 if (type == LEVEL_FILE_TYPE_UNKNOWN ||
2082 strcpy(basename, entry_basename);
2089 closeDirectory(dir);
2094 static char *getSingleLevelFilename(int nr)
2096 return getLevelFilenameFromBasename(getSingleLevelBasename(nr));
2099 #if ENABLE_UNUSED_CODE
2100 static char *getPackedLevelFilename(int type)
2102 return getLevelFilenameFromBasename(getPackedLevelBasename(type));
2106 char *getDefaultLevelFilename(int nr)
2108 return getSingleLevelFilename(nr);
2111 #if ENABLE_UNUSED_CODE
2112 static void setLevelFileInfo_SingleLevelFilename(struct LevelFileInfo *lfi,
2116 lfi->packed = FALSE;
2118 setString(&lfi->basename, getSingleLevelBasename(lfi->nr, lfi->type));
2119 setString(&lfi->filename, getLevelFilenameFromBasename(lfi->basename));
2123 static void setLevelFileInfo_FormatLevelFilename(struct LevelFileInfo *lfi,
2124 int type, char *format, ...)
2126 static char basename[MAX_FILENAME_LEN];
2129 va_start(ap, format);
2130 vsprintf(basename, format, ap);
2134 lfi->packed = FALSE;
2136 setString(&lfi->basename, basename);
2137 setString(&lfi->filename, getLevelFilenameFromBasename(lfi->basename));
2140 static void setLevelFileInfo_PackedLevelFilename(struct LevelFileInfo *lfi,
2146 setString(&lfi->basename, getPackedLevelBasename(lfi->type));
2147 setString(&lfi->filename, getLevelFilenameFromBasename(lfi->basename));
2150 static int getFiletypeFromID(char *filetype_id)
2152 char *filetype_id_lower;
2153 int filetype = LEVEL_FILE_TYPE_UNKNOWN;
2156 if (filetype_id == NULL)
2157 return LEVEL_FILE_TYPE_UNKNOWN;
2159 filetype_id_lower = getStringToLower(filetype_id);
2161 for (i = 0; filetype_id_list[i].id != NULL; i++)
2163 char *id_lower = getStringToLower(filetype_id_list[i].id);
2165 if (strEqual(filetype_id_lower, id_lower))
2166 filetype = filetype_id_list[i].filetype;
2170 if (filetype != LEVEL_FILE_TYPE_UNKNOWN)
2174 free(filetype_id_lower);
2179 char *getLocalLevelTemplateFilename(void)
2181 return getDefaultLevelFilename(-1);
2184 char *getGlobalLevelTemplateFilename(void)
2186 // global variable "leveldir_current" must be modified in the loop below
2187 LevelDirTree *leveldir_current_last = leveldir_current;
2188 char *filename = NULL;
2190 // check for template level in path from current to topmost tree node
2192 while (leveldir_current != NULL)
2194 filename = getDefaultLevelFilename(-1);
2196 if (fileExists(filename))
2199 leveldir_current = leveldir_current->node_parent;
2202 // restore global variable "leveldir_current" modified in above loop
2203 leveldir_current = leveldir_current_last;
2208 static void determineLevelFileInfo_Filename(struct LevelFileInfo *lfi)
2212 // special case: level number is negative => check for level template file
2215 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
2216 getSingleLevelBasename(-1));
2218 // replace local level template filename with global template filename
2219 setString(&lfi->filename, getGlobalLevelTemplateFilename());
2221 // no fallback if template file not existing
2225 // special case: check for file name/pattern specified in "levelinfo.conf"
2226 if (leveldir_current->level_filename != NULL)
2228 int filetype = getFiletypeFromID(leveldir_current->level_filetype);
2230 setLevelFileInfo_FormatLevelFilename(lfi, filetype,
2231 leveldir_current->level_filename, nr);
2233 lfi->packed = checkForPackageFromBasename(leveldir_current->level_filename);
2235 if (fileExists(lfi->filename))
2238 else if (leveldir_current->level_filetype != NULL)
2240 int filetype = getFiletypeFromID(leveldir_current->level_filetype);
2242 // check for specified native level file with standard file name
2243 setLevelFileInfo_FormatLevelFilename(lfi, filetype,
2244 "%03d.%s", nr, LEVELFILE_EXTENSION);
2245 if (fileExists(lfi->filename))
2249 // check for native Rocks'n'Diamonds level file
2250 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
2251 "%03d.%s", nr, LEVELFILE_EXTENSION);
2252 if (fileExists(lfi->filename))
2255 // check for Emerald Mine level file (V1)
2256 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "a%c%c",
2257 'a' + (nr / 10) % 26, '0' + nr % 10);
2258 if (fileExists(lfi->filename))
2260 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "A%c%c",
2261 'A' + (nr / 10) % 26, '0' + nr % 10);
2262 if (fileExists(lfi->filename))
2265 // check for Emerald Mine level file (V2 to V5)
2266 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%d", nr);
2267 if (fileExists(lfi->filename))
2270 // check for Emerald Mine level file (V6 / single mode)
2271 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02ds", nr);
2272 if (fileExists(lfi->filename))
2274 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dS", nr);
2275 if (fileExists(lfi->filename))
2278 // check for Emerald Mine level file (V6 / teamwork mode)
2279 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dt", nr);
2280 if (fileExists(lfi->filename))
2282 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dT", nr);
2283 if (fileExists(lfi->filename))
2286 // check for various packed level file formats
2287 setLevelFileInfo_PackedLevelFilename(lfi, LEVEL_FILE_TYPE_UNKNOWN);
2288 if (fileExists(lfi->filename))
2291 // no known level file found -- use default values (and fail later)
2292 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
2293 "%03d.%s", nr, LEVELFILE_EXTENSION);
2296 static void determineLevelFileInfo_Filetype(struct LevelFileInfo *lfi)
2298 if (lfi->type == LEVEL_FILE_TYPE_UNKNOWN)
2299 lfi->type = getFileTypeFromBasename(lfi->basename);
2301 if (lfi->type == LEVEL_FILE_TYPE_RND)
2302 lfi->type = getFileTypeFromMagicBytes(lfi->filename, lfi->type);
2305 static void setLevelFileInfo(struct LevelFileInfo *level_file_info, int nr)
2307 // always start with reliable default values
2308 setFileInfoToDefaults(level_file_info);
2310 level_file_info->nr = nr; // set requested level number
2312 determineLevelFileInfo_Filename(level_file_info);
2313 determineLevelFileInfo_Filetype(level_file_info);
2316 static void copyLevelFileInfo(struct LevelFileInfo *lfi_from,
2317 struct LevelFileInfo *lfi_to)
2319 lfi_to->nr = lfi_from->nr;
2320 lfi_to->type = lfi_from->type;
2321 lfi_to->packed = lfi_from->packed;
2323 setString(&lfi_to->basename, lfi_from->basename);
2324 setString(&lfi_to->filename, lfi_from->filename);
2327 // ----------------------------------------------------------------------------
2328 // functions for loading R'n'D level
2329 // ----------------------------------------------------------------------------
2331 static int getMappedElement(int element)
2333 // remap some (historic, now obsolete) elements
2337 case EL_PLAYER_OBSOLETE:
2338 element = EL_PLAYER_1;
2341 case EL_KEY_OBSOLETE:
2345 case EL_EM_KEY_1_FILE_OBSOLETE:
2346 element = EL_EM_KEY_1;
2349 case EL_EM_KEY_2_FILE_OBSOLETE:
2350 element = EL_EM_KEY_2;
2353 case EL_EM_KEY_3_FILE_OBSOLETE:
2354 element = EL_EM_KEY_3;
2357 case EL_EM_KEY_4_FILE_OBSOLETE:
2358 element = EL_EM_KEY_4;
2361 case EL_ENVELOPE_OBSOLETE:
2362 element = EL_ENVELOPE_1;
2370 if (element >= NUM_FILE_ELEMENTS)
2372 Error(ERR_WARN, "invalid level element %d", element);
2374 element = EL_UNKNOWN;
2382 static int getMappedElementByVersion(int element, int game_version)
2384 // remap some elements due to certain game version
2386 if (game_version <= VERSION_IDENT(2,2,0,0))
2388 // map game font elements
2389 element = (element == EL_CHAR('[') ? EL_CHAR_AUMLAUT :
2390 element == EL_CHAR('\\') ? EL_CHAR_OUMLAUT :
2391 element == EL_CHAR(']') ? EL_CHAR_UUMLAUT :
2392 element == EL_CHAR('^') ? EL_CHAR_COPYRIGHT : element);
2395 if (game_version < VERSION_IDENT(3,0,0,0))
2397 // map Supaplex gravity tube elements
2398 element = (element == EL_SP_GRAVITY_PORT_LEFT ? EL_SP_PORT_LEFT :
2399 element == EL_SP_GRAVITY_PORT_RIGHT ? EL_SP_PORT_RIGHT :
2400 element == EL_SP_GRAVITY_PORT_UP ? EL_SP_PORT_UP :
2401 element == EL_SP_GRAVITY_PORT_DOWN ? EL_SP_PORT_DOWN :
2408 static int LoadLevel_VERS(File *file, int chunk_size, struct LevelInfo *level)
2410 level->file_version = getFileVersion(file);
2411 level->game_version = getFileVersion(file);
2416 static int LoadLevel_DATE(File *file, int chunk_size, struct LevelInfo *level)
2418 level->creation_date.year = getFile16BitBE(file);
2419 level->creation_date.month = getFile8Bit(file);
2420 level->creation_date.day = getFile8Bit(file);
2422 level->creation_date.src = DATE_SRC_LEVELFILE;
2427 static int LoadLevel_HEAD(File *file, int chunk_size, struct LevelInfo *level)
2429 int initial_player_stepsize;
2430 int initial_player_gravity;
2433 level->fieldx = getFile8Bit(file);
2434 level->fieldy = getFile8Bit(file);
2436 level->time = getFile16BitBE(file);
2437 level->gems_needed = getFile16BitBE(file);
2439 for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
2440 level->name[i] = getFile8Bit(file);
2441 level->name[MAX_LEVEL_NAME_LEN] = 0;
2443 for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
2444 level->score[i] = getFile8Bit(file);
2446 level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
2447 for (i = 0; i < STD_ELEMENT_CONTENTS; i++)
2448 for (y = 0; y < 3; y++)
2449 for (x = 0; x < 3; x++)
2450 level->yamyam_content[i].e[x][y] = getMappedElement(getFile8Bit(file));
2452 level->amoeba_speed = getFile8Bit(file);
2453 level->time_magic_wall = getFile8Bit(file);
2454 level->time_wheel = getFile8Bit(file);
2455 level->amoeba_content = getMappedElement(getFile8Bit(file));
2457 initial_player_stepsize = (getFile8Bit(file) == 1 ? STEPSIZE_FAST :
2460 for (i = 0; i < MAX_PLAYERS; i++)
2461 level->initial_player_stepsize[i] = initial_player_stepsize;
2463 initial_player_gravity = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2465 for (i = 0; i < MAX_PLAYERS; i++)
2466 level->initial_player_gravity[i] = initial_player_gravity;
2468 level->encoding_16bit_field = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2469 level->em_slippery_gems = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2471 level->use_custom_template = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2473 level->block_last_field = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2474 level->sp_block_last_field = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2475 level->can_move_into_acid_bits = getFile32BitBE(file);
2476 level->dont_collide_with_bits = getFile8Bit(file);
2478 level->use_spring_bug = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2479 level->use_step_counter = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2481 level->instant_relocation = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2482 level->can_pass_to_walkable = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2483 level->grow_into_diggable = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2485 level->game_engine_type = getFile8Bit(file);
2487 ReadUnusedBytesFromFile(file, LEVEL_CHUNK_HEAD_UNUSED);
2492 static int LoadLevel_NAME(File *file, int chunk_size, struct LevelInfo *level)
2496 for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
2497 level->name[i] = getFile8Bit(file);
2498 level->name[MAX_LEVEL_NAME_LEN] = 0;
2503 static int LoadLevel_AUTH(File *file, int chunk_size, struct LevelInfo *level)
2507 for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
2508 level->author[i] = getFile8Bit(file);
2509 level->author[MAX_LEVEL_AUTHOR_LEN] = 0;
2514 static int LoadLevel_BODY(File *file, int chunk_size, struct LevelInfo *level)
2517 int chunk_size_expected = level->fieldx * level->fieldy;
2519 /* Note: "chunk_size" was wrong before version 2.0 when elements are
2520 stored with 16-bit encoding (and should be twice as big then).
2521 Even worse, playfield data was stored 16-bit when only yamyam content
2522 contained 16-bit elements and vice versa. */
2524 if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
2525 chunk_size_expected *= 2;
2527 if (chunk_size_expected != chunk_size)
2529 ReadUnusedBytesFromFile(file, chunk_size);
2530 return chunk_size_expected;
2533 for (y = 0; y < level->fieldy; y++)
2534 for (x = 0; x < level->fieldx; x++)
2535 level->field[x][y] =
2536 getMappedElement(level->encoding_16bit_field ? getFile16BitBE(file) :
2541 static int LoadLevel_CONT(File *file, int chunk_size, struct LevelInfo *level)
2544 int header_size = 4;
2545 int content_size = MAX_ELEMENT_CONTENTS * 3 * 3;
2546 int chunk_size_expected = header_size + content_size;
2548 /* Note: "chunk_size" was wrong before version 2.0 when elements are
2549 stored with 16-bit encoding (and should be twice as big then).
2550 Even worse, playfield data was stored 16-bit when only yamyam content
2551 contained 16-bit elements and vice versa. */
2553 if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
2554 chunk_size_expected += content_size;
2556 if (chunk_size_expected != chunk_size)
2558 ReadUnusedBytesFromFile(file, chunk_size);
2559 return chunk_size_expected;
2563 level->num_yamyam_contents = getFile8Bit(file);
2567 // correct invalid number of content fields -- should never happen
2568 if (level->num_yamyam_contents < 1 ||
2569 level->num_yamyam_contents > MAX_ELEMENT_CONTENTS)
2570 level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
2572 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
2573 for (y = 0; y < 3; y++)
2574 for (x = 0; x < 3; x++)
2575 level->yamyam_content[i].e[x][y] =
2576 getMappedElement(level->encoding_16bit_field ?
2577 getFile16BitBE(file) : getFile8Bit(file));
2581 static int LoadLevel_CNT2(File *file, int chunk_size, struct LevelInfo *level)
2586 int content_array[MAX_ELEMENT_CONTENTS][3][3];
2588 element = getMappedElement(getFile16BitBE(file));
2589 num_contents = getFile8Bit(file);
2591 getFile8Bit(file); // content x size (unused)
2592 getFile8Bit(file); // content y size (unused)
2594 ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED);
2596 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
2597 for (y = 0; y < 3; y++)
2598 for (x = 0; x < 3; x++)
2599 content_array[i][x][y] = getMappedElement(getFile16BitBE(file));
2601 // correct invalid number of content fields -- should never happen
2602 if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS)
2603 num_contents = STD_ELEMENT_CONTENTS;
2605 if (element == EL_YAMYAM)
2607 level->num_yamyam_contents = num_contents;
2609 for (i = 0; i < num_contents; i++)
2610 for (y = 0; y < 3; y++)
2611 for (x = 0; x < 3; x++)
2612 level->yamyam_content[i].e[x][y] = content_array[i][x][y];
2614 else if (element == EL_BD_AMOEBA)
2616 level->amoeba_content = content_array[0][0][0];
2620 Error(ERR_WARN, "cannot load content for element '%d'", element);
2626 static int LoadLevel_CNT3(File *file, int chunk_size, struct LevelInfo *level)
2632 int chunk_size_expected;
2634 element = getMappedElement(getFile16BitBE(file));
2635 if (!IS_ENVELOPE(element))
2636 element = EL_ENVELOPE_1;
2638 envelope_nr = element - EL_ENVELOPE_1;
2640 envelope_len = getFile16BitBE(file);
2642 level->envelope[envelope_nr].xsize = getFile8Bit(file);
2643 level->envelope[envelope_nr].ysize = getFile8Bit(file);
2645 ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT3_UNUSED);
2647 chunk_size_expected = LEVEL_CHUNK_CNT3_SIZE(envelope_len);
2648 if (chunk_size_expected != chunk_size)
2650 ReadUnusedBytesFromFile(file, chunk_size - LEVEL_CHUNK_CNT3_HEADER);
2651 return chunk_size_expected;
2654 for (i = 0; i < envelope_len; i++)
2655 level->envelope[envelope_nr].text[i] = getFile8Bit(file);
2660 static int LoadLevel_CUS1(File *file, int chunk_size, struct LevelInfo *level)
2662 int num_changed_custom_elements = getFile16BitBE(file);
2663 int chunk_size_expected = 2 + num_changed_custom_elements * 6;
2666 if (chunk_size_expected != chunk_size)
2668 ReadUnusedBytesFromFile(file, chunk_size - 2);
2669 return chunk_size_expected;
2672 for (i = 0; i < num_changed_custom_elements; i++)
2674 int element = getMappedElement(getFile16BitBE(file));
2675 int properties = getFile32BitBE(file);
2677 if (IS_CUSTOM_ELEMENT(element))
2678 element_info[element].properties[EP_BITFIELD_BASE_NR] = properties;
2680 Error(ERR_WARN, "invalid custom element number %d", element);
2682 // older game versions that wrote level files with CUS1 chunks used
2683 // different default push delay values (not yet stored in level file)
2684 element_info[element].push_delay_fixed = 2;
2685 element_info[element].push_delay_random = 8;
2688 level->file_has_custom_elements = TRUE;
2693 static int LoadLevel_CUS2(File *file, int chunk_size, struct LevelInfo *level)
2695 int num_changed_custom_elements = getFile16BitBE(file);
2696 int chunk_size_expected = 2 + num_changed_custom_elements * 4;
2699 if (chunk_size_expected != chunk_size)
2701 ReadUnusedBytesFromFile(file, chunk_size - 2);
2702 return chunk_size_expected;
2705 for (i = 0; i < num_changed_custom_elements; i++)
2707 int element = getMappedElement(getFile16BitBE(file));
2708 int custom_target_element = getMappedElement(getFile16BitBE(file));
2710 if (IS_CUSTOM_ELEMENT(element))
2711 element_info[element].change->target_element = custom_target_element;
2713 Error(ERR_WARN, "invalid custom element number %d", element);
2716 level->file_has_custom_elements = TRUE;
2721 static int LoadLevel_CUS3(File *file, int chunk_size, struct LevelInfo *level)
2723 int num_changed_custom_elements = getFile16BitBE(file);
2724 int chunk_size_expected = LEVEL_CHUNK_CUS3_SIZE(num_changed_custom_elements);
2727 if (chunk_size_expected != chunk_size)
2729 ReadUnusedBytesFromFile(file, chunk_size - 2);
2730 return chunk_size_expected;
2733 for (i = 0; i < num_changed_custom_elements; i++)
2735 int element = getMappedElement(getFile16BitBE(file));
2736 struct ElementInfo *ei = &element_info[element];
2737 unsigned int event_bits;
2739 if (!IS_CUSTOM_ELEMENT(element))
2741 Error(ERR_WARN, "invalid custom element number %d", element);
2743 element = EL_INTERNAL_DUMMY;
2746 for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++)
2747 ei->description[j] = getFile8Bit(file);
2748 ei->description[MAX_ELEMENT_NAME_LEN] = 0;
2750 ei->properties[EP_BITFIELD_BASE_NR] = getFile32BitBE(file);
2752 // some free bytes for future properties and padding
2753 ReadUnusedBytesFromFile(file, 7);
2755 ei->use_gfx_element = getFile8Bit(file);
2756 ei->gfx_element_initial = getMappedElement(getFile16BitBE(file));
2758 ei->collect_score_initial = getFile8Bit(file);
2759 ei->collect_count_initial = getFile8Bit(file);
2761 ei->push_delay_fixed = getFile16BitBE(file);
2762 ei->push_delay_random = getFile16BitBE(file);
2763 ei->move_delay_fixed = getFile16BitBE(file);
2764 ei->move_delay_random = getFile16BitBE(file);
2766 ei->move_pattern = getFile16BitBE(file);
2767 ei->move_direction_initial = getFile8Bit(file);
2768 ei->move_stepsize = getFile8Bit(file);
2770 for (y = 0; y < 3; y++)
2771 for (x = 0; x < 3; x++)
2772 ei->content.e[x][y] = getMappedElement(getFile16BitBE(file));
2774 event_bits = getFile32BitBE(file);
2775 for (j = 0; j < NUM_CHANGE_EVENTS; j++)
2776 if (event_bits & (1 << j))
2777 ei->change->has_event[j] = TRUE;
2779 ei->change->target_element = getMappedElement(getFile16BitBE(file));
2781 ei->change->delay_fixed = getFile16BitBE(file);
2782 ei->change->delay_random = getFile16BitBE(file);
2783 ei->change->delay_frames = getFile16BitBE(file);
2785 ei->change->initial_trigger_element= getMappedElement(getFile16BitBE(file));
2787 ei->change->explode = getFile8Bit(file);
2788 ei->change->use_target_content = getFile8Bit(file);
2789 ei->change->only_if_complete = getFile8Bit(file);
2790 ei->change->use_random_replace = getFile8Bit(file);
2792 ei->change->random_percentage = getFile8Bit(file);
2793 ei->change->replace_when = getFile8Bit(file);
2795 for (y = 0; y < 3; y++)
2796 for (x = 0; x < 3; x++)
2797 ei->change->target_content.e[x][y] =
2798 getMappedElement(getFile16BitBE(file));
2800 ei->slippery_type = getFile8Bit(file);
2802 // some free bytes for future properties and padding
2803 ReadUnusedBytesFromFile(file, LEVEL_CPART_CUS3_UNUSED);
2805 // mark that this custom element has been modified
2806 ei->modified_settings = TRUE;
2809 level->file_has_custom_elements = TRUE;
2814 static int LoadLevel_CUS4(File *file, int chunk_size, struct LevelInfo *level)
2816 struct ElementInfo *ei;
2817 int chunk_size_expected;
2821 // ---------- custom element base property values (96 bytes) ----------------
2823 element = getMappedElement(getFile16BitBE(file));
2825 if (!IS_CUSTOM_ELEMENT(element))
2827 Error(ERR_WARN, "invalid custom element number %d", element);
2829 ReadUnusedBytesFromFile(file, chunk_size - 2);
2833 ei = &element_info[element];
2835 for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
2836 ei->description[i] = getFile8Bit(file);
2837 ei->description[MAX_ELEMENT_NAME_LEN] = 0;
2839 ei->properties[EP_BITFIELD_BASE_NR] = getFile32BitBE(file);
2841 ReadUnusedBytesFromFile(file, 4); // reserved for more base properties
2843 ei->num_change_pages = getFile8Bit(file);
2845 chunk_size_expected = LEVEL_CHUNK_CUS4_SIZE(ei->num_change_pages);
2846 if (chunk_size_expected != chunk_size)
2848 ReadUnusedBytesFromFile(file, chunk_size - 43);
2849 return chunk_size_expected;
2852 ei->ce_value_fixed_initial = getFile16BitBE(file);
2853 ei->ce_value_random_initial = getFile16BitBE(file);
2854 ei->use_last_ce_value = getFile8Bit(file);
2856 ei->use_gfx_element = getFile8Bit(file);
2857 ei->gfx_element_initial = getMappedElement(getFile16BitBE(file));
2859 ei->collect_score_initial = getFile8Bit(file);
2860 ei->collect_count_initial = getFile8Bit(file);
2862 ei->drop_delay_fixed = getFile8Bit(file);
2863 ei->push_delay_fixed = getFile8Bit(file);
2864 ei->drop_delay_random = getFile8Bit(file);
2865 ei->push_delay_random = getFile8Bit(file);
2866 ei->move_delay_fixed = getFile16BitBE(file);
2867 ei->move_delay_random = getFile16BitBE(file);
2869 // bits 0 - 15 of "move_pattern" ...
2870 ei->move_pattern = getFile16BitBE(file);
2871 ei->move_direction_initial = getFile8Bit(file);
2872 ei->move_stepsize = getFile8Bit(file);
2874 ei->slippery_type = getFile8Bit(file);
2876 for (y = 0; y < 3; y++)
2877 for (x = 0; x < 3; x++)
2878 ei->content.e[x][y] = getMappedElement(getFile16BitBE(file));
2880 ei->move_enter_element = getMappedElement(getFile16BitBE(file));
2881 ei->move_leave_element = getMappedElement(getFile16BitBE(file));
2882 ei->move_leave_type = getFile8Bit(file);
2884 // ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible)
2885 ei->move_pattern |= (getFile16BitBE(file) << 16);
2887 ei->access_direction = getFile8Bit(file);
2889 ei->explosion_delay = getFile8Bit(file);
2890 ei->ignition_delay = getFile8Bit(file);
2891 ei->explosion_type = getFile8Bit(file);
2893 // some free bytes for future custom property values and padding
2894 ReadUnusedBytesFromFile(file, 1);
2896 // ---------- change page property values (48 bytes) ------------------------
2898 setElementChangePages(ei, ei->num_change_pages);
2900 for (i = 0; i < ei->num_change_pages; i++)
2902 struct ElementChangeInfo *change = &ei->change_page[i];
2903 unsigned int event_bits;
2905 // always start with reliable default values
2906 setElementChangeInfoToDefaults(change);
2908 // bits 0 - 31 of "has_event[]" ...
2909 event_bits = getFile32BitBE(file);
2910 for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
2911 if (event_bits & (1 << j))
2912 change->has_event[j] = TRUE;
2914 change->target_element = getMappedElement(getFile16BitBE(file));
2916 change->delay_fixed = getFile16BitBE(file);
2917 change->delay_random = getFile16BitBE(file);
2918 change->delay_frames = getFile16BitBE(file);
2920 change->initial_trigger_element = getMappedElement(getFile16BitBE(file));
2922 change->explode = getFile8Bit(file);
2923 change->use_target_content = getFile8Bit(file);
2924 change->only_if_complete = getFile8Bit(file);
2925 change->use_random_replace = getFile8Bit(file);
2927 change->random_percentage = getFile8Bit(file);
2928 change->replace_when = getFile8Bit(file);
2930 for (y = 0; y < 3; y++)
2931 for (x = 0; x < 3; x++)
2932 change->target_content.e[x][y]= getMappedElement(getFile16BitBE(file));
2934 change->can_change = getFile8Bit(file);
2936 change->trigger_side = getFile8Bit(file);
2938 change->trigger_player = getFile8Bit(file);
2939 change->trigger_page = getFile8Bit(file);
2941 change->trigger_page = (change->trigger_page == CH_PAGE_ANY_FILE ?
2942 CH_PAGE_ANY : (1 << change->trigger_page));
2944 change->has_action = getFile8Bit(file);
2945 change->action_type = getFile8Bit(file);
2946 change->action_mode = getFile8Bit(file);
2947 change->action_arg = getFile16BitBE(file);
2949 // ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible)
2950 event_bits = getFile8Bit(file);
2951 for (j = 32; j < NUM_CHANGE_EVENTS; j++)
2952 if (event_bits & (1 << (j - 32)))
2953 change->has_event[j] = TRUE;
2956 // mark this custom element as modified
2957 ei->modified_settings = TRUE;
2959 level->file_has_custom_elements = TRUE;
2964 static int LoadLevel_GRP1(File *file, int chunk_size, struct LevelInfo *level)
2966 struct ElementInfo *ei;
2967 struct ElementGroupInfo *group;
2971 element = getMappedElement(getFile16BitBE(file));
2973 if (!IS_GROUP_ELEMENT(element))
2975 Error(ERR_WARN, "invalid group element number %d", element);
2977 ReadUnusedBytesFromFile(file, chunk_size - 2);
2981 ei = &element_info[element];
2983 for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
2984 ei->description[i] = getFile8Bit(file);
2985 ei->description[MAX_ELEMENT_NAME_LEN] = 0;
2987 group = element_info[element].group;
2989 group->num_elements = getFile8Bit(file);
2991 ei->use_gfx_element = getFile8Bit(file);
2992 ei->gfx_element_initial = getMappedElement(getFile16BitBE(file));
2994 group->choice_mode = getFile8Bit(file);
2996 // some free bytes for future values and padding
2997 ReadUnusedBytesFromFile(file, 3);
2999 for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
3000 group->element[i] = getMappedElement(getFile16BitBE(file));
3002 // mark this group element as modified
3003 element_info[element].modified_settings = TRUE;
3005 level->file_has_custom_elements = TRUE;
3010 static int LoadLevel_MicroChunk(File *file, struct LevelFileConfigInfo *conf,
3011 int element, int real_element)
3013 int micro_chunk_size = 0;
3014 int conf_type = getFile8Bit(file);
3015 int byte_mask = conf_type & CONF_MASK_BYTES;
3016 boolean element_found = FALSE;
3019 micro_chunk_size += 1;
3021 if (byte_mask == CONF_MASK_MULTI_BYTES)
3023 int num_bytes = getFile16BitBE(file);
3024 byte *buffer = checked_malloc(num_bytes);
3026 ReadBytesFromFile(file, buffer, num_bytes);
3028 for (i = 0; conf[i].data_type != -1; i++)
3030 if (conf[i].element == element &&
3031 conf[i].conf_type == conf_type)
3033 int data_type = conf[i].data_type;
3034 int num_entities = num_bytes / CONF_ENTITY_NUM_BYTES(data_type);
3035 int max_num_entities = conf[i].max_num_entities;
3037 if (num_entities > max_num_entities)
3040 "truncating number of entities for element %d from %d to %d",
3041 element, num_entities, max_num_entities);
3043 num_entities = max_num_entities;
3046 if (num_entities == 0 && (data_type == TYPE_ELEMENT_LIST ||
3047 data_type == TYPE_CONTENT_LIST))
3049 // for element and content lists, zero entities are not allowed
3050 Error(ERR_WARN, "found empty list of entities for element %d",
3053 // do not set "num_entities" here to prevent reading behind buffer
3055 *(int *)(conf[i].num_entities) = 1; // at least one is required
3059 *(int *)(conf[i].num_entities) = num_entities;
3062 element_found = TRUE;
3064 if (data_type == TYPE_STRING)
3066 char *string = (char *)(conf[i].value);
3069 for (j = 0; j < max_num_entities; j++)
3070 string[j] = (j < num_entities ? buffer[j] : '\0');
3072 else if (data_type == TYPE_ELEMENT_LIST)
3074 int *element_array = (int *)(conf[i].value);
3077 for (j = 0; j < num_entities; j++)
3079 getMappedElement(CONF_ELEMENTS_ELEMENT(buffer, j));
3081 else if (data_type == TYPE_CONTENT_LIST)
3083 struct Content *content= (struct Content *)(conf[i].value);
3086 for (c = 0; c < num_entities; c++)
3087 for (y = 0; y < 3; y++)
3088 for (x = 0; x < 3; x++)
3089 content[c].e[x][y] =
3090 getMappedElement(CONF_CONTENTS_ELEMENT(buffer, c, x, y));
3093 element_found = FALSE;
3099 checked_free(buffer);
3101 micro_chunk_size += 2 + num_bytes;
3103 else // constant size configuration data (1, 2 or 4 bytes)
3105 int value = (byte_mask == CONF_MASK_1_BYTE ? getFile8Bit (file) :
3106 byte_mask == CONF_MASK_2_BYTE ? getFile16BitBE(file) :
3107 byte_mask == CONF_MASK_4_BYTE ? getFile32BitBE(file) : 0);
3109 for (i = 0; conf[i].data_type != -1; i++)
3111 if (conf[i].element == element &&
3112 conf[i].conf_type == conf_type)
3114 int data_type = conf[i].data_type;
3116 if (data_type == TYPE_ELEMENT)
3117 value = getMappedElement(value);
3119 if (data_type == TYPE_BOOLEAN)
3120 *(boolean *)(conf[i].value) = value;
3122 *(int *) (conf[i].value) = value;
3124 element_found = TRUE;
3130 micro_chunk_size += CONF_VALUE_NUM_BYTES(byte_mask);
3135 char *error_conf_chunk_bytes =
3136 (byte_mask == CONF_MASK_1_BYTE ? "CONF_VALUE_8_BIT" :
3137 byte_mask == CONF_MASK_2_BYTE ? "CONF_VALUE_16_BIT" :
3138 byte_mask == CONF_MASK_4_BYTE ? "CONF_VALUE_32_BIT" :"CONF_VALUE_BYTES");
3139 int error_conf_chunk_token = conf_type & CONF_MASK_TOKEN;
3140 int error_element = real_element;
3142 Error(ERR_WARN, "cannot load micro chunk '%s(%d)' value for element %d ['%s']",
3143 error_conf_chunk_bytes, error_conf_chunk_token,
3144 error_element, EL_NAME(error_element));
3147 return micro_chunk_size;
3150 static int LoadLevel_INFO(File *file, int chunk_size, struct LevelInfo *level)
3152 int real_chunk_size = 0;
3154 li = *level; // copy level data into temporary buffer
3156 while (!checkEndOfFile(file))
3158 real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_INFO, -1, -1);
3160 if (real_chunk_size >= chunk_size)
3164 *level = li; // copy temporary buffer back to level data
3166 return real_chunk_size;
3169 static int LoadLevel_CONF(File *file, int chunk_size, struct LevelInfo *level)
3171 int real_chunk_size = 0;
3173 li = *level; // copy level data into temporary buffer
3175 while (!checkEndOfFile(file))
3177 int element = getMappedElement(getFile16BitBE(file));
3179 real_chunk_size += 2;
3180 real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CONF,
3182 if (real_chunk_size >= chunk_size)
3186 *level = li; // copy temporary buffer back to level data
3188 return real_chunk_size;
3191 static int LoadLevel_ELEM(File *file, int chunk_size, struct LevelInfo *level)
3193 int real_chunk_size = 0;
3195 li = *level; // copy level data into temporary buffer
3197 while (!checkEndOfFile(file))
3199 int element = getMappedElement(getFile16BitBE(file));
3201 real_chunk_size += 2;
3202 real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_ELEM,
3204 if (real_chunk_size >= chunk_size)
3208 *level = li; // copy temporary buffer back to level data
3210 return real_chunk_size;
3213 static int LoadLevel_NOTE(File *file, int chunk_size, struct LevelInfo *level)
3215 int element = getMappedElement(getFile16BitBE(file));
3216 int envelope_nr = element - EL_ENVELOPE_1;
3217 int real_chunk_size = 2;
3219 xx_envelope = level->envelope[envelope_nr]; // copy into temporary buffer
3221 while (!checkEndOfFile(file))
3223 real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_NOTE,
3226 if (real_chunk_size >= chunk_size)
3230 level->envelope[envelope_nr] = xx_envelope; // copy from temporary buffer
3232 return real_chunk_size;
3235 static int LoadLevel_CUSX(File *file, int chunk_size, struct LevelInfo *level)
3237 int element = getMappedElement(getFile16BitBE(file));
3238 int real_chunk_size = 2;
3239 struct ElementInfo *ei = &element_info[element];
3242 xx_ei = *ei; // copy element data into temporary buffer
3244 xx_ei.num_change_pages = -1;
3246 while (!checkEndOfFile(file))
3248 real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CUSX_base,
3250 if (xx_ei.num_change_pages != -1)
3253 if (real_chunk_size >= chunk_size)
3259 if (ei->num_change_pages == -1)
3261 Error(ERR_WARN, "LoadLevel_CUSX(): missing 'num_change_pages' for '%s'",
3264 ei->num_change_pages = 1;
3266 setElementChangePages(ei, 1);
3267 setElementChangeInfoToDefaults(ei->change);
3269 return real_chunk_size;
3272 // initialize number of change pages stored for this custom element
3273 setElementChangePages(ei, ei->num_change_pages);
3274 for (i = 0; i < ei->num_change_pages; i++)
3275 setElementChangeInfoToDefaults(&ei->change_page[i]);
3277 // start with reading properties for the first change page
3278 xx_current_change_page = 0;
3280 while (!checkEndOfFile(file))
3282 struct ElementChangeInfo *change = &ei->change_page[xx_current_change_page];
3284 xx_change = *change; // copy change data into temporary buffer
3286 resetEventBits(); // reset bits; change page might have changed
3288 real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CUSX_change,
3291 *change = xx_change;
3293 setEventFlagsFromEventBits(change);
3295 if (real_chunk_size >= chunk_size)
3299 level->file_has_custom_elements = TRUE;
3301 return real_chunk_size;
3304 static int LoadLevel_GRPX(File *file, int chunk_size, struct LevelInfo *level)
3306 int element = getMappedElement(getFile16BitBE(file));
3307 int real_chunk_size = 2;
3308 struct ElementInfo *ei = &element_info[element];
3309 struct ElementGroupInfo *group = ei->group;
3311 xx_ei = *ei; // copy element data into temporary buffer
3312 xx_group = *group; // copy group data into temporary buffer
3314 while (!checkEndOfFile(file))
3316 real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_GRPX,
3319 if (real_chunk_size >= chunk_size)
3326 level->file_has_custom_elements = TRUE;
3328 return real_chunk_size;
3331 static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
3332 struct LevelFileInfo *level_file_info,
3333 boolean level_info_only)
3335 char *filename = level_file_info->filename;
3336 char cookie[MAX_LINE_LEN];
3337 char chunk_name[CHUNK_ID_LEN + 1];
3341 if (!(file = openFile(filename, MODE_READ)))
3343 level->no_valid_file = TRUE;
3344 level->no_level_file = TRUE;
3346 if (level_info_only)
3349 Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
3351 if (!setup.editor.use_template_for_new_levels)
3354 // if level file not found, try to initialize level data from template
3355 filename = getGlobalLevelTemplateFilename();
3357 if (!(file = openFile(filename, MODE_READ)))
3360 // default: for empty levels, use level template for custom elements
3361 level->use_custom_template = TRUE;
3363 level->no_valid_file = FALSE;
3366 getFileChunkBE(file, chunk_name, NULL);
3367 if (strEqual(chunk_name, "RND1"))
3369 getFile32BitBE(file); // not used
3371 getFileChunkBE(file, chunk_name, NULL);
3372 if (!strEqual(chunk_name, "CAVE"))
3374 level->no_valid_file = TRUE;
3376 Error(ERR_WARN, "unknown format of level file '%s'", filename);
3383 else // check for pre-2.0 file format with cookie string
3385 strcpy(cookie, chunk_name);
3386 if (getStringFromFile(file, &cookie[4], MAX_LINE_LEN - 4) == NULL)
3388 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
3389 cookie[strlen(cookie) - 1] = '\0';
3391 if (!checkCookieString(cookie, LEVEL_COOKIE_TMPL))
3393 level->no_valid_file = TRUE;
3395 Error(ERR_WARN, "unknown format of level file '%s'", filename);
3402 if ((level->file_version = getFileVersionFromCookieString(cookie)) == -1)
3404 level->no_valid_file = TRUE;
3406 Error(ERR_WARN, "unsupported version of level file '%s'", filename);
3413 // pre-2.0 level files have no game version, so use file version here
3414 level->game_version = level->file_version;
3417 if (level->file_version < FILE_VERSION_1_2)
3419 // level files from versions before 1.2.0 without chunk structure
3420 LoadLevel_HEAD(file, LEVEL_CHUNK_HEAD_SIZE, level);
3421 LoadLevel_BODY(file, level->fieldx * level->fieldy, level);
3429 int (*loader)(File *, int, struct LevelInfo *);
3433 { "VERS", LEVEL_CHUNK_VERS_SIZE, LoadLevel_VERS },
3434 { "DATE", LEVEL_CHUNK_DATE_SIZE, LoadLevel_DATE },
3435 { "HEAD", LEVEL_CHUNK_HEAD_SIZE, LoadLevel_HEAD },
3436 { "NAME", LEVEL_CHUNK_NAME_SIZE, LoadLevel_NAME },
3437 { "AUTH", LEVEL_CHUNK_AUTH_SIZE, LoadLevel_AUTH },
3438 { "INFO", -1, LoadLevel_INFO },
3439 { "BODY", -1, LoadLevel_BODY },
3440 { "CONT", -1, LoadLevel_CONT },
3441 { "CNT2", LEVEL_CHUNK_CNT2_SIZE, LoadLevel_CNT2 },
3442 { "CNT3", -1, LoadLevel_CNT3 },
3443 { "CUS1", -1, LoadLevel_CUS1 },
3444 { "CUS2", -1, LoadLevel_CUS2 },
3445 { "CUS3", -1, LoadLevel_CUS3 },
3446 { "CUS4", -1, LoadLevel_CUS4 },
3447 { "GRP1", -1, LoadLevel_GRP1 },
3448 { "CONF", -1, LoadLevel_CONF },
3449 { "ELEM", -1, LoadLevel_ELEM },
3450 { "NOTE", -1, LoadLevel_NOTE },
3451 { "CUSX", -1, LoadLevel_CUSX },
3452 { "GRPX", -1, LoadLevel_GRPX },
3457 while (getFileChunkBE(file, chunk_name, &chunk_size))
3461 while (chunk_info[i].name != NULL &&
3462 !strEqual(chunk_name, chunk_info[i].name))
3465 if (chunk_info[i].name == NULL)
3467 Error(ERR_WARN, "unknown chunk '%s' in level file '%s'",
3468 chunk_name, filename);
3469 ReadUnusedBytesFromFile(file, chunk_size);
3471 else if (chunk_info[i].size != -1 &&
3472 chunk_info[i].size != chunk_size)
3474 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
3475 chunk_size, chunk_name, filename);
3476 ReadUnusedBytesFromFile(file, chunk_size);
3480 // call function to load this level chunk
3481 int chunk_size_expected =
3482 (chunk_info[i].loader)(file, chunk_size, level);
3484 // the size of some chunks cannot be checked before reading other
3485 // chunks first (like "HEAD" and "BODY") that contain some header
3486 // information, so check them here
3487 if (chunk_size_expected != chunk_size)
3489 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
3490 chunk_size, chunk_name, filename);
3500 // ----------------------------------------------------------------------------
3501 // functions for loading EM level
3502 // ----------------------------------------------------------------------------
3504 static void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
3506 static int ball_xy[8][2] =
3517 struct LevelInfo_EM *level_em = level->native_em_level;
3518 struct LEVEL *lev = level_em->lev;
3519 struct PLAYER **ply = level_em->ply;
3522 lev->width = MIN(level->fieldx, EM_MAX_CAVE_WIDTH);
3523 lev->height = MIN(level->fieldy, EM_MAX_CAVE_HEIGHT);
3525 lev->time_seconds = level->time;
3526 lev->required_initial = level->gems_needed;
3528 lev->emerald_score = level->score[SC_EMERALD];
3529 lev->diamond_score = level->score[SC_DIAMOND];
3530 lev->alien_score = level->score[SC_ROBOT];
3531 lev->tank_score = level->score[SC_SPACESHIP];
3532 lev->bug_score = level->score[SC_BUG];
3533 lev->eater_score = level->score[SC_YAMYAM];
3534 lev->nut_score = level->score[SC_NUT];
3535 lev->dynamite_score = level->score[SC_DYNAMITE];
3536 lev->key_score = level->score[SC_KEY];
3537 lev->exit_score = level->score[SC_TIME_BONUS];
3539 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3540 for (y = 0; y < 3; y++)
3541 for (x = 0; x < 3; x++)
3542 lev->eater_array[i][y * 3 + x] =
3543 map_element_RND_to_EM(level->yamyam_content[i].e[x][y]);
3545 lev->amoeba_time = level->amoeba_speed;
3546 lev->wonderwall_time_initial = level->time_magic_wall;
3547 lev->wheel_time = level->time_wheel;
3549 lev->android_move_time = level->android_move_time;
3550 lev->android_clone_time = level->android_clone_time;
3551 lev->ball_random = level->ball_random;
3552 lev->ball_state_initial = level->ball_state_initial;
3553 lev->ball_time = level->ball_time;
3554 lev->num_ball_arrays = level->num_ball_contents;
3556 lev->lenses_score = level->lenses_score;
3557 lev->magnify_score = level->magnify_score;
3558 lev->slurp_score = level->slurp_score;
3560 lev->lenses_time = level->lenses_time;
3561 lev->magnify_time = level->magnify_time;
3563 lev->wind_direction_initial =
3564 map_direction_RND_to_EM(level->wind_direction_initial);
3565 lev->wind_cnt_initial = (level->wind_direction_initial != MV_NONE ?
3566 lev->wind_time : 0);
3568 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3569 for (j = 0; j < 8; j++)
3570 lev->ball_array[i][j] =
3571 map_element_RND_to_EM(level->
3572 ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
3574 map_android_clone_elements_RND_to_EM(level);
3576 // first fill the complete playfield with the default border element
3577 for (y = 0; y < EM_MAX_CAVE_HEIGHT; y++)
3578 for (x = 0; x < EM_MAX_CAVE_WIDTH; x++)
3579 level_em->cave[x][y] = ZBORDER;
3581 if (BorderElement == EL_STEELWALL)
3583 for (y = 0; y < lev->height + 2; y++)
3584 for (x = 0; x < lev->width + 2; x++)
3585 level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_STEELWALL);
3588 // then copy the real level contents from level file into the playfield
3589 for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
3591 int new_element = map_element_RND_to_EM(level->field[x][y]);
3592 int offset = (BorderElement == EL_STEELWALL ? 1 : 0);
3593 int xx = x + 1 + offset;
3594 int yy = y + 1 + offset;
3596 if (level->field[x][y] == EL_AMOEBA_DEAD)
3597 new_element = map_element_RND_to_EM(EL_AMOEBA_WET);
3599 level_em->cave[xx][yy] = new_element;
3602 for (i = 0; i < MAX_PLAYERS; i++)
3604 ply[i]->x_initial = 0;
3605 ply[i]->y_initial = 0;
3608 // initialize player positions and delete players from the playfield
3609 for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
3611 if (ELEM_IS_PLAYER(level->field[x][y]))
3613 int player_nr = GET_PLAYER_NR(level->field[x][y]);
3614 int offset = (BorderElement == EL_STEELWALL ? 1 : 0);
3615 int xx = x + 1 + offset;
3616 int yy = y + 1 + offset;
3618 ply[player_nr]->x_initial = xx;
3619 ply[player_nr]->y_initial = yy;
3621 level_em->cave[xx][yy] = map_element_RND_to_EM(EL_EMPTY);
3625 if (BorderElement == EL_STEELWALL)
3632 static void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
3634 static int ball_xy[8][2] =
3645 struct LevelInfo_EM *level_em = level->native_em_level;
3646 struct LEVEL *lev = level_em->lev;
3647 struct PLAYER **ply = level_em->ply;
3650 level->fieldx = MIN(lev->width, MAX_LEV_FIELDX);
3651 level->fieldy = MIN(lev->height, MAX_LEV_FIELDY);
3653 level->time = lev->time_seconds;
3654 level->gems_needed = lev->required_initial;
3656 sprintf(level->name, "Level %d", level->file_info.nr);
3658 level->score[SC_EMERALD] = lev->emerald_score;
3659 level->score[SC_DIAMOND] = lev->diamond_score;
3660 level->score[SC_ROBOT] = lev->alien_score;
3661 level->score[SC_SPACESHIP] = lev->tank_score;
3662 level->score[SC_BUG] = lev->bug_score;
3663 level->score[SC_YAMYAM] = lev->eater_score;
3664 level->score[SC_NUT] = lev->nut_score;
3665 level->score[SC_DYNAMITE] = lev->dynamite_score;
3666 level->score[SC_KEY] = lev->key_score;
3667 level->score[SC_TIME_BONUS] = lev->exit_score;
3669 level->num_yamyam_contents = MAX_ELEMENT_CONTENTS;
3671 for (i = 0; i < level->num_yamyam_contents; i++)
3672 for (y = 0; y < 3; y++)
3673 for (x = 0; x < 3; x++)
3674 level->yamyam_content[i].e[x][y] =
3675 map_element_EM_to_RND(lev->eater_array[i][y * 3 + x]);
3677 level->amoeba_speed = lev->amoeba_time;
3678 level->time_magic_wall = lev->wonderwall_time_initial;
3679 level->time_wheel = lev->wheel_time;
3681 level->android_move_time = lev->android_move_time;
3682 level->android_clone_time = lev->android_clone_time;
3683 level->ball_random = lev->ball_random;
3684 level->ball_state_initial = lev->ball_state_initial;
3685 level->ball_time = lev->ball_time;
3686 level->num_ball_contents = lev->num_ball_arrays;
3688 level->lenses_score = lev->lenses_score;
3689 level->magnify_score = lev->magnify_score;
3690 level->slurp_score = lev->slurp_score;
3692 level->lenses_time = lev->lenses_time;
3693 level->magnify_time = lev->magnify_time;
3695 level->wind_direction_initial =
3696 map_direction_EM_to_RND(lev->wind_direction_initial);
3698 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3699 for (j = 0; j < 8; j++)
3700 level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]] =
3701 map_element_EM_to_RND(lev->ball_array[i][j]);
3703 map_android_clone_elements_EM_to_RND(level);
3705 // convert the playfield (some elements need special treatment)
3706 for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
3708 int new_element = map_element_EM_to_RND(level_em->cave[x + 1][y + 1]);
3710 if (new_element == EL_AMOEBA_WET && level->amoeba_speed == 0)
3711 new_element = EL_AMOEBA_DEAD;
3713 level->field[x][y] = new_element;
3716 for (i = 0; i < MAX_PLAYERS; i++)
3718 // in case of all players set to the same field, use the first player
3719 int nr = MAX_PLAYERS - i - 1;
3720 int jx = ply[nr]->x_initial - 1;
3721 int jy = ply[nr]->y_initial - 1;
3723 if (jx != -1 && jy != -1)
3724 level->field[jx][jy] = EL_PLAYER_1 + nr;
3729 // ----------------------------------------------------------------------------
3730 // functions for loading SP level