1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
19 #include "libgame/libgame.h"
27 #define CHUNK_ID_LEN 4 /* IFF style chunk id length */
28 #define CHUNK_SIZE_UNDEFINED 0 /* undefined chunk size == 0 */
29 #define CHUNK_SIZE_NONE -1 /* do not write chunk size */
30 #define FILE_VERS_CHUNK_SIZE 8 /* size of file version chunk */
31 #define LEVEL_HEADER_SIZE 80 /* size of level file header */
32 #define LEVEL_HEADER_UNUSED 0 /* unused level header bytes */
33 #define LEVEL_CHUNK_CNT2_SIZE 160 /* size of level CNT2 chunk */
34 #define LEVEL_CHUNK_CNT2_UNUSED 11 /* unused CNT2 chunk bytes */
35 #define LEVEL_CHUNK_CNT3_HEADER 16 /* size of level CNT3 header */
36 #define LEVEL_CHUNK_CNT3_UNUSED 10 /* unused CNT3 chunk bytes */
37 #define LEVEL_CPART_CUS3_SIZE 134 /* size of CUS3 chunk part */
38 #define LEVEL_CPART_CUS3_UNUSED 15 /* unused CUS3 bytes / part */
39 #define LEVEL_CHUNK_GRP1_SIZE 74 /* size of level GRP1 chunk */
40 #define TAPE_HEADER_SIZE 20 /* size of tape file header */
41 #define TAPE_HEADER_UNUSED 3 /* unused tape header bytes */
43 #define LEVEL_CHUNK_CNT3_SIZE(x) (LEVEL_CHUNK_CNT3_HEADER + (x))
44 #define LEVEL_CHUNK_CUS3_SIZE(x) (2 + (x) * LEVEL_CPART_CUS3_SIZE)
45 #define LEVEL_CHUNK_CUS4_SIZE(x) (96 + (x) * 48)
47 /* file identifier strings */
48 #define LEVEL_COOKIE_TMPL "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x"
49 #define TAPE_COOKIE_TMPL "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
50 #define SCORE_COOKIE "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
52 /* values for "CONF" chunk */
53 #define CONF_MASK_1_BYTE 0x00
54 #define CONF_MASK_2_BYTE 0x40
55 #define CONF_MASK_4_BYTE 0x80
56 #define CONF_MASK_MULTI_BYTES 0xc0
58 #define CONF_MASK_BYTES 0xc0
59 #define CONF_MASK_TOKEN 0x3f
61 #define CONF_VALUE_1_BYTE(x) (CONF_MASK_1_BYTE | (x))
62 #define CONF_VALUE_2_BYTE(x) (CONF_MASK_2_BYTE | (x))
63 #define CONF_VALUE_4_BYTE(x) (CONF_MASK_4_BYTE | (x))
64 #define CONF_VALUE_MULTI_BYTES(x) (CONF_MASK_MULTI_BYTES | (x))
66 /* a sequence of configuration values can be terminated by this value */
67 #define CONF_LAST_ENTRY CONF_VALUE_1_BYTE(0)
69 /* these definitions are just for convenience of use and readability */
70 #define CONF_VALUE_8_BIT(x) CONF_VALUE_1_BYTE(x)
71 #define CONF_VALUE_16_BIT(x) CONF_VALUE_2_BYTE(x)
72 #define CONF_VALUE_32_BIT(x) CONF_VALUE_4_BYTE(x)
73 #define CONF_VALUE_BYTES(x) CONF_VALUE_MULTI_BYTES(x)
75 #define CONF_VALUE_INTEGER_1 CONF_VALUE_8_BIT(1)
76 #define CONF_VALUE_INTEGER_2 CONF_VALUE_8_BIT(2)
77 #define CONF_VALUE_INTEGER_3 CONF_VALUE_8_BIT(3)
78 #define CONF_VALUE_INTEGER_4 CONF_VALUE_8_BIT(4)
79 #define CONF_VALUE_INTEGER_5 CONF_VALUE_8_BIT(5)
80 #define CONF_VALUE_INTEGER_6 CONF_VALUE_8_BIT(6)
81 #define CONF_VALUE_INTEGER_7 CONF_VALUE_8_BIT(7)
82 #define CONF_VALUE_INTEGER_8 CONF_VALUE_8_BIT(8)
83 #define CONF_VALUE_BOOLEAN_1 CONF_VALUE_8_BIT(9)
84 #define CONF_VALUE_BOOLEAN_2 CONF_VALUE_8_BIT(10)
85 #define CONF_VALUE_BOOLEAN_3 CONF_VALUE_8_BIT(11)
86 #define CONF_VALUE_BOOLEAN_4 CONF_VALUE_8_BIT(12)
87 #define CONF_VALUE_BOOLEAN_5 CONF_VALUE_8_BIT(13)
88 #define CONF_VALUE_BOOLEAN_6 CONF_VALUE_8_BIT(14)
89 #define CONF_VALUE_BOOLEAN_7 CONF_VALUE_8_BIT(15)
90 #define CONF_VALUE_BOOLEAN_8 CONF_VALUE_8_BIT(16)
92 #define CONF_VALUE_ELEMENT_1 CONF_VALUE_16_BIT(1)
93 #define CONF_VALUE_ELEMENT_2 CONF_VALUE_16_BIT(2)
94 #define CONF_VALUE_ELEMENT_3 CONF_VALUE_16_BIT(3)
95 #define CONF_VALUE_ELEMENT_4 CONF_VALUE_16_BIT(4)
96 #define CONF_VALUE_ELEMENT_5 CONF_VALUE_16_BIT(5)
97 #define CONF_VALUE_ELEMENT_6 CONF_VALUE_16_BIT(6)
98 #define CONF_VALUE_ELEMENT_7 CONF_VALUE_16_BIT(7)
99 #define CONF_VALUE_ELEMENT_8 CONF_VALUE_16_BIT(8)
102 #define CONF_VALUE_ELEMENTS CONF_VALUE_BYTES(1)
103 #define CONF_VALUE_CONTENTS CONF_VALUE_BYTES(2)
107 #define CONF_VALUE_INTEGER(x) ((x) >= CONF_VALUE_INTEGER_1 && \
108 (x) <= CONF_VALUE_INTEGER_8)
110 #define CONF_VALUE_BOOLEAN(x) ((x) >= CONF_VALUE_BOOLEAN_1 && \
111 (x) <= CONF_VALUE_BOOLEAN_8)
114 #define CONF_VALUE_NUM_BYTES(x) ((x) == CONF_MASK_1_BYTE ? 1 : \
115 (x) == CONF_MASK_2_BYTE ? 2 : \
116 (x) == CONF_MASK_4_BYTE ? 4 : 0)
119 #define CONF_CONTENT_NUM_ELEMENTS (3 * 3)
120 #define CONF_CONTENT_NUM_BYTES (CONF_CONTENT_NUM_ELEMENTS * 2)
121 #define CONF_ELEMENT_NUM_BYTES (2)
123 #define CONF_ENTITY_NUM_BYTES(t) ((t) == CONF_VALUE_ELEMENTS ? \
124 CONF_ELEMENT_NUM_BYTES : \
125 (t) == CONF_VALUE_CONTENTS ? \
126 CONF_CONTENT_NUM_BYTES : 1)
129 #define CONF_CONTENT_NUM_ELEMENTS (3 * 3)
130 #define CONF_CONTENT_NUM_BYTES (CONF_CONTENT_NUM_ELEMENTS * 2)
131 #define CONF_ELEMENT_NUM_BYTES (2)
133 #define CONF_ENTITY_NUM_BYTES(t) ((t) == TYPE_ELEMENT || \
134 (t) == TYPE_ELEMENT_LIST ? \
135 CONF_ELEMENT_NUM_BYTES : \
136 (t) == TYPE_CONTENT || \
137 (t) == TYPE_CONTENT_LIST ? \
138 CONF_CONTENT_NUM_BYTES : 1)
140 #define CONF_ELEMENT_BYTE_POS(i) ((i) * CONF_ELEMENT_NUM_BYTES)
141 #define CONF_ELEMENTS_ELEMENT(b,i) ((b[CONF_ELEMENT_BYTE_POS(i)] << 8) | \
142 (b[CONF_ELEMENT_BYTE_POS(i) + 1]))
144 #define CONF_CONTENT_ELEMENT_POS(c,x,y) ((c) * CONF_CONTENT_NUM_ELEMENTS + \
146 #define CONF_CONTENT_BYTE_POS(c,x,y) (CONF_CONTENT_ELEMENT_POS(c,x,y) * \
147 CONF_ELEMENT_NUM_BYTES)
148 #define CONF_CONTENTS_ELEMENT(b,c,x,y) ((b[CONF_CONTENT_BYTE_POS(c,x,y)]<< 8)|\
149 (b[CONF_CONTENT_BYTE_POS(c,x,y) + 1]))
152 static void LoadLevel_InitPlayfield(struct LevelInfo *, char *);
155 /* temporary variables used to store pointers to structure members */
156 static struct LevelInfo li;
157 static struct ElementInfo xx_ei;
158 static struct ElementChangeInfo xx_change;
159 static struct ElementGroupInfo xx_group;
160 static unsigned int xx_event_bits[NUM_CE_BITFIELDS];
161 static char xx_default_description[MAX_ELEMENT_NAME_LEN + 1];
162 static int xx_default_description_length;
163 static int xx_num_contents;
164 static int xx_current_change_page;
166 struct ElementFileConfig
168 int element; /* element for which data is to be stored */
169 int data_type; /* internal type of data */
170 int conf_type; /* special type identifier stored in file */
173 void *value; /* variable that holds the data to be stored */
174 int default_value; /* initial default value for this variable */
177 void *num_entities; /* number of entities for multi-byte data */
178 int default_num_entities; /* default number of entities for this data */
179 int max_num_entities; /* maximal number of entities for this data */
180 char *default_string; /* optional default string for string data */
183 static struct ElementFileConfig element_conf[] =
185 /* ---------- 1-byte values ---------------------------------------------- */
189 TYPE_INTEGER, CONF_VALUE_INTEGER_1,
190 &li.android_move_time, 10
194 TYPE_INTEGER, CONF_VALUE_INTEGER_2,
195 &li.android_clone_time, 10
199 TYPE_INTEGER, CONF_VALUE_INTEGER_1,
204 TYPE_INTEGER, CONF_VALUE_INTEGER_2,
209 TYPE_INTEGER, CONF_VALUE_INTEGER_1,
210 &li.magnify_score, 10
214 TYPE_INTEGER, CONF_VALUE_INTEGER_2,
219 TYPE_INTEGER, CONF_VALUE_INTEGER_1,
224 TYPE_INTEGER, CONF_VALUE_INTEGER_1,
225 &li.game_of_life[0], 2
229 TYPE_INTEGER, CONF_VALUE_INTEGER_2,
230 &li.game_of_life[1], 3
234 TYPE_INTEGER, CONF_VALUE_INTEGER_3,
235 &li.game_of_life[2], 3
239 TYPE_INTEGER, CONF_VALUE_INTEGER_4,
240 &li.game_of_life[3], 3
244 TYPE_INTEGER, CONF_VALUE_INTEGER_1,
249 TYPE_INTEGER, CONF_VALUE_INTEGER_2,
254 TYPE_INTEGER, CONF_VALUE_INTEGER_3,
259 TYPE_INTEGER, CONF_VALUE_INTEGER_4,
264 TYPE_BITFIELD, CONF_VALUE_INTEGER_1,
265 &li.wind_direction_initial, MV_NONE
269 TYPE_INTEGER, CONF_VALUE_INTEGER_1,
270 &li.time_timegate, 10
273 EL_LIGHT_SWITCH_ACTIVE,
274 TYPE_INTEGER, CONF_VALUE_INTEGER_1,
279 TYPE_INTEGER, CONF_VALUE_INTEGER_1,
280 &li.shield_normal_time, 10
284 TYPE_INTEGER, CONF_VALUE_INTEGER_1,
285 &li.shield_deadly_time, 10
289 TYPE_INTEGER, CONF_VALUE_INTEGER_1,
294 TYPE_INTEGER, CONF_VALUE_INTEGER_2,
295 &li.extra_time_score, 10
299 TYPE_INTEGER, CONF_VALUE_INTEGER_1,
300 &li.time_orb_time, 10
304 TYPE_BOOLEAN, CONF_VALUE_BOOLEAN_1,
305 &li.use_time_orb_bug, FALSE
309 TYPE_BOOLEAN, CONF_VALUE_BOOLEAN_1,
310 &li.block_snap_field, TRUE
314 TYPE_BOOLEAN, CONF_VALUE_BOOLEAN_2,
315 &li.use_start_element[0], FALSE
319 TYPE_BOOLEAN, CONF_VALUE_BOOLEAN_2,
320 &li.use_start_element[1], FALSE
324 TYPE_BOOLEAN, CONF_VALUE_BOOLEAN_2,
325 &li.use_start_element[2], FALSE
329 TYPE_BOOLEAN, CONF_VALUE_BOOLEAN_2,
330 &li.use_start_element[3], FALSE
334 TYPE_BOOLEAN, CONF_VALUE_BOOLEAN_3,
335 &li.use_artwork_element[0], FALSE
339 TYPE_BOOLEAN, CONF_VALUE_BOOLEAN_3,
340 &li.use_artwork_element[1], FALSE
344 TYPE_BOOLEAN, CONF_VALUE_BOOLEAN_3,
345 &li.use_artwork_element[2], FALSE
349 TYPE_BOOLEAN, CONF_VALUE_BOOLEAN_3,
350 &li.use_artwork_element[3], FALSE
354 TYPE_BOOLEAN, CONF_VALUE_BOOLEAN_4,
355 &li.use_explosion_element[0], FALSE
359 TYPE_BOOLEAN, CONF_VALUE_BOOLEAN_4,
360 &li.use_explosion_element[1], FALSE
364 TYPE_BOOLEAN, CONF_VALUE_BOOLEAN_4,
365 &li.use_explosion_element[2], FALSE
369 TYPE_BOOLEAN, CONF_VALUE_BOOLEAN_4,
370 &li.use_explosion_element[3], FALSE
374 TYPE_BOOLEAN, CONF_VALUE_BOOLEAN_5,
375 &li.continuous_snapping, TRUE
379 TYPE_INTEGER, CONF_VALUE_INTEGER_1,
380 &li.initial_player_stepsize, STEPSIZE_NORMAL
384 TYPE_INTEGER, CONF_VALUE_INTEGER_1,
389 TYPE_BOOLEAN, CONF_VALUE_BOOLEAN_1,
390 &li.ball_random, FALSE
394 TYPE_BOOLEAN, CONF_VALUE_BOOLEAN_2,
395 &li.ball_state_initial, FALSE
398 /* ---------- 2-byte values ---------------------------------------------- */
402 TYPE_ELEMENT, CONF_VALUE_ELEMENT_1,
403 &li.start_element[0], EL_PLAYER_1
407 TYPE_ELEMENT, CONF_VALUE_ELEMENT_1,
408 &li.start_element[1], EL_PLAYER_2
412 TYPE_ELEMENT, CONF_VALUE_ELEMENT_1,
413 &li.start_element[2], EL_PLAYER_3
417 TYPE_ELEMENT, CONF_VALUE_ELEMENT_1,
418 &li.start_element[3], EL_PLAYER_4
422 TYPE_ELEMENT, CONF_VALUE_ELEMENT_2,
423 &li.artwork_element[0], EL_PLAYER_1
427 TYPE_ELEMENT, CONF_VALUE_ELEMENT_2,
428 &li.artwork_element[1], EL_PLAYER_2
432 TYPE_ELEMENT, CONF_VALUE_ELEMENT_2,
433 &li.artwork_element[2], EL_PLAYER_3
437 TYPE_ELEMENT, CONF_VALUE_ELEMENT_2,
438 &li.artwork_element[3], EL_PLAYER_4
442 TYPE_ELEMENT, CONF_VALUE_ELEMENT_3,
443 &li.explosion_element[0], EL_PLAYER_1
447 TYPE_ELEMENT, CONF_VALUE_ELEMENT_3,
448 &li.explosion_element[1], EL_PLAYER_2
452 TYPE_ELEMENT, CONF_VALUE_ELEMENT_3,
453 &li.explosion_element[2], EL_PLAYER_3
457 TYPE_ELEMENT, CONF_VALUE_ELEMENT_3,
458 &li.explosion_element[3], EL_PLAYER_4
461 /* ---------- multi-byte values ------------------------------------------ */
465 TYPE_ELEMENT_LIST, CONF_VALUE_BYTES(1),
466 &li.android_clone_element[0], EL_EMPTY,
467 &li.num_android_clone_elements, 1, MAX_ANDROID_ELEMENTS
471 TYPE_CONTENT_LIST, CONF_VALUE_BYTES(2),
472 &li.ball_content, EL_EMPTY,
473 &li.num_ball_contents, 4, MAX_ELEMENT_CONTENTS
483 static struct ElementFileConfig custom_element_conf[] =
487 TYPE_STRING, CONF_VALUE_BYTES(1),
488 &xx_ei.description[0], -1,
489 &xx_default_description_length, -1, MAX_ELEMENT_NAME_LEN,
490 &xx_default_description[0]
495 TYPE_BITFIELD, CONF_VALUE_32_BIT(1),
496 &xx_ei.properties[EP_BITFIELD_BASE],
500 (1 << EP_CAN_MOVE_INTO_ACID)
507 TYPE_BITFIELD, CONF_VALUE_32_BIT(2),
508 &xx_ei.properties[EP_BITFIELD_BASE + 1], EP_BITMASK_DEFAULT
514 TYPE_BOOLEAN, CONF_VALUE_8_BIT(1),
515 &xx_ei.use_gfx_element, FALSE
519 TYPE_ELEMENT, CONF_VALUE_16_BIT(1),
520 &xx_ei.gfx_element, EL_EMPTY_SPACE
525 TYPE_BITFIELD, CONF_VALUE_8_BIT(2),
526 &xx_ei.access_direction, MV_ALL_DIRECTIONS
531 TYPE_INTEGER, CONF_VALUE_16_BIT(2),
532 &xx_ei.collect_score_initial, 10
536 TYPE_INTEGER, CONF_VALUE_16_BIT(3),
537 &xx_ei.collect_count_initial, 1
542 TYPE_INTEGER, CONF_VALUE_16_BIT(4),
543 &xx_ei.ce_value_fixed_initial, 0
547 TYPE_INTEGER, CONF_VALUE_16_BIT(5),
548 &xx_ei.ce_value_random_initial, 0
552 TYPE_BOOLEAN, CONF_VALUE_8_BIT(3),
553 &xx_ei.use_last_ce_value, FALSE
558 TYPE_INTEGER, CONF_VALUE_16_BIT(6),
559 &xx_ei.push_delay_fixed, 8,
563 TYPE_INTEGER, CONF_VALUE_16_BIT(7),
564 &xx_ei.push_delay_random, 8,
568 TYPE_INTEGER, CONF_VALUE_16_BIT(8),
569 &xx_ei.drop_delay_fixed, 0
573 TYPE_INTEGER, CONF_VALUE_16_BIT(9),
574 &xx_ei.drop_delay_random, 0
578 TYPE_INTEGER, CONF_VALUE_16_BIT(10),
579 &xx_ei.move_delay_fixed, 0
583 TYPE_INTEGER, CONF_VALUE_16_BIT(11),
584 &xx_ei.move_delay_random, 0
589 TYPE_BITFIELD, CONF_VALUE_32_BIT(3),
590 &xx_ei.move_pattern, MV_ALL_DIRECTIONS
594 TYPE_BITFIELD, CONF_VALUE_8_BIT(4),
595 &xx_ei.move_direction_initial, MV_START_AUTOMATIC
599 TYPE_INTEGER, CONF_VALUE_8_BIT(5),
600 &xx_ei.move_stepsize, TILEX / 8
605 TYPE_ELEMENT, CONF_VALUE_16_BIT(12),
606 &xx_ei.move_enter_element, EL_EMPTY_SPACE
610 TYPE_ELEMENT, CONF_VALUE_16_BIT(13),
611 &xx_ei.move_leave_element, EL_EMPTY_SPACE
615 TYPE_INTEGER, CONF_VALUE_8_BIT(6),
616 &xx_ei.move_leave_type, LEAVE_TYPE_UNLIMITED
621 TYPE_INTEGER, CONF_VALUE_8_BIT(7),
622 &xx_ei.slippery_type, SLIPPERY_ANY_RANDOM
627 TYPE_INTEGER, CONF_VALUE_8_BIT(8),
628 &xx_ei.explosion_type, EXPLODES_3X3
632 TYPE_INTEGER, CONF_VALUE_16_BIT(14),
633 &xx_ei.explosion_delay, 16
637 TYPE_INTEGER, CONF_VALUE_16_BIT(15),
638 &xx_ei.ignition_delay, 8
643 TYPE_CONTENT_LIST, CONF_VALUE_BYTES(2),
644 &xx_ei.content, EL_EMPTY_SPACE,
645 &xx_num_contents, 1, 1
648 /* ---------- "num_change_pages" must be the last entry ------------------- */
652 TYPE_INTEGER, CONF_VALUE_8_BIT(9),
653 &xx_ei.num_change_pages, -1 /* always save this value */
663 static struct ElementFileConfig custom_element_change_conf[] =
665 /* ---------- "current_change_page" must be the first entry --------------- */
669 TYPE_INTEGER, CONF_VALUE_8_BIT(1),
670 &xx_current_change_page, -1
675 TYPE_BOOLEAN, CONF_VALUE_8_BIT(2),
676 &xx_change.can_change, FALSE
681 TYPE_BITFIELD, CONF_VALUE_32_BIT(1),
686 TYPE_BITFIELD, CONF_VALUE_32_BIT(2),
692 TYPE_INTEGER, CONF_VALUE_8_BIT(3),
693 &xx_change.trigger_player, CH_PLAYER_ANY
697 TYPE_INTEGER, CONF_VALUE_8_BIT(4),
698 &xx_change.trigger_side, CH_SIDE_ANY
702 TYPE_INTEGER, CONF_VALUE_8_BIT(5),
703 &xx_change.trigger_page, CH_PAGE_ANY
708 TYPE_ELEMENT, CONF_VALUE_16_BIT(1),
709 &xx_change.target_element, EL_EMPTY_SPACE
714 TYPE_INTEGER, CONF_VALUE_16_BIT(2),
715 &xx_change.delay_fixed, 0
719 TYPE_INTEGER, CONF_VALUE_16_BIT(3),
720 &xx_change.delay_random, 0
724 TYPE_INTEGER, CONF_VALUE_16_BIT(4),
725 &xx_change.delay_frames, FRAMES_PER_SECOND
730 TYPE_ELEMENT, CONF_VALUE_16_BIT(5),
731 &xx_change.trigger_element, EL_EMPTY_SPACE
736 TYPE_BOOLEAN, CONF_VALUE_8_BIT(6),
737 &xx_change.explode, FALSE
741 TYPE_BOOLEAN, CONF_VALUE_8_BIT(7),
742 &xx_change.use_target_content, FALSE
746 TYPE_BOOLEAN, CONF_VALUE_8_BIT(8),
747 &xx_change.only_if_complete, FALSE
751 TYPE_BOOLEAN, CONF_VALUE_8_BIT(9),
752 &xx_change.use_random_replace, FALSE
756 TYPE_INTEGER, CONF_VALUE_8_BIT(10),
757 &xx_change.random_percentage, 100
761 TYPE_INTEGER, CONF_VALUE_8_BIT(11),
762 &xx_change.replace_when, CP_WHEN_EMPTY
767 TYPE_BOOLEAN, CONF_VALUE_8_BIT(12),
768 &xx_change.has_action, FALSE
772 TYPE_INTEGER, CONF_VALUE_8_BIT(13),
773 &xx_change.action_type, CA_NO_ACTION
777 TYPE_INTEGER, CONF_VALUE_8_BIT(14),
778 &xx_change.action_mode, CA_MODE_UNDEFINED
782 TYPE_INTEGER, CONF_VALUE_16_BIT(6),
783 &xx_change.action_arg, CA_ARG_UNDEFINED
788 TYPE_CONTENT_LIST, CONF_VALUE_BYTES(1),
789 &xx_change.target_content, EL_EMPTY_SPACE,
790 &xx_num_contents, 1, 1
800 static struct ElementFileConfig group_element_conf[] =
804 TYPE_STRING, CONF_VALUE_BYTES(1),
805 &xx_ei.description[0], -1,
806 &xx_default_description_length, -1, MAX_ELEMENT_NAME_LEN,
807 &xx_default_description[0]
812 TYPE_BOOLEAN, CONF_VALUE_8_BIT(1),
813 &xx_ei.use_gfx_element, FALSE
817 TYPE_ELEMENT, CONF_VALUE_16_BIT(1),
818 &xx_ei.gfx_element, EL_EMPTY_SPACE
823 TYPE_INTEGER, CONF_VALUE_8_BIT(2),
824 &xx_group.choice_mode, ANIM_RANDOM
829 TYPE_ELEMENT_LIST, CONF_VALUE_BYTES(2),
830 &xx_group.element[0], EL_EMPTY_SPACE,
831 &xx_group.num_elements, 1, MAX_ELEMENTS_IN_GROUP
848 { LEVEL_FILE_TYPE_RND, "RND" },
849 { LEVEL_FILE_TYPE_BD, "BD" },
850 { LEVEL_FILE_TYPE_EM, "EM" },
851 { LEVEL_FILE_TYPE_SP, "SP" },
852 { LEVEL_FILE_TYPE_DX, "DX" },
853 { LEVEL_FILE_TYPE_SB, "SB" },
854 { LEVEL_FILE_TYPE_DC, "DC" },
859 /* ========================================================================= */
860 /* level file functions */
861 /* ========================================================================= */
863 static void resetEventFlags(struct ElementChangeInfo *change)
867 for (i = 0; i < NUM_CHANGE_EVENTS; i++)
868 change->has_event[i] = FALSE;
871 static void resetEventBits()
875 for (i = 0; i < NUM_CE_BITFIELDS; i++)
876 xx_event_bits[i] = 0;
879 static void setEventFlagsFromEventBits(struct ElementChangeInfo *change)
883 /* important: only change event flag if corresponding event bit is set */
884 for (i = 0; i < NUM_CHANGE_EVENTS; i++)
885 if (xx_event_bits[EVENT_BITFIELD_NR(i)] & EVENT_BIT(i))
886 change->has_event[i] = TRUE;
889 static void setEventBitsFromEventFlags(struct ElementChangeInfo *change)
893 /* important: only change event bit if corresponding event flag is set */
894 for (i = 0; i < NUM_CHANGE_EVENTS; i++)
895 if (change->has_event[i])
896 xx_event_bits[EVENT_BITFIELD_NR(i)] |= EVENT_BIT(i);
899 static char *getDefaultElementDescription(struct ElementInfo *ei)
901 static char description[MAX_ELEMENT_NAME_LEN + 1];
902 char *default_description = (ei->custom_description != NULL ?
903 ei->custom_description :
904 ei->editor_description);
907 /* always start with reliable default values */
908 for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++)
909 description[i] = '\0';
911 /* truncate element description to MAX_ELEMENT_NAME_LEN bytes */
912 strncpy(description, default_description, MAX_ELEMENT_NAME_LEN);
914 return &description[0];
917 static void setElementDescriptionToDefault(struct ElementInfo *ei)
919 char *default_description = getDefaultElementDescription(ei);
922 for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++)
923 ei->description[i] = default_description[i];
926 static void setConfigToDefaultsFromConfigList(struct ElementFileConfig *config)
930 for (i = 0; config[i].data_type != -1; i++)
932 int default_value = config[i].default_value;
933 int data_type = config[i].data_type;
934 int conf_type = config[i].conf_type;
935 int byte_mask = conf_type & CONF_MASK_BYTES;
937 if (byte_mask == CONF_MASK_MULTI_BYTES)
939 int default_num_entities = config[i].default_num_entities;
940 int max_num_entities = config[i].max_num_entities;
942 *(int *)(config[i].num_entities) = default_num_entities;
944 if (data_type == TYPE_STRING)
946 char *default_string = config[i].default_string;
947 char *string = (char *)(config[i].value);
949 strncpy(string, default_string, max_num_entities);
951 else if (data_type == TYPE_ELEMENT_LIST)
953 int *element_array = (int *)(config[i].value);
956 for (j = 0; j < max_num_entities; j++)
957 element_array[j] = default_value;
959 else if (data_type == TYPE_CONTENT_LIST)
961 struct Content *content = (struct Content *)(config[i].value);
964 for (c = 0; c < max_num_entities; c++)
965 for (y = 0; y < 3; y++)
966 for (x = 0; x < 3; x++)
967 content[c].e[x][y] = default_value;
970 else /* constant size configuration data (1, 2 or 4 bytes) */
972 if (data_type == TYPE_BOOLEAN)
973 *(boolean *)(config[i].value) = default_value;
975 *(int *) (config[i].value) = default_value;
980 void setElementChangePages(struct ElementInfo *ei, int change_pages)
982 int change_page_size = sizeof(struct ElementChangeInfo);
984 ei->num_change_pages = MAX(1, change_pages);
987 checked_realloc(ei->change_page, ei->num_change_pages * change_page_size);
989 if (ei->current_change_page >= ei->num_change_pages)
990 ei->current_change_page = ei->num_change_pages - 1;
992 ei->change = &ei->change_page[ei->current_change_page];
995 void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
997 xx_change = *change; /* copy change data into temporary buffer */
1000 setConfigToDefaultsFromConfigList(custom_element_change_conf);
1002 *change = xx_change;
1004 resetEventFlags(change);
1007 change->can_change = FALSE;
1009 for (i = 0; i < NUM_CHANGE_EVENTS; i++)
1010 change->has_event[i] = FALSE;
1012 change->trigger_player = CH_PLAYER_ANY;
1013 change->trigger_side = CH_SIDE_ANY;
1014 change->trigger_page = CH_PAGE_ANY;
1016 change->target_element = EL_EMPTY_SPACE;
1018 change->delay_fixed = 0;
1019 change->delay_random = 0;
1020 change->delay_frames = FRAMES_PER_SECOND;
1022 change->trigger_element = EL_EMPTY_SPACE;
1024 change->explode = FALSE;
1025 change->use_target_content = FALSE;
1026 change->only_if_complete = FALSE;
1027 change->use_random_replace = FALSE;
1028 change->random_percentage = 100;
1029 change->replace_when = CP_WHEN_EMPTY;
1031 change->has_action = FALSE;
1032 change->action_type = CA_NO_ACTION;
1033 change->action_mode = CA_MODE_UNDEFINED;
1034 change->action_arg = CA_ARG_UNDEFINED;
1036 for (x = 0; x < 3; x++)
1037 for (y = 0; y < 3; y++)
1038 change->target_content.e[x][y] = EL_EMPTY_SPACE;
1041 change->direct_action = 0;
1042 change->other_action = 0;
1044 change->pre_change_function = NULL;
1045 change->change_function = NULL;
1046 change->post_change_function = NULL;
1049 static void setLevelInfoToDefaults(struct LevelInfo *level)
1051 static boolean clipboard_elements_initialized = FALSE;
1055 InitElementPropertiesStatic();
1058 li = *level; /* copy level data into temporary buffer */
1060 setConfigToDefaultsFromConfigList(element_conf);
1062 *level = li; /* copy temporary buffer back to level data */
1064 setLevelInfoToDefaults_EM();
1066 level->native_em_level = &native_em_level;
1068 level->game_engine_type = GAME_ENGINE_TYPE_RND;
1070 level->file_version = FILE_VERSION_ACTUAL;
1071 level->game_version = GAME_VERSION_ACTUAL;
1073 level->encoding_16bit_field = FALSE; /* default: only 8-bit elements */
1074 level->encoding_16bit_yamyam = FALSE; /* default: only 8-bit elements */
1075 level->encoding_16bit_amoeba = FALSE; /* default: only 8-bit elements */
1077 level->fieldx = STD_LEV_FIELDX;
1078 level->fieldy = STD_LEV_FIELDY;
1080 for (x = 0; x < MAX_LEV_FIELDX; x++)
1081 for (y = 0; y < MAX_LEV_FIELDY; y++)
1082 level->field[x][y] = EL_SAND;
1085 level->gems_needed = 0;
1087 level->amoeba_speed = 10;
1089 level->time_magic_wall = 10;
1090 level->time_wheel = 10;
1092 level->time_light = 10;
1093 level->time_timegate = 10;
1096 level->amoeba_content = EL_DIAMOND;
1099 level->game_of_life[0] = 2;
1100 level->game_of_life[1] = 3;
1101 level->game_of_life[2] = 3;
1102 level->game_of_life[3] = 3;
1104 level->biomaze[0] = 2;
1105 level->biomaze[1] = 3;
1106 level->biomaze[2] = 3;
1107 level->biomaze[3] = 3;
1111 level->double_speed = FALSE;
1113 level->initial_gravity = FALSE;
1114 level->em_slippery_gems = FALSE;
1115 level->instant_relocation = FALSE;
1116 level->can_pass_to_walkable = FALSE;
1117 level->grow_into_diggable = TRUE;
1120 level->block_snap_field = TRUE;
1123 level->block_last_field = FALSE; /* EM does not block by default */
1124 level->sp_block_last_field = TRUE; /* SP blocks the last field */
1126 level->can_move_into_acid_bits = ~0; /* everything can move into acid */
1127 level->dont_collide_with_bits = ~0; /* always deadly when colliding */
1129 level->use_spring_bug = FALSE;
1130 level->use_time_orb_bug = FALSE;
1132 level->use_step_counter = FALSE;
1134 /* values for the new EMC elements */
1136 level->android_move_time = 10;
1137 level->android_clone_time = 10;
1138 level->ball_time = 10;
1139 level->lenses_score = 10;
1140 level->lenses_time = 10;
1141 level->magnify_score = 10;
1142 level->magnify_time = 10;
1143 level->slurp_score = 10;
1144 level->wind_direction_initial = MV_NONE;
1145 level->ball_random = FALSE;
1146 level->ball_state_initial = FALSE;
1148 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
1149 for (x = 0; x < 3; x++)
1150 for (y = 0; y < 3; y++)
1151 level->ball_content[i].e[x][y] = EL_EMPTY;
1153 for (i = 0; i < 16; i++)
1154 level->android_array[i] = FALSE;
1157 level->use_custom_template = FALSE;
1159 for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
1160 level->name[i] = '\0';
1161 for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
1162 level->author[i] = '\0';
1164 strcpy(level->name, NAMELESS_LEVEL_NAME);
1165 strcpy(level->author, ANONYMOUS_NAME);
1167 for (i = 0; i < 4; i++)
1169 level->envelope_text[i][0] = '\0';
1170 level->envelope_xsize[i] = MAX_ENVELOPE_XSIZE;
1171 level->envelope_ysize[i] = MAX_ENVELOPE_YSIZE;
1174 for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
1175 level->score[i] = (i == SC_TIME_BONUS ? 1 : 10);
1177 level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
1178 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
1179 for (x = 0; x < 3; x++)
1180 for (y = 0; y < 3; y++)
1181 level->yamyam_content[i].e[x][y] =
1182 (i < STD_ELEMENT_CONTENTS ? EL_ROCK : EL_EMPTY);
1184 level->field[0][0] = EL_PLAYER_1;
1185 level->field[STD_LEV_FIELDX - 1][STD_LEV_FIELDY - 1] = EL_EXIT_CLOSED;
1187 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1190 struct ElementInfo *ei = &element_info[element];
1192 xx_ei = *ei; /* copy element data into temporary buffer */
1194 setConfigToDefaultsFromConfigList(custom_element_conf);
1198 /* never initialize clipboard elements after the very first time */
1199 /* (to be able to use clipboard elements between several levels) */
1200 if (IS_CLIPBOARD_ELEMENT(element) && clipboard_elements_initialized)
1203 setElementChangePages(ei, 1);
1204 setElementChangeInfoToDefaults(ei->change);
1206 if (IS_CUSTOM_ELEMENT(element) ||
1207 IS_GROUP_ELEMENT(element) ||
1208 IS_INTERNAL_ELEMENT(element))
1211 setElementDescriptionToDefault(ei);
1213 for (j = 0; j < MAX_ELEMENT_NAME_LEN + 1; j++)
1214 ei->description[j] = '\0';
1216 if (ei->custom_description != NULL)
1217 strncpy(ei->description, ei->custom_description,MAX_ELEMENT_NAME_LEN);
1219 strcpy(ei->description, ei->editor_description);
1223 ei->use_gfx_element = FALSE;
1224 ei->gfx_element = EL_EMPTY_SPACE;
1227 ei->modified_settings = FALSE;
1230 if (IS_CUSTOM_ELEMENT(element) ||
1231 IS_INTERNAL_ELEMENT(element))
1234 ei->access_direction = MV_ALL_DIRECTIONS;
1236 ei->collect_score_initial = 10; /* special default */
1237 ei->collect_count_initial = 1; /* special default */
1239 ei->ce_value_fixed_initial = 0;
1240 ei->ce_value_random_initial = 0;
1241 ei->use_last_ce_value = FALSE;
1243 ei->push_delay_fixed = -1; /* initialize later */
1244 ei->push_delay_random = -1; /* initialize later */
1245 ei->drop_delay_fixed = 0;
1246 ei->drop_delay_random = 0;
1247 ei->move_delay_fixed = 0;
1248 ei->move_delay_random = 0;
1250 ei->move_pattern = MV_ALL_DIRECTIONS;
1251 ei->move_direction_initial = MV_START_AUTOMATIC;
1252 ei->move_stepsize = TILEX / 8;
1254 ei->move_enter_element = EL_EMPTY_SPACE;
1255 ei->move_leave_element = EL_EMPTY_SPACE;
1256 ei->move_leave_type = LEAVE_TYPE_UNLIMITED;
1258 ei->slippery_type = SLIPPERY_ANY_RANDOM;
1260 ei->explosion_type = EXPLODES_3X3;
1261 ei->explosion_delay = 16;
1262 ei->ignition_delay = 8;
1264 for (x = 0; x < 3; x++)
1265 for (y = 0; y < 3; y++)
1266 ei->content.e[x][y] = EL_EMPTY_SPACE;
1269 ei->access_type = 0;
1270 ei->access_layer = 0;
1271 ei->access_protected = 0;
1272 ei->walk_to_action = 0;
1273 ei->smash_targets = 0;
1276 ei->can_explode_by_fire = FALSE;
1277 ei->can_explode_smashed = FALSE;
1278 ei->can_explode_impact = FALSE;
1280 ei->current_change_page = 0;
1283 /* !!! now done in InitElementPropertiesStatic() (see above) !!! */
1284 /* !!! (else properties set there will be overwritten here) !!! */
1285 /* start with no properties at all */
1287 for (j = 0; j < NUM_EP_BITFIELDS; j++)
1288 ei->properties[j] = EP_BITMASK_DEFAULT;
1290 for (j = 0; j < NUM_EP_BITFIELDS; j++)
1291 Properties[element][j] = EP_BITMASK_DEFAULT;
1295 /* now set default properties */
1296 SET_PROPERTY(element, EP_CAN_MOVE_INTO_ACID, TRUE);
1299 if (IS_GROUP_ELEMENT(element) ||
1300 IS_INTERNAL_ELEMENT(element))
1302 struct ElementGroupInfo *group;
1304 /* initialize memory for list of elements in group */
1305 if (ei->group == NULL)
1306 ei->group = checked_malloc(sizeof(struct ElementGroupInfo));
1310 xx_group = *group; /* copy group data into temporary buffer */
1312 setConfigToDefaultsFromConfigList(group_element_conf);
1317 for (j = 0; j < MAX_ELEMENTS_IN_GROUP; j++)
1318 group->element[j] = EL_EMPTY_SPACE;
1320 /* default: only one element in group */
1321 group->num_elements = 1;
1323 group->choice_mode = ANIM_RANDOM;
1328 clipboard_elements_initialized = TRUE;
1330 BorderElement = EL_STEELWALL;
1332 level->no_valid_file = FALSE;
1334 level->changed = FALSE;
1336 if (leveldir_current == NULL) /* only when dumping level */
1339 /* try to determine better author name than 'anonymous' */
1340 if (!strEqual(leveldir_current->author, ANONYMOUS_NAME))
1342 strncpy(level->author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN);
1343 level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
1347 switch (LEVELCLASS(leveldir_current))
1349 case LEVELCLASS_TUTORIAL:
1350 strcpy(level->author, PROGRAM_AUTHOR_STRING);
1353 case LEVELCLASS_CONTRIB:
1354 strncpy(level->author, leveldir_current->name, MAX_LEVEL_AUTHOR_LEN);
1355 level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
1358 case LEVELCLASS_PRIVATE:
1359 strncpy(level->author, getRealName(), MAX_LEVEL_AUTHOR_LEN);
1360 level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
1364 /* keep default value */
1370 static void setFileInfoToDefaults(struct LevelFileInfo *level_file_info)
1372 level_file_info->nr = 0;
1373 level_file_info->type = LEVEL_FILE_TYPE_UNKNOWN;
1374 level_file_info->packed = FALSE;
1375 level_file_info->basename = NULL;
1376 level_file_info->filename = NULL;
1379 static void ActivateLevelTemplate()
1382 /* Currently there is no special action needed to activate the template
1383 data, because 'element_info' property settings overwrite the original
1384 level data, while all other variables do not change. */
1386 /* Currently there is no special action needed to activate the template
1387 data, because 'element_info' and 'Properties' overwrite the original
1388 level data, while all other variables do not change. */
1392 static char *getLevelFilenameFromBasename(char *basename)
1394 static char *filename = NULL;
1396 checked_free(filename);
1398 filename = getPath2(getCurrentLevelDir(), basename);
1403 static int getFileTypeFromBasename(char *basename)
1405 static char *filename = NULL;
1406 struct stat file_status;
1408 /* ---------- try to determine file type from filename ---------- */
1410 /* check for typical filename of a Supaplex level package file */
1411 if (strlen(basename) == 10 && (strncmp(basename, "levels.d", 8) == 0 ||
1412 strncmp(basename, "LEVELS.D", 8) == 0))
1413 return LEVEL_FILE_TYPE_SP;
1415 /* ---------- try to determine file type from filesize ---------- */
1417 checked_free(filename);
1418 filename = getPath2(getCurrentLevelDir(), basename);
1420 if (stat(filename, &file_status) == 0)
1422 /* check for typical filesize of a Supaplex level package file */
1423 if (file_status.st_size == 170496)
1424 return LEVEL_FILE_TYPE_SP;
1427 return LEVEL_FILE_TYPE_UNKNOWN;
1430 static char *getSingleLevelBasename(int nr)
1432 static char basename[MAX_FILENAME_LEN];
1435 sprintf(basename, "template.%s", LEVELFILE_EXTENSION);
1437 sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION);
1442 static char *getPackedLevelBasename(int type)
1444 static char basename[MAX_FILENAME_LEN];
1445 char *directory = getCurrentLevelDir();
1447 struct dirent *dir_entry;
1449 strcpy(basename, UNDEFINED_FILENAME); /* default: undefined file */
1451 if ((dir = opendir(directory)) == NULL)
1453 Error(ERR_WARN, "cannot read current level directory '%s'", directory);
1458 while ((dir_entry = readdir(dir)) != NULL) /* loop until last dir entry */
1460 char *entry_basename = dir_entry->d_name;
1461 int entry_type = getFileTypeFromBasename(entry_basename);
1463 if (entry_type != LEVEL_FILE_TYPE_UNKNOWN) /* found valid level package */
1465 if (type == LEVEL_FILE_TYPE_UNKNOWN ||
1468 strcpy(basename, entry_basename);
1480 static char *getSingleLevelFilename(int nr)
1482 return getLevelFilenameFromBasename(getSingleLevelBasename(nr));
1486 static char *getPackedLevelFilename(int type)
1488 return getLevelFilenameFromBasename(getPackedLevelBasename(type));
1492 char *getDefaultLevelFilename(int nr)
1494 return getSingleLevelFilename(nr);
1498 static void setLevelFileInfo_SingleLevelFilename(struct LevelFileInfo *lfi,
1502 lfi->packed = FALSE;
1503 lfi->basename = getSingleLevelBasename(lfi->nr, lfi->type);
1504 lfi->filename = getLevelFilenameFromBasename(lfi->basename);
1508 static void setLevelFileInfo_FormatLevelFilename(struct LevelFileInfo *lfi,
1509 int type, char *format, ...)
1511 static char basename[MAX_FILENAME_LEN];
1514 va_start(ap, format);
1515 vsprintf(basename, format, ap);
1519 lfi->packed = FALSE;
1520 lfi->basename = basename;
1521 lfi->filename = getLevelFilenameFromBasename(lfi->basename);
1524 static void setLevelFileInfo_PackedLevelFilename(struct LevelFileInfo *lfi,
1529 lfi->basename = getPackedLevelBasename(lfi->type);
1530 lfi->filename = getLevelFilenameFromBasename(lfi->basename);
1533 static int getFiletypeFromID(char *filetype_id)
1535 char *filetype_id_lower;
1536 int filetype = LEVEL_FILE_TYPE_UNKNOWN;
1539 if (filetype_id == NULL)
1540 return LEVEL_FILE_TYPE_UNKNOWN;
1542 filetype_id_lower = getStringToLower(filetype_id);
1544 for (i = 0; filetype_id_list[i].id != NULL; i++)
1546 char *id_lower = getStringToLower(filetype_id_list[i].id);
1548 if (strEqual(filetype_id_lower, id_lower))
1549 filetype = filetype_id_list[i].filetype;
1553 if (filetype != LEVEL_FILE_TYPE_UNKNOWN)
1557 free(filetype_id_lower);
1562 static void determineLevelFileInfo_Filename(struct LevelFileInfo *lfi)
1566 /* special case: level number is negative => check for level template file */
1569 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
1570 "template.%s", LEVELFILE_EXTENSION);
1572 /* no fallback if template file not existing */
1576 /* special case: check for file name/pattern specified in "levelinfo.conf" */
1577 if (leveldir_current->level_filename != NULL)
1579 int filetype = getFiletypeFromID(leveldir_current->level_filetype);
1581 setLevelFileInfo_FormatLevelFilename(lfi, filetype,
1582 leveldir_current->level_filename, nr);
1583 if (fileExists(lfi->filename))
1587 /* check for native Rocks'n'Diamonds level file */
1588 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
1589 "%03d.%s", nr, LEVELFILE_EXTENSION);
1590 if (fileExists(lfi->filename))
1593 /* check for Emerald Mine level file (V1) */
1594 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "a%c%c",
1595 'a' + (nr / 10) % 26, '0' + nr % 10);
1596 if (fileExists(lfi->filename))
1598 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "A%c%c",
1599 'A' + (nr / 10) % 26, '0' + nr % 10);
1600 if (fileExists(lfi->filename))
1603 /* check for Emerald Mine level file (V2 to V5) */
1604 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%d", nr);
1605 if (fileExists(lfi->filename))
1608 /* check for Emerald Mine level file (V6 / single mode) */
1609 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02ds", nr);
1610 if (fileExists(lfi->filename))
1612 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dS", nr);
1613 if (fileExists(lfi->filename))
1616 /* check for Emerald Mine level file (V6 / teamwork mode) */
1617 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dt", nr);
1618 if (fileExists(lfi->filename))
1620 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dT", nr);
1621 if (fileExists(lfi->filename))
1624 /* check for various packed level file formats */
1625 setLevelFileInfo_PackedLevelFilename(lfi, LEVEL_FILE_TYPE_UNKNOWN);
1626 if (fileExists(lfi->filename))
1629 /* no known level file found -- use default values (and fail later) */
1630 setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
1631 "%03d.%s", nr, LEVELFILE_EXTENSION);
1634 static void determineLevelFileInfo_Filetype(struct LevelFileInfo *lfi)
1636 if (lfi->type == LEVEL_FILE_TYPE_UNKNOWN)
1637 lfi->type = getFileTypeFromBasename(lfi->basename);
1640 static void setLevelFileInfo(struct LevelFileInfo *level_file_info, int nr)
1642 /* always start with reliable default values */
1643 setFileInfoToDefaults(level_file_info);
1645 level_file_info->nr = nr; /* set requested level number */
1647 determineLevelFileInfo_Filename(level_file_info);
1648 determineLevelFileInfo_Filetype(level_file_info);
1651 /* ------------------------------------------------------------------------- */
1652 /* functions for loading R'n'D level */
1653 /* ------------------------------------------------------------------------- */
1655 int getMappedElement(int element)
1657 /* remap some (historic, now obsolete) elements */
1661 case EL_PLAYER_OBSOLETE:
1662 element = EL_PLAYER_1;
1665 case EL_KEY_OBSOLETE:
1668 case EL_EM_KEY_1_FILE_OBSOLETE:
1669 element = EL_EM_KEY_1;
1672 case EL_EM_KEY_2_FILE_OBSOLETE:
1673 element = EL_EM_KEY_2;
1676 case EL_EM_KEY_3_FILE_OBSOLETE:
1677 element = EL_EM_KEY_3;
1680 case EL_EM_KEY_4_FILE_OBSOLETE:
1681 element = EL_EM_KEY_4;
1684 case EL_ENVELOPE_OBSOLETE:
1685 element = EL_ENVELOPE_1;
1693 if (element >= NUM_FILE_ELEMENTS)
1695 Error(ERR_WARN, "invalid level element %d", element);
1697 element = EL_UNKNOWN;
1705 int getMappedElementByVersion(int element, int game_version)
1707 /* remap some elements due to certain game version */
1709 if (game_version <= VERSION_IDENT(2,2,0,0))
1711 /* map game font elements */
1712 element = (element == EL_CHAR('[') ? EL_CHAR_AUMLAUT :
1713 element == EL_CHAR('\\') ? EL_CHAR_OUMLAUT :
1714 element == EL_CHAR(']') ? EL_CHAR_UUMLAUT :
1715 element == EL_CHAR('^') ? EL_CHAR_COPYRIGHT : element);
1718 if (game_version < VERSION_IDENT(3,0,0,0))
1720 /* map Supaplex gravity tube elements */
1721 element = (element == EL_SP_GRAVITY_PORT_LEFT ? EL_SP_PORT_LEFT :
1722 element == EL_SP_GRAVITY_PORT_RIGHT ? EL_SP_PORT_RIGHT :
1723 element == EL_SP_GRAVITY_PORT_UP ? EL_SP_PORT_UP :
1724 element == EL_SP_GRAVITY_PORT_DOWN ? EL_SP_PORT_DOWN :
1731 static int LoadLevel_VERS(FILE *file, int chunk_size, struct LevelInfo *level)
1733 level->file_version = getFileVersion(file);
1734 level->game_version = getFileVersion(file);
1739 static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
1743 level->fieldx = getFile8Bit(file);
1744 level->fieldy = getFile8Bit(file);
1746 level->time = getFile16BitBE(file);
1747 level->gems_needed = getFile16BitBE(file);
1749 for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
1750 level->name[i] = getFile8Bit(file);
1751 level->name[MAX_LEVEL_NAME_LEN] = 0;
1753 for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
1754 level->score[i] = getFile8Bit(file);
1756 level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
1757 for (i = 0; i < STD_ELEMENT_CONTENTS; i++)
1758 for (y = 0; y < 3; y++)
1759 for (x = 0; x < 3; x++)
1760 level->yamyam_content[i].e[x][y] = getMappedElement(getFile8Bit(file));
1762 level->amoeba_speed = getFile8Bit(file);
1763 level->time_magic_wall = getFile8Bit(file);
1764 level->time_wheel = getFile8Bit(file);
1765 level->amoeba_content = getMappedElement(getFile8Bit(file));
1767 level->initial_player_stepsize = (getFile8Bit(file) == 1 ? STEPSIZE_FAST :
1770 level->initial_gravity = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1771 level->encoding_16bit_field = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1772 level->em_slippery_gems = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1774 level->use_custom_template = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1776 level->block_last_field = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1777 level->sp_block_last_field = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1778 level->can_move_into_acid_bits = getFile32BitBE(file);
1779 level->dont_collide_with_bits = getFile8Bit(file);
1781 level->use_spring_bug = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1782 level->use_step_counter = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1784 level->instant_relocation = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1785 level->can_pass_to_walkable = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1786 level->grow_into_diggable = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1788 level->game_engine_type = getFile8Bit(file);
1790 ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED);
1795 static int LoadLevel_AUTH(FILE *file, int chunk_size, struct LevelInfo *level)
1799 for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
1800 level->author[i] = getFile8Bit(file);
1801 level->author[MAX_LEVEL_NAME_LEN] = 0;
1806 static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level)
1809 int chunk_size_expected = level->fieldx * level->fieldy;
1811 /* Note: "chunk_size" was wrong before version 2.0 when elements are
1812 stored with 16-bit encoding (and should be twice as big then).
1813 Even worse, playfield data was stored 16-bit when only yamyam content
1814 contained 16-bit elements and vice versa. */
1816 if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
1817 chunk_size_expected *= 2;
1819 if (chunk_size_expected != chunk_size)
1821 ReadUnusedBytesFromFile(file, chunk_size);
1822 return chunk_size_expected;
1825 for (y = 0; y < level->fieldy; y++)
1826 for (x = 0; x < level->fieldx; x++)
1827 level->field[x][y] =
1828 getMappedElement(level->encoding_16bit_field ? getFile16BitBE(file) :
1833 static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
1836 int header_size = 4;
1837 int content_size = MAX_ELEMENT_CONTENTS * 3 * 3;
1838 int chunk_size_expected = header_size + content_size;
1840 /* Note: "chunk_size" was wrong before version 2.0 when elements are
1841 stored with 16-bit encoding (and should be twice as big then).
1842 Even worse, playfield data was stored 16-bit when only yamyam content
1843 contained 16-bit elements and vice versa. */
1845 if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
1846 chunk_size_expected += content_size;
1848 if (chunk_size_expected != chunk_size)
1850 ReadUnusedBytesFromFile(file, chunk_size);
1851 return chunk_size_expected;
1855 level->num_yamyam_contents = getFile8Bit(file);
1859 /* correct invalid number of content fields -- should never happen */
1860 if (level->num_yamyam_contents < 1 ||
1861 level->num_yamyam_contents > MAX_ELEMENT_CONTENTS)
1862 level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
1864 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
1865 for (y = 0; y < 3; y++)
1866 for (x = 0; x < 3; x++)
1867 level->yamyam_content[i].e[x][y] =
1868 getMappedElement(level->encoding_16bit_field ?
1869 getFile16BitBE(file) : getFile8Bit(file));
1873 static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
1877 int num_contents, content_xsize, content_ysize;
1878 int content_array[MAX_ELEMENT_CONTENTS][3][3];
1880 element = getMappedElement(getFile16BitBE(file));
1881 num_contents = getFile8Bit(file);
1882 content_xsize = getFile8Bit(file);
1883 content_ysize = getFile8Bit(file);
1885 ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED);
1887 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
1888 for (y = 0; y < 3; y++)
1889 for (x = 0; x < 3; x++)
1890 content_array[i][x][y] = getMappedElement(getFile16BitBE(file));
1892 /* correct invalid number of content fields -- should never happen */
1893 if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS)
1894 num_contents = STD_ELEMENT_CONTENTS;
1896 if (element == EL_YAMYAM)
1898 level->num_yamyam_contents = num_contents;
1900 for (i = 0; i < num_contents; i++)
1901 for (y = 0; y < 3; y++)
1902 for (x = 0; x < 3; x++)
1903 level->yamyam_content[i].e[x][y] = content_array[i][x][y];
1905 else if (element == EL_BD_AMOEBA)
1907 level->amoeba_content = content_array[0][0][0];
1911 Error(ERR_WARN, "cannot load content for element '%d'", element);
1917 static int LoadLevel_CNT3(FILE *file, int chunk_size, struct LevelInfo *level)
1923 int chunk_size_expected;
1925 element = getMappedElement(getFile16BitBE(file));
1926 if (!IS_ENVELOPE(element))
1927 element = EL_ENVELOPE_1;
1929 envelope_nr = element - EL_ENVELOPE_1;
1931 envelope_len = getFile16BitBE(file);
1933 level->envelope_xsize[envelope_nr] = getFile8Bit(file);
1934 level->envelope_ysize[envelope_nr] = getFile8Bit(file);
1936 ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT3_UNUSED);
1938 chunk_size_expected = LEVEL_CHUNK_CNT3_SIZE(envelope_len);
1939 if (chunk_size_expected != chunk_size)
1941 ReadUnusedBytesFromFile(file, chunk_size - LEVEL_CHUNK_CNT3_HEADER);
1942 return chunk_size_expected;
1945 for (i = 0; i < envelope_len; i++)
1946 level->envelope_text[envelope_nr][i] = getFile8Bit(file);
1951 static int LoadLevel_CUS1(FILE *file, int chunk_size, struct LevelInfo *level)
1953 int num_changed_custom_elements = getFile16BitBE(file);
1954 int chunk_size_expected = 2 + num_changed_custom_elements * 6;
1957 if (chunk_size_expected != chunk_size)
1959 ReadUnusedBytesFromFile(file, chunk_size - 2);
1960 return chunk_size_expected;
1963 for (i = 0; i < num_changed_custom_elements; i++)
1965 int element = getFile16BitBE(file);
1966 int properties = getFile32BitBE(file);
1969 if (IS_CUSTOM_ELEMENT(element))
1970 element_info[element].properties[EP_BITFIELD_BASE] = properties;
1972 Error(ERR_WARN, "invalid custom element number %d", element);
1974 if (IS_CUSTOM_ELEMENT(element))
1975 Properties[element][EP_BITFIELD_BASE] = properties;
1977 Error(ERR_WARN, "invalid custom element number %d", element);
1984 static int LoadLevel_CUS2(FILE *file, int chunk_size, struct LevelInfo *level)
1986 int num_changed_custom_elements = getFile16BitBE(file);
1987 int chunk_size_expected = 2 + num_changed_custom_elements * 4;
1990 if (chunk_size_expected != chunk_size)
1992 ReadUnusedBytesFromFile(file, chunk_size - 2);
1993 return chunk_size_expected;
1996 for (i = 0; i < num_changed_custom_elements; i++)
1998 int element = getFile16BitBE(file);
1999 int custom_target_element = getFile16BitBE(file);
2001 if (IS_CUSTOM_ELEMENT(element))
2002 element_info[element].change->target_element = custom_target_element;
2004 Error(ERR_WARN, "invalid custom element number %d", element);
2010 static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level)
2012 int num_changed_custom_elements = getFile16BitBE(file);
2013 int chunk_size_expected = LEVEL_CHUNK_CUS3_SIZE(num_changed_custom_elements);
2016 if (chunk_size_expected != chunk_size)
2018 ReadUnusedBytesFromFile(file, chunk_size - 2);
2019 return chunk_size_expected;
2022 for (i = 0; i < num_changed_custom_elements; i++)
2024 int element = getFile16BitBE(file);
2025 struct ElementInfo *ei = &element_info[element];
2026 unsigned int event_bits;
2028 if (!IS_CUSTOM_ELEMENT(element))
2030 Error(ERR_WARN, "invalid custom element number %d", element);
2032 element = EL_INTERNAL_DUMMY;
2035 for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++)
2036 ei->description[j] = getFile8Bit(file);
2037 ei->description[MAX_ELEMENT_NAME_LEN] = 0;
2040 ei->properties[EP_BITFIELD_BASE] = getFile32BitBE(file);
2042 Properties[element][EP_BITFIELD_BASE] = getFile32BitBE(file);
2045 /* some free bytes for future properties and padding */
2046 ReadUnusedBytesFromFile(file, 7);
2048 ei->use_gfx_element = getFile8Bit(file);
2049 ei->gfx_element = getMappedElement(getFile16BitBE(file));
2051 ei->collect_score_initial = getFile8Bit(file);
2052 ei->collect_count_initial = getFile8Bit(file);
2054 ei->push_delay_fixed = getFile16BitBE(file);
2055 ei->push_delay_random = getFile16BitBE(file);
2056 ei->move_delay_fixed = getFile16BitBE(file);
2057 ei->move_delay_random = getFile16BitBE(file);
2059 ei->move_pattern = getFile16BitBE(file);
2060 ei->move_direction_initial = getFile8Bit(file);
2061 ei->move_stepsize = getFile8Bit(file);
2063 for (y = 0; y < 3; y++)
2064 for (x = 0; x < 3; x++)
2065 ei->content.e[x][y] = getMappedElement(getFile16BitBE(file));
2067 event_bits = getFile32BitBE(file);
2068 for (j = 0; j < NUM_CHANGE_EVENTS; j++)
2069 if (event_bits & (1 << j))
2070 ei->change->has_event[j] = TRUE;
2072 ei->change->target_element = getMappedElement(getFile16BitBE(file));
2074 ei->change->delay_fixed = getFile16BitBE(file);
2075 ei->change->delay_random = getFile16BitBE(file);
2076 ei->change->delay_frames = getFile16BitBE(file);
2078 ei->change->trigger_element = getMappedElement(getFile16BitBE(file));
2080 ei->change->explode = getFile8Bit(file);
2081 ei->change->use_target_content = getFile8Bit(file);
2082 ei->change->only_if_complete = getFile8Bit(file);
2083 ei->change->use_random_replace = getFile8Bit(file);
2085 ei->change->random_percentage = getFile8Bit(file);
2086 ei->change->replace_when = getFile8Bit(file);
2088 for (y = 0; y < 3; y++)
2089 for (x = 0; x < 3; x++)
2090 ei->change->target_content.e[x][y] =
2091 getMappedElement(getFile16BitBE(file));
2093 ei->slippery_type = getFile8Bit(file);
2095 /* some free bytes for future properties and padding */
2096 ReadUnusedBytesFromFile(file, LEVEL_CPART_CUS3_UNUSED);
2098 /* mark that this custom element has been modified */
2099 ei->modified_settings = TRUE;
2105 static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
2107 struct ElementInfo *ei;
2108 int chunk_size_expected;
2112 /* ---------- custom element base property values (96 bytes) ------------- */
2114 element = getFile16BitBE(file);
2116 if (!IS_CUSTOM_ELEMENT(element))
2118 Error(ERR_WARN, "invalid custom element number %d", element);
2120 ReadUnusedBytesFromFile(file, chunk_size - 2);
2124 ei = &element_info[element];
2126 for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
2127 ei->description[i] = getFile8Bit(file);
2128 ei->description[MAX_ELEMENT_NAME_LEN] = 0;
2131 ei->properties[EP_BITFIELD_BASE] = getFile32BitBE(file);
2133 Properties[element][EP_BITFIELD_BASE] = getFile32BitBE(file);
2135 ReadUnusedBytesFromFile(file, 4); /* reserved for more base properties */
2137 ei->num_change_pages = getFile8Bit(file);
2139 chunk_size_expected = LEVEL_CHUNK_CUS4_SIZE(ei->num_change_pages);
2140 if (chunk_size_expected != chunk_size)
2142 ReadUnusedBytesFromFile(file, chunk_size - 43);
2143 return chunk_size_expected;
2146 ei->ce_value_fixed_initial = getFile16BitBE(file);
2147 ei->ce_value_random_initial = getFile16BitBE(file);
2148 ei->use_last_ce_value = getFile8Bit(file);
2150 ei->use_gfx_element = getFile8Bit(file);
2151 ei->gfx_element = getMappedElement(getFile16BitBE(file));
2153 ei->collect_score_initial = getFile8Bit(file);
2154 ei->collect_count_initial = getFile8Bit(file);
2156 ei->drop_delay_fixed = getFile8Bit(file);
2157 ei->push_delay_fixed = getFile8Bit(file);
2158 ei->drop_delay_random = getFile8Bit(file);
2159 ei->push_delay_random = getFile8Bit(file);
2160 ei->move_delay_fixed = getFile16BitBE(file);
2161 ei->move_delay_random = getFile16BitBE(file);
2163 /* bits 0 - 15 of "move_pattern" ... */
2164 ei->move_pattern = getFile16BitBE(file);
2165 ei->move_direction_initial = getFile8Bit(file);
2166 ei->move_stepsize = getFile8Bit(file);
2168 ei->slippery_type = getFile8Bit(file);
2170 for (y = 0; y < 3; y++)
2171 for (x = 0; x < 3; x++)
2172 ei->content.e[x][y] = getMappedElement(getFile16BitBE(file));
2174 ei->move_enter_element = getMappedElement(getFile16BitBE(file));
2175 ei->move_leave_element = getMappedElement(getFile16BitBE(file));
2176 ei->move_leave_type = getFile8Bit(file);
2178 /* ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible) */
2179 ei->move_pattern |= (getFile16BitBE(file) << 16);
2181 ei->access_direction = getFile8Bit(file);
2183 ei->explosion_delay = getFile8Bit(file);
2184 ei->ignition_delay = getFile8Bit(file);
2185 ei->explosion_type = getFile8Bit(file);
2187 /* some free bytes for future custom property values and padding */
2188 ReadUnusedBytesFromFile(file, 1);
2190 /* ---------- change page property values (48 bytes) --------------------- */
2192 setElementChangePages(ei, ei->num_change_pages);
2194 for (i = 0; i < ei->num_change_pages; i++)
2196 struct ElementChangeInfo *change = &ei->change_page[i];
2197 unsigned int event_bits;
2199 /* always start with reliable default values */
2200 setElementChangeInfoToDefaults(change);
2202 /* bits 0 - 31 of "has_event[]" ... */
2203 event_bits = getFile32BitBE(file);
2204 for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
2205 if (event_bits & (1 << j))
2206 change->has_event[j] = TRUE;
2208 change->target_element = getMappedElement(getFile16BitBE(file));
2210 change->delay_fixed = getFile16BitBE(file);
2211 change->delay_random = getFile16BitBE(file);
2212 change->delay_frames = getFile16BitBE(file);
2214 change->trigger_element = getMappedElement(getFile16BitBE(file));
2216 change->explode = getFile8Bit(file);
2217 change->use_target_content = getFile8Bit(file);
2218 change->only_if_complete = getFile8Bit(file);
2219 change->use_random_replace = getFile8Bit(file);
2221 change->random_percentage = getFile8Bit(file);
2222 change->replace_when = getFile8Bit(file);
2224 for (y = 0; y < 3; y++)
2225 for (x = 0; x < 3; x++)
2226 change->target_content.e[x][y]= getMappedElement(getFile16BitBE(file));
2228 change->can_change = getFile8Bit(file);
2230 change->trigger_side = getFile8Bit(file);
2232 change->trigger_player = getFile8Bit(file);
2233 change->trigger_page = getFile8Bit(file);
2235 change->trigger_page = (change->trigger_page == CH_PAGE_ANY_FILE ?
2236 CH_PAGE_ANY : (1 << change->trigger_page));
2238 change->has_action = getFile8Bit(file);
2239 change->action_type = getFile8Bit(file);
2240 change->action_mode = getFile8Bit(file);
2241 change->action_arg = getFile16BitBE(file);
2243 /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */
2244 event_bits = getFile8Bit(file);
2245 for (j = 32; j < NUM_CHANGE_EVENTS; j++)
2246 if (event_bits & (1 << (j - 32)))
2247 change->has_event[j] = TRUE;
2250 /* mark this custom element as modified */
2251 ei->modified_settings = TRUE;
2256 static int LoadLevel_GRP1(FILE *file, int chunk_size, struct LevelInfo *level)
2258 struct ElementInfo *ei;
2259 struct ElementGroupInfo *group;
2263 element = getFile16BitBE(file);
2265 if (!IS_GROUP_ELEMENT(element))
2267 Error(ERR_WARN, "invalid group element number %d", element);
2269 ReadUnusedBytesFromFile(file, chunk_size - 2);
2273 ei = &element_info[element];
2275 for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
2276 ei->description[i] = getFile8Bit(file);
2277 ei->description[MAX_ELEMENT_NAME_LEN] = 0;
2279 group = element_info[element].group;
2281 group->num_elements = getFile8Bit(file);
2283 ei->use_gfx_element = getFile8Bit(file);
2284 ei->gfx_element = getMappedElement(getFile16BitBE(file));
2286 group->choice_mode = getFile8Bit(file);
2288 /* some free bytes for future values and padding */
2289 ReadUnusedBytesFromFile(file, 3);
2291 for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
2292 group->element[i] = getMappedElement(getFile16BitBE(file));
2294 /* mark this group element as modified */
2295 element_info[element].modified_settings = TRUE;
2300 static int LoadLevel_MicroChunk(FILE *file, struct ElementFileConfig *config,
2303 int micro_chunk_size = 0;
2304 int conf_type = getFile8Bit(file);
2305 int byte_mask = conf_type & CONF_MASK_BYTES;
2306 boolean element_found = FALSE;
2309 micro_chunk_size += 1;
2311 if (byte_mask == CONF_MASK_MULTI_BYTES)
2313 int num_bytes = getFile16BitBE(file);
2314 byte *buffer = checked_malloc(num_bytes);
2317 printf("::: - found multi bytes\n");
2320 ReadBytesFromFile(file, buffer, num_bytes);
2322 for (i = 0; config[i].data_type != -1; i++)
2324 if (config[i].element == element &&
2325 config[i].conf_type == conf_type)
2327 int data_type = config[i].data_type;
2328 int num_entities = num_bytes / CONF_ENTITY_NUM_BYTES(data_type);
2329 int max_num_entities = config[i].max_num_entities;
2331 if (num_entities > max_num_entities)
2334 "truncating number of entities for element %d from %d to %d",
2335 element, num_entities, max_num_entities);
2337 num_entities = max_num_entities;
2340 *(int *)(config[i].num_entities) = num_entities;
2342 element_found = TRUE;
2344 if (data_type == TYPE_STRING)
2346 char *string = (char *)(config[i].value);
2349 for (j = 0; j < max_num_entities; j++)
2350 string[j] = (j < num_entities ? buffer[j] : '\0');
2352 else if (data_type == TYPE_ELEMENT_LIST)
2354 int *element_array = (int *)(config[i].value);
2357 for (j = 0; j < num_entities; j++)
2359 getMappedElement(CONF_ELEMENTS_ELEMENT(buffer, j));
2361 else if (data_type == TYPE_CONTENT_LIST)
2363 struct Content *content= (struct Content *)(config[i].value);
2366 for (c = 0; c < num_entities; c++)
2367 for (y = 0; y < 3; y++)
2368 for (x = 0; x < 3; x++)
2369 content[c].e[x][y] =
2370 getMappedElement(CONF_CONTENTS_ELEMENT(buffer, c, x, y));
2373 element_found = FALSE;
2379 checked_free(buffer);
2381 micro_chunk_size += 2 + num_bytes;
2383 else /* constant size configuration data (1, 2 or 4 bytes) */
2385 int value = (byte_mask == CONF_MASK_1_BYTE ? getFile8Bit (file) :
2386 byte_mask == CONF_MASK_2_BYTE ? getFile16BitBE(file) :
2387 byte_mask == CONF_MASK_4_BYTE ? getFile32BitBE(file) : 0);
2390 printf("::: - found single bytes\n");
2393 for (i = 0; config[i].data_type != -1; i++)
2395 if (config[i].element == element &&
2396 config[i].conf_type == conf_type)
2398 int data_type = config[i].data_type;
2400 if (data_type == TYPE_BOOLEAN)
2401 *(boolean *)(config[i].value) = value;
2403 *(int *) (config[i].value) = value;
2405 element_found = TRUE;
2411 micro_chunk_size += CONF_VALUE_NUM_BYTES(byte_mask);
2415 Error(ERR_WARN, "cannot load micro chunk value for element %d", element);
2417 return micro_chunk_size;
2420 static int LoadLevel_CONF(FILE *file, int chunk_size, struct LevelInfo *level)
2422 int real_chunk_size = 0;
2425 li = *level; /* copy level data into temporary buffer */
2430 int element = getFile16BitBE(file);
2432 real_chunk_size += 2;
2433 real_chunk_size += LoadLevel_MicroChunk(file, element_conf, element);
2435 int conf_type = getFile8Bit(file);
2436 int byte_mask = conf_type & CONF_MASK_BYTES;
2437 boolean element_found = FALSE;
2440 real_chunk_size += 3;
2443 li = *level; /* copy level data into temporary buffer */
2446 if (byte_mask == CONF_MASK_MULTI_BYTES)
2448 int num_bytes = getFile16BitBE(file);
2449 byte *buffer = checked_malloc(num_bytes);
2451 ReadBytesFromFile(file, buffer, num_bytes);
2453 for (i = 0; element_conf[i].data_type != -1; i++)
2455 if (element_conf[i].element == element &&
2456 element_conf[i].conf_type == conf_type)
2458 int data_type = element_conf[i].data_type;
2459 int num_entities = num_bytes / CONF_ENTITY_NUM_BYTES(data_type);
2460 int max_num_entities = element_conf[i].max_num_entities;
2462 if (num_entities > max_num_entities)
2465 "truncating number of entities for element %d from %d to %d",
2466 element, num_entities, max_num_entities);
2468 num_entities = max_num_entities;
2471 *(int *)(element_conf[i].num_entities) = num_entities;
2473 element_found = TRUE;
2475 if (data_type == TYPE_ELEMENT_LIST)
2477 int *element_array = (int *)(element_conf[i].value);
2480 for (j = 0; j < num_entities; j++)
2482 getMappedElement(CONF_ELEMENTS_ELEMENT(buffer, j));
2484 else if (data_type == TYPE_CONTENT_LIST)
2486 struct Content *content= (struct Content *)(element_conf[i].value);
2489 for (c = 0; c < num_entities; c++)
2490 for (y = 0; y < 3; y++)
2491 for (x = 0; x < 3; x++)
2492 content[c].e[x][y] =
2493 getMappedElement(CONF_CONTENTS_ELEMENT(buffer, c, x, y));
2496 element_found = FALSE;
2502 checked_free(buffer);
2504 real_chunk_size += 2 + num_bytes;
2506 else /* constant size configuration data (1, 2 or 4 bytes) */
2508 int value = (byte_mask == CONF_MASK_1_BYTE ? getFile8Bit (file) :
2509 byte_mask == CONF_MASK_2_BYTE ? getFile16BitBE(file) :
2510 byte_mask == CONF_MASK_4_BYTE ? getFile32BitBE(file) : 0);
2512 for (i = 0; element_conf[i].data_type != -1; i++)
2514 if (element_conf[i].element == element &&
2515 element_conf[i].conf_type == conf_type)
2517 int data_type = element_conf[i].data_type;
2519 if (data_type == TYPE_BOOLEAN)
2520 *(boolean *)(element_conf[i].value) = value;
2522 *(int *) (element_conf[i].value) = value;
2524 element_found = TRUE;
2530 real_chunk_size += CONF_VALUE_NUM_BYTES(byte_mask);
2534 Error(ERR_WARN, "cannot load CONF value for element %d", element);
2538 *level = li; /* copy temporary buffer back to level data */
2542 if (real_chunk_size >= chunk_size)
2545 if (conf_type == CONF_LAST_ENTRY || real_chunk_size >= chunk_size)
2551 *level = li; /* copy temporary buffer back to level data */
2554 return real_chunk_size;
2557 static int LoadLevel_CUSX(FILE *file, int chunk_size, struct LevelInfo *level)
2559 int element = getFile16BitBE(file);
2560 int real_chunk_size = 2;
2561 struct ElementInfo *ei = &element_info[element];
2565 printf("::: CUSX: loading element '%s' ...\n", EL_NAME(element));
2568 xx_ei = *ei; /* copy element data into temporary buffer */
2570 xx_ei.num_change_pages = -1;
2574 real_chunk_size += LoadLevel_MicroChunk(file, custom_element_conf, -1);
2577 printf("::: - real_chunk_size now %d\n", real_chunk_size);
2580 if (xx_ei.num_change_pages != -1)
2583 if (real_chunk_size >= chunk_size)
2589 if (ei->num_change_pages == -1)
2591 Error(ERR_WARN, "LoadLevel_CUSX(): missing 'num_change_pages' for '%s'",
2594 ei->num_change_pages = 1;
2596 setElementChangePages(ei, 1);
2597 setElementChangeInfoToDefaults(ei->change);
2599 return real_chunk_size;
2602 /* initialize number of change pages stored for this custom element */
2603 setElementChangePages(ei, ei->num_change_pages);
2604 for (i = 0; i < ei->num_change_pages; i++)
2605 setElementChangeInfoToDefaults(&ei->change_page[i]);
2607 /* start with reading properties for the first change page */
2608 xx_current_change_page = 0;
2612 struct ElementChangeInfo *change = &ei->change_page[xx_current_change_page];
2614 xx_change = *change; /* copy change data into temporary buffer */
2616 resetEventBits(); /* reset bits; change page might have changed */
2618 real_chunk_size += LoadLevel_MicroChunk(file,custom_element_change_conf,-1);
2620 *change = xx_change;
2622 setEventFlagsFromEventBits(change);
2624 if (real_chunk_size >= chunk_size)
2628 return real_chunk_size;
2631 static int LoadLevel_GRPX(FILE *file, int chunk_size, struct LevelInfo *level)
2633 int element = getFile16BitBE(file);
2634 int real_chunk_size = 2;
2635 struct ElementInfo *ei = &element_info[element];
2636 struct ElementGroupInfo *group = ei->group;
2638 xx_ei = *ei; /* copy element data into temporary buffer */
2639 xx_group = *group; /* copy group data into temporary buffer */
2643 real_chunk_size += LoadLevel_MicroChunk(file, group_element_conf, -1);
2645 if (real_chunk_size >= chunk_size)
2652 return real_chunk_size;
2655 static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
2656 struct LevelFileInfo *level_file_info)
2658 char *filename = level_file_info->filename;
2659 char cookie[MAX_LINE_LEN];
2660 char chunk_name[CHUNK_ID_LEN + 1];
2664 if (!(file = fopen(filename, MODE_READ)))
2666 level->no_valid_file = TRUE;
2668 if (level != &level_template)
2669 Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
2674 getFileChunkBE(file, chunk_name, NULL);
2675 if (strEqual(chunk_name, "RND1"))
2677 getFile32BitBE(file); /* not used */
2679 getFileChunkBE(file, chunk_name, NULL);
2680 if (!strEqual(chunk_name, "CAVE"))
2682 level->no_valid_file = TRUE;
2684 Error(ERR_WARN, "unknown format of level file '%s'", filename);
2689 else /* check for pre-2.0 file format with cookie string */
2691 strcpy(cookie, chunk_name);
2692 fgets(&cookie[4], MAX_LINE_LEN - 4, file);
2693 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
2694 cookie[strlen(cookie) - 1] = '\0';
2696 if (!checkCookieString(cookie, LEVEL_COOKIE_TMPL))
2698 level->no_valid_file = TRUE;
2700 Error(ERR_WARN, "unknown format of level file '%s'", filename);
2705 if ((level->file_version = getFileVersionFromCookieString(cookie)) == -1)
2707 level->no_valid_file = TRUE;
2709 Error(ERR_WARN, "unsupported version of level file '%s'", filename);
2714 /* pre-2.0 level files have no game version, so use file version here */
2715 level->game_version = level->file_version;
2718 if (level->file_version < FILE_VERSION_1_2)
2720 /* level files from versions before 1.2.0 without chunk structure */
2721 LoadLevel_HEAD(file, LEVEL_HEADER_SIZE, level);
2722 LoadLevel_BODY(file, level->fieldx * level->fieldy, level);
2730 int (*loader)(FILE *, int, struct LevelInfo *);
2734 { "VERS", FILE_VERS_CHUNK_SIZE, LoadLevel_VERS },
2735 { "HEAD", LEVEL_HEADER_SIZE, LoadLevel_HEAD },
2736 { "AUTH", MAX_LEVEL_AUTHOR_LEN, LoadLevel_AUTH },
2737 { "BODY", -1, LoadLevel_BODY },
2738 { "CONT", -1, LoadLevel_CONT },
2739 { "CNT2", LEVEL_CHUNK_CNT2_SIZE, LoadLevel_CNT2 },
2740 { "CNT3", -1, LoadLevel_CNT3 },
2741 { "CUS1", -1, LoadLevel_CUS1 },
2742 { "CUS2", -1, LoadLevel_CUS2 },
2743 { "CUS3", -1, LoadLevel_CUS3 },
2744 { "CUS4", -1, LoadLevel_CUS4 },
2745 { "GRP1", -1, LoadLevel_GRP1 },
2746 { "CONF", -1, LoadLevel_CONF },
2748 { "CUSX", -1, LoadLevel_CUSX },
2749 { "GRPX", -1, LoadLevel_GRPX },
2755 while (getFileChunkBE(file, chunk_name, &chunk_size))
2759 while (chunk_info[i].name != NULL &&
2760 !strEqual(chunk_name, chunk_info[i].name))
2763 if (chunk_info[i].name == NULL)
2765 Error(ERR_WARN, "unknown chunk '%s' in level file '%s'",
2766 chunk_name, filename);
2767 ReadUnusedBytesFromFile(file, chunk_size);
2769 else if (chunk_info[i].size != -1 &&
2770 chunk_info[i].size != chunk_size)
2772 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
2773 chunk_size, chunk_name, filename);
2774 ReadUnusedBytesFromFile(file, chunk_size);
2778 /* call function to load this level chunk */
2779 int chunk_size_expected =
2780 (chunk_info[i].loader)(file, chunk_size, level);
2782 /* the size of some chunks cannot be checked before reading other
2783 chunks first (like "HEAD" and "BODY") that contain some header
2784 information, so check them here */
2785 if (chunk_size_expected != chunk_size)
2787 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
2788 chunk_size, chunk_name, filename);
2797 /* ------------------------------------------------------------------------- */
2798 /* functions for loading EM level */
2799 /* ------------------------------------------------------------------------- */
2803 static int map_em_element_yam(int element)
2807 case 0x00: return EL_EMPTY;
2808 case 0x01: return EL_EMERALD;
2809 case 0x02: return EL_DIAMOND;
2810 case 0x03: return EL_ROCK;
2811 case 0x04: return EL_ROBOT;
2812 case 0x05: return EL_SPACESHIP_UP;
2813 case 0x06: return EL_BOMB;
2814 case 0x07: return EL_BUG_UP;
2815 case 0x08: return EL_AMOEBA_DROP;
2816 case 0x09: return EL_NUT;
2817 case 0x0a: return EL_YAMYAM;
2818 case 0x0b: return EL_QUICKSAND_FULL;
2819 case 0x0c: return EL_SAND;
2820 case 0x0d: return EL_WALL_SLIPPERY;
2821 case 0x0e: return EL_STEELWALL;
2822 case 0x0f: return EL_WALL;
2823 case 0x10: return EL_EM_KEY_1;
2824 case 0x11: return EL_EM_KEY_2;
2825 case 0x12: return EL_EM_KEY_4;
2826 case 0x13: return EL_EM_KEY_3;
2827 case 0x14: return EL_MAGIC_WALL;
2828 case 0x15: return EL_ROBOT_WHEEL;
2829 case 0x16: return EL_DYNAMITE;
2831 case 0x17: return EL_EM_KEY_1; /* EMC */
2832 case 0x18: return EL_BUG_UP; /* EMC */
2833 case 0x1a: return EL_DIAMOND; /* EMC */
2834 case 0x1b: return EL_EMERALD; /* EMC */
2835 case 0x25: return EL_NUT; /* EMC */
2836 case 0x80: return EL_EMPTY; /* EMC */
2837 case 0x85: return EL_EM_KEY_1; /* EMC */
2838 case 0x86: return EL_EM_KEY_2; /* EMC */
2839 case 0x87: return EL_EM_KEY_4; /* EMC */
2840 case 0x88: return EL_EM_KEY_3; /* EMC */
2841 case 0x94: return EL_QUICKSAND_EMPTY; /* EMC */
2842 case 0x9a: return EL_AMOEBA_WET; /* EMC */
2843 case 0xaf: return EL_DYNAMITE; /* EMC */
2844 case 0xbd: return EL_SAND; /* EMC */
2847 Error(ERR_WARN, "invalid level element %d", element);
2852 static int map_em_element_field(int element)
2854 if (element >= 0xc8 && element <= 0xe1)
2855 return EL_CHAR_A + (element - 0xc8);
2856 else if (element >= 0xe2 && element <= 0xeb)
2857 return EL_CHAR_0 + (element - 0xe2);
2861 case 0x00: return EL_ROCK;
2862 case 0x01: return EL_ROCK; /* EMC */
2863 case 0x02: return EL_DIAMOND;
2864 case 0x03: return EL_DIAMOND;
2865 case 0x04: return EL_ROBOT;
2866 case 0x05: return EL_ROBOT; /* EMC */
2867 case 0x06: return EL_EMPTY_SPACE; /* EMC */
2868 case 0x07: return EL_EMPTY_SPACE; /* EMC */
2869 case 0x08: return EL_SPACESHIP_UP;
2870 case 0x09: return EL_SPACESHIP_RIGHT;
2871 case 0x0a: return EL_SPACESHIP_DOWN;
2872 case 0x0b: return EL_SPACESHIP_LEFT;
2873 case 0x0c: return EL_SPACESHIP_UP;
2874 case 0x0d: return EL_SPACESHIP_RIGHT;
2875 case 0x0e: return EL_SPACESHIP_DOWN;
2876 case 0x0f: return EL_SPACESHIP_LEFT;
2878 case 0x10: return EL_BOMB;
2879 case 0x11: return EL_BOMB; /* EMC */
2880 case 0x12: return EL_EMERALD;
2881 case 0x13: return EL_EMERALD;
2882 case 0x14: return EL_BUG_UP;
2883 case 0x15: return EL_BUG_RIGHT;
2884 case 0x16: return EL_BUG_DOWN;
2885 case 0x17: return EL_BUG_LEFT;
2886 case 0x18: return EL_BUG_UP;
2887 case 0x19: return EL_BUG_RIGHT;
2888 case 0x1a: return EL_BUG_DOWN;
2889 case 0x1b: return EL_BUG_LEFT;
2890 case 0x1c: return EL_AMOEBA_DROP;
2891 case 0x1d: return EL_AMOEBA_DROP; /* EMC */
2892 case 0x1e: return EL_AMOEBA_DROP; /* EMC */
2893 case 0x1f: return EL_AMOEBA_DROP; /* EMC */
2895 case 0x20: return EL_ROCK;
2896 case 0x21: return EL_BOMB; /* EMC */
2897 case 0x22: return EL_DIAMOND; /* EMC */
2898 case 0x23: return EL_EMERALD; /* EMC */
2899 case 0x24: return EL_MAGIC_WALL;
2900 case 0x25: return EL_NUT;
2901 case 0x26: return EL_NUT; /* EMC */
2902 case 0x27: return EL_NUT; /* EMC */
2904 /* looks like magic wheel, but is _always_ activated */
2905 case 0x28: return EL_ROBOT_WHEEL; /* EMC */
2907 case 0x29: return EL_YAMYAM; /* up */
2908 case 0x2a: return EL_YAMYAM; /* down */
2909 case 0x2b: return EL_YAMYAM; /* left */ /* EMC */
2910 case 0x2c: return EL_YAMYAM; /* right */ /* EMC */
2911 case 0x2d: return EL_QUICKSAND_FULL;
2912 case 0x2e: return EL_EMPTY_SPACE; /* EMC */
2913 case 0x2f: return EL_EMPTY_SPACE; /* EMC */
2915 case 0x30: return EL_EMPTY_SPACE; /* EMC */
2916 case 0x31: return EL_SAND; /* EMC */
2917 case 0x32: return EL_SAND; /* EMC */
2918 case 0x33: return EL_SAND; /* EMC */
2919 case 0x34: return EL_QUICKSAND_FULL; /* EMC */
2920 case 0x35: return EL_QUICKSAND_FULL; /* EMC */
2921 case 0x36: return EL_QUICKSAND_FULL; /* EMC */
2922 case 0x37: return EL_SAND; /* EMC */
2923 case 0x38: return EL_ROCK; /* EMC */
2924 case 0x39: return EL_EXPANDABLE_WALL_HORIZONTAL; /* EMC */
2925 case 0x3a: return EL_EXPANDABLE_WALL_VERTICAL; /* EMC */
2926 case 0x3b: return EL_DYNAMITE_ACTIVE; /* 1 */
2927 case 0x3c: return EL_DYNAMITE_ACTIVE; /* 2 */
2928 case 0x3d: return EL_DYNAMITE_ACTIVE; /* 3 */
2929 case 0x3e: return EL_DYNAMITE_ACTIVE; /* 4 */
2930 case 0x3f: return EL_ACID_POOL_BOTTOM;
2932 case 0x40: return EL_EXIT_OPEN; /* 1 */
2933 case 0x41: return EL_EXIT_OPEN; /* 2 */
2934 case 0x42: return EL_EXIT_OPEN; /* 3 */
2935 case 0x43: return EL_BALLOON; /* EMC */
2936 case 0x44: return EL_UNKNOWN; /* EMC ("plant") */
2937 case 0x45: return EL_SPRING; /* EMC */
2938 case 0x46: return EL_SPRING; /* falling */ /* EMC */
2939 case 0x47: return EL_SPRING; /* left */ /* EMC */
2940 case 0x48: return EL_SPRING; /* right */ /* EMC */
2941 case 0x49: return EL_UNKNOWN; /* EMC ("ball 1") */
2942 case 0x4a: return EL_UNKNOWN; /* EMC ("ball 2") */
2943 case 0x4b: return EL_UNKNOWN; /* EMC ("android") */
2944 case 0x4c: return EL_EMPTY_SPACE; /* EMC */
2945 case 0x4d: return EL_UNKNOWN; /* EMC ("android") */
2946 case 0x4e: return EL_INVISIBLE_WALL; /* EMC (? "android") */
2947 case 0x4f: return EL_UNKNOWN; /* EMC ("android") */
2949 case 0x50: return EL_UNKNOWN; /* EMC ("android") */
2950 case 0x51: return EL_UNKNOWN; /* EMC ("android") */
2951 case 0x52: return EL_UNKNOWN; /* EMC ("android") */
2952 case 0x53: return EL_UNKNOWN; /* EMC ("android") */
2953 case 0x54: return EL_UNKNOWN; /* EMC ("android") */
2954 case 0x55: return EL_EMPTY_SPACE; /* EMC */
2955 case 0x56: return EL_EMPTY_SPACE; /* EMC */
2956 case 0x57: return EL_EMPTY_SPACE; /* EMC */
2957 case 0x58: return EL_EMPTY_SPACE; /* EMC */
2958 case 0x59: return EL_EMPTY_SPACE; /* EMC */
2959 case 0x5a: return EL_EMPTY_SPACE; /* EMC */
2960 case 0x5b: return EL_EMPTY_SPACE; /* EMC */
2961 case 0x5c: return EL_EMPTY_SPACE; /* EMC */
2962 case 0x5d: return EL_EMPTY_SPACE; /* EMC */
2963 case 0x5e: return EL_EMPTY_SPACE; /* EMC */
2964 case 0x5f: return EL_EMPTY_SPACE; /* EMC */
2966 case 0x60: return EL_EMPTY_SPACE; /* EMC */
2967 case 0x61: return EL_EMPTY_SPACE; /* EMC */
2968 case 0x62: return EL_EMPTY_SPACE; /* EMC */
2969 case 0x63: return EL_SPRING; /* left */ /* EMC */
2970 case 0x64: return EL_SPRING; /* right */ /* EMC */
2971 case 0x65: return EL_ACID; /* 1 */ /* EMC */
2972 case 0x66: return EL_ACID; /* 2 */ /* EMC */
2973 case 0x67: return EL_ACID; /* 3 */ /* EMC */
2974 case 0x68: return EL_ACID; /* 4 */ /* EMC */
2975 case 0x69: return EL_ACID; /* 5 */ /* EMC */
2976 case 0x6a: return EL_ACID; /* 6 */ /* EMC */
2977 case 0x6b: return EL_ACID; /* 7 */ /* EMC */
2978 case 0x6c: return EL_ACID; /* 8 */ /* EMC */
2979 case 0x6d: return EL_EMPTY_SPACE; /* EMC */
2980 case 0x6e: return EL_EMPTY_SPACE; /* EMC */
2981 case 0x6f: return EL_EMPTY_SPACE; /* EMC */
2983 case 0x70: return EL_EMPTY_SPACE; /* EMC */
2984 case 0x71: return EL_EMPTY_SPACE; /* EMC */
2985 case 0x72: return EL_NUT; /* left */ /* EMC */
2986 case 0x73: return EL_SAND; /* EMC (? "nut") */
2987 case 0x74: return EL_STEELWALL;
2988 case 0x75: return EL_EMPTY_SPACE; /* EMC */
2989 case 0x76: return EL_EMPTY_SPACE; /* EMC */
2990 case 0x77: return EL_BOMB; /* left */ /* EMC */
2991 case 0x78: return EL_BOMB; /* right */ /* EMC */
2992 case 0x79: return EL_ROCK; /* left */ /* EMC */
2993 case 0x7a: return EL_ROCK; /* right */ /* EMC */
2994 case 0x7b: return EL_ACID; /* (? EMC "blank") */
2995 case 0x7c: return EL_EMPTY_SPACE; /* EMC */
2996 case 0x7d: return EL_EMPTY_SPACE; /* EMC */
2997 case 0x7e: return EL_EMPTY_SPACE; /* EMC */
2998 case 0x7f: return EL_EMPTY_SPACE; /* EMC */
3000 case 0x80: return EL_EMPTY;
3001 case 0x81: return EL_WALL_SLIPPERY;
3002 case 0x82: return EL_SAND;
3003 case 0x83: return EL_STEELWALL;
3004 case 0x84: return EL_WALL;
3005 case 0x85: return EL_EM_KEY_1;
3006 case 0x86: return EL_EM_KEY_2;
3007 case 0x87: return EL_EM_KEY_4;
3008 case 0x88: return EL_EM_KEY_3;
3009 case 0x89: return EL_EM_GATE_1;
3010 case 0x8a: return EL_EM_GATE_2;
3011 case 0x8b: return EL_EM_GATE_4;
3012 case 0x8c: return EL_EM_GATE_3;
3013 case 0x8d: return EL_INVISIBLE_WALL; /* EMC (? "dripper") */
3014 case 0x8e: return EL_EM_GATE_1_GRAY;
3015 case 0x8f: return EL_EM_GATE_2_GRAY;
3017 case 0x90: return EL_EM_GATE_4_GRAY;
3018 case 0x91: return EL_EM_GATE_3_GRAY;
3019 case 0x92: return EL_MAGIC_WALL;
3020 case 0x93: return EL_ROBOT_WHEEL;
3021 case 0x94: return EL_QUICKSAND_EMPTY; /* (? EMC "sand") */
3022 case 0x95: return EL_ACID_POOL_TOPLEFT;
3023 case 0x96: return EL_ACID_POOL_TOPRIGHT;
3024 case 0x97: return EL_ACID_POOL_BOTTOMLEFT;
3025 case 0x98: return EL_ACID_POOL_BOTTOMRIGHT;
3026 case 0x99: return EL_ACID; /* (? EMC "fake blank") */
3027 case 0x9a: return EL_AMOEBA_DEAD; /* 1 */
3028 case 0x9b: return EL_AMOEBA_DEAD; /* 2 */
3029 case 0x9c: return EL_AMOEBA_DEAD; /* 3 */
3030 case 0x9d: return EL_AMOEBA_DEAD; /* 4 */
3031 case 0x9e: return EL_EXIT_CLOSED;
3032 case 0x9f: return EL_CHAR_LESS; /* arrow left */
3034 /* looks like normal sand, but behaves like wall */
3035 case 0xa0: return EL_UNKNOWN; /* EMC ("fake grass") */
3036 case 0xa1: return EL_UNKNOWN; /* EMC ("lenses") */
3037 case 0xa2: return EL_UNKNOWN; /* EMC ("magnify") */
3038 case 0xa3: return EL_UNKNOWN; /* EMC ("fake blank") */
3039 case 0xa4: return EL_UNKNOWN; /* EMC ("fake grass") */
3040 case 0xa5: return EL_UNKNOWN; /* EMC ("switch") */
3041 case 0xa6: return EL_UNKNOWN; /* EMC ("switch") */
3042 case 0xa7: return EL_EMPTY_SPACE; /* EMC */
3043 case 0xa8: return EL_EMC_WALL_1; /* EMC ("decor 8") */
3044 case 0xa9: return EL_EMC_WALL_2; /* EMC ("decor 9") */
3045 case 0xaa: return EL_EMC_WALL_3; /* EMC ("decor 10") */
3046 case 0xab: return EL_EMC_WALL_7; /* EMC ("decor 5") */
3047 case 0xac: return EL_CHAR_COMMA; /* EMC */
3048 case 0xad: return EL_CHAR_QUOTEDBL; /* EMC */
3049 case 0xae: return EL_CHAR_MINUS; /* EMC */
3050 case 0xaf: return EL_DYNAMITE;
3052 case 0xb0: return EL_EMC_STEELWALL_1; /* EMC ("steel 3") */
3053 case 0xb1: return EL_EMC_WALL_8; /* EMC ("decor 6") */
3054 case 0xb2: return EL_UNKNOWN; /* EMC ("decor 7") */
3055 case 0xb3: return EL_STEELWALL; /* 2 */ /* EMC */
3056 case 0xb4: return EL_WALL_SLIPPERY; /* 2 */ /* EMC */
3057 case 0xb5: return EL_EMC_WALL_6; /* EMC ("decor 2") */
3058 case 0xb6: return EL_EMC_WALL_5; /* EMC ("decor 4") */
3059 case 0xb7: return EL_EMC_WALL_4; /* EMC ("decor 3") */
3060 case 0xb8: return EL_BALLOON_SWITCH_ANY; /* EMC */
3061 case 0xb9: return EL_BALLOON_SWITCH_RIGHT; /* EMC */
3062 case 0xba: return EL_BALLOON_SWITCH_DOWN; /* EMC */
3063 case 0xbb: return EL_BALLOON_SWITCH_LEFT; /* EMC */
3064 case 0xbc: return EL_BALLOON_SWITCH_UP; /* EMC */
3065 case 0xbd: return EL_SAND; /* EMC ("dirt") */
3066 case 0xbe: return EL_UNKNOWN; /* EMC ("plant") */
3067 case 0xbf: return EL_UNKNOWN; /* EMC ("key 5") */
3069 case 0xc0: return EL_UNKNOWN; /* EMC ("key 6") */
3070 case 0xc1: return EL_UNKNOWN; /* EMC ("key 7") */
3071 case 0xc2: return EL_UNKNOWN; /* EMC ("key 8") */
3072 case 0xc3: return EL_UNKNOWN; /* EMC ("door 5") */
3073 case 0xc4: return EL_UNKNOWN; /* EMC ("door 6") */
3074 case 0xc5: return EL_UNKNOWN; /* EMC ("door 7") */
3075 case 0xc6: return EL_UNKNOWN; /* EMC ("door 8") */
3076 case 0xc7: return EL_UNKNOWN; /* EMC ("bumper") */
3078 /* characters: see above */
3080 case 0xec: return EL_CHAR_PERIOD;
3081 case 0xed: return EL_CHAR_EXCLAM;
3082 case 0xee: return EL_CHAR_COLON;
3083 case 0xef: return EL_CHAR_QUESTION;
3085 case 0xf0: return EL_CHAR_GREATER; /* arrow right */
3086 case 0xf1: return EL_CHAR_COPYRIGHT; /* EMC: "decor 1" */
3087 case 0xf2: return EL_UNKNOWN; /* EMC ("fake door 5") */
3088 case 0xf3: return EL_UNKNOWN; /* EMC ("fake door 6") */
3089 case 0xf4: return EL_UNKNOWN; /* EMC ("fake door 7") */
3090 case 0xf5: return EL_UNKNOWN; /* EMC ("fake door 8") */
3091 case 0xf6: return EL_EMPTY_SPACE; /* EMC */
3092 case 0xf7: return EL_EMPTY_SPACE; /* EMC */
3094 case 0xf8: return EL_EMPTY_SPACE; /* EMC */
3095 case 0xf9: return EL_EMPTY_SPACE; /* EMC */
3096 case 0xfa: return EL_EMPTY_SPACE; /* EMC */
3097 case 0xfb: return EL_EMPTY_SPACE; /* EMC */
3098 case 0xfc: return EL_EMPTY_SPACE; /* EMC */
3099 case 0xfd: return EL_EMPTY_SPACE; /* EMC */
3101 case 0xfe: return EL_PLAYER_1; /* EMC: "blank" */
3102 case 0xff: return EL_PLAYER_2; /* EMC: "blank" */
3105 /* should never happen (all 8-bit value cases should be handled) */
3106 Error(ERR_WARN, "invalid level element %d", element);
3111 #define EM_LEVEL_SIZE 2106
3112 #define EM_LEVEL_XSIZE 64
3113 #define EM_LEVEL_YSIZE 32
3115 static void OLD_LoadLevelFromFileInfo_EM(struct LevelInfo *level,
3116 struct LevelFileInfo *level_file_info)
3118 char *filename = level_file_info->filename;
3120 unsigned char leveldata[EM_LEVEL_SIZE];
3121 unsigned char *header = &leveldata[EM_LEVEL_XSIZE * EM_LEVEL_YSIZE];
3122 int nr = level_file_info->nr;
3125 if (!(file = fopen(filename, MODE_READ)))
3127 level->no_valid_file = TRUE;
3129 Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
3134 for (i = 0; i < EM_LEVEL_SIZE; i++)
3135 leveldata[i] = fgetc(file);
3139 /* check if level data is crypted by testing against known starting bytes
3140 of the few existing crypted level files (from Emerald Mine 1 + 2) */
3142 if ((leveldata[0] == 0xf1 ||
3143 leveldata[0] == 0xf5) && leveldata[2] == 0xe7 && leveldata[3] == 0xee)
3145 unsigned char code0 = 0x65;
3146 unsigned char code1 = 0x11;
3148 if (leveldata[0] == 0xf5) /* error in crypted Emerald Mine 2 levels */
3149 leveldata[0] = 0xf1;
3151 /* decode crypted level data */
3153 for (i = 0; i < EM_LEVEL_SIZE; i++)
3155 leveldata[i] ^= code0;
3156 leveldata[i] -= code1;
3158 code0 = (code0 + 7) & 0xff;
3162 level->fieldx = EM_LEVEL_XSIZE;
3163 level->fieldy = EM_LEVEL_YSIZE;
3165 level->time = header[46] * 10;
3166 level->gems_needed = header[47];
3168 /* The original Emerald Mine levels have their level number stored
3169 at the second byte of the level file...
3170 Do not trust this information at other level files, e.g. EMC,
3171 but correct it anyway (normally the first row is completely
3172 steel wall, so the correction does not hurt anyway). */
3174 if (leveldata[1] == nr)
3175 leveldata[1] = leveldata[2]; /* correct level number field */
3177 sprintf(level->name, "Level %d", nr); /* set level name */
3179 level->score[SC_EMERALD] = header[36];
3180 level->score[SC_DIAMOND] = header[37];
3181 level->score[SC_ROBOT] = header[38];
3182 level->score[SC_SPACESHIP] = header[39];
3183 level->score[SC_BUG] = header[40];
3184 level->score[SC_YAMYAM] = header[41];
3185 level->score[SC_NUT] = header[42];
3186 level->score[SC_DYNAMITE] = header[43];
3187 level->score[SC_TIME_BONUS] = header[44];
3189 level->num_yamyam_contents = 4;
3191 for (i = 0; i < level->num_yamyam_contents; i++)
3192 for (y = 0; y < 3; y++)
3193 for (x = 0; x < 3; x++)
3194 level->yamyam_content[i].e[x][y] =
3195 map_em_element_yam(header[i * 9 + y * 3 + x]);
3197 level->amoeba_speed = (header[52] * 256 + header[53]) % 256;
3198 level->time_magic_wall = (header[54] * 256 + header[55]) * 16 / 100;
3199 level->time_wheel = (header[56] * 256 + header[57]) * 16 / 100;
3200 level->amoeba_content = EL_DIAMOND;
3202 for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
3204 int new_element = map_em_element_field(leveldata[y * EM_LEVEL_XSIZE + x]);
3206 if (new_element == EL_AMOEBA_DEAD && level->amoeba_speed)
3207 new_element = EL_AMOEBA_WET;
3209 level->field[x][y] = new_element;
3212 x = (header[48] * 256 + header[49]) % EM_LEVEL_XSIZE;
3213 y = (header[48] * 256 + header[49]) / EM_LEVEL_XSIZE;
3214 level->field[x][y] = EL_PLAYER_1;
3216 x = (header[50] * 256 + header[51]) % EM_LEVEL_XSIZE;
3217 y = (header[50] * 256 + header[51]) / EM_LEVEL_XSIZE;
3218 level->field[x][y] = EL_PLAYER_2;
3223 void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
3225 static int ball_xy[8][2] =
3236 struct LevelInfo_EM *level_em = level->native_em_level;
3237 struct LEVEL *lev = level_em->lev;
3238 struct PLAYER **ply = level_em->ply;
3243 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3244 for (j = 0; j < 8; j++)
3245 printf("::: ball %d, %d: %d\n", i, j,
3246 level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
3249 lev->width = MIN(level->fieldx, EM_MAX_CAVE_WIDTH);
3250 lev->height = MIN(level->fieldy, EM_MAX_CAVE_HEIGHT);
3252 lev->time_seconds = level->time;
3253 lev->required_initial = level->gems_needed;
3255 lev->emerald_score = level->score[SC_EMERALD];
3256 lev->diamond_score = level->score[SC_DIAMOND];
3257 lev->alien_score = level->score[SC_ROBOT];
3258 lev->tank_score = level->score[SC_SPACESHIP];
3259 lev->bug_score = level->score[SC_BUG];
3260 lev->eater_score = level->score[SC_YAMYAM];
3261 lev->nut_score = level->score[SC_NUT];
3262 lev->dynamite_score = level->score[SC_DYNAMITE];
3263 lev->key_score = level->score[SC_KEY];
3264 lev->exit_score = level->score[SC_TIME_BONUS];
3266 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3267 for (y = 0; y < 3; y++)
3268 for (x = 0; x < 3; x++)
3269 lev->eater_array[i][y * 3 + x] =
3270 map_element_RND_to_EM(level->yamyam_content[i].e[x][y]);
3272 lev->amoeba_time = level->amoeba_speed;
3273 lev->wonderwall_time_initial = level->time_magic_wall;
3274 lev->wheel_time = level->time_wheel;
3276 lev->android_move_time = level->android_move_time;
3277 lev->android_clone_time = level->android_clone_time;
3278 lev->ball_random = level->ball_random;
3279 lev->ball_state_initial = level->ball_state_initial;
3280 lev->ball_time = level->ball_time;
3281 lev->num_ball_arrays = level->num_ball_contents;
3283 lev->lenses_score = level->lenses_score;
3284 lev->magnify_score = level->magnify_score;
3285 lev->slurp_score = level->slurp_score;
3287 lev->lenses_time = level->lenses_time;
3288 lev->magnify_time = level->magnify_time;
3290 lev->wind_direction_initial =
3291 map_direction_RND_to_EM(level->wind_direction_initial);
3292 lev->wind_cnt_initial = (level->wind_direction_initial != MV_NONE ?
3293 lev->wind_time : 0);
3295 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3296 for (j = 0; j < 8; j++)
3297 lev->ball_array[i][j] =
3298 map_element_RND_to_EM(level->
3299 ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
3302 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3303 for (j = 0; j < 8; j++)
3304 printf("::: ball %d, %d: %d\n", i, j,
3305 level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
3308 map_android_clone_elements_RND_to_EM(level);
3311 for (i = 0; i < 16; i++)
3312 lev->android_array[i] = FALSE; /* !!! YET TO COME !!! */
3315 /* first fill the complete playfield with the default border element */
3316 for (y = 0; y < EM_MAX_CAVE_HEIGHT; y++)
3317 for (x = 0; x < EM_MAX_CAVE_WIDTH; x++)
3318 level_em->cave[x][y] = ZBORDER;
3324 LoadLevel_InitPlayfield();
3326 lev_fieldx = lev->width; /* !!! also in LoadLevel_InitPlayfield() !!! */
3327 lev_fieldy = lev->height; /* !!! also in LoadLevel_InitPlayfield() !!! */
3328 SetBorderElement(); /* !!! also in LoadLevel_InitPlayfield() !!! */
3333 printf("::: BorderElement == %d\n", BorderElement);
3336 if (BorderElement == EL_STEELWALL)
3338 for (y = 0; y < lev->height + 2; y++)
3339 for (x = 0; x < lev->width + 2; x++)
3340 level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_STEELWALL);
3343 /* then copy the real level contents from level file into the playfield */
3344 for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
3346 int new_element = map_element_RND_to_EM(level->field[x][y]);
3347 int offset = (BorderElement == EL_STEELWALL ? 1 : 0);
3348 int xx = x + 1 + offset;
3349 int yy = y + 1 + offset;
3351 if (level->field[x][y] == EL_AMOEBA_DEAD)
3352 new_element = map_element_RND_to_EM(EL_AMOEBA_WET);
3354 level_em->cave[xx][yy] = new_element;
3359 /* then copy the real level contents from level file into the playfield */
3360 for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
3362 int new_element = map_element_RND_to_EM(level->field[x][y]);
3364 if (level->field[x][y] == EL_AMOEBA_DEAD)
3365 new_element = map_element_RND_to_EM(EL_AMOEBA_WET);
3367 level_em->cave[x + 1][y + 1] = new_element;
3374 for (i = 0; i < MAX_PLAYERS; i++)
3376 ply[i]->x_initial = 0;
3377 ply[i]->y_initial = 0;
3382 ply1->x_initial = 0;
3383 ply1->y_initial = 0;
3385 ply2->x_initial = 0;
3386 ply2->y_initial = 0;
3390 /* initialize player positions and delete players from the playfield */
3391 for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
3395 if (ELEM_IS_PLAYER(level->field[x][y]))
3397 int player_nr = GET_PLAYER_NR(level->field[x][y]);
3398 int offset = (BorderElement == EL_STEELWALL ? 1 : 0);
3399 int xx = x + 1 + offset;
3400 int yy = y + 1 + offset;
3402 ply[player_nr]->x_initial = xx;
3403 ply[player_nr]->y_initial = yy;
3405 level_em->cave[xx][yy] = map_element_RND_to_EM(EL_EMPTY);
3411 /* !!! CURRENTLY ONLY SUPPORT FOR ONE PLAYER !!! */
3412 if (ELEM_IS_PLAYER(level->field[x][y]))
3414 ply1->x_initial = x + 1;
3415 ply1->y_initial = y + 1;
3416 level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_EMPTY);
3419 /* !!! ADD SUPPORT FOR MORE THAN ONE PLAYER !!! */
3420 if (level->field[x][y] == EL_PLAYER_1)
3422 ply1->x_initial = x + 1;
3423 ply1->y_initial = y + 1;
3424 level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_EMPTY);
3426 else if (level->field[x][y] == EL_PLAYER_2)
3428 ply2->x_initial = x + 1;
3429 ply2->y_initial = y + 1;
3430 level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_EMPTY);
3438 if (BorderElement == EL_STEELWALL)
3447 void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
3449 static int ball_xy[8][2] =
3460 struct LevelInfo_EM *level_em = level->native_em_level;
3461 struct LEVEL *lev = level_em->lev;
3462 struct PLAYER **ply = level_em->ply;
3465 level->fieldx = MIN(lev->width, MAX_LEV_FIELDX);
3466 level->fieldy = MIN(lev->height, MAX_LEV_FIELDY);
3468 level->time = lev->time_seconds;
3469 level->gems_needed = lev->required_initial;
3471 sprintf(level->name, "Level %d", level->file_info.nr);
3473 level->score[SC_EMERALD] = lev->emerald_score;
3474 level->score[SC_DIAMOND] = lev->diamond_score;
3475 level->score[SC_ROBOT] = lev->alien_score;
3476 level->score[SC_SPACESHIP] = lev->tank_score;
3477 level->score[SC_BUG] = lev->bug_score;
3478 level->score[SC_YAMYAM] = lev->eater_score;
3479 level->score[SC_NUT] = lev->nut_score;
3480 level->score[SC_DYNAMITE] = lev->dynamite_score;
3481 level->score[SC_KEY] = lev->key_score;
3482 level->score[SC_TIME_BONUS] = lev->exit_score;
3484 level->num_yamyam_contents = MAX_ELEMENT_CONTENTS;
3486 for (i = 0; i < level->num_yamyam_contents; i++)
3487 for (y = 0; y < 3; y++)
3488 for (x = 0; x < 3; x++)
3489 level->yamyam_content[i].e[x][y] =
3490 map_element_EM_to_RND(lev->eater_array[i][y * 3 + x]);
3492 level->amoeba_speed = lev->amoeba_time;
3493 level->time_magic_wall = lev->wonderwall_time_initial;
3494 level->time_wheel = lev->wheel_time;
3496 level->android_move_time = lev->android_move_time;
3497 level->android_clone_time = lev->android_clone_time;
3498 level->ball_random = lev->ball_random;
3499 level->ball_state_initial = lev->ball_state_initial;
3500 level->ball_time = lev->ball_time;
3501 level->num_ball_contents = lev->num_ball_arrays;
3503 level->lenses_score = lev->lenses_score;
3504 level->magnify_score = lev->magnify_score;
3505 level->slurp_score = lev->slurp_score;
3507 level->lenses_time = lev->lenses_time;
3508 level->magnify_time = lev->magnify_time;
3510 level->wind_direction_initial =
3511 map_direction_EM_to_RND(lev->wind_direction_initial);
3514 printf("::: foo\n");
3515 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3516 for (j = 0; j < 8; j++)
3517 printf("::: ball %d, %d: %d\n", i, j,
3518 level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
3521 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3522 for (j = 0; j < 8; j++)
3523 level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]] =
3524 map_element_EM_to_RND(lev->ball_array[i][j]);
3527 printf("::: bar\n");
3528 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3529 for (j = 0; j < 8; j++)
3530 printf("::: ball %d, %d: %d\n", i, j,
3531 level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
3534 map_android_clone_elements_EM_to_RND(level);
3537 for (i = 0; i < 16; i++)
3538 level->android_array[i] = FALSE; /* !!! YET TO COME !!! */
3541 /* convert the playfield (some elements need special treatment) */
3542 for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
3544 int new_element = map_element_EM_to_RND(level_em->cave[x + 1][y + 1]);
3546 if (new_element == EL_AMOEBA_WET && level->amoeba_speed == 0)
3547 new_element = EL_AMOEBA_DEAD;
3549 level->field[x][y] = new_element;
3553 printf("::: bar 0\n");
3554 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3555 for (j = 0; j < 8; j++)
3556 printf("::: ball %d, %d: %d\n", i, j,
3557 level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
3562 for (i = 0; i < MAX_PLAYERS; i++)
3564 /* in case of all players set to the same field, use the first player */
3565 int nr = MAX_PLAYERS - i - 1;
3566 int jx = ply[nr]->x_initial - 1;
3567 int jy = ply[nr]->y_initial - 1;
3570 printf("::: player %d: %d, %d\n", nr, jx, jy);
3573 if (jx != -1 && jy != -1)
3574 level->field[jx][jy] = EL_PLAYER_1 + nr;
3579 /* in case of both players set to the same field, use the first player */
3580 level->field[ply2->x_initial - 1][ply2->y_initial - 1] = EL_PLAYER_2;
3581 level->field[ply1->x_initial - 1][ply1->y_initial - 1] = EL_PLAYER_1;
3586 printf("::: native Emerald Mine file version: %d\n", level_em->file_version);
3590 printf("::: bar 2\n");
3591 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3592 for (j = 0; j < 8; j++)
3593 printf("::: ball %d, %d: %d\n", i, j,
3594 level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
3598 static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,
3599 struct LevelFileInfo *level_file_info)
3601 if (!LoadNativeLevel_EM(level_file_info->filename))
3602 level->no_valid_file = TRUE;
3605 void CopyNativeLevel_RND_to_Native(struct LevelInfo *level)
3607 if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
3608 CopyNativeLevel_RND_to_EM(level);
3611 void CopyNativeLevel_Native_to_RND(struct LevelInfo *level)
3616 static int ball_xy[8][2] =
3630 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3631 for (j = 0; j < 8; j++)
3632 printf("::: ball %d, %d: %d\n", i, j,
3633 level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
3637 if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
3638 CopyNativeLevel_EM_to_RND(level);
3642 /* ------------------------------------------------------------------------- */
3643 /* functions for loading SP level */
3644 /* ------------------------------------------------------------------------- */
3646 #define NUM_SUPAPLEX_LEVELS_PER_PACKAGE 111
3647 #define SP_LEVEL_SIZE 1536
3648 #define SP_LEVEL_XSIZE 60
3649 #define SP_LEVEL_YSIZE 24
3650 #define SP_LEVEL_NAME_LEN 23
3652 static void LoadLevelFromFileStream_SP(FILE *file, struct LevelInfo *level,
3655 int num_special_ports;
3658 /* for details of the Supaplex level format, see Herman Perk's Supaplex
3659 documentation file "SPFIX63.DOC" from his Supaplex "SpeedFix" package */
3661 /* read level body (width * height == 60 * 24 tiles == 1440 bytes) */
3662 for (y = 0; y < SP_LEVEL_YSIZE; y++)
3664 for (x = 0; x < SP_LEVEL_XSIZE; x++)
3666 int element_old = fgetc(file);
3669 if (element_old <= 0x27)
3670 element_new = getMappedElement(EL_SP_START + element_old);
3671 else if (element_old == 0x28)
3672 element_new = EL_INVISIBLE_WALL;
3675 Error(ERR_WARN, "in level %d, at position %d, %d:", nr, x, y);
3676 Error(ERR_WARN, "invalid level element %d", element_old);
3678 element_new = EL_UNKNOWN;
3681 level->field[x][y] = element_new;
3685 ReadUnusedBytesFromFile(file, 4); /* (not used by Supaplex engine) */
3687 /* initial gravity: 1 == "on", anything else (0) == "off" */
3688 level->initial_gravity = (fgetc(file) == 1 ? TRUE : FALSE);
3690 ReadUnusedBytesFromFile(file, 1); /* (not used by Supaplex engine) */
3692 /* level title in uppercase letters, padded with dashes ("-") (23 bytes) */
3693 for (i = 0; i < SP_LEVEL_NAME_LEN; i++)
3694 level->name[i] = fgetc(file);
3695 level->name[SP_LEVEL_NAME_LEN] = '\0';
3697 /* initial "freeze zonks": 2 == "on", anything else (0, 1) == "off" */
3698 ReadUnusedBytesFromFile(file, 1); /* (not used by R'n'D engine) */
3700 /* number of infotrons needed; 0 means that Supaplex will count the total
3701 amount of infotrons in the level and use the low byte of that number
3702 (a multiple of 256 infotrons will result in "0 infotrons needed"!) */
3703 level->gems_needed = fgetc(file);
3705 /* number of special ("gravity") port entries below (maximum 10 allowed) */
3706 num_special_ports = fgetc(file);
3708 /* database of properties of up to 10 special ports (6 bytes per port) */
3709 for (i = 0; i < 10; i++)
3711 int port_location, port_x, port_y, port_element;
3714 /* high and low byte of the location of a special port; if (x, y) are the
3715 coordinates of a port in the field and (0, 0) is the top-left corner,
3716 the 16 bit value here calculates as 2 * (x + (y * 60)) (this is twice
3717 of what may be expected: Supaplex works with a game field in memory
3718 which is 2 bytes per tile) */
3719 port_location = getFile16BitBE(file);
3721 /* change gravity: 1 == "turn on", anything else (0) == "turn off" */
3722 gravity = fgetc(file);
3724 /* "freeze zonks": 2 == "turn on", anything else (0, 1) == "turn off" */
3725 ReadUnusedBytesFromFile(file, 1); /* (not used by R'n'D engine) */
3727 /* "freeze enemies": 1 == "turn on", anything else (0) == "turn off" */
3728 ReadUnusedBytesFromFile(file, 1); /* (not used by R'n'D engine) */
3730 ReadUnusedBytesFromFile(file, 1); /* (not used by Supaplex engine) */
3732 if (i >= num_special_ports)
3735 port_x = (port_location / 2) % SP_LEVEL_XSIZE;
3736 port_y = (port_location / 2) / SP_LEVEL_XSIZE;
3738 if (port_x < 0 || port_x >= SP_LEVEL_XSIZE ||
3739 port_y < 0 || port_y >= SP_LEVEL_YSIZE)
3741 Error(ERR_WARN, "special port position (%d, %d) out of bounds",
3747 port_element = level->field[port_x][port_y];
3749 if (port_element < EL_SP_GRAVITY_PORT_RIGHT ||
3750 port_element > EL_SP_GRAVITY_PORT_UP)
3752 Error(ERR_WARN, "no special port at position (%d, %d)", port_x, port_y);
3757 /* change previous (wrong) gravity inverting special port to either
3758 gravity enabling special port or gravity disabling special port */
3759 level->field[port_x][port_y] +=
3760 (gravity == 1 ? EL_SP_GRAVITY_ON_PORT_RIGHT :
3761 EL_SP_GRAVITY_OFF_PORT_RIGHT) - EL_SP_GRAVITY_PORT_RIGHT;
3764 ReadUnusedBytesFromFile(file, 4); /* (not used by Supaplex engine) */
3766 /* change special gravity ports without database entries to normal ports */
3767 for (y = 0; y < SP_LEVEL_YSIZE; y++)
3768 for (x = 0; x < SP_LEVEL_XSIZE; x++)
3769 if (level->field[x][y] >= EL_SP_GRAVITY_PORT_RIGHT &&
3770 level->field[x][y] <= EL_SP_GRAVITY_PORT_UP)
3771 level->field[x][y] += EL_SP_PORT_RIGHT - EL_SP_GRAVITY_PORT_RIGHT;
3773 /* auto-determine number of infotrons if it was stored as "0" -- see above */
3774 if (level->gems_needed == 0)
3776 for (y = 0; y < SP_LEVEL_YSIZE; y++)
3777 for (x = 0; x < SP_LEVEL_XSIZE; x++)
3778 if (level->field[x][y] == EL_SP_INFOTRON)
3779 level->gems_needed++;
3781 level->gems_needed &= 0xff; /* only use low byte -- see above */
3784 level->fieldx = SP_LEVEL_XSIZE;
3785 level->fieldy = SP_LEVEL_YSIZE;
3787 level->time = 0; /* no time limit */
3788 level->amoeba_speed = 0;
3789 level->time_magic_wall = 0;
3790 level->time_wheel = 0;
3791 level->amoeba_content = EL_EMPTY;
3794 /* original Supaplex does not use score values -- use default values */
3796 for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
3797 level->score[i] = 0; /* !!! CORRECT THIS !!! */
3800 /* there are no yamyams in supaplex levels */
3801 for (i = 0; i < level->num_yamyam_contents; i++)
3802 for (y = 0; y < 3; y++)
3803 for (x = 0; x < 3; x++)
3804 level->yamyam_content[i].e[x][y] = EL_EMPTY;
3807 static void LoadLevelFromFileInfo_SP(struct LevelInfo *level,
3808 struct LevelFileInfo *level_file_info)
3810 char *filename = level_file_info->filename;
3812 int nr = level_file_info->nr - leveldir_current->first_level;
3814 char name_first, name_last;
3815 struct LevelInfo multipart_level;
3816 int multipart_xpos, multipart_ypos;
3817 boolean is_multipart_level;
3818 boolean is_first_part;
3819 boolean reading_multipart_level = FALSE;
3820 boolean use_empty_level = FALSE;
3822 if (!(file = fopen(filename, MODE_READ)))
3824 level->no_valid_file = TRUE;
3826 Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
3831 /* position file stream to the requested level inside the level package */
3832 if (fseek(file, nr * SP_LEVEL_SIZE, SEEK_SET) != 0)
3834 level->no_valid_file = TRUE;
3836 Error(ERR_WARN, "cannot fseek level '%s' -- using empty level", filename);
3841 /* there exist Supaplex level package files with multi-part levels which
3842 can be detected as follows: instead of leading and trailing dashes ('-')
3843 to pad the level name, they have leading and trailing numbers which are
3844 the x and y coordinations of the current part of the multi-part level;
3845 if there are '?' characters instead of numbers on the left or right side
3846 of the level name, the multi-part level consists of only horizontal or
3849 for (l = nr; l < NUM_SUPAPLEX_LEVELS_PER_PACKAGE; l++)
3851 LoadLevelFromFileStream_SP(file, level, l);
3853 /* check if this level is a part of a bigger multi-part level */
3855 name_first = level->name[0];
3856 name_last = level->name[SP_LEVEL_NAME_LEN - 1];
3858 is_multipart_level =
3859 ((name_first == '?' || (name_first >= '0' && name_first <= '9')) &&
3860 (name_last == '?' || (name_last >= '0' && name_last <= '9')));
3863 ((name_first == '?' || name_first == '1') &&
3864 (name_last == '?' || name_last == '1'));
3866 /* correct leading multipart level meta information in level name */
3867 for (i = 0; i < SP_LEVEL_NAME_LEN && level->name[i] == name_first; i++)
3868 level->name[i] = '-';
3870 /* correct trailing multipart level meta information in level name */
3871 for (i = SP_LEVEL_NAME_LEN - 1; i>=0 && level->name[i] == name_last; i--)
3872 level->name[i] = '-';
3874 /* ---------- check for normal single level ---------- */
3876 if (!reading_multipart_level && !is_multipart_level)
3878 /* the current level is simply a normal single-part level, and we are
3879 not reading a multi-part level yet, so return the level as it is */
3884 /* ---------- check for empty level (unused multi-part) ---------- */
3886 if (!reading_multipart_level && is_multipart_level && !is_first_part)
3888 /* this is a part of a multi-part level, but not the first part
3889 (and we are not already reading parts of a multi-part level);
3890 in this case, use an empty level instead of the single part */
3892 use_empty_level = TRUE;
3897 /* ---------- check for finished multi-part level ---------- */
3899 if (reading_multipart_level &&
3900 (!is_multipart_level ||
3901 !strEqual(level->name, multipart_level.name)))
3903 /* we are already reading parts of a multi-part level, but this level is
3904 either not a multi-part level, or a part of a different multi-part
3905 level; in both cases, the multi-part level seems to be complete */
3910 /* ---------- here we have one part of a multi-part level ---------- */
3912 reading_multipart_level = TRUE;
3914 if (is_first_part) /* start with first part of new multi-part level */
3916 /* copy level info structure from first part */
3917 multipart_level = *level;
3919 /* clear playfield of new multi-part level */
3920 for (y = 0; y < MAX_LEV_FIELDY; y++)
3921 for (x = 0; x < MAX_LEV_FIELDX; x++)
3922 multipart_level.field[x][y] = EL_EMPTY;
3925 if (name_first == '?')
3927 if (name_last == '?')
3930 multipart_xpos = (int)(name_first - '0');
3931 multipart_ypos = (int)(name_last - '0');
3934 printf("----------> part (%d/%d) of multi-part level '%s'\n",
3935 multipart_xpos, multipart_ypos, multipart_level.name);
3938 if (multipart_xpos * SP_LEVEL_XSIZE > MAX_LEV_FIELDX ||
3939 multipart_ypos * SP_LEVEL_YSIZE > MAX_LEV_FIELDY)
3941 Error(ERR_WARN, "multi-part level is too big -- ignoring part of it");
3946 multipart_level.fieldx = MAX(multipart_level.fieldx,
3947 multipart_xpos * SP_LEVEL_XSIZE);
3948 multipart_level.fieldy = MAX(multipart_level.fieldy,
3949 multipart_ypos * SP_LEVEL_YSIZE);
3951 /* copy level part at the right position of multi-part level */
3952 for (y = 0; y < SP_LEVEL_YSIZE; y++)
3954 for (x = 0; x < SP_LEVEL_XSIZE; x++)
3956 int start_x = (multipart_xpos - 1) * SP_LEVEL_XSIZE;
3957 int start_y = (multipart_ypos - 1) * SP_LEVEL_YSIZE;
3959 multipart_level.field[start_x + x][start_y + y] = level->field[x][y];
3966 if (use_empty_level)
3968 setLevelInfoToDefaults(level);
3970 level->fieldx = SP_LEVEL_XSIZE;
3971 level->fieldy = SP_LEVEL_YSIZE;
3973 for (y = 0; y < SP_LEVEL_YSIZE; y++)
3974 for (x = 0; x < SP_LEVEL_XSIZE; x++)
3975 level->field[x][y] = EL_EMPTY;
3977 strcpy(level->name, "-------- EMPTY --------");
3979 Error(ERR_WARN, "single part of multi-part level -- using empty level");
3982 if (reading_multipart_level)
3983 *level = multipart_level;
3986 /* ------------------------------------------------------------------------- */
3987 /* functions for loading generic level */
3988 /* ------------------------------------------------------------------------- */
3990 void LoadLevelFromFileInfo(struct LevelInfo *level,
3991 struct LevelFileInfo *level_file_info)
3993 /* always start with reliable default values */
3994 setLevelInfoToDefaults(level);
3996 switch (level_file_info->type)
3998 case LEVEL_FILE_TYPE_RND:
3999 LoadLevelFromFileInfo_RND(level, level_file_info);
4002 case LEVEL_FILE_TYPE_EM:
4003 LoadLevelFromFileInfo_EM(level, level_file_info);
4004 level->game_engine_type = GAME_ENGINE_TYPE_EM;
4007 case LEVEL_FILE_TYPE_SP:
4008 LoadLevelFromFileInfo_SP(level, level_file_info);
4012 LoadLevelFromFileInfo_RND(level, level_file_info);
4016 /* if level file is invalid, restore level structure to default values */
4017 if (level->no_valid_file)
4018 setLevelInfoToDefaults(level);
4020 if (level->game_engine_type == GAME_ENGINE_TYPE_UNKNOWN)
4021 level->game_engine_type = GAME_ENGINE_TYPE_RND;
4024 if (level_file_info->type != LEVEL_FILE_TYPE_RND)
4025 CopyNativeLevel_Native_to_RND(level);
4027 if (level_file_info->type == LEVEL_FILE_TYPE_RND)
4028 CopyNativeLevel_RND_to_Native(level);
4030 CopyNativeLevel_Native_to_RND(level);
4034 void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
4036 static struct LevelFileInfo level_file_info;
4038 /* always start with reliable default values */
4039 setFileInfoToDefaults(&level_file_info);
4041 level_file_info.nr = 0; /* unknown level number */
4042 level_file_info.type = LEVEL_FILE_TYPE_RND; /* no others supported yet */
4043 level_file_info.filename = filename;
4045 LoadLevelFromFileInfo(level, &level_file_info);
4048 static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
4050 if (leveldir_current == NULL) /* only when dumping level */
4053 /* all engine modifications also valid for levels which use latest engine */
4055 if (level->game_version < VERSION_IDENT(3,2,0,5))
4057 /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */
4058 level->score[SC_TIME_BONUS] /= 10;
4063 leveldir_current->latest_engine = TRUE; /* !!! TEST ONLY !!! */
4066 if (leveldir_current->latest_engine)
4068 /* ---------- use latest game engine ----------------------------------- */
4070 /* For all levels which are forced to use the latest game engine version
4071 (normally all but user contributed, private and undefined levels), set
4072 the game engine version to the actual version; this allows for actual
4073 corrections in the game engine to take effect for existing, converted
4074 levels (from "classic" or other existing games) to make the emulation
4075 of the corresponding game more accurate, while (hopefully) not breaking
4076 existing levels created from other players. */
4078 level->game_version = GAME_VERSION_ACTUAL;
4080 /* Set special EM style gems behaviour: EM style gems slip down from
4081 normal, steel and growing wall. As this is a more fundamental change,
4082 it seems better to set the default behaviour to "off" (as it is more
4083 natural) and make it configurable in the level editor (as a property
4084 of gem style elements). Already existing converted levels (neither
4085 private nor contributed levels) are changed to the new behaviour. */
4087 if (level->file_version < FILE_VERSION_2_0)
4088 level->em_slippery_gems = TRUE;
4093 /* ---------- use game engine the level was created with ----------------- */
4095 /* For all levels which are not forced to use the latest game engine
4096 version (normally user contributed, private and undefined levels),
4097 use the version of the game engine the levels were created for.
4099 Since 2.0.1, the game engine version is now directly stored
4100 in the level file (chunk "VERS"), so there is no need anymore
4101 to set the game version from the file version (except for old,
4102 pre-2.0 levels, where the game version is still taken from the
4103 file format version used to store the level -- see above). */
4105 /* player was faster than enemies in 1.0.0 and before */
4106 if (level->file_version == FILE_VERSION_1_0)
4107 level->initial_player_stepsize = STEPSIZE_FAST;
4109 /* default behaviour for EM style gems was "slippery" only in 2.0.1 */
4110 if (level->game_version == VERSION_IDENT(2,0,1,0))
4111 level->em_slippery_gems = TRUE;
4113 /* springs could be pushed over pits before (pre-release version) 2.2.0 */
4114 if (level->game_version < VERSION_IDENT(2,2,0,0))
4115 level->use_spring_bug = TRUE;
4117 if (level->game_version < VERSION_IDENT(3,2,0,5))
4119 /* time orb caused limited time in endless time levels before 3.2.0-5 */
4120 level->use_time_orb_bug = TRUE;
4122 /* default behaviour for snapping was "no snap delay" before 3.2.0-5 */
4123 level->block_snap_field = FALSE;
4125 /* extra time score was same value as time left score before 3.2.0-5 */
4126 level->extra_time_score = level->score[SC_TIME_BONUS];
4129 /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */
4130 level->score[SC_TIME_BONUS] /= 10;
4134 if (level->game_version < VERSION_IDENT(3,2,0,7))
4136 /* default behaviour for snapping was "not continuous" before 3.2.0-7 */
4137 level->continuous_snapping = FALSE;
4140 /* only few elements were able to actively move into acid before 3.1.0 */
4141 /* trigger settings did not exist before 3.1.0; set to default "any" */
4142 if (level->game_version < VERSION_IDENT(3,1,0,0))
4146 /* correct "can move into acid" settings (all zero in old levels) */
4148 level->can_move_into_acid_bits = 0; /* nothing can move into acid */
4149 level->dont_collide_with_bits = 0; /* nothing is deadly when colliding */
4151 setMoveIntoAcidProperty(level, EL_ROBOT, TRUE);
4152 setMoveIntoAcidProperty(level, EL_SATELLITE, TRUE);
4153 setMoveIntoAcidProperty(level, EL_PENGUIN, TRUE);
4154 setMoveIntoAcidProperty(level, EL_BALLOON, TRUE);
4156 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4157 SET_PROPERTY(EL_CUSTOM_START + i, EP_CAN_MOVE_INTO_ACID, TRUE);
4159 /* correct trigger settings (stored as zero == "none" in old levels) */
4161 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4163 int element = EL_CUSTOM_START + i;
4164 struct ElementInfo *ei = &element_info[element];
4166 for (j = 0; j < ei->num_change_pages; j++)
4168 struct ElementChangeInfo *change = &ei->change_page[j];
4170 change->trigger_player = CH_PLAYER_ANY;
4171 change->trigger_page = CH_PAGE_ANY;
4177 static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
4181 /* map custom element change events that have changed in newer versions
4182 (these following values were accidentally changed in version 3.0.1)
4183 (this seems to be needed only for 'ab_levelset3' and 'ab_levelset4') */
4184 if (level->game_version <= VERSION_IDENT(3,0,0,0))
4186 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4188 int element = EL_CUSTOM_START + i;
4190 /* order of checking and copying events to be mapped is important */
4191 /* (do not change the start and end value -- they are constant) */
4192 for (j = CE_BY_OTHER_ACTION; j >= CE_VALUE_GETS_ZERO; j--)
4194 if (HAS_CHANGE_EVENT(element, j - 2))
4196 SET_CHANGE_EVENT(element, j - 2, FALSE);
4197 SET_CHANGE_EVENT(element, j, TRUE);
4201 /* order of checking and copying events to be mapped is important */
4202 /* (do not change the start and end value -- they are constant) */
4203 for (j = CE_PLAYER_COLLECTS_X; j >= CE_HITTING_SOMETHING; j--)
4205 if (HAS_CHANGE_EVENT(element, j - 1))
4207 SET_CHANGE_EVENT(element, j - 1, FALSE);
4208 SET_CHANGE_EVENT(element, j, TRUE);
4214 /* initialize "can_change" field for old levels with only one change page */
4215 if (level->game_version <= VERSION_IDENT(3,0,2,0))
4217 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4219 int element = EL_CUSTOM_START + i;
4221 if (CAN_CHANGE(element))
4222 element_info[element].change->can_change = TRUE;
4226 /* correct custom element values (for old levels without these options) */
4227 if (level->game_version < VERSION_IDENT(3,1,1,0))
4229 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4231 int element = EL_CUSTOM_START + i;
4232 struct ElementInfo *ei = &element_info[element];
4234 if (ei->access_direction == MV_NO_DIRECTION)
4235 ei->access_direction = MV_ALL_DIRECTIONS;
4238 for (j = 0; j < ei->num_change_pages; j++)
4240 struct ElementChangeInfo *change = &ei->change_page[j];
4242 if (change->trigger_side == CH_SIDE_NONE)
4243 change->trigger_side = CH_SIDE_ANY;
4250 /* correct custom element values (fix invalid values for all versions) */
4253 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4255 int element = EL_CUSTOM_START + i;
4256 struct ElementInfo *ei = &element_info[element];
4258 for (j = 0; j < ei->num_change_pages; j++)
4260 struct ElementChangeInfo *change = &ei->change_page[j];
4262 if (change->trigger_player == CH_PLAYER_NONE)
4263 change->trigger_player = CH_PLAYER_ANY;
4265 if (change->trigger_side == CH_SIDE_NONE)
4266 change->trigger_side = CH_SIDE_ANY;
4272 /* initialize "can_explode" field for old levels which did not store this */
4273 /* !!! CHECK THIS -- "<= 3,1,0,0" IS PROBABLY WRONG !!! */
4274 if (level->game_version <= VERSION_IDENT(3,1,0,0))
4276 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4278 int element = EL_CUSTOM_START + i;
4280 if (EXPLODES_1X1_OLD(element))
4281 element_info[element].explosion_type = EXPLODES_1X1;
4283 SET_PROPERTY(element, EP_CAN_EXPLODE, (EXPLODES_BY_FIRE(element) ||
4284 EXPLODES_SMASHED(element) ||
4285 EXPLODES_IMPACT(element)));
4289 /* correct previously hard-coded move delay values for maze runner style */
4290 if (level->game_version < VERSION_IDENT(3,1,1,0))
4292 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4294 int element = EL_CUSTOM_START + i;
4296 if (element_info[element].move_pattern & MV_MAZE_RUNNER_STYLE)
4298 /* previously hard-coded and therefore ignored */
4299 element_info[element].move_delay_fixed = 9;
4300 element_info[element].move_delay_random = 0;
4305 /* map elements that have changed in newer versions */
4306 level->amoeba_content = getMappedElementByVersion(level->amoeba_content,
4307 level->game_version);
4308 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
4309 for (x = 0; x < 3; x++)
4310 for (y = 0; y < 3; y++)
4311 level->yamyam_content[i].e[x][y] =
4312 getMappedElementByVersion(level->yamyam_content[i].e[x][y],
4313 level->game_version);
4315 /* initialize element properties for level editor etc. */
4316 InitElementPropertiesEngine(level->game_version);
4319 static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
4323 /* map elements that have changed in newer versions */
4324 for (y = 0; y < level->fieldy; y++)
4325 for (x = 0; x < level->fieldx; x++)
4326 level->field[x][y] = getMappedElementByVersion(level->field[x][y],
4327 level->game_version);
4329 /* copy elements to runtime playfield array */
4330 for (x = 0; x < MAX_LEV_FIELDX; x++)
4331 for (y = 0; y < MAX_LEV_FIELDY; y++)
4332 Feld[x][y] = level->field[x][y];
4334 /* initialize level size variables for faster access */
4335 lev_fieldx = level->fieldx;
4336 lev_fieldy = level->fieldy;
4338 /* determine border element for this level */
4342 static void LoadLevel_InitNativeEngines(struct LevelInfo *level,char *filename)
4344 struct LevelFileInfo *level_file_info = &level->file_info;
4347 if (level_file_info->type == LEVEL_FILE_TYPE_RND)
4348 CopyNativeLevel_RND_to_Native(level);
4350 if (level_file_info->type == LEVEL_FILE_TYPE_RND)
4351 CopyNativeLevel_RND_to_Native(level);
4353 CopyNativeLevel_Native_to_RND(level);
4357 void LoadLevelTemplate(int nr)
4361 setLevelFileInfo(&level_template.file_info, nr);
4362 filename = level_template.file_info.filename;
4364 LoadLevelFromFileInfo(&level_template, &level_template.file_info);
4366 LoadLevel_InitVersion(&level_template, filename);
4367 LoadLevel_InitElements(&level_template, filename);
4369 ActivateLevelTemplate();
4372 void LoadLevel(int nr)
4376 setLevelFileInfo(&level.file_info, nr);
4377 filename = level.file_info.filename;
4379 LoadLevelFromFileInfo(&level, &level.file_info);
4381 if (level.use_custom_template)
4382 LoadLevelTemplate(-1);
4384 LoadLevel_InitVersion(&level, filename);
4385 LoadLevel_InitElements(&level, filename);
4386 LoadLevel_InitPlayfield(&level, filename);
4388 LoadLevel_InitNativeEngines(&level, filename);
4391 static void SaveLevel_VERS(FILE *file, struct LevelInfo *level)
4393 putFileVersion(file, level->file_version);
4394 putFileVersion(file, level->game_version);
4397 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
4401 putFile8Bit(file, level->fieldx);
4402 putFile8Bit(file, level->fieldy);
4404 putFile16BitBE(file, level->time);
4405 putFile16BitBE(file, level->gems_needed);
4407 for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
4408 putFile8Bit(file, level->name[i]);
4410 for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
4411 putFile8Bit(file, level->score[i]);
4413 for (i = 0; i < STD_ELEMENT_CONTENTS; i++)
4414 for (y = 0; y < 3; y++)
4415 for (x = 0; x < 3; x++)
4416 putFile8Bit(file, (level->encoding_16bit_yamyam ? EL_EMPTY :
4417 level->yamyam_content[i].e[x][y]));
4418 putFile8Bit(file, level->amoeba_speed);
4419 putFile8Bit(file, level->time_magic_wall);
4420 putFile8Bit(file, level->time_wheel);
4421 putFile8Bit(file, (level->encoding_16bit_amoeba ? EL_EMPTY :
4422 level->amoeba_content));
4423 putFile8Bit(file, (level->initial_player_stepsize == STEPSIZE_FAST ? 1 : 0));
4424 putFile8Bit(file, (level->initial_gravity ? 1 : 0));
4425 putFile8Bit(file, (level->encoding_16bit_field ? 1 : 0));
4426 putFile8Bit(file, (level->em_slippery_gems ? 1 : 0));
4428 putFile8Bit(file, (level->use_custom_template ? 1 : 0));
4430 putFile8Bit(file, (level->block_last_field ? 1 : 0));
4431 putFile8Bit(file, (level->sp_block_last_field ? 1 : 0));
4432 putFile32BitBE(file, level->can_move_into_acid_bits);
4433 putFile8Bit(file, level->dont_collide_with_bits);
4435 putFile8Bit(file, (level->use_spring_bug ? 1 : 0));
4436 putFile8Bit(file, (level->use_step_counter ? 1 : 0));
4438 putFile8Bit(file, (level->instant_relocation ? 1 : 0));
4439 putFile8Bit(file, (level->can_pass_to_walkable ? 1 : 0));
4440 putFile8Bit(file, (level->grow_into_diggable ? 1 : 0));
4442 putFile8Bit(file, level->game_engine_type);
4444 WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
4447 static void SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
4451 for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
4452 putFile8Bit(file, level->author[i]);
4455 static void SaveLevel_BODY(FILE *file, struct LevelInfo *level)
4459 for (y = 0; y < level->fieldy; y++)
4460 for (x = 0; x < level->fieldx; x++)
4461 if (level->encoding_16bit_field)
4462 putFile16BitBE(file, level->field[x][y]);
4464 putFile8Bit(file, level->field[x][y]);
4468 static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
4472 putFile8Bit(file, EL_YAMYAM);
4473 putFile8Bit(file, level->num_yamyam_contents);
4474 putFile8Bit(file, 0);
4475 putFile8Bit(file, 0);
4477 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
4478 for (y = 0; y < 3; y++)
4479 for (x = 0; x < 3; x++)
4480 if (level->encoding_16bit_field)
4481 putFile16BitBE(file, level->yamyam_content[i].e[x][y]);
4483 putFile8Bit(file, level->yamyam_content[i].e[x][y]);
4487 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
4490 int num_contents, content_xsize, content_ysize;
4491 int content_array[MAX_ELEMENT_CONTENTS][3][3];
4493 if (element == EL_YAMYAM)
4495 num_contents = level->num_yamyam_contents;
4499 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
4500 for (y = 0; y < 3; y++)
4501 for (x = 0; x < 3; x++)
4502 content_array[i][x][y] = level->yamyam_content[i].e[x][y];
4504 else if (element == EL_BD_AMOEBA)
4510 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
4511 for (y = 0; y < 3; y++)
4512 for (x = 0; x < 3; x++)
4513 content_array[i][x][y] = EL_EMPTY;
4514 content_array[0][0][0] = level->amoeba_content;
4518 /* chunk header already written -- write empty chunk data */
4519 WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_SIZE);
4521 Error(ERR_WARN, "cannot save content for element '%d'", element);
4525 putFile16BitBE(file, element);
4526 putFile8Bit(file, num_contents);
4527 putFile8Bit(file, content_xsize);
4528 putFile8Bit(file, content_ysize);
4530 WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED);
4532 for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
4533 for (y = 0; y < 3; y++)
4534 for (x = 0; x < 3; x++)
4535 putFile16BitBE(file, content_array[i][x][y]);
4538 static void SaveLevel_CNT3(FILE *file, struct LevelInfo *level, int element)
4541 int envelope_nr = element - EL_ENVELOPE_1;
4542 int envelope_len = strlen(level->envelope_text[envelope_nr]) + 1;
4544 putFile16BitBE(file, element);
4545 putFile16BitBE(file, envelope_len);
4546 putFile8Bit(file, level->envelope_xsize[envelope_nr]);
4547 putFile8Bit(file, level->envelope_ysize[envelope_nr]);
4549 WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT3_UNUSED);
4551 for (i = 0; i < envelope_len; i++)
4552 putFile8Bit(file, level->envelope_text[envelope_nr][i]);
4556 static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level,
4557 int num_changed_custom_elements)
4561 putFile16BitBE(file, num_changed_custom_elements);
4563 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4565 int element = EL_CUSTOM_START + i;
4568 struct ElementInfo *ei = &element_info[element];
4570 if (ei->properties[EP_BITFIELD_BASE] != EP_BITMASK_DEFAULT)
4572 if (check < num_changed_custom_elements)
4574 putFile16BitBE(file, element);
4575 putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE]);
4581 if (Properties[element][EP_BITFIELD_BASE] != EP_BITMASK_DEFAULT)
4583 if (check < num_changed_custom_elements)
4585 putFile16BitBE(file, element);
4586 putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
4594 if (check != num_changed_custom_elements) /* should not happen */
4595 Error(ERR_WARN, "inconsistent number of custom element properties");
4600 static void SaveLevel_CUS2(FILE *file, struct LevelInfo *level,
4601 int num_changed_custom_elements)
4605 putFile16BitBE(file, num_changed_custom_elements);
4607 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4609 int element = EL_CUSTOM_START + i;
4611 if (element_info[element].change->target_element != EL_EMPTY_SPACE)
4613 if (check < num_changed_custom_elements)
4615 putFile16BitBE(file, element);
4616 putFile16BitBE(file, element_info[element].change->target_element);
4623 if (check != num_changed_custom_elements) /* should not happen */
4624 Error(ERR_WARN, "inconsistent number of custom target elements");
4629 static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
4630 int num_changed_custom_elements)
4632 int i, j, x, y, check = 0;
4634 putFile16BitBE(file, num_changed_custom_elements);
4636 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4638 int element = EL_CUSTOM_START + i;
4639 struct ElementInfo *ei = &element_info[element];
4641 if (ei->modified_settings)
4643 if (check < num_changed_custom_elements)
4645 putFile16BitBE(file, element);
4647 for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++)
4648 putFile8Bit(file, ei->description[j]);
4651 putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE]);
4653 putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
4656 /* some free bytes for future properties and padding */
4657 WriteUnusedBytesToFile(file, 7);
4659 putFile8Bit(file, ei->use_gfx_element);
4660 putFile16BitBE(file, ei->gfx_element);
4662 putFile8Bit(file, ei->collect_score_initial);
4663 putFile8Bit(file, ei->collect_count_initial);
4665 putFile16BitBE(file, ei->push_delay_fixed);
4666 putFile16BitBE(file, ei->push_delay_random);
4667 putFile16BitBE(file, ei->move_delay_fixed);
4668 putFile16BitBE(file, ei->move_delay_random);
4670 putFile16BitBE(file, ei->move_pattern);
4671 putFile8Bit(file, ei->move_direction_initial);
4672 putFile8Bit(file, ei->move_stepsize);
4674 for (y = 0; y < 3; y++)
4675 for (x = 0; x < 3; x++)
4676 putFile16BitBE(file, ei->content.e[x][y]);
4678 putFile32BitBE(file, ei->change->events);
4680 putFile16BitBE(file, ei->change->target_element);
4682 putFile16BitBE(file, ei->change->delay_fixed);
4683 putFile16BitBE(file, ei->change->delay_random);
4684 putFile16BitBE(file, ei->change->delay_frames);
4686 putFile16BitBE(file, ei->change->trigger_element);
4688 putFile8Bit(file, ei->change->explode);
4689 putFile8Bit(file, ei->change->use_target_content);
4690 putFile8Bit(file, ei->change->only_if_complete);
4691 putFile8Bit(file, ei->change->use_random_replace);
4693 putFile8Bit(file, ei->change->random_percentage);
4694 putFile8Bit(file, ei->change->replace_when);
4696 for (y = 0; y < 3; y++)
4697 for (x = 0; x < 3; x++)
4698 putFile16BitBE(file, ei->change->content.e[x][y]);
4700 putFile8Bit(file, ei->slippery_type);
4702 /* some free bytes for future properties and padding */
4703 WriteUnusedBytesToFile(file, LEVEL_CPART_CUS3_UNUSED);
4710 if (check != num_changed_custom_elements) /* should not happen */
4711 Error(ERR_WARN, "inconsistent number of custom element properties");
4715 static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
4717 struct ElementInfo *ei = &element_info[element];
4720 /* ---------- custom element base property values (96 bytes) ------------- */
4722 putFile16BitBE(file, element);
4724 for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
4725 putFile8Bit(file, ei->description[i]);
4728 putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE]);
4730 putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
4732 WriteUnusedBytesToFile(file, 4); /* reserved for more base properties */
4734 putFile8Bit(file, ei->num_change_pages);
4736 putFile16BitBE(file, ei->ce_value_fixed_initial);
4737 putFile16BitBE(file, ei->ce_value_random_initial);
4738 putFile8Bit(file, ei->use_last_ce_value);
4740 putFile8Bit(file, ei->use_gfx_element);
4741 putFile16BitBE(file, ei->gfx_element);
4743 putFile8Bit(file, ei->collect_score_initial);
4744 putFile8Bit(file, ei->collect_count_initial);
4746 putFile8Bit(file, ei->drop_delay_fixed);
4747 putFile8Bit(file, ei->push_delay_fixed);
4748 putFile8Bit(file, ei->drop_delay_random);
4749 putFile8Bit(file, ei->push_delay_random);
4750 putFile16BitBE(file, ei->move_delay_fixed);
4751 putFile16BitBE(file, ei->move_delay_random);
4753 /* bits 0 - 15 of "move_pattern" ... */
4754 putFile16BitBE(file, ei->move_pattern & 0xffff);
4755 putFile8Bit(file, ei->move_direction_initial);
4756 putFile8Bit(file, ei->move_stepsize);
4758 putFile8Bit(file, ei->slippery_type);
4760 for (y = 0; y < 3; y++)
4761 for (x = 0; x < 3; x++)
4762 putFile16BitBE(file, ei->content.e[x][y]);
4764 putFile16BitBE(file, ei->move_enter_element);
4765 putFile16BitBE(file, ei->move_leave_element);
4766 putFile8Bit(file, ei->move_leave_type);
4768 /* ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible) */
4769 putFile16BitBE(file, (ei->move_pattern >> 16) & 0xffff);
4771 putFile8Bit(file, ei->access_direction);
4773 putFile8Bit(file, ei->explosion_delay);
4774 putFile8Bit(file, ei->ignition_delay);
4775 putFile8Bit(file, ei->explosion_type);
4777 /* some free bytes for future custom property values and padding */
4778 WriteUnusedBytesToFile(file, 1);
4780 /* ---------- change page property values (48 bytes) --------------------- */
4782 for (i = 0; i < ei->num_change_pages; i++)
4784 struct ElementChangeInfo *change = &ei->change_page[i];
4785 unsigned int event_bits;
4787 /* bits 0 - 31 of "has_event[]" ... */
4789 for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
4790 if (change->has_event[j])
4791 event_bits |= (1 << j);
4792 putFile32BitBE(file, event_bits);
4794 putFile16BitBE(file, change->target_element);
4796 putFile16BitBE(file, change->delay_fixed);
4797 putFile16BitBE(file, change->delay_random);
4798 putFile16BitBE(file, change->delay_frames);
4800 putFile16BitBE(file, change->trigger_element);
4802 putFile8Bit(file, change->explode);
4803 putFile8Bit(file, change->use_target_content);
4804 putFile8Bit(file, change->only_if_complete);
4805 putFile8Bit(file, change->use_random_replace);
4807 putFile8Bit(file, change->random_percentage);
4808 putFile8Bit(file, change->replace_when);
4810 for (y = 0; y < 3; y++)
4811 for (x = 0; x < 3; x++)
4812 putFile16BitBE(file, change->target_content.e[x][y]);
4814 putFile8Bit(file, change->can_change);
4816 putFile8Bit(file, change->trigger_side);
4818 putFile8Bit(file, change->trigger_player);
4819 putFile8Bit(file, (change->trigger_page == CH_PAGE_ANY ? CH_PAGE_ANY_FILE :
4820 log_2(change->trigger_page)));
4822 putFile8Bit(file, change->has_action);
4823 putFile8Bit(file, change->action_type);
4824 putFile8Bit(file, change->action_mode);
4825 putFile16BitBE(file, change->action_arg);
4827 /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */
4829 for (j = 32; j < NUM_CHANGE_EVENTS; j++)
4830 if (change->has_event[j])
4831 event_bits |= (1 << (j - 32));
4832 putFile8Bit(file, event_bits);
4836 static void SaveLevel_GRP1(FILE *file, struct LevelInfo *level, int element)
4838 struct ElementInfo *ei = &element_info[element];
4839 struct ElementGroupInfo *group = ei->group;
4842 putFile16BitBE(file, element);
4844 for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
4845 putFile8Bit(file, ei->description[i]);
4847 putFile8Bit(file, group->num_elements);
4849 putFile8Bit(file, ei->use_gfx_element);
4850 putFile16BitBE(file, ei->gfx_element);
4852 putFile8Bit(file, group->choice_mode);
4854 /* some free bytes for future values and padding */
4855 WriteUnusedBytesToFile(file, 3);
4857 for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
4858 putFile16BitBE(file, group->element[i]);
4861 static int SaveLevel_MicroChunk(FILE *file, struct ElementFileConfig *entry)
4863 int data_type = entry->data_type;
4864 int conf_type = entry->conf_type;
4865 int byte_mask = conf_type & CONF_MASK_BYTES;
4866 int element = entry->element;
4867 int default_value = entry->default_value;
4869 boolean modified = FALSE;
4871 if (byte_mask != CONF_MASK_MULTI_BYTES)
4873 void *value_ptr = entry->value;
4874 int value = (data_type == TYPE_BOOLEAN ? *(boolean *)value_ptr :
4877 /* check if any settings have been modified before saving them */
4878 if (value != default_value)
4881 if (!modified) /* do not save unmodified default settings */
4885 num_bytes += putFile16BitBE(file, element);
4887 num_bytes += putFile8Bit(file, conf_type);
4888 num_bytes += (byte_mask == CONF_MASK_1_BYTE ? putFile8Bit (file, value) :
4889 byte_mask == CONF_MASK_2_BYTE ? putFile16BitBE(file, value) :
4890 byte_mask == CONF_MASK_4_BYTE ? putFile32BitBE(file, value) :
4895 else if (data_type == TYPE_STRING)
4897 char *default_string = entry->default_string;
4898 char *string = (char *)(entry->value);
4899 int string_length = strlen(string);
4902 /* check if any settings have been modified before saving them */
4903 if (!strEqual(string, default_string))
4906 if (!modified) /* do not save unmodified default settings */
4910 num_bytes += putFile16BitBE(file, element);
4912 num_bytes += putFile8Bit(file, conf_type);
4913 num_bytes += putFile16BitBE(file, string_length);
4915 for (i = 0; i < string_length; i++)
4916 num_bytes += putFile8Bit(file, string[i]);
4920 else if (data_type == TYPE_ELEMENT_LIST)
4922 int *element_array = (int *)(entry->value);
4923 int num_elements = *(int *)(entry->num_entities);
4926 /* check if any settings have been modified before saving them */
4927 for (i = 0; i < num_elements; i++)
4928 if (element_array[i] != default_value)
4931 if (!modified) /* do not save unmodified default settings */
4935 num_bytes += putFile16BitBE(file, element);
4937 num_bytes += putFile8Bit(file, conf_type);
4938 num_bytes += putFile16BitBE(file, num_elements * CONF_ELEMENT_NUM_BYTES);
4940 for (i = 0; i < num_elements; i++)
4941 num_bytes += putFile16BitBE(file, element_array[i]);
4945 else if (data_type == TYPE_CONTENT_LIST)
4947 struct Content *content = (struct Content *)(entry->value);
4948 int num_contents = *(int *)(entry->num_entities);
4951 /* check if any settings have been modified before saving them */
4952 for (i = 0; i < num_contents; i++)
4953 for (y = 0; y < 3; y++)
4954 for (x = 0; x < 3; x++)
4955 if (content[i].e[x][y] != default_value)
4958 if (!modified) /* do not save unmodified default settings */
4962 num_bytes += putFile16BitBE(file, element);
4964 num_bytes += putFile8Bit(file, conf_type);
4965 num_bytes += putFile16BitBE(file, num_contents * CONF_CONTENT_NUM_BYTES);
4967 for (i = 0; i < num_contents; i++)
4968 for (y = 0; y < 3; y++)
4969 for (x = 0; x < 3; x++)
4970 num_bytes += putFile16BitBE(file, content[i].e[x][y]);
4980 static int SaveLevel_MicroChunk_SingleValue(FILE *file,
4981 struct ElementFileConfig *entry)
4983 int default_value = entry->default_value;
4984 int element = entry->element;
4985 int data_type = entry->data_type;
4986 int conf_type = entry->conf_type;
4987 int byte_mask = conf_type & CONF_MASK_BYTES;
4988 void *value_ptr = entry->value;
4989 int value = (data_type == TYPE_BOOLEAN ? *(boolean *)value_ptr :
4992 boolean modified = FALSE;
4994 /* check if any settings have been modified before saving them */
4995 if (value != default_value)
4998 if (!modified) /* do not save unmodified default settings */
5002 printf("::: %02x, %d: %d != %d\n",
5003 byte_mask, conf_type & CONF_MASK_TOKEN,
5004 value, default_value);
5008 num_bytes += putFile16BitBE(file, element);
5010 num_bytes += putFile8Bit(file, conf_type);
5011 num_bytes += (byte_mask == CONF_MASK_1_BYTE ? putFile8Bit (file, value) :
5012 byte_mask == CONF_MASK_2_BYTE ? putFile16BitBE(file, value) :
5013 byte_mask == CONF_MASK_4_BYTE ? putFile32BitBE(file, value) :0);
5018 static int SaveLevel_MicroChunk_ElementList(FILE *file,
5019 struct ElementFileConfig *entry)
5021 int *element_array = (int *)(entry->value);
5022 int num_elements = *(int *)(entry->num_entities);
5023 int default_value = entry->default_value;
5024 int element = entry->element;
5025 int conf_type = entry->conf_type;
5027 boolean modified = FALSE;
5030 /* check if any settings have been modified before saving them */
5031 for (i = 0; i < num_elements; i++)
5032 if (element_array[i] != default_value)
5035 if (!modified) /* do not save unmodified default settings */
5039 num_bytes += putFile16BitBE(file, element);
5041 num_bytes += putFile8Bit(file, conf_type);
5042 num_bytes += putFile16BitBE(file, num_elements * CONF_ELEMENT_NUM_BYTES);
5044 for (i = 0; i < num_elements; i++)
5045 num_bytes += putFile16BitBE(file, element_array[i]);
5050 static int SaveLevel_MicroChunk_ContentList(FILE *file,
5051 struct ElementFileConfig *entry)
5053 struct Content *content = (struct Content *)(entry->value);
5054 int num_contents = *(int *)(entry->num_entities);
5055 int default_value = entry->default_value;
5056 int element = entry->element;
5057 int conf_type = entry->conf_type;
5059 boolean modified = FALSE;
5062 /* check if any settings have been modified before saving them */
5063 for (i = 0; i < num_contents; i++)
5064 for (y = 0; y < 3; y++)
5065 for (x = 0; x < 3; x++)
5066 if (content[i].e[x][y] != default_value)
5069 if (!modified) /* do not save unmodified default settings */
5073 num_bytes += putFile16BitBE(file, element);
5075 num_bytes += putFile8Bit(file, conf_type);
5076 num_bytes += putFile16BitBE(file, num_contents * CONF_CONTENT_NUM_BYTES);
5078 for (i = 0; i < num_contents; i++)
5079 for (y = 0; y < 3; y++)
5080 for (x = 0; x < 3; x++)
5081 num_bytes += putFile16BitBE(file, content[i].e[x][y]);
5088 static int SaveLevel_CONF(FILE *file, struct LevelInfo *level)
5093 li = *level; /* copy level data into temporary buffer */
5095 for (i = 0; element_conf[i].data_type != -1; i++)
5098 chunk_size += SaveLevel_MicroChunk(file, &element_conf[i]);
5100 struct ElementFileConfig *config = &element_conf[i];
5101 int data_type = config->data_type;
5102 int conf_type = config->conf_type;
5103 int byte_mask = conf_type & CONF_MASK_BYTES;
5105 if (byte_mask != CONF_MASK_MULTI_BYTES)
5106 chunk_size += SaveLevel_MicroChunk_SingleValue(file, config);
5107 else if (data_type == TYPE_ELEMENT_LIST)
5108 chunk_size += SaveLevel_MicroChunk_ElementList(file, config);
5109 else if (data_type == TYPE_CONTENT_LIST)
5110 chunk_size += SaveLevel_MicroChunk_ContentList(file, config);
5117 static int SaveLevel_CUSX(FILE *file, struct LevelInfo *level, int element)
5119 struct ElementInfo *ei = &element_info[element];
5123 chunk_size += putFile16BitBE(file, element);
5125 xx_ei = *ei; /* copy element data into temporary buffer */
5127 /* set default description string for this specific element */
5128 strcpy(xx_default_description, getDefaultElementDescription(ei));
5130 /* set (fixed) number of content areas (may have been overwritten earlier) */
5131 xx_num_contents = 1;
5134 printf("::: - element config\n");
5137 for (i = 0; custom_element_conf[i].data_type != -1; i++)
5138 chunk_size += SaveLevel_MicroChunk(file, &custom_element_conf[i]);
5141 printf("::: - change pages\n");
5144 for (i = 0; i < ei->num_change_pages; i++)
5146 struct ElementChangeInfo *change = &ei->change_page[i];
5148 xx_current_change_page = i;
5150 xx_change = *change; /* copy change data into temporary buffer */
5153 printf("::: %d: xx_change.action_mode == %d\n",
5154 i, xx_change.action_mode);
5155 printf("::: %d: xx_change.action_arg == %d\n",
5156 i, xx_change.action_arg);
5160 setEventBitsFromEventFlags(change);
5162 for (j = 0; custom_element_change_conf[j].data_type != -1; j++)
5163 chunk_size += SaveLevel_MicroChunk(file, &custom_element_change_conf[j]);
5166 if (element == EL_CUSTOM_START)
5167 printf("::: - saving change page %d / %d (%d bytes)\n",
5168 i, ei->num_change_pages, chunk_size);
5175 static int SaveLevel_GRPX(FILE *file, struct LevelInfo *level, int element)
5177 struct ElementInfo *ei = &element_info[element];
5178 struct ElementGroupInfo *group = ei->group;
5182 chunk_size += putFile16BitBE(file, element);
5184 xx_ei = *ei; /* copy element data into temporary buffer */
5185 xx_group = *group; /* copy group data into temporary buffer */
5187 /* set default description string for this specific element */
5188 strcpy(xx_default_description, getDefaultElementDescription(ei));
5190 for (i = 0; group_element_conf[i].data_type != -1; i++)
5191 chunk_size += SaveLevel_MicroChunk(file, &group_element_conf[i]);
5196 static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
5198 int body_chunk_size, conf_chunk_size;
5202 if (!(file = fopen(filename, MODE_WRITE)))
5204 Error(ERR_WARN, "cannot save level file '%s'", filename);
5208 level->file_version = FILE_VERSION_ACTUAL;
5209 level->game_version = GAME_VERSION_ACTUAL;
5211 /* check level field for 16-bit elements */
5212 level->encoding_16bit_field = FALSE;
5213 for (y = 0; y < level->fieldy; y++)
5214 for (x = 0; x < level->fieldx; x++)
5215 if (level->field[x][y] > 255)
5216 level->encoding_16bit_field = TRUE;
5218 /* check yamyam content for 16-bit elements */
5219 level->encoding_16bit_yamyam = FALSE;
5220 for (i = 0; i < level->num_yamyam_contents; i++)
5221 for (y = 0; y < 3; y++)
5222 for (x = 0; x < 3; x++)
5223 if (level->yamyam_content[i].e[x][y] > 255)
5224 level->encoding_16bit_yamyam = TRUE;
5226 /* check amoeba content for 16-bit elements */
5227 level->encoding_16bit_amoeba = FALSE;
5228 if (level->amoeba_content > 255)
5229 level->encoding_16bit_amoeba = TRUE;
5231 /* calculate size of "BODY" chunk */
5233 level->fieldx * level->fieldy * (level->encoding_16bit_field ? 2 : 1);
5235 putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
5236 putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
5238 putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
5239 SaveLevel_VERS(file, level);
5241 putFileChunkBE(file, "HEAD", LEVEL_HEADER_SIZE);
5242 SaveLevel_HEAD(file, level);
5244 putFileChunkBE(file, "AUTH", MAX_LEVEL_AUTHOR_LEN);
5245 SaveLevel_AUTH(file, level);
5247 putFileChunkBE(file, "BODY", body_chunk_size);
5248 SaveLevel_BODY(file, level);
5250 if (level->encoding_16bit_yamyam ||
5251 level->num_yamyam_contents != STD_ELEMENT_CONTENTS)
5253 putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
5254 SaveLevel_CNT2(file, level, EL_YAMYAM);
5257 if (level->encoding_16bit_amoeba)
5259 putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
5260 SaveLevel_CNT2(file, level, EL_BD_AMOEBA);
5263 /* check for envelope content */
5264 for (i = 0; i < 4; i++)
5266 if (strlen(level->envelope_text[i]) > 0)
5268 int envelope_len = strlen(level->envelope_text[i]) + 1;
5270 putFileChunkBE(file, "CNT3", LEVEL_CHUNK_CNT3_SIZE(envelope_len));
5271 SaveLevel_CNT3(file, level, EL_ENVELOPE_1 + i);
5275 /* if not using template level, check for non-default custom/group elements */
5276 if (!level->use_custom_template)
5279 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
5281 int element = EL_CUSTOM_START + i;
5283 if (element_info[element].modified_settings)
5285 int num_change_pages = element_info[element].num_change_pages;
5287 putFileChunkBE(file, "CUS4", LEVEL_CHUNK_CUS4_SIZE(num_change_pages));
5288 SaveLevel_CUS4(file, level, element);
5292 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
5294 int element = EL_GROUP_START + i;
5296 if (element_info[element].modified_settings)
5298 putFileChunkBE(file, "GRP1", LEVEL_CHUNK_GRP1_SIZE);
5299 SaveLevel_GRP1(file, level, element);
5305 conf_chunk_size = SaveLevel_CONF(NULL, level);
5307 /* check if non-default element settings need to be saved */
5308 if (conf_chunk_size > 0)
5310 putFileChunkBE(file, "CONF", conf_chunk_size);
5311 SaveLevel_CONF(file, level);
5314 /* if not using template level, check for non-default custom/group elements */
5315 if (!level->use_custom_template)
5317 /* (element number, number of change pages, change page number) */
5318 int cusx_chunk_size_no_changes = (2) + (1 + 1) + (1 + 1);
5319 /* (element number only) */
5320 int grpx_chunk_size_no_changes = (2);
5323 for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
5325 int element = EL_CUSTOM_START + i;
5326 int cusx_chunk_size = SaveLevel_CUSX(NULL, level, element);
5328 /* check if non-default element settings need to be saved */
5329 if (cusx_chunk_size > cusx_chunk_size_no_changes)
5332 printf("::: SAVING CE %d\n", i + 1);
5335 putFileChunkBE(file, "CUSX", cusx_chunk_size);
5336 SaveLevel_CUSX(file, level, element);
5340 for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
5342 int element = EL_GROUP_START + i;
5343 int grpx_chunk_size = SaveLevel_GRPX(NULL, level, element);
5345 /* check if non-default element settings need to be saved */
5346 if (grpx_chunk_size > grpx_chunk_size_no_changes)
5349 printf("::: SAVING GE %d\n", i + 1);
5352 putFileChunkBE(file, "GRPX", grpx_chunk_size);
5353 SaveLevel_GRPX(file, level, element);
5361 SetFilePermissions(filename, PERMS_PRIVATE);
5364 void SaveLevel(int nr)
5366 char *filename = getDefaultLevelFilename(nr);
5368 SaveLevelFromFilename(&level, filename);
5371 void SaveLevelTemplate()
5373 char *filename = getDefaultLevelFilename(-1);
5375 SaveLevelFromFilename(&level, filename);
5378 void DumpLevel(struct LevelInfo *level)
5380 if (level->no_valid_file)
5382 Error(ERR_WARN, "cannot dump -- no valid level file found");
5387 printf_line("-", 79);
5388 printf("Level xxx (file version %08d, game version %08d)\n",
5389 level->file_version, level->game_version);
5390 printf_line("-", 79);
5392 printf("Level author: '%s'\n", level->author);
5393 printf("Level title: '%s'\n", level->name);
5395 printf("Playfield size: %d x %d\n", level->fieldx, level->fieldy);
5397 printf("Level time: %d seconds\n", level->time);
5398 printf("Gems needed: %d\n", level->gems_needed);
5400 printf("Time for magic wall: %d seconds\n", level->time_magic_wall);
5401 printf("Time for wheel: %d seconds\n", level->time_wheel);
5402 printf("Time for light: %d seconds\n", level->time_light);
5403 printf("Time for timegate: %d seconds\n", level->time_timegate);
5405 printf("Amoeba speed: %d\n", level->amoeba_speed);
5407 printf("Initial gravity: %s\n", (level->initial_gravity ? "yes" : "no"));
5408 printf("Initial player stepsize: %d\n", level->initial_player_stepsize);
5409 printf("EM style slippery gems: %s\n", (level->em_slippery_gems ? "yes" : "no"));
5410 printf("Player blocks last field: %s\n", (level->block_last_field ? "yes" : "no"));
5411 printf("SP player blocks last field: %s\n", (level->sp_block_last_field ? "yes" : "no"));
5412 printf("use spring bug: %s\n", (level->use_spring_bug ? "yes" : "no"));
5413 printf("use step counter: %s\n", (level->use_step_counter ? "yes" : "no"));
5415 printf_line("-", 79);
5419 /* ========================================================================= */
5420 /* tape file functions */
5421 /* ========================================================================= */
5423 static void setTapeInfoToDefaults()
5427 /* always start with reliable default values (empty tape) */
5430 /* default values (also for pre-1.2 tapes) with only the first player */
5431 tape.player_participates[0] = TRUE;
5432 for (i = 1; i < MAX_PLAYERS; i++)
5433 tape.player_participates[i] = FALSE;
5435 /* at least one (default: the first) player participates in every tape */
5436 tape.num_participating_players = 1;
5438 tape.level_nr = level_nr;
5440 tape.changed = FALSE;
5442 tape.recording = FALSE;
5443 tape.playing = FALSE;
5444 tape.pausing = FALSE;
5446 tape.no_valid_file = FALSE;
5449 static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
5451 tape->file_version = getFileVersion(file);
5452 tape->game_version = getFileVersion(file);
5457 static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
5461 tape->random_seed = getFile32BitBE(file);
5462 tape->date = getFile32BitBE(file);
5463 tape->length = getFile32BitBE(file);
5465 /* read header fields that are new since version 1.2 */
5466 if (tape->file_version >= FILE_VERSION_1_2)
5468 byte store_participating_players = getFile8Bit(file);
5471 /* since version 1.2, tapes store which players participate in the tape */
5472 tape->num_participating_players = 0;
5473 for (i = 0; i < MAX_PLAYERS; i++)
5475 tape->player_participates[i] = FALSE;
5477 if (store_participating_players & (1 << i))
5479 tape->player_participates[i] = TRUE;
5480 tape->num_participating_players++;
5484 ReadUnusedBytesFromFile(file, TAPE_HEADER_UNUSED);
5486 engine_version = getFileVersion(file);
5487 if (engine_version > 0)
5488 tape->engine_version = engine_version;
5490 tape->engine_version = tape->game_version;
5496 static int LoadTape_INFO(FILE *file, int chunk_size, struct TapeInfo *tape)
5498 int level_identifier_size;
5501 level_identifier_size = getFile16BitBE(file);
5503 tape->level_identifier =
5504 checked_realloc(tape->level_identifier, level_identifier_size);
5506 for (i = 0; i < level_identifier_size; i++)
5507 tape->level_identifier[i] = getFile8Bit(file);
5509 tape->level_nr = getFile16BitBE(file);
5511 chunk_size = 2 + level_identifier_size + 2;
5516 static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
5519 int chunk_size_expected =
5520 (tape->num_participating_players + 1) * tape->length;
5522 if (chunk_size_expected != chunk_size)
5524 ReadUnusedBytesFromFile(file, chunk_size);
5525 return chunk_size_expected;
5528 for (i = 0; i < tape->length; i++)
5530 if (i >= MAX_TAPE_LEN)
5533 for (j = 0; j < MAX_PLAYERS; j++)
5535 tape->pos[i].action[j] = MV_NONE;
5537 if (tape->player_participates[j])
5538 tape->pos[i].action[j] = getFile8Bit(file);
5541 tape->pos[i].delay = getFile8Bit(file);
5543 if (tape->file_version == FILE_VERSION_1_0)
5545 /* eliminate possible diagonal moves in old tapes */
5546 /* this is only for backward compatibility */
5548 byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
5549 byte action = tape->pos[i].action[0];
5550 int k, num_moves = 0;
5552 for (k = 0; k<4; k++)
5554 if (action & joy_dir[k])
5556 tape->pos[i + num_moves].action[0] = joy_dir[k];
5558 tape->pos[i + num_moves].delay = 0;
5567 tape->length += num_moves;
5570 else if (tape->file_version < FILE_VERSION_2_0)
5572 /* convert pre-2.0 tapes to new tape format */
5574 if (tape->pos[i].delay > 1)
5577 tape->pos[i + 1] = tape->pos[i];
5578 tape->pos[i + 1].delay = 1;
5581 for (j = 0; j < MAX_PLAYERS; j++)
5582 tape->pos[i].action[j] = MV_NONE;
5583 tape->pos[i].delay--;
5594 if (i != tape->length)
5595 chunk_size = (tape->num_participating_players + 1) * i;
5600 void LoadTapeFromFilename(char *filename)
5602 char cookie[MAX_LINE_LEN];
5603 char chunk_name[CHUNK_ID_LEN + 1];
5607 /* always start with reliable default values */
5608 setTapeInfoToDefaults();
5610 if (!(file = fopen(filename, MODE_READ)))
5612 tape.no_valid_file = TRUE;
5617 getFileChunkBE(file, chunk_name, NULL);
5618 if (strEqual(chunk_name, "RND1"))
5620 getFile32BitBE(file); /* not used */
5622 getFileChunkBE(file, chunk_name, NULL);
5623 if (!strEqual(chunk_name, "TAPE"))
5625 tape.no_valid_file = TRUE;
5627 Error(ERR_WARN, "unknown format of tape file '%s'", filename);
5632 else /* check for pre-2.0 file format with cookie string */
5634 strcpy(cookie, chunk_name);
5635 fgets(&cookie[4], MAX_LINE_LEN - 4, file);
5636 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
5637 cookie[strlen(cookie) - 1] = '\0';
5639 if (!checkCookieString(cookie, TAPE_COOKIE_TMPL))
5641 tape.no_valid_file = TRUE;
5643 Error(ERR_WARN, "unknown format of tape file '%s'", filename);
5648 if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1)
5650 tape.no_valid_file = TRUE;
5652 Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
5657 /* pre-2.0 tape files have no game version, so use file version here */
5658 tape.game_version = tape.file_version;
5661 if (tape.file_version < FILE_VERSION_1_2)
5663 /* tape files from versions before 1.2.0 without chunk structure */
5664 LoadTape_HEAD(file, TAPE_HEADER_SIZE, &tape);
5665 LoadTape_BODY(file, 2 * tape.length, &tape);
5673 int (*loader)(FILE *, int, struct TapeInfo *);
5677 { "VERS", FILE_VERS_CHUNK_SIZE, LoadTape_VERS },
5678 { "HEAD", TAPE_HEADER_SIZE, LoadTape_HEAD },
5679 { "INFO", -1, LoadTape_INFO },
5680 { "BODY", -1, LoadTape_BODY },
5684 while (getFileChunkBE(file, chunk_name, &chunk_size))
5688 while (chunk_info[i].name != NULL &&
5689 !strEqual(chunk_name, chunk_info[i].name))
5692 if (chunk_info[i].name == NULL)
5694 Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'",
5695 chunk_name, filename);
5696 ReadUnusedBytesFromFile(file, chunk_size);
5698 else if (chunk_info[i].size != -1 &&
5699 chunk_info[i].size != chunk_size)
5701 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
5702 chunk_size, chunk_name, filename);
5703 ReadUnusedBytesFromFile(file, chunk_size);
5707 /* call function to load this tape chunk */
5708 int chunk_size_expected =
5709 (chunk_info[i].loader)(file, chunk_size, &tape);
5711 /* the size of some chunks cannot be checked before reading other
5712 chunks first (like "HEAD" and "BODY") that contain some header
5713 information, so check them here */
5714 if (chunk_size_expected != chunk_size)
5716 Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
5717 chunk_size, chunk_name, filename);
5725 tape.length_seconds = GetTapeLength();
5728 printf("::: tape game version: %d\n", tape.game_version);
5729 printf("::: tape engine version: %d\n", tape.engine_version);
5733 void LoadTape(int nr)
5735 char *filename = getTapeFilename(nr);
5737 LoadTapeFromFilename(filename);
5740 void LoadSolutionTape(int nr)
5742 char *filename = getSolutionTapeFilename(nr);
5744 LoadTapeFromFilename(filename);
5747 static void SaveTape_VERS(FILE *file, struct TapeInfo *tape)
5749 putFileVersion(file, tape->file_version);
5750 putFileVersion(file, tape->game_version);
5753 static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
5756 byte store_participating_players = 0;
5758 /* set bits for participating players for compact storage */
5759 for (i = 0; i < MAX_PLAYERS; i++)
5760 if (tape->player_participates[i])
5761 store_participating_players |= (1 << i);
5763 putFile32BitBE(file, tape->random_seed);
5764 putFile32BitBE(file, tape->date);
5765 putFile32BitBE(file, tape->length);
5767 putFile8Bit(file, store_participating_players);
5769 /* unused bytes not at the end here for 4-byte alignment of engine_version */
5770 WriteUnusedBytesToFile(file, TAPE_HEADER_UNUSED);
5772 putFileVersion(file, tape->engine_version);
5775 static void SaveTape_INFO(FILE *file, struct TapeInfo *tape)
5777 int level_identifier_size = strlen(tape->level_identifier) + 1;
5780 putFile16BitBE(file, level_identifier_size);
5782 for (i = 0; i < level_identifier_size; i++)
5783 putFile8Bit(file, tape->level_identifier[i]);
5785 putFile16BitBE(file, tape->level_nr);
5788 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
5792 for (i = 0; i < tape->length; i++)
5794 for (j = 0; j < MAX_PLAYERS; j++)
5795 if (tape->player_participates[j])
5796 putFile8Bit(file, tape->pos[i].action[j]);
5798 putFile8Bit(file, tape->pos[i].delay);
5802 void SaveTape(int nr)
5804 char *filename = getTapeFilename(nr);
5806 boolean new_tape = TRUE;
5807 int num_participating_players = 0;
5808 int info_chunk_size;
5809 int body_chunk_size;
5812 InitTapeDirectory(leveldir_current->subdir);
5814 /* if a tape still exists, ask to overwrite it */
5815 if (fileExists(filename))
5818 if (!Request("Replace old tape ?", REQ_ASK))
5822 if (!(file = fopen(filename, MODE_WRITE)))
5824 Error(ERR_WARN, "cannot save level recording file '%s'", filename);
5828 tape.file_version = FILE_VERSION_ACTUAL;
5829 tape.game_version = GAME_VERSION_ACTUAL;
5831 /* count number of participating players */
5832 for (i = 0; i < MAX_PLAYERS; i++)
5833 if (tape.player_participates[i])
5834 num_participating_players++;
5836 info_chunk_size = 2 + (strlen(tape.level_identifier) + 1) + 2;
5837 body_chunk_size = (num_participating_players + 1) * tape.length;
5839 putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
5840 putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
5842 putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
5843 SaveTape_VERS(file, &tape);
5845 putFileChunkBE(file, "HEAD", TAPE_HEADER_SIZE);
5846 SaveTape_HEAD(file, &tape);
5848 putFileChunkBE(file, "INFO", info_chunk_size);
5849 SaveTape_INFO(file, &tape);
5851 putFileChunkBE(file, "BODY", body_chunk_size);
5852 SaveTape_BODY(file, &tape);
5856 SetFilePermissions(filename, PERMS_PRIVATE);
5858 tape.changed = FALSE;
5861 Request("Tape saved !", REQ_CONFIRM);
5864 void DumpTape(struct TapeInfo *tape)
5866 int tape_frame_counter;
5869 if (tape->no_valid_file)
5871 Error(ERR_WARN, "cannot dump -- no valid tape file found");
5876 printf_line("-", 79);
5877 printf("Tape of Level %03d (file version %08d, game version %08d)\n",
5878 tape->level_nr, tape->file_version, tape->game_version);
5879 printf(" (effective engine version %08d)\n",
5880 tape->engine_version);
5881 printf("Level series identifier: '%s'\n", tape->level_identifier);
5882 printf_line("-", 79);
5884 tape_frame_counter = 0;
5886 for (i = 0; i < tape->length; i++)
5888 if (i >= MAX_TAPE_LEN)
5891 printf("%04d: ", i);
5893 for (j = 0; j < MAX_PLAYERS; j++)
5895 if (tape->player_participates[j])
5897 int action = tape->pos[i].action[j];
5899 printf("%d:%02x ", j, action);
5900 printf("[%c%c%c%c|%c%c] - ",
5901 (action & JOY_LEFT ? '<' : ' '),
5902 (action & JOY_RIGHT ? '>' : ' '),
5903 (action & JOY_UP ? '^' : ' '),
5904 (action & JOY_DOWN ? 'v' : ' '),
5905 (action & JOY_BUTTON_1 ? '1' : ' '),
5906 (action & JOY_BUTTON_2 ? '2' : ' '));
5910 printf("(%03d) ", tape->pos[i].delay);
5911 printf("[%05d]\n", tape_frame_counter);
5913 tape_frame_counter += tape->pos[i].delay;
5916 printf_line("-", 79);
5920 /* ========================================================================= */
5921 /* score file functions */
5922 /* ========================================================================= */
5924 void LoadScore(int nr)
5927 char *filename = getScoreFilename(nr);
5928 char cookie[MAX_LINE_LEN];
5929 char line[MAX_LINE_LEN];
5933 /* always start with reliable default values */
5934 for (i = 0; i < MAX_SCORE_ENTRIES; i++)
5936 strcpy(highscore[i].Name, EMPTY_PLAYER_NAME);
5937 highscore[i].Score = 0;
5940 if (!(file = fopen(filename, MODE_READ)))
5943 /* check file identifier */
5944 fgets(cookie, MAX_LINE_LEN, file);
5945 if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
5946 cookie[strlen(cookie) - 1] = '\0';
5948 if (!checkCookieString(cookie, SCORE_COOKIE))
5950 Error(ERR_WARN, "unknown format of score file '%s'", filename);
5955 for (i = 0; i < MAX_SCORE_ENTRIES; i++)
5957 fscanf(file, "%d", &highscore[i].Score);
5958 fgets(line, MAX_LINE_LEN, file);
5960 if (line[strlen(line) - 1] == '\n')
5961 line[strlen(line) - 1] = '\0';
5963 for (line_ptr = line; *line_ptr; line_ptr++)
5965 if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
5967 strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN);
5968 highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0';
5977 void SaveScore(int nr)
5980 char *filename = getScoreFilename(nr);
5983 InitScoreDirectory(leveldir_current->subdir);
5985 if (!(file = fopen(filename, MODE_WRITE)))
5987 Error(ERR_WARN, "cannot save score for level %d", nr);
5991 fprintf(file, "%s\n\n", SCORE_COOKIE);
5993 for (i = 0; i < MAX_SCORE_ENTRIES; i++)
5994 fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name);
5998 SetFilePermissions(filename, PERMS_PUBLIC);
6002 /* ========================================================================= */
6003 /* setup file functions */
6004 /* ========================================================================= */
6006 #define TOKEN_STR_PLAYER_PREFIX "player_"
6009 #define SETUP_TOKEN_PLAYER_NAME 0
6010 #define SETUP_TOKEN_SOUND 1
6011 #define SETUP_TOKEN_SOUND_LOOPS 2
6012 #define SETUP_TOKEN_SOUND_MUSIC 3
6013 #define SETUP_TOKEN_SOUND_SIMPLE 4
6014 #define SETUP_TOKEN_TOONS 5
6015 #define SETUP_TOKEN_SCROLL_DELAY 6
6016 #define SETUP_TOKEN_SOFT_SCROLLING 7
6017 #define SETUP_TOKEN_FADING 8
6018 #define SETUP_TOKEN_AUTORECORD 9
6019 #define SETUP_TOKEN_SHOW_TITLESCREEN 10
6020 #define SETUP_TOKEN_QUICK_DOORS 11
6021 #define SETUP_TOKEN_TEAM_MODE 12
6022 #define SETUP_TOKEN_HANDICAP 13
6023 #define SETUP_TOKEN_SKIP_LEVELS 14
6024 #define SETUP_TOKEN_TIME_LIMIT 15
6025 #define SETUP_TOKEN_FULLSCREEN 16
6026 #define SETUP_TOKEN_ASK_ON_ESCAPE 17
6027 #define SETUP_TOKEN_ASK_ON_ESCAPE_EDITOR 18
6028 #define SETUP_TOKEN_QUICK_SWITCH 19
6029 #define SETUP_TOKEN_INPUT_ON_FOCUS 20
6030 #define SETUP_TOKEN_PREFER_AGA_GRAPHICS 21
6031 #define SETUP_TOKEN_GRAPHICS_SET 22
6032 #define SETUP_TOKEN_SOUNDS_SET 23
6033 #define SETUP_TOKEN_MUSIC_SET 24
6034 #define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS 25
6035 #define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS 26
6036 #define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC 27
6038 #define NUM_GLOBAL_SETUP_TOKENS 28
6041 #define SETUP_TOKEN_EDITOR_EL_BOULDERDASH 0
6042 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE 1
6043 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE_CLUB 2
6044 #define SETUP_TOKEN_EDITOR_EL_MORE 3
6045 #define SETUP_TOKEN_EDITOR_EL_SOKOBAN 4
6046 #define SETUP_TOKEN_EDITOR_EL_SUPAPLEX 5
6047 #define SETUP_TOKEN_EDITOR_EL_DIAMOND_CAVES 6
6048 #define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH 7
6049 #define SETUP_TOKEN_EDITOR_EL_CHARS 8
6050 #define SETUP_TOKEN_EDITOR_EL_CUSTOM 9
6051 #define SETUP_TOKEN_EDITOR_EL_HEADLINES 10
6052 #define SETUP_TOKEN_EDITOR_EL_USER_DEFINED 11
6053 #define SETUP_TOKEN_EDITOR_EL_DYNAMIC 12
6054 #define SETUP_TOKEN_EDITOR_SHOW_ELEMENT_TOKEN 13
6056 #define NUM_EDITOR_SETUP_TOKENS 14
6058 /* editor cascade setup */
6059 #define SETUP_TOKEN_EDITOR_CASCADE_BD 0
6060 #define SETUP_TOKEN_EDITOR_CASCADE_EM 1
6061 #define SETUP_TOKEN_EDITOR_CASCADE_EMC 2
6062 #define SETUP_TOKEN_EDITOR_CASCADE_RND 3
6063 #define SETUP_TOKEN_EDITOR_CASCADE_SB 4
6064 #define SETUP_TOKEN_EDITOR_CASCADE_SP 5
6065 #define SETUP_TOKEN_EDITOR_CASCADE_DC 6
6066 #define SETUP_TOKEN_EDITOR_CASCADE_DX 7
6067 #define SETUP_TOKEN_EDITOR_CASCADE_TEXT 8
6068 #define SETUP_TOKEN_EDITOR_CASCADE_CE 9
6069 #define SETUP_TOKEN_EDITOR_CASCADE_GE 10
6070 #define SETUP_TOKEN_EDITOR_CASCADE_USER 11
6071 #define SETUP_TOKEN_EDITOR_CASCADE_GENERIC 12
6072 #define SETUP_TOKEN_EDITOR_CASCADE_DYNAMIC 13
6074 #define NUM_EDITOR_CASCADE_SETUP_TOKENS 14
6076 /* shortcut setup */
6077 #define SETUP_TOKEN_SHORTCUT_SAVE_GAME 0
6078 #define SETUP_TOKEN_SHORTCUT_LOAD_GAME 1
6079 #define SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE 2
6080 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_1 3
6081 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_2 4
6082 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_3 5
6083 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_4 6
6084 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_ALL 7
6086 #define NUM_SHORTCUT_SETUP_TOKENS 8
6089 #define SETUP_TOKEN_PLAYER_USE_JOYSTICK 0
6090 #define SETUP_TOKEN_PLAYER_JOY_DEVICE_NAME 1
6091 #define SETUP_TOKEN_PLAYER_JOY_XLEFT 2
6092 #define SETUP_TOKEN_PLAYER_JOY_XMIDDLE 3
6093 #define SETUP_TOKEN_PLAYER_JOY_XRIGHT 4
6094 #define SETUP_TOKEN_PLAYER_JOY_YUPPER 5
6095 #define SETUP_TOKEN_PLAYER_JOY_YMIDDLE 6
6096 #define SETUP_TOKEN_PLAYER_JOY_YLOWER 7
6097 #define SETUP_TOKEN_PLAYER_JOY_SNAP 8
6098 #define SETUP_TOKEN_PLAYER_JOY_DROP 9
6099 #define SETUP_TOKEN_PLAYER_KEY_LEFT 10
6100 #define SETUP_TOKEN_PLAYER_KEY_RIGHT 11
6101 #define SETUP_TOKEN_PLAYER_KEY_UP 12
6102 #define SETUP_TOKEN_PLAYER_KEY_DOWN 13
6103 #define SETUP_TOKEN_PLAYER_KEY_SNAP 14
6104 #define SETUP_TOKEN_PLAYER_KEY_DROP 15
6106 #define NUM_PLAYER_SETUP_TOKENS 16
6109 #define SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER 0
6110 #define SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE 1
6112 #define NUM_SYSTEM_SETUP_TOKENS 2
6115 #define SETUP_TOKEN_OPTIONS_VERBOSE 0
6117 #define NUM_OPTIONS_SETUP_TOKENS 1
6120 static struct SetupInfo si;
6121 static struct SetupEditorInfo sei;
6122 static struct SetupEditorCascadeInfo seci;
6123 static struct SetupShortcutInfo ssi;
6124 static struct SetupInputInfo sii;
6125 static struct SetupSystemInfo syi;
6126 static struct OptionInfo soi;
6128 static struct TokenInfo global_setup_tokens[] =
6130 { TYPE_STRING, &si.player_name, "player_name" },
6131 { TYPE_SWITCH, &si.sound, "sound" },
6132 { TYPE_SWITCH, &si.sound_loops, "repeating_sound_loops" },
6133 { TYPE_SWITCH, &si.sound_music, "background_music" },
6134 { TYPE_SWITCH, &si.sound_simple, "simple_sound_effects" },
6135 { TYPE_SWITCH, &si.toons, "toons" },
6136 { TYPE_SWITCH, &si.scroll_delay, "scroll_delay" },
6137 { TYPE_SWITCH, &si.soft_scrolling, "soft_scrolling" },
6138 { TYPE_SWITCH, &si.fading, "screen_fading" },
6139 { TYPE_SWITCH, &si.autorecord, "automatic_tape_recording" },
6140 { TYPE_SWITCH, &si.show_titlescreen, "show_titlescreen" },
6141 { TYPE_SWITCH, &si.quick_doors, "quick_doors" },
6142 { TYPE_SWITCH, &si.team_mode, "team_mode" },
6143 { TYPE_SWITCH, &si.handicap, "handicap" },
6144 { TYPE_SWITCH, &si.skip_levels, "skip_levels" },
6145 { TYPE_SWITCH, &si.time_limit, "time_limit" },
6146 { TYPE_SWITCH, &si.fullscreen, "fullscreen" },
6147 { TYPE_SWITCH, &si.ask_on_escape, "ask_on_escape" },
6148 { TYPE_SWITCH, &si.ask_on_escape_editor, "ask_on_escape_editor" },
6149 { TYPE_SWITCH, &si.quick_switch, "quick_player_switch" },
6150 { TYPE_SWITCH, &si.input_on_focus, "input_on_focus" },
6151 { TYPE_SWITCH, &si.prefer_aga_graphics, "prefer_aga_graphics" },
6152 { TYPE_STRING, &si.graphics_set, "graphics_set" },
6153 { TYPE_STRING, &si.sounds_set, "sounds_set" },
6154 { TYPE_STRING, &si.music_set, "music_set" },
6155 { TYPE_SWITCH, &si.override_level_graphics, "override_level_graphics" },
6156 { TYPE_SWITCH, &si.override_level_sounds, "override_level_sounds" },
6157 { TYPE_SWITCH, &si.override_level_music, "override_level_music" },
6160 static struct TokenInfo editor_setup_tokens[] =
6162 { TYPE_SWITCH, &sei.el_boulderdash, "editor.el_boulderdash" },
6163 { TYPE_SWITCH, &sei.el_emerald_mine, "editor.el_emerald_mine" },
6164 { TYPE_SWITCH, &sei.el_emerald_mine_club,"editor.el_emerald_mine_club"},
6165 { TYPE_SWITCH, &sei.el_more, "editor.el_more" },
6166 { TYPE_SWITCH, &sei.el_sokoban, "editor.el_sokoban" },
6167 { TYPE_SWITCH, &sei.el_supaplex, "editor.el_supaplex" },
6168 { TYPE_SWITCH, &sei.el_diamond_caves, "editor.el_diamond_caves" },
6169 { TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash" },
6170 { TYPE_SWITCH, &sei.el_chars, "editor.el_chars" },
6171 { TYPE_SWITCH, &sei.el_custom, "editor.el_custom" },
6172 { TYPE_SWITCH, &sei.el_headlines, "editor.el_headlines" },
6173 { TYPE_SWITCH, &sei.el_user_defined, "editor.el_user_defined" },
6174 { TYPE_SWITCH, &sei.el_dynamic, "editor.el_dynamic" },
6175 { TYPE_SWITCH, &sei.show_element_token,"editor.show_element_token" },
6178 static struct TokenInfo editor_cascade_setup_tokens[] =
6180 { TYPE_SWITCH, &seci.el_bd, "editor.cascade.el_bd" },
6181 { TYPE_SWITCH, &seci.el_em, "editor.cascade.el_em" },
6182 { TYPE_SWITCH, &seci.el_emc, "editor.cascade.el_emc" },
6183 { TYPE_SWITCH, &seci.el_rnd, "editor.cascade.el_rnd" },
6184 { TYPE_SWITCH, &seci.el_sb, "editor.cascade.el_sb" },
6185 { TYPE_SWITCH, &seci.el_sp, "editor.cascade.el_sp" },
6186 { TYPE_SWITCH, &seci.el_dc, "editor.cascade.el_dc" },
6187 { TYPE_SWITCH, &seci.el_dx, "editor.cascade.el_dx" },
6188 { TYPE_SWITCH, &seci.el_chars, "editor.cascade.el_chars" },
6189 { TYPE_SWITCH, &seci.el_ce, "editor.cascade.el_ce" },
6190 { TYPE_SWITCH, &seci.el_ge, "editor.cascade.el_ge" },
6191 { TYPE_SWITCH, &seci.el_user, "editor.cascade.el_user" },
6192 { TYPE_SWITCH, &seci.el_dynamic, "editor.cascade.el_dynamic" },
6195 static struct TokenInfo shortcut_setup_tokens[] =
6197 { TYPE_KEY_X11, &ssi.save_game, "shortcut.save_game" },
6198 { TYPE_KEY_X11, &ssi.load_game, "shortcut.load_game" },
6199 { TYPE_KEY_X11, &ssi.toggle_pause, "shortcut.toggle_pause" },
6200 { TYPE_KEY_X11, &ssi.focus_player[0], "shortcut.focus_player_1" },
6201 { TYPE_KEY_X11, &ssi.focus_player[1], "shortcut.focus_player_2" },
6202 { TYPE_KEY_X11, &ssi.focus_player[2], "shortcut.focus_player_3" },
6203 { TYPE_KEY_X11, &ssi.focus_player[3], "shortcut.focus_player_4" },
6204 { TYPE_KEY_X11, &ssi.focus_player_all,"shortcut.focus_player_all" },
6207 static struct TokenInfo player_setup_tokens[] =
6209 { TYPE_BOOLEAN, &sii.use_joystick, ".use_joystick" },
6210 { TYPE_STRING, &sii.joy.device_name, ".joy.device_name" },
6211 { TYPE_INTEGER, &sii.joy.xleft, ".joy.xleft" },
6212 { TYPE_INTEGER, &sii.joy.xmiddle, ".joy.xmiddle" },
6213 { TYPE_INTEGER, &sii.joy.xright, ".joy.xright" },
6214 { TYPE_INTEGER, &sii.joy.yupper, ".joy.yupper" },
6215 { TYPE_INTEGER, &sii.joy.ymiddle, ".joy.ymiddle" },
6216 { TYPE_INTEGER, &sii.joy.ylower, ".joy.ylower" },
6217 { TYPE_INTEGER, &sii.joy.snap, ".joy.snap_field" },
6218 { TYPE_INTEGER, &sii.joy.drop, ".joy.place_bomb" },
6219 { TYPE_KEY_X11, &sii.key.left, ".key.move_left" },
6220 { TYPE_KEY_X11, &sii.key.right, ".key.move_right" },
6221 { TYPE_KEY_X11, &sii.key.up, ".key.move_up" },
6222 { TYPE_KEY_X11, &sii.key.down, ".key.move_down" },
6223 { TYPE_KEY_X11, &sii.key.snap, ".key.snap_field" },
6224 { TYPE_KEY_X11, &sii.key.drop, ".key.place_bomb" },
6227 static struct TokenInfo system_setup_tokens[] =
6229 { TYPE_STRING, &syi.sdl_audiodriver, "system.sdl_audiodriver" },
6230 { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size" },
6233 static struct TokenInfo options_setup_tokens[] =
6235 { TYPE_BOOLEAN, &soi.verbose, "options.verbose" },
6238 static char *get_corrected_login_name(char *login_name)
6240 /* needed because player name must be a fixed length string */
6241 char *login_name_new = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
6243 strncpy(login_name_new, login_name, MAX_PLAYER_NAME_LEN);
6244 login_name_new[MAX_PLAYER_NAME_LEN] = '\0';
6246 if (strlen(login_name) > MAX_PLAYER_NAME_LEN) /* name has been cut */
6247 if (strchr(login_name_new, ' '))
6248 *strchr(login_name_new, ' ') = '\0';
6250 return login_name_new;
6253 static void setSetupInfoToDefaults(struct SetupInfo *si)
6257 si->player_name = get_corrected_login_name(getLoginName());
6260 si->sound_loops = TRUE;
6261 si->sound_music = TRUE;
6262 si->sound_simple = TRUE;
6264 si->double_buffering = TRUE;
6265 si->direct_draw = !si->double_buffering;
6266 si->scroll_delay = TRUE;
6267 si->soft_scrolling = TRUE;
6269 si->autorecord = TRUE;
6270 si->show_titlescreen = TRUE;
6271 si->quick_doors = FALSE;
6272 si->team_mode = FALSE;
6273 si->handicap = TRUE;
6274 si->skip_levels = TRUE;
6275 si->time_limit = TRUE;
6276 si->fullscreen = FALSE;
6277 si->ask_on_escape = TRUE;
6278 si->ask_on_escape_editor = TRUE;
6279 si->quick_switch = FALSE;
6280 si->input_on_focus = FALSE;
6281 si->prefer_aga_graphics = TRUE;
6283 si->graphics_set = getStringCopy(GFX_CLASSIC_SUBDIR);
6284 si->sounds_set = getStringCopy(SND_CLASSIC_SUBDIR);
6285 si->music_set = getStringCopy(MUS_CLASSIC_SUBDIR);
6286 si->override_level_graphics = FALSE;
6287 si->override_level_sounds = FALSE;
6288 si->override_level_music = FALSE;
6290 si->editor.el_boulderdash = TRUE;
6291 si->editor.el_emerald_mine = TRUE;
6292 si->editor.el_emerald_mine_club = TRUE;
6293 si->editor.el_more = TRUE;
6294 si->editor.el_sokoban = TRUE;
6295 si->editor.el_supaplex = TRUE;
6296 si->editor.el_diamond_caves = TRUE;
6297 si->editor.el_dx_boulderdash = TRUE;
6298 si->editor.el_chars = TRUE;
6299 si->editor.el_custom = TRUE;
6301 si->editor.el_headlines = TRUE;
6302 si->editor.el_user_defined = FALSE;
6303 si->editor.el_dynamic = TRUE;
6305 si->editor.show_element_token = FALSE;
6307 si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
6308 si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME;
6309 si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE;
6311 si->shortcut.focus_player[0] = DEFAULT_KEY_FOCUS_PLAYER_1;
6312 si->shortcut.focus_player[1] = DEFAULT_KEY_FOCUS_PLAYER_2;
6313 si->shortcut.focus_player[2] = DEFAULT_KEY_FOCUS_PLAYER_3;
6314 si->shortcut.focus_player[3] = DEFAULT_KEY_FOCUS_PLAYER_4;
6315 si->shortcut.focus_player_all = DEFAULT_KEY_FOCUS_PLAYER_ALL;
6317 for (i = 0; i < MAX_PLAYERS; i++)
6319 si->input[i].use_joystick = FALSE;
6320 si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
6321 si->input[i].joy.xleft = JOYSTICK_XLEFT;
6322 si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
6323 si->input[i].joy.xright = JOYSTICK_XRIGHT;
6324 si->input[i].joy.yupper = JOYSTICK_YUPPER;
6325 si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
6326 si->input[i].joy.ylower = JOYSTICK_YLOWER;
6327 si->input[i].joy.snap = (i == 0 ? JOY_BUTTON_1 : 0);
6328 si->input[i].joy.drop = (i == 0 ? JOY_BUTTON_2 : 0);
6329 si->input[i].key.left = (i == 0 ? DEFAULT_KEY_LEFT : KSYM_UNDEFINED);
6330 si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
6331 si->input[i].key.up = (i == 0 ? DEFAULT_KEY_UP : KSYM_UNDEFINED);
6332 si->input[i].key.down = (i == 0 ? DEFAULT_KEY_DOWN : KSYM_UNDEFINED);
6333 si->input[i].key.snap = (i == 0 ? DEFAULT_KEY_SNAP : KSYM_UNDEFINED);
6334 si->input[i].key.drop = (i == 0 ? DEFAULT_KEY_DROP : KSYM_UNDEFINED);
6337 si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT);
6338 si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
6340 si->options.verbose = FALSE;
6343 static void setSetupInfoToDefaults_EditorCascade(struct SetupInfo *si)
6345 si->editor_cascade.el_bd = TRUE;
6346 si->editor_cascade.el_em = TRUE;
6347 si->editor_cascade.el_emc = TRUE;
6348 si->editor_cascade.el_rnd = TRUE;
6349 si->editor_cascade.el_sb = TRUE;
6350 si->editor_cascade.el_sp = TRUE;
6351 si->editor_cascade.el_dc = TRUE;
6352 si->editor_cascade.el_dx = TRUE;
6354 si->editor_cascade.el_chars = FALSE;
6355 si->editor_cascade.el_ce = FALSE;
6356 si->editor_cascade.el_ge = FALSE;
6357 si->editor_cascade.el_user = FALSE;
6358 si->editor_cascade.el_dynamic = FALSE;
6361 static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
6365 if (!setup_file_hash)
6370 for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
6371 setSetupInfo(global_setup_tokens, i,
6372 getHashEntry(setup_file_hash, global_setup_tokens[i].text));
6377 for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
6378 setSetupInfo(editor_setup_tokens, i,
6379 getHashEntry(setup_file_hash,editor_setup_tokens[i].text));
6382 /* shortcut setup */
6383 ssi = setup.shortcut;
6384 for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
6385 setSetupInfo(shortcut_setup_tokens, i,
6386 getHashEntry(setup_file_hash,shortcut_setup_tokens[i].text));
6387 setup.shortcut = ssi;
6390 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
6394 sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
6396 sii = setup.input[pnr];
6397 for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
6399 char full_token[100];
6401 sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
6402 setSetupInfo(player_setup_tokens, i,
6403 getHashEntry(setup_file_hash, full_token));
6405 setup.input[pnr] = sii;
6410 for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
6411 setSetupInfo(system_setup_tokens, i,
6412 getHashEntry(setup_file_hash, system_setup_tokens[i].text));
6416 soi = setup.options;
6417 for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
6418 setSetupInfo(options_setup_tokens, i,
6419 getHashEntry(setup_file_hash, options_setup_tokens[i].text));
6420 setup.options = soi;
6423 static void decodeSetupFileHash_EditorCascade(SetupFileHash *setup_file_hash)
6427 if (!setup_file_hash)
6430 /* editor cascade setup */
6431 seci = setup.editor_cascade;
6432 for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
6433 setSetupInfo(editor_cascade_setup_tokens, i,
6434 getHashEntry(setup_file_hash,
6435 editor_cascade_setup_tokens[i].text));
6436 setup.editor_cascade = seci;
6441 char *filename = getSetupFilename();
6442 SetupFileHash *setup_file_hash = NULL;
6444 /* always start with reliable default values */
6445 setSetupInfoToDefaults(&setup);
6447 setup_file_hash = loadSetupFileHash(filename);
6449 if (setup_file_hash)
6451 char *player_name_new;
6453 checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP"));
6454 decodeSetupFileHash(setup_file_hash);
6456 setup.direct_draw = !setup.double_buffering;
6458 freeSetupFileHash(setup_file_hash);
6460 /* needed to work around problems with fixed length strings */
6461 player_name_new = get_corrected_login_name(setup.player_name);
6462 free(setup.player_name);
6463 setup.player_name = player_name_new;
6466 Error(ERR_WARN, "using default setup values");
6469 void LoadSetup_EditorCascade()
6471 char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
6472 SetupFileHash *setup_file_hash = NULL;
6474 /* always start with reliable default values */
6475 setSetupInfoToDefaults_EditorCascade(&setup);
6477 setup_file_hash = loadSetupFileHash(filename);
6479 if (setup_file_hash)
6481 checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP"));
6482 decodeSetupFileHash_EditorCascade(setup_file_hash);
6484 freeSetupFileHash(setup_file_hash);
6492 char *filename = getSetupFilename();
6496 InitUserDataDirectory();
6498 if (!(file = fopen(filename, MODE_WRITE)))
6500 Error(ERR_WARN, "cannot write setup file '%s'", filename);
6504 fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
6505 getCookie("SETUP")));
6506 fprintf(file, "\n");
6510 for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
6512 /* just to make things nicer :) */
6513 if (i == SETUP_TOKEN_PLAYER_NAME + 1 ||
6514 i == SETUP_TOKEN_GRAPHICS_SET)
6515 fprintf(file, "\n");
6517 fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
6522 fprintf(file, "\n");
6523 for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
6524 fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i));
6526 /* shortcut setup */
6527 ssi = setup.shortcut;
6528 fprintf(file, "\n");
6529 for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
6530 fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
6533 for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
6537 sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
6538 fprintf(file, "\n");
6540 sii = setup.input[pnr];
6541 for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
6542 fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
6547 fprintf(file, "\n");
6548 for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
6549 fprintf(file, "%s\n", getSetupLine(system_setup_tokens, "", i));
6552 soi = setup.options;
6553 fprintf(file, "\n");
6554 for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
6555 fprintf(file, "%s\n", getSetupLine(options_setup_tokens, "", i));
6559 SetFilePermissions(filename, PERMS_PRIVATE);
6562 void SaveSetup_EditorCascade()
6564 char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
6568 InitUserDataDirectory();
6570 if (!(file = fopen(filename, MODE_WRITE)))
6572 Error(ERR_WARN, "cannot write editor cascade state file '%s'", filename);
6577 fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
6578 getCookie("SETUP")));
6579 fprintf(file, "\n");
6581 seci = setup.editor_cascade;
6582 fprintf(file, "\n");
6583 for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
6584 fprintf(file, "%s\n", getSetupLine(editor_cascade_setup_tokens, "", i));
6588 SetFilePermissions(filename, PERMS_PRIVATE);
6593 void LoadCustomElementDescriptions()
6595 char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
6596 SetupFileHash *setup_file_hash;
6599 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6601 if (element_info[i].custom_description != NULL)
6603 free(element_info[i].custom_description);
6604 element_info[i].custom_description = NULL;
6608 if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
6611 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6613 char *token = getStringCat2(element_info[i].token_name, ".name");
6614 char *value = getHashEntry(setup_file_hash, token);
6617 element_info[i].custom_description = getStringCopy(value);
6622 freeSetupFileHash(setup_file_hash);
6625 static void LoadSpecialMenuDesignSettingsFromFilename(char *filename)
6627 SetupFileHash *setup_file_hash;
6631 printf("LoadSpecialMenuDesignSettings from file '%s' ...\n", filename);
6634 if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
6637 /* special case: initialize with default values that may be overwritten */
6638 for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
6640 char *value_x = getHashEntry(setup_file_hash, "menu.draw_xoffset");
6641 char *value_y = getHashEntry(setup_file_hash, "menu.draw_yoffset");
6642 char *list_size = getHashEntry(setup_file_hash, "menu.list_size");
6644 if (value_x != NULL)
6645 menu.draw_xoffset[i] = get_integer_from_string(value_x);
6646 if (value_y != NULL)
6647 menu.draw_yoffset[i] = get_integer_from_string(value_y);
6648 if (list_size != NULL)
6649 menu.list_size[i] = get_integer_from_string(list_size);
6652 /* read (and overwrite with) values that may be specified in config file */
6653 for (i = 0; image_config_vars[i].token != NULL; i++)
6655 char *value = getHashEntry(setup_file_hash, image_config_vars[i].token);
6658 *image_config_vars[i].value =
6659 get_auto_parameter_value(image_config_vars[i].token, value);
6662 freeSetupFileHash(setup_file_hash);
6665 void LoadSpecialMenuDesignSettings()
6667 char *filename_base = UNDEFINED_FILENAME, *filename_local;
6670 /* always start with reliable default values from default config */
6671 for (i = 0; image_config_vars[i].token != NULL; i++)
6672 for (j = 0; image_config[j].token != NULL; j++)
6673 if (strEqual(image_config_vars[i].token, image_config[j].token))
6674 *image_config_vars[i].value =
6675 get_auto_parameter_value(image_config_vars[i].token,
6676 image_config[j].value);
6679 if (!SETUP_OVERRIDE_ARTWORK(setup, ARTWORK_TYPE_GRAPHICS))
6681 /* first look for special settings configured in level series config */
6682 filename_base = getCustomArtworkLevelConfigFilename(ARTWORK_TYPE_GRAPHICS);
6684 if (fileExists(filename_base))
6685 LoadSpecialMenuDesignSettingsFromFilename(filename_base);
6688 filename_local = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
6690 if (filename_local != NULL && !strEqual(filename_base, filename_local))
6691 LoadSpecialMenuDesignSettingsFromFilename(filename_local);
6695 filename_local = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
6697 LoadSpecialMenuDesignSettingsFromFilename(filename_local);
6701 void LoadUserDefinedEditorElementList(int **elements, int *num_elements)
6703 char *filename = getEditorSetupFilename();
6704 SetupFileList *setup_file_list, *list;
6705 SetupFileHash *element_hash;
6706 int num_unknown_tokens = 0;
6709 if ((setup_file_list = loadSetupFileList(filename)) == NULL)
6712 element_hash = newSetupFileHash();
6714 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6715 setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
6717 /* determined size may be larger than needed (due to unknown elements) */
6719 for (list = setup_file_list; list != NULL; list = list->next)
6722 /* add space for up to 3 more elements for padding that may be needed */
6725 /* free memory for old list of elements, if needed */
6726 checked_free(*elements);
6728 /* allocate memory for new list of elements */
6729 *elements = checked_malloc(*num_elements * sizeof(int));
6732 for (list = setup_file_list; list != NULL; list = list->next)
6734 char *value = getHashEntry(element_hash, list->token);
6736 if (value == NULL) /* try to find obsolete token mapping */
6738 char *mapped_token = get_mapped_token(list->token);
6740 if (mapped_token != NULL)
6742 value = getHashEntry(element_hash, mapped_token);
6750 (*elements)[(*num_elements)++] = atoi(value);
6754 if (num_unknown_tokens == 0)
6756 Error(ERR_RETURN_LINE, "-");
6757 Error(ERR_RETURN, "warning: unknown token(s) found in config file:");
6758 Error(ERR_RETURN, "- config file: '%s'", filename);
6760 num_unknown_tokens++;
6763 Error(ERR_RETURN, "- token: '%s'", list->token);
6767 if (num_unknown_tokens > 0)
6768 Error(ERR_RETURN_LINE, "-");
6770 while (*num_elements % 4) /* pad with empty elements, if needed */
6771 (*elements)[(*num_elements)++] = EL_EMPTY;
6773 freeSetupFileList(setup_file_list);
6774 freeSetupFileHash(element_hash);
6777 for (i = 0; i < *num_elements; i++)
6778 printf("editor: element '%s' [%d]\n",
6779 element_info[(*elements)[i]].token_name, (*elements)[i]);
6783 static struct MusicFileInfo *get_music_file_info_ext(char *basename, int music,
6786 SetupFileHash *setup_file_hash = NULL;
6787 struct MusicFileInfo tmp_music_file_info, *new_music_file_info;
6788 char *filename_music, *filename_prefix, *filename_info;
6794 token_to_value_ptr[] =
6796 { "title_header", &tmp_music_file_info.title_header },
6797 { "artist_header", &tmp_music_file_info.artist_header },
6798 { "album_header", &tmp_music_file_info.album_header },
6799 { "year_header", &tmp_music_file_info.year_header },
6801 { "title", &tmp_music_file_info.title },
6802 { "artist", &tmp_music_file_info.artist },
6803 { "album", &tmp_music_file_info.album },
6804 { "year", &tmp_music_file_info.year },
6810 filename_music = (is_sound ? getCustomSoundFilename(basename) :
6811 getCustomMusicFilename(basename));
6813 if (filename_music == NULL)
6816 /* ---------- try to replace file extension ---------- */
6818 filename_prefix = getStringCopy(filename_music);
6819 if (strrchr(filename_prefix, '.') != NULL)
6820 *strrchr(filename_prefix, '.') = '\0';
6821 filename_info = getStringCat2(filename_prefix, ".txt");
6824 printf("trying to load file '%s'...\n", filename_info);
6827 if (fileExists(filename_info))
6828 setup_file_hash = loadSetupFileHash(filename_info);
6830 free(filename_prefix);
6831 free(filename_info);
6833 if (setup_file_hash == NULL)
6835 /* ---------- try to add file extension ---------- */
6837 filename_prefix = getStringCopy(filename_music);
6838 filename_info = getStringCat2(filename_prefix, ".txt");
6841 printf("trying to load file '%s'...\n", filename_info);
6844 if (fileExists(filename_info))
6845 setup_file_hash = loadSetupFileHash(filename_info);
6847 free(filename_prefix);
6848 free(filename_info);
6851 if (setup_file_hash == NULL)
6854 /* ---------- music file info found ---------- */
6856 memset(&tmp_music_file_info, 0, sizeof(struct MusicFileInfo));
6858 for (i = 0; token_to_value_ptr[i].token != NULL; i++)
6860 char *value = getHashEntry(setup_file_hash, token_to_value_ptr[i].token);
6862 *token_to_value_ptr[i].value_ptr =
6863 getStringCopy(value != NULL && *value != '\0' ? value : UNKNOWN_NAME);
6866 tmp_music_file_info.basename = getStringCopy(basename);
6867 tmp_music_file_info.music = music;
6868 tmp_music_file_info.is_sound = is_sound;
6870 new_music_file_info = checked_malloc(sizeof(struct MusicFileInfo));
6871 *new_music_file_info = tmp_music_file_info;
6873 return new_music_file_info;
6876 static struct MusicFileInfo *get_music_file_info(char *basename, int music)
6878 return get_music_file_info_ext(basename, music, FALSE);
6881 static struct MusicFileInfo *get_sound_file_info(char *basename, int sound)
6883 return get_music_file_info_ext(basename, sound, TRUE);
6886 static boolean music_info_listed_ext(struct MusicFileInfo *list,
6887 char *basename, boolean is_sound)
6889 for (; list != NULL; list = list->next)
6890 if (list->is_sound == is_sound && strEqual(list->basename, basename))
6896 static boolean music_info_listed(struct MusicFileInfo *list, char *basename)
6898 return music_info_listed_ext(list, basename, FALSE);
6901 static boolean sound_info_listed(struct MusicFileInfo *list, char *basename)
6903 return music_info_listed_ext(list, basename, TRUE);
6906 void LoadMusicInfo()
6908 char *music_directory = getCustomMusicDirectory();
6909 int num_music = getMusicListSize();
6910 int num_music_noconf = 0;
6911 int num_sounds = getSoundListSize();
6913 struct dirent *dir_entry;
6914 struct FileInfo *music, *sound;
6915 struct MusicFileInfo *next, **new;
6918 while (music_file_info != NULL)
6920 next = music_file_info->next;
6922 checked_free(music_file_info->basename);
6924 checked_free(music_file_info->title_header);
6925 checked_free(music_file_info->artist_header);
6926 checked_free(music_file_info->album_header);
6927 checked_free(music_file_info->year_header);
6929 checked_free(music_file_info->title);
6930 checked_free(music_file_info->artist);
6931 checked_free(music_file_info->album);
6932 checked_free(music_file_info->year);
6934 free(music_file_info);
6936 music_file_info = next;
6939 new = &music_file_info;
6941 for (i = 0; i < num_music; i++)
6943 music = getMusicListEntry(i);
6945 if (music->filename == NULL)
6948 if (strEqual(music->filename, UNDEFINED_FILENAME))
6951 /* a configured file may be not recognized as music */
6952 if (!FileIsMusic(music->filename))
6956 printf("::: -> '%s' (configured)\n", music->filename);
6959 if (!music_info_listed(music_file_info, music->filename))
6961 *new = get_music_file_info(music->filename, i);
6963 new = &(*new)->next;
6967 if ((dir = opendir(music_directory)) == NULL)
6969 Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
6973 while ((dir_entry = readdir(dir)) != NULL) /* loop until last dir entry */
6975 char *basename = dir_entry->d_name;
6976 boolean music_already_used = FALSE;
6979 /* skip all music files that are configured in music config file */
6980 for (i = 0; i < num_music; i++)
6982 music = getMusicListEntry(i);
6984 if (music->filename == NULL)
6987 if (strEqual(basename, music->filename))
6989 music_already_used = TRUE;
6994 if (music_already_used)
6997 if (!FileIsMusic(basename))
7001 printf("::: -> '%s' (found in directory)\n", basename);
7004 if (!music_info_listed(music_file_info, basename))
7006 *new = get_music_file_info(basename, MAP_NOCONF_MUSIC(num_music_noconf));
7008 new = &(*new)->next;
7016 for (i = 0; i < num_sounds; i++)
7018 sound = getSoundListEntry(i);
7020 if (sound->filename == NULL)
7023 if (strEqual(sound->filename, UNDEFINED_FILENAME))
7026 /* a configured file may be not recognized as sound */
7027 if (!FileIsSound(sound->filename))
7031 printf("::: -> '%s' (configured)\n", sound->filename);
7034 if (!sound_info_listed(music_file_info, sound->filename))
7036 *new = get_sound_file_info(sound->filename, i);
7038 new = &(*new)->next;
7043 for (next = music_file_info; next != NULL; next = next->next)
7044 printf("::: title == '%s'\n", next->title);
7048 void add_helpanim_entry(int element, int action, int direction, int delay,
7049 int *num_list_entries)
7051 struct HelpAnimInfo *new_list_entry;
7052 (*num_list_entries)++;
7055 checked_realloc(helpanim_info,
7056 *num_list_entries * sizeof(struct HelpAnimInfo));
7057 new_list_entry = &helpanim_info[*num_list_entries - 1];
7059 new_list_entry->element = element;
7060 new_list_entry->action = action;
7061 new_list_entry->direction = direction;
7062 new_list_entry->delay = delay;
7065 void print_unknown_token(char *filename, char *token, int token_nr)
7069 Error(ERR_RETURN_LINE, "-");
7070 Error(ERR_RETURN, "warning: unknown token(s) found in config file:");
7071 Error(ERR_RETURN, "- config file: '%s'", filename);
7074 Error(ERR_RETURN, "- token: '%s'", token);
7077 void print_unknown_token_end(int token_nr)
7080 Error(ERR_RETURN_LINE, "-");
7083 void LoadHelpAnimInfo()
7085 char *filename = getHelpAnimFilename();
7086 SetupFileList *setup_file_list = NULL, *list;
7087 SetupFileHash *element_hash, *action_hash, *direction_hash;
7088 int num_list_entries = 0;
7089 int num_unknown_tokens = 0;
7092 if (fileExists(filename))
7093 setup_file_list = loadSetupFileList(filename);
7095 if (setup_file_list == NULL)
7097 /* use reliable default values from static configuration */
7098 SetupFileList *insert_ptr;
7100 insert_ptr = setup_file_list =
7101 newSetupFileList(helpanim_config[0].token,
7102 helpanim_config[0].value);
7104 for (i = 1; helpanim_config[i].token; i++)
7105 insert_ptr = addListEntry(insert_ptr,
7106 helpanim_config[i].token,
7107 helpanim_config[i].value);
7110 element_hash = newSetupFileHash();
7111 action_hash = newSetupFileHash();
7112 direction_hash = newSetupFileHash();
7114 for (i = 0; i < MAX_NUM_ELEMENTS; i++)
7115 setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
7117 for (i = 0; i < NUM_ACTIONS; i++)
7118 setHashEntry(action_hash, element_action_info[i].suffix,
7119 i_to_a(element_action_info[i].value));
7121 /* do not store direction index (bit) here, but direction value! */
7122 for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
7123 setHashEntry(direction_hash, element_direction_info[i].suffix,
7124 i_to_a(1 << element_direction_info[i].value));
7126 for (list = setup_file_list; list != NULL; list = list->next)
7128 char *element_token, *action_token, *direction_token;
7129 char *element_value, *action_value, *direction_value;
7130 int delay = atoi(list->value);
7132 if (strEqual(list->token, "end"))
7134 add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
7139 /* first try to break element into element/action/direction parts;
7140 if this does not work, also accept combined "element[.act][.dir]"
7141 elements (like "dynamite.active"), which are unique elements */
7143 if (strchr(list->token, '.') == NULL) /* token contains no '.' */
7145 element_value = getHashEntry(element_hash, list->token);
7146 if (element_value != NULL) /* element found */
7147 add_helpanim_entry(atoi(element_value), -1, -1, delay,
7151 /* no further suffixes found -- this is not an element */
7152 print_unknown_token(filename, list->token, num_unknown_tokens++);
7158 /* token has format "<prefix>.<something>" */
7160 action_token = strchr(list->token, '.'); /* suffix may be action ... */
7161 direction_token = action_token; /* ... or direction */
7163 element_token = getStringCopy(list->token);
7164 *strchr(element_token, '.') = '\0';
7166 element_value = getHashEntry(element_hash, element_token);
7168 if (element_value == NULL) /* this is no element */
7170 element_value = getHashEntry(element_hash, list->token);
7171 if (element_value != NULL) /* combined element found */
7172 add_helpanim_entry(atoi(element_value), -1, -1, delay,
7175 print_unknown_token(filename, list->token, num_unknown_tokens++);
7177 free(element_token);
7182 action_value = getHashEntry(action_hash, action_token);
7184 if (action_value != NULL) /* action found */
7186 add_helpanim_entry(atoi(element_value), atoi(action_value), -1, delay,
7189 free(element_token);
7194 direction_value = getHashEntry(direction_hash, direction_token);
7196 if (direction_value != NULL) /* direction found */
7198 add_helpanim_entry(atoi(element_value), -1, atoi(direction_value), delay,
7201 free(element_token);
7206 if (strchr(action_token + 1, '.') == NULL)
7208 /* no further suffixes found -- this is not an action nor direction */
7210 element_value = getHashEntry(element_hash, list->token);
7211 if (element_value != NULL) /* combined element found */
7212 add_helpanim_entry(atoi(element_value), -1, -1, delay,
7215 print_unknown_token(filename, list->token, num_unknown_tokens++);
7217 free(element_token);
7222 /* token has format "<prefix>.<suffix>.<something>" */
7224 direction_token = strchr(action_token + 1, '.');
7226 action_token = getStringCopy(action_token);
7227 *strchr(action_token + 1, '.') = '\0';
7229 action_value = getHashEntry(action_hash, action_token);
7231 if (action_value == NULL) /* this is no action */
7233 element_value = getHashEntry(element_hash, list->token);
7234 if (element_value != NULL) /* combined element found */
7235 add_helpanim_entry(atoi(element_value), -1, -1, delay,
7238 print_unknown_token(filename, list->token, num_unknown_tokens++);
7240 free(element_token);
7246 direction_value = getHashEntry(direction_hash, direction_token);
7248 if (direction_value != NULL) /* direction found */
7250 add_helpanim_entry(atoi(element_value), atoi(action_value),
7251 atoi(direction_value), delay, &num_list_entries);
7253 free(element_token);
7259 /* this is no direction */
7261 element_value = getHashEntry(element_hash, list->token);
7262 if (element_value != NULL) /* combined element found */
7263 add_helpanim_entry(atoi(element_value), -1, -1, delay,
7266 print_unknown_token(filename, list->token, num_unknown_tokens++);
7268 free(element_token);
7272 print_unknown_token_end(num_unknown_tokens);
7274 add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
7275 add_helpanim_entry(HELPANIM_LIST_END, -1, -1, -1, &num_list_entries);
7277 freeSetupFileList(setup_file_list);
7278 freeSetupFileHash(element_hash);
7279 freeSetupFileHash(action_hash);
7280 freeSetupFileHash(direction_hash);
7283 for (i = 0; i < num_list_entries; i++)
7284 printf("::: '%s': %d, %d, %d => %d\n",
7285 EL_NAME(helpanim_info[i].element),
7286 helpanim_info[i].element,
7287 helpanim_info[i].action,
7288 helpanim_info[i].direction,
7289 helpanim_info[i].delay);
7293 void LoadHelpTextInfo()
7295 char *filename = getHelpTextFilename();
7298 if (helptext_info != NULL)
7300 freeSetupFileHash(helptext_info);
7301 helptext_info = NULL;
7304 if (fileExists(filename))
7305 helptext_info = loadSetupFileHash(filename);
7307 if (helptext_info == NULL)
7309 /* use reliable default values from static configuration */
7310 helptext_info = newSetupFileHash();
7312 for (i = 0; helptext_config[i].token; i++)
7313 setHashEntry(helptext_info,
7314 helptext_config[i].token,
7315 helptext_config[i].value);
7319 BEGIN_HASH_ITERATION(helptext_info, itr)
7321 printf("::: '%s' => '%s'\n",
7322 HASH_ITERATION_TOKEN(itr), HASH_ITERATION_VALUE(itr));
7324 END_HASH_ITERATION(hash, itr)
7329 /* ------------------------------------------------------------------------- *
7331 * ------------------------------------------------------------------------- */
7333 #define MAX_NUM_CONVERT_LEVELS 1000
7335 void ConvertLevels()
7337 static LevelDirTree *convert_leveldir = NULL;
7338 static int convert_level_nr = -1;
7339 static int num_levels_handled = 0;
7340 static int num_levels_converted = 0;
7341 static boolean levels_failed[MAX_NUM_CONVERT_LEVELS];
7344 convert_leveldir = getTreeInfoFromIdentifier(leveldir_first,
7345 global.convert_leveldir);
7347 if (convert_leveldir == NULL)
7348 Error(ERR_EXIT, "no such level identifier: '%s'",
7349 global.convert_leveldir);
7351 leveldir_current = convert_leveldir;
7353 if (global.convert_level_nr != -1)
7355 convert_leveldir->first_level = global.convert_level_nr;
7356 convert_leveldir->last_level = global.convert_level_nr;
7359 convert_level_nr = convert_leveldir->first_level;
7361 printf_line("=", 79);
7362 printf("Converting levels\n");
7363 printf_line("-", 79);
7364 printf("Level series identifier: '%s'\n", convert_leveldir->identifier);
7365 printf("Level series name: '%s'\n", convert_leveldir->name);
7366 printf("Level series author: '%s'\n", convert_leveldir->author);
7367 printf("Number of levels: %d\n", convert_leveldir->levels);
7368 printf_line("=", 79);
7371 for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++)
7372 levels_failed[i] = FALSE;
7374 while (convert_level_nr <= convert_leveldir->last_level)
7376 char *level_filename;
7379 level_nr = convert_level_nr++;
7381 printf("Level %03d: ", level_nr);
7383 LoadLevel(level_nr);
7384 if (level.no_valid_file)
7386 printf("(no level)\n");
7390 printf("converting level ... ");
7392 level_filename = getDefaultLevelFilename(level_nr);
7393 new_level = !fileExists(level_filename);
7397 SaveLevel(level_nr);
7399 num_levels_converted++;
7401 printf("converted.\n");
7405 if (level_nr >= 0 && level_nr < MAX_NUM_CONVERT_LEVELS)
7406 levels_failed[level_nr] = TRUE;
7408 printf("NOT CONVERTED -- LEVEL ALREADY EXISTS.\n");
7411 num_levels_handled++;
7415 printf_line("=", 79);
7416 printf("Number of levels handled: %d\n", num_levels_handled);
7417 printf("Number of levels converted: %d (%d%%)\n", num_levels_converted,
7418 (num_levels_handled ?
7419 num_levels_converted * 100 / num_levels_handled : 0));
7420 printf_line("-", 79);
7421 printf("Summary (for automatic parsing by scripts):\n");
7422 printf("LEVELDIR '%s', CONVERTED %d/%d (%d%%)",
7423 convert_leveldir->identifier, num_levels_converted,
7425 (num_levels_handled ?
7426 num_levels_converted * 100 / num_levels_handled : 0));
7428 if (num_levels_handled != num_levels_converted)
7430 printf(", FAILED:");
7431 for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++)
7432 if (levels_failed[i])
7437 printf_line("=", 79);