rnd-20060511-1-src
[rocksndiamonds.git] / src / files.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * files.c                                                  *
12 ***********************************************************/
13
14 #include <ctype.h>
15 #include <sys/stat.h>
16 #include <dirent.h>
17 #include <math.h>
18
19 #include "libgame/libgame.h"
20
21 #include "files.h"
22 #include "init.h"
23 #include "tools.h"
24 #include "tape.h"
25
26
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   */
42
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)
46
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"
51
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
57
58 #define CONF_MASK_BYTES                 0xc0
59 #define CONF_MASK_TOKEN                 0x3f
60
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))
65
66 /* a sequence of configuration values can be terminated by this value */
67 #define CONF_LAST_ENTRY                 CONF_VALUE_1_BYTE(0)
68
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)
74
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)
91
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)
100
101 #if 0
102 #define CONF_VALUE_ELEMENTS             CONF_VALUE_BYTES(1)
103 #define CONF_VALUE_CONTENTS             CONF_VALUE_BYTES(2)
104 #endif
105
106 #if 0
107 #define CONF_VALUE_INTEGER(x)           ((x) >= CONF_VALUE_INTEGER_1 && \
108                                          (x) <= CONF_VALUE_INTEGER_8)
109
110 #define CONF_VALUE_BOOLEAN(x)           ((x) >= CONF_VALUE_BOOLEAN_1 && \
111                                          (x) <= CONF_VALUE_BOOLEAN_8)
112 #endif
113
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)
117
118 #if 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)
122
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)
127 #endif
128
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)
132
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)
139
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]))
143
144 #define CONF_CONTENT_ELEMENT_POS(c,x,y) ((c) * CONF_CONTENT_NUM_ELEMENTS +    \
145                                          (y) * 3 + (x))
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]))
150
151 #if 0
152 static void LoadLevel_InitPlayfield(struct LevelInfo *, char *);
153 #endif
154
155 /* temporary variables used to store pointers to structure members */
156 static struct LevelInfo li;
157 static struct ElementInfo xx_ei, yy_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;
165
166 struct ElementFileConfig
167 {
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 */
171
172   /* (mandatory) */
173   void *value;                  /* variable that holds the data to be stored */
174   int default_value;            /* initial default value for this variable */
175
176   /* (optional) */
177   void *value_copy;             /* variable that holds the data to be copied */
178   void *num_entities;           /* number of entities for multi-byte data */
179   int default_num_entities;     /* default number of entities for this data */
180   int max_num_entities;         /* maximal number of entities for this data */
181   char *default_string;         /* optional default string for string data */
182 };
183
184 static struct ElementFileConfig element_conf[] =
185 {
186   /* ---------- 1-byte values ---------------------------------------------- */
187
188   {
189     EL_EMC_ANDROID,
190     TYPE_INTEGER,                       CONF_VALUE_INTEGER_1,
191     &li.android_move_time,              10
192   },
193   {
194     EL_EMC_ANDROID,
195     TYPE_INTEGER,                       CONF_VALUE_INTEGER_2,
196     &li.android_clone_time,             10
197   },
198   {
199     EL_EMC_LENSES,
200     TYPE_INTEGER,                       CONF_VALUE_INTEGER_1,
201     &li.lenses_score,                   10
202   },
203   {
204     EL_EMC_LENSES,
205     TYPE_INTEGER,                       CONF_VALUE_INTEGER_2,
206     &li.lenses_time,                    10
207   },
208   {
209     EL_EMC_MAGNIFIER,
210     TYPE_INTEGER,                       CONF_VALUE_INTEGER_1,
211     &li.magnify_score,                  10
212   },
213   {
214     EL_EMC_MAGNIFIER,
215     TYPE_INTEGER,                       CONF_VALUE_INTEGER_2,
216     &li.magnify_time,                   10
217   },
218   {
219     EL_ROBOT,
220     TYPE_INTEGER,                       CONF_VALUE_INTEGER_1,
221     &li.slurp_score,                    10
222   },
223   {
224     EL_GAME_OF_LIFE,
225     TYPE_INTEGER,                       CONF_VALUE_INTEGER_1,
226     &li.game_of_life[0],                2
227   },
228   {
229     EL_GAME_OF_LIFE,
230     TYPE_INTEGER,                       CONF_VALUE_INTEGER_2,
231     &li.game_of_life[1],                3
232   },
233   {
234     EL_GAME_OF_LIFE,
235     TYPE_INTEGER,                       CONF_VALUE_INTEGER_3,
236     &li.game_of_life[2],                3
237   },
238   {
239     EL_GAME_OF_LIFE,
240     TYPE_INTEGER,                       CONF_VALUE_INTEGER_4,
241     &li.game_of_life[3],                3
242   },
243   {
244     EL_BIOMAZE,
245     TYPE_INTEGER,                       CONF_VALUE_INTEGER_1,
246     &li.biomaze[0],                     2
247   },
248   {
249     EL_BIOMAZE,
250     TYPE_INTEGER,                       CONF_VALUE_INTEGER_2,
251     &li.biomaze[1],                     3
252   },
253   {
254     EL_BIOMAZE,
255     TYPE_INTEGER,                       CONF_VALUE_INTEGER_3,
256     &li.biomaze[2],                     3
257   },
258   {
259     EL_BIOMAZE,
260     TYPE_INTEGER,                       CONF_VALUE_INTEGER_4,
261     &li.biomaze[3],                     3
262   },
263   {
264     EL_BALLOON,
265     TYPE_BITFIELD,                      CONF_VALUE_INTEGER_1,
266     &li.wind_direction_initial,         MV_NONE
267   },
268   {
269     EL_TIMEGATE_SWITCH,
270     TYPE_INTEGER,                       CONF_VALUE_INTEGER_1,
271     &li.time_timegate,                  10
272   },
273   {
274     EL_LIGHT_SWITCH_ACTIVE,
275     TYPE_INTEGER,                       CONF_VALUE_INTEGER_1,
276     &li.time_light,                     10
277   },
278   {
279     EL_SHIELD_NORMAL,
280     TYPE_INTEGER,                       CONF_VALUE_INTEGER_1,
281     &li.shield_normal_time,             10
282   },
283   {
284     EL_SHIELD_DEADLY,
285     TYPE_INTEGER,                       CONF_VALUE_INTEGER_1,
286     &li.shield_deadly_time,             10
287   },
288   {
289     EL_EXTRA_TIME,
290     TYPE_INTEGER,                       CONF_VALUE_INTEGER_1,
291     &li.extra_time,                     10
292   },
293   {
294     EL_EXTRA_TIME,
295     TYPE_INTEGER,                       CONF_VALUE_INTEGER_2,
296     &li.extra_time_score,               10
297   },
298   {
299     EL_TIME_ORB_FULL,
300     TYPE_INTEGER,                       CONF_VALUE_INTEGER_1,
301     &li.time_orb_time,                  10
302   },
303   {
304     EL_TIME_ORB_FULL,
305     TYPE_BOOLEAN,                       CONF_VALUE_BOOLEAN_1,
306     &li.use_time_orb_bug,               FALSE
307   },
308   {
309     EL_PLAYER_1,
310     TYPE_BOOLEAN,                       CONF_VALUE_BOOLEAN_1,
311     &li.block_snap_field,               TRUE
312   },
313   {
314     EL_PLAYER_1,
315     TYPE_BOOLEAN,                       CONF_VALUE_BOOLEAN_2,
316     &li.use_start_element[0],           FALSE
317   },
318   {
319     EL_PLAYER_2,
320     TYPE_BOOLEAN,                       CONF_VALUE_BOOLEAN_2,
321     &li.use_start_element[1],           FALSE
322   },
323   {
324     EL_PLAYER_3,
325     TYPE_BOOLEAN,                       CONF_VALUE_BOOLEAN_2,
326     &li.use_start_element[2],           FALSE
327   },
328   {
329     EL_PLAYER_4,
330     TYPE_BOOLEAN,                       CONF_VALUE_BOOLEAN_2,
331     &li.use_start_element[3],           FALSE
332   },
333   {
334     EL_PLAYER_1,
335     TYPE_BOOLEAN,                       CONF_VALUE_BOOLEAN_3,
336     &li.use_artwork_element[0],         FALSE
337   },
338   {
339     EL_PLAYER_2,
340     TYPE_BOOLEAN,                       CONF_VALUE_BOOLEAN_3,
341     &li.use_artwork_element[1],         FALSE
342   },
343   {
344     EL_PLAYER_3,
345     TYPE_BOOLEAN,                       CONF_VALUE_BOOLEAN_3,
346     &li.use_artwork_element[2],         FALSE
347   },
348   {
349     EL_PLAYER_4,
350     TYPE_BOOLEAN,                       CONF_VALUE_BOOLEAN_3,
351     &li.use_artwork_element[3],         FALSE
352   },
353   {
354     EL_PLAYER_1,
355     TYPE_BOOLEAN,                       CONF_VALUE_BOOLEAN_4,
356     &li.use_explosion_element[0],       FALSE
357   },
358   {
359     EL_PLAYER_2,
360     TYPE_BOOLEAN,                       CONF_VALUE_BOOLEAN_4,
361     &li.use_explosion_element[1],       FALSE
362   },
363   {
364     EL_PLAYER_3,
365     TYPE_BOOLEAN,                       CONF_VALUE_BOOLEAN_4,
366     &li.use_explosion_element[2],       FALSE
367   },
368   {
369     EL_PLAYER_4,
370     TYPE_BOOLEAN,                       CONF_VALUE_BOOLEAN_4,
371     &li.use_explosion_element[3],       FALSE
372   },
373   {
374     EL_PLAYER_1,
375     TYPE_BOOLEAN,                       CONF_VALUE_BOOLEAN_5,
376     &li.continuous_snapping,            TRUE
377   },
378   {
379     EL_PLAYER_1,
380     TYPE_INTEGER,                       CONF_VALUE_INTEGER_1,
381     &li.initial_player_stepsize,        STEPSIZE_NORMAL
382   },
383   {
384     EL_EMC_MAGIC_BALL,
385     TYPE_INTEGER,                       CONF_VALUE_INTEGER_1,
386     &li.ball_time,                      10
387   },
388   {
389     EL_EMC_MAGIC_BALL,
390     TYPE_BOOLEAN,                       CONF_VALUE_BOOLEAN_1,
391     &li.ball_random,                    FALSE
392   },
393   {
394     EL_EMC_MAGIC_BALL,
395     TYPE_BOOLEAN,                       CONF_VALUE_BOOLEAN_2,
396     &li.ball_state_initial,             FALSE
397   },
398
399   /* ---------- 2-byte values ---------------------------------------------- */
400
401   {
402     EL_PLAYER_1,
403     TYPE_ELEMENT,                       CONF_VALUE_ELEMENT_1,
404     &li.start_element[0],               EL_PLAYER_1
405   },
406   {
407     EL_PLAYER_2,
408     TYPE_ELEMENT,                       CONF_VALUE_ELEMENT_1,
409     &li.start_element[1],               EL_PLAYER_2
410   },
411   {
412     EL_PLAYER_3,
413     TYPE_ELEMENT,                       CONF_VALUE_ELEMENT_1,
414     &li.start_element[2],               EL_PLAYER_3
415   },
416   {
417     EL_PLAYER_4,
418     TYPE_ELEMENT,                       CONF_VALUE_ELEMENT_1,
419     &li.start_element[3],               EL_PLAYER_4
420   },
421   {
422     EL_PLAYER_1,
423     TYPE_ELEMENT,                       CONF_VALUE_ELEMENT_2,
424     &li.artwork_element[0],             EL_PLAYER_1
425   },
426   {
427     EL_PLAYER_2,
428     TYPE_ELEMENT,                       CONF_VALUE_ELEMENT_2,
429     &li.artwork_element[1],             EL_PLAYER_2
430   },
431   {
432     EL_PLAYER_3,
433     TYPE_ELEMENT,                       CONF_VALUE_ELEMENT_2,
434     &li.artwork_element[2],             EL_PLAYER_3
435   },
436   {
437     EL_PLAYER_4,
438     TYPE_ELEMENT,                       CONF_VALUE_ELEMENT_2,
439     &li.artwork_element[3],             EL_PLAYER_4
440   },
441   {
442     EL_PLAYER_1,
443     TYPE_ELEMENT,                       CONF_VALUE_ELEMENT_3,
444     &li.explosion_element[0],           EL_PLAYER_1
445   },
446   {
447     EL_PLAYER_2,
448     TYPE_ELEMENT,                       CONF_VALUE_ELEMENT_3,
449     &li.explosion_element[1],           EL_PLAYER_2
450   },
451   {
452     EL_PLAYER_3,
453     TYPE_ELEMENT,                       CONF_VALUE_ELEMENT_3,
454     &li.explosion_element[2],           EL_PLAYER_3
455   },
456   {
457     EL_PLAYER_4,
458     TYPE_ELEMENT,                       CONF_VALUE_ELEMENT_3,
459     &li.explosion_element[3],           EL_PLAYER_4
460   },
461
462   /* ---------- multi-byte values ------------------------------------------ */
463
464   {
465     EL_EMC_ANDROID,
466     TYPE_ELEMENT_LIST,                  CONF_VALUE_BYTES(1),
467     &li.android_clone_element[0],       EL_EMPTY, NULL,
468     &li.num_android_clone_elements,     1, MAX_ANDROID_ELEMENTS
469   },
470   {
471     EL_EMC_MAGIC_BALL,
472     TYPE_CONTENT_LIST,                  CONF_VALUE_BYTES(2),
473     &li.ball_content,                   EL_EMPTY, NULL,
474     &li.num_ball_contents,              4, MAX_ELEMENT_CONTENTS
475   },
476
477   {
478     -1,
479     -1,                                 -1,
480     NULL,                               -1,
481   },
482 };
483
484 static struct ElementFileConfig custom_element_conf[] =
485 {
486   {
487     -1,
488     TYPE_STRING,                        CONF_VALUE_BYTES(1),
489     &xx_ei.description[0],              -1,
490     &yy_ei.description[0],
491     &xx_default_description_length,     -1, MAX_ELEMENT_NAME_LEN,
492     &xx_default_description[0]
493   },
494
495   {
496     -1,
497     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(1),
498     &xx_ei.properties[EP_BITFIELD_BASE_NR], EP_BITMASK_BASE_DEFAULT,
499     &yy_ei.properties[EP_BITFIELD_BASE_NR]
500   },
501 #if 0
502   /* (reserved) */
503   {
504     -1,
505     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(2),
506     &xx_ei.properties[EP_BITFIELD_BASE_NR + 1], EP_BITMASK_DEFAULT,
507     &yy_ei.properties[EP_BITFIELD_BASE_NR + 1]
508   },
509 #endif
510
511   {
512     -1,
513     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
514     &xx_ei.use_gfx_element,             FALSE,
515     &yy_ei.use_gfx_element
516   },
517   {
518     -1,
519     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
520     &xx_ei.gfx_element,                 EL_EMPTY_SPACE,
521     &yy_ei.gfx_element
522   },
523
524   {
525     -1,
526     TYPE_BITFIELD,                      CONF_VALUE_8_BIT(2),
527     &xx_ei.access_direction,            MV_ALL_DIRECTIONS,
528     &yy_ei.access_direction
529   },
530
531   {
532     -1,
533     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
534     &xx_ei.collect_score_initial,       10,
535     &yy_ei.collect_score_initial
536   },
537   {
538     -1,
539     TYPE_INTEGER,                       CONF_VALUE_16_BIT(3),
540     &xx_ei.collect_count_initial,       1,
541     &yy_ei.collect_count_initial
542   },
543
544   {
545     -1,
546     TYPE_INTEGER,                       CONF_VALUE_16_BIT(4),
547     &xx_ei.ce_value_fixed_initial,      0,
548     &yy_ei.ce_value_fixed_initial
549   },
550   {
551     -1,
552     TYPE_INTEGER,                       CONF_VALUE_16_BIT(5),
553     &xx_ei.ce_value_random_initial,     0,
554     &yy_ei.ce_value_random_initial
555   },
556   {
557     -1,
558     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(3),
559     &xx_ei.use_last_ce_value,           FALSE,
560     &yy_ei.use_last_ce_value
561   },
562
563   {
564     -1,
565     TYPE_INTEGER,                       CONF_VALUE_16_BIT(6),
566     &xx_ei.push_delay_fixed,            8,
567     &yy_ei.push_delay_fixed
568   },
569   {
570     -1,
571     TYPE_INTEGER,                       CONF_VALUE_16_BIT(7),
572     &xx_ei.push_delay_random,           8,
573     &yy_ei.push_delay_random
574   },
575   {
576     -1,
577     TYPE_INTEGER,                       CONF_VALUE_16_BIT(8),
578     &xx_ei.drop_delay_fixed,            0,
579     &yy_ei.drop_delay_fixed
580   },
581   {
582     -1,
583     TYPE_INTEGER,                       CONF_VALUE_16_BIT(9),
584     &xx_ei.drop_delay_random,           0,
585     &yy_ei.drop_delay_random
586   },
587   {
588     -1,
589     TYPE_INTEGER,                       CONF_VALUE_16_BIT(10),
590     &xx_ei.move_delay_fixed,            0,
591     &yy_ei.move_delay_fixed
592   },
593   {
594     -1,
595     TYPE_INTEGER,                       CONF_VALUE_16_BIT(11),
596     &xx_ei.move_delay_random,           0,
597     &yy_ei.move_delay_random
598   },
599
600   {
601     -1,
602     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(3),
603     &xx_ei.move_pattern,                MV_ALL_DIRECTIONS,
604     &yy_ei.move_pattern
605   },
606   {
607     -1,
608     TYPE_BITFIELD,                      CONF_VALUE_8_BIT(4),
609     &xx_ei.move_direction_initial,      MV_START_AUTOMATIC,
610     &yy_ei.move_direction_initial
611   },
612   {
613     -1,
614     TYPE_INTEGER,                       CONF_VALUE_8_BIT(5),
615     &xx_ei.move_stepsize,               TILEX / 8,
616     &yy_ei.move_stepsize
617   },
618
619   {
620     -1,
621     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(12),
622     &xx_ei.move_enter_element,          EL_EMPTY_SPACE,
623     &yy_ei.move_enter_element
624   },
625   {
626     -1,
627     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(13),
628     &xx_ei.move_leave_element,          EL_EMPTY_SPACE,
629     &yy_ei.move_leave_element
630   },
631   {
632     -1,
633     TYPE_INTEGER,                       CONF_VALUE_8_BIT(6),
634     &xx_ei.move_leave_type,             LEAVE_TYPE_UNLIMITED,
635     &yy_ei.move_leave_type
636   },
637
638   {
639     -1,
640     TYPE_INTEGER,                       CONF_VALUE_8_BIT(7),
641     &xx_ei.slippery_type,               SLIPPERY_ANY_RANDOM,
642     &yy_ei.slippery_type
643   },
644
645   {
646     -1,
647     TYPE_INTEGER,                       CONF_VALUE_8_BIT(8),
648     &xx_ei.explosion_type,              EXPLODES_3X3,
649     &yy_ei.explosion_type
650   },
651   {
652     -1,
653     TYPE_INTEGER,                       CONF_VALUE_16_BIT(14),
654     &xx_ei.explosion_delay,             16,
655     &yy_ei.explosion_delay
656   },
657   {
658     -1,
659     TYPE_INTEGER,                       CONF_VALUE_16_BIT(15),
660     &xx_ei.ignition_delay,              8,
661     &yy_ei.ignition_delay
662   },
663
664   {
665     -1,
666     TYPE_CONTENT_LIST,                  CONF_VALUE_BYTES(2),
667     &xx_ei.content,                     EL_EMPTY_SPACE,
668     &yy_ei.content,
669     &xx_num_contents,                   1, 1
670   },
671
672   /* ---------- "num_change_pages" must be the last entry ------------------- */
673
674   {
675     -1,
676     TYPE_INTEGER,                       CONF_VALUE_8_BIT(9),
677     &xx_ei.num_change_pages,            -1,     /* value must always be saved */
678     &yy_ei.num_change_pages
679   },
680
681   {
682     -1,
683     -1,                                 -1,
684     NULL,                               -1,
685     NULL
686   },
687 };
688
689 static struct ElementFileConfig custom_element_change_conf[] =
690 {
691   /* ---------- "current_change_page" must be the first entry --------------- */
692
693   {
694     -1,
695     TYPE_INTEGER,                       CONF_VALUE_8_BIT(1),
696     &xx_current_change_page,            -1      /* value must always be saved */
697   },
698
699   /* ---------- (the remaining entries can be in any order) ----------------- */
700
701   {
702     -1,
703     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(2),
704     &xx_change.can_change,              FALSE
705   },
706
707   {
708     -1,
709     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(1),
710     &xx_event_bits[0],                  0
711   },
712   {
713     -1,
714     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(2),
715     &xx_event_bits[1],                  0
716   },
717
718   {
719     -1,
720     TYPE_INTEGER,                       CONF_VALUE_8_BIT(3),
721     &xx_change.trigger_player,          CH_PLAYER_ANY
722   },
723   {
724     -1,
725     TYPE_INTEGER,                       CONF_VALUE_8_BIT(4),
726     &xx_change.trigger_side,            CH_SIDE_ANY
727   },
728   {
729     -1,
730     TYPE_INTEGER,                       CONF_VALUE_8_BIT(5),
731     &xx_change.trigger_page,            CH_PAGE_ANY
732   },
733
734   {
735     -1,
736     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
737     &xx_change.target_element,          EL_EMPTY_SPACE
738   },
739
740   {
741     -1,
742     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
743     &xx_change.delay_fixed,             0
744   },
745   {
746     -1,
747     TYPE_INTEGER,                       CONF_VALUE_16_BIT(3),
748     &xx_change.delay_random,            0
749   },
750   {
751     -1,
752     TYPE_INTEGER,                       CONF_VALUE_16_BIT(4),
753     &xx_change.delay_frames,            FRAMES_PER_SECOND
754   },
755
756   {
757     -1,
758     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(5),
759     &xx_change.trigger_element,         EL_EMPTY_SPACE
760   },
761
762   {
763     -1,
764     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(6),
765     &xx_change.explode,                 FALSE
766   },
767   {
768     -1,
769     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(7),
770     &xx_change.use_target_content,      FALSE
771   },
772   {
773     -1,
774     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(8),
775     &xx_change.only_if_complete,        FALSE
776   },
777   {
778     -1,
779     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(9),
780     &xx_change.use_random_replace,      FALSE
781   },
782   {
783     -1,
784     TYPE_INTEGER,                       CONF_VALUE_8_BIT(10),
785     &xx_change.random_percentage,       100
786   },
787   {
788     -1,
789     TYPE_INTEGER,                       CONF_VALUE_8_BIT(11),
790     &xx_change.replace_when,            CP_WHEN_EMPTY
791   },
792
793   {
794     -1,
795     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(12),
796     &xx_change.has_action,              FALSE
797   },
798   {
799     -1,
800     TYPE_INTEGER,                       CONF_VALUE_8_BIT(13),
801     &xx_change.action_type,             CA_NO_ACTION
802   },
803   {
804     -1,
805     TYPE_INTEGER,                       CONF_VALUE_8_BIT(14),
806     &xx_change.action_mode,             CA_MODE_UNDEFINED
807   },
808   {
809     -1,
810     TYPE_INTEGER,                       CONF_VALUE_16_BIT(6),
811     &xx_change.action_arg,              CA_ARG_UNDEFINED
812   },
813
814   {
815     -1,
816     TYPE_CONTENT_LIST,                  CONF_VALUE_BYTES(1),
817     &xx_change.target_content,          EL_EMPTY_SPACE, NULL,
818     &xx_num_contents,                   1, 1
819   },
820
821   {
822     -1,
823     -1,                                 -1,
824     NULL,                               -1,
825   },
826 };
827
828 static struct ElementFileConfig group_element_conf[] =
829 {
830   {
831     -1,
832     TYPE_STRING,                        CONF_VALUE_BYTES(1),
833     &xx_ei.description[0],              -1, NULL,
834     &xx_default_description_length,     -1, MAX_ELEMENT_NAME_LEN,
835     &xx_default_description[0]
836   },
837
838   {
839     -1,
840     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
841     &xx_ei.use_gfx_element,             FALSE
842   },
843   {
844     -1,
845     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
846     &xx_ei.gfx_element,                 EL_EMPTY_SPACE
847   },
848
849   {
850     -1,
851     TYPE_INTEGER,                       CONF_VALUE_8_BIT(2),
852     &xx_group.choice_mode,              ANIM_RANDOM
853   },
854
855   {
856     -1,
857     TYPE_ELEMENT_LIST,                  CONF_VALUE_BYTES(2),
858     &xx_group.element[0],               EL_EMPTY_SPACE, NULL,
859     &xx_group.num_elements,             1, MAX_ELEMENTS_IN_GROUP
860   },
861
862   {
863     -1,
864     -1,                                 -1,
865     NULL,                               -1,
866   },
867 };
868
869 static struct
870 {
871   int filetype;
872   char *id;
873 }
874 filetype_id_list[] =
875 {
876   { LEVEL_FILE_TYPE_RND,        "RND"   },
877   { LEVEL_FILE_TYPE_BD,         "BD"    },
878   { LEVEL_FILE_TYPE_EM,         "EM"    },
879   { LEVEL_FILE_TYPE_SP,         "SP"    },
880   { LEVEL_FILE_TYPE_DX,         "DX"    },
881   { LEVEL_FILE_TYPE_SB,         "SB"    },
882   { LEVEL_FILE_TYPE_DC,         "DC"    },
883   { -1,                         NULL    },
884 };
885
886
887 /* ========================================================================= */
888 /* level file functions                                                      */
889 /* ========================================================================= */
890
891 static void resetEventFlags(struct ElementChangeInfo *change)
892 {
893   int i;
894
895   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
896     change->has_event[i] = FALSE;
897 }
898
899 static void resetEventBits()
900 {
901   int i;
902
903   for (i = 0; i < NUM_CE_BITFIELDS; i++)
904     xx_event_bits[i] = 0;
905 }
906
907 static void setEventFlagsFromEventBits(struct ElementChangeInfo *change)
908 {
909   int i;
910
911   /* important: only change event flag if corresponding event bit is set */
912   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
913     if (xx_event_bits[CH_EVENT_BITFIELD_NR(i)] & CH_EVENT_BIT(i))
914       change->has_event[i] = TRUE;
915 }
916
917 static void setEventBitsFromEventFlags(struct ElementChangeInfo *change)
918 {
919   int i;
920
921   /* important: only change event bit if corresponding event flag is set */
922   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
923     if (change->has_event[i])
924       xx_event_bits[CH_EVENT_BITFIELD_NR(i)] |= CH_EVENT_BIT(i);
925 }
926
927 static char *getDefaultElementDescription(struct ElementInfo *ei)
928 {
929   static char description[MAX_ELEMENT_NAME_LEN + 1];
930   char *default_description = (ei->custom_description != NULL ?
931                                ei->custom_description :
932                                ei->editor_description);
933   int i;
934
935   /* always start with reliable default values */
936   for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++)
937     description[i] = '\0';
938
939   /* truncate element description to MAX_ELEMENT_NAME_LEN bytes */
940   strncpy(description, default_description, MAX_ELEMENT_NAME_LEN);
941
942   return &description[0];
943 }
944
945 static void setElementDescriptionToDefault(struct ElementInfo *ei)
946 {
947   char *default_description = getDefaultElementDescription(ei);
948   int i;
949
950   for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++)
951     ei->description[i] = default_description[i];
952 }
953
954 static void setConfigToDefaultsFromConfigList(struct ElementFileConfig *config)
955 {
956   int i;
957
958   for (i = 0; config[i].data_type != -1; i++)
959   {
960     int default_value = config[i].default_value;
961     int data_type = config[i].data_type;
962     int conf_type = config[i].conf_type;
963     int byte_mask = conf_type & CONF_MASK_BYTES;
964
965     if (byte_mask == CONF_MASK_MULTI_BYTES)
966     {
967       int default_num_entities = config[i].default_num_entities;
968       int max_num_entities = config[i].max_num_entities;
969
970       *(int *)(config[i].num_entities) = default_num_entities;
971
972       if (data_type == TYPE_STRING)
973       {
974         char *default_string = config[i].default_string;
975         char *string = (char *)(config[i].value);
976
977         strncpy(string, default_string, max_num_entities);
978       }
979       else if (data_type == TYPE_ELEMENT_LIST)
980       {
981         int *element_array = (int *)(config[i].value);
982         int j;
983
984         for (j = 0; j < max_num_entities; j++)
985           element_array[j] = default_value;
986       }
987       else if (data_type == TYPE_CONTENT_LIST)
988       {
989         struct Content *content = (struct Content *)(config[i].value);
990         int c, x, y;
991
992         for (c = 0; c < max_num_entities; c++)
993           for (y = 0; y < 3; y++)
994             for (x = 0; x < 3; x++)
995               content[c].e[x][y] = default_value;
996       }
997     }
998     else        /* constant size configuration data (1, 2 or 4 bytes) */
999     {
1000       if (data_type == TYPE_BOOLEAN)
1001         *(boolean *)(config[i].value) = default_value;
1002       else
1003         *(int *)    (config[i].value) = default_value;
1004     }
1005   }
1006 }
1007
1008 static void copyConfigFromConfigList(struct ElementFileConfig *config)
1009 {
1010   int i;
1011
1012   for (i = 0; config[i].data_type != -1; i++)
1013   {
1014     int data_type = config[i].data_type;
1015     int conf_type = config[i].conf_type;
1016     int byte_mask = conf_type & CONF_MASK_BYTES;
1017
1018     if (byte_mask == CONF_MASK_MULTI_BYTES)
1019     {
1020       int max_num_entities = config[i].max_num_entities;
1021
1022       if (data_type == TYPE_STRING)
1023       {
1024         char *string      = (char *)(config[i].value);
1025         char *string_copy = (char *)(config[i].value_copy);
1026
1027         strncpy(string_copy, string, max_num_entities);
1028       }
1029       else if (data_type == TYPE_ELEMENT_LIST)
1030       {
1031         int *element_array      = (int *)(config[i].value);
1032         int *element_array_copy = (int *)(config[i].value_copy);
1033         int j;
1034
1035         for (j = 0; j < max_num_entities; j++)
1036           element_array_copy[j] = element_array[j];
1037       }
1038       else if (data_type == TYPE_CONTENT_LIST)
1039       {
1040         struct Content *content      = (struct Content *)(config[i].value);
1041         struct Content *content_copy = (struct Content *)(config[i].value_copy);
1042         int c, x, y;
1043
1044         for (c = 0; c < max_num_entities; c++)
1045           for (y = 0; y < 3; y++)
1046             for (x = 0; x < 3; x++)
1047               content_copy[c].e[x][y] = content[c].e[x][y];
1048       }
1049     }
1050     else        /* constant size configuration data (1, 2 or 4 bytes) */
1051     {
1052       if (data_type == TYPE_BOOLEAN)
1053         *(boolean *)(config[i].value_copy) = *(boolean *)(config[i].value);
1054       else
1055         *(int *)    (config[i].value_copy) = *(int *)    (config[i].value);
1056     }
1057   }
1058 }
1059
1060 #if 1
1061 void copyElementInfo(struct ElementInfo *ei_from, struct ElementInfo *ei_to)
1062 {
1063 #if 1
1064   int i;
1065 #else
1066   int i, x, y;
1067 #endif
1068
1069 #if 1
1070   xx_ei = *ei_from;     /* copy element data into temporary buffer */
1071   yy_ei = *ei_to;       /* copy element data into temporary buffer */
1072
1073   copyConfigFromConfigList(custom_element_conf);
1074
1075   *ei_from = xx_ei;
1076   *ei_to   = yy_ei;
1077 #endif
1078
1079 #if 0
1080   /* ---------- copy element description ---------- */
1081   for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++)
1082     ei_to->description[i] = ei_from->description[i];
1083
1084   /* ---------- copy element base properties ---------- */
1085   ei_to->properties[EP_BITFIELD_BASE_NR] =
1086     ei_from->properties[EP_BITFIELD_BASE_NR];
1087
1088   /* ---------- copy custom property values ---------- */
1089
1090   ei_to->use_gfx_element = ei_from->use_gfx_element;
1091   ei_to->gfx_element = ei_from->gfx_element;
1092
1093   ei_to->access_direction = ei_from->access_direction;
1094
1095   ei_to->collect_score_initial = ei_from->collect_score_initial;
1096   ei_to->collect_count_initial = ei_from->collect_count_initial;
1097
1098   ei_to->ce_value_fixed_initial = ei_from->ce_value_fixed_initial;
1099   ei_to->ce_value_random_initial = ei_from->ce_value_random_initial;
1100   ei_to->use_last_ce_value = ei_from->use_last_ce_value;
1101
1102   ei_to->push_delay_fixed = ei_from->push_delay_fixed;
1103   ei_to->push_delay_random = ei_from->push_delay_random;
1104   ei_to->drop_delay_fixed = ei_from->drop_delay_fixed;
1105   ei_to->drop_delay_random = ei_from->drop_delay_random;
1106   ei_to->move_delay_fixed = ei_from->move_delay_fixed;
1107   ei_to->move_delay_random = ei_from->move_delay_random;
1108
1109   ei_to->move_pattern = ei_from->move_pattern;
1110   ei_to->move_direction_initial = ei_from->move_direction_initial;
1111   ei_to->move_stepsize = ei_from->move_stepsize;
1112
1113   ei_to->move_enter_element = ei_from->move_enter_element;
1114   ei_to->move_leave_element = ei_from->move_leave_element;
1115   ei_to->move_leave_type = ei_from->move_leave_type;
1116
1117   ei_to->slippery_type = ei_from->slippery_type;
1118
1119   ei_to->explosion_type = ei_from->explosion_type;
1120   ei_to->explosion_delay = ei_from->explosion_delay;
1121   ei_to->ignition_delay = ei_from->ignition_delay;
1122
1123   for (y = 0; y < 3; y++)
1124     for (x = 0; x < 3; x++)
1125       ei_to->content.e[x][y] = ei_from->content.e[x][y];
1126 #endif
1127
1128   /* ---------- reinitialize and copy change pages ---------- */
1129
1130   ei_to->num_change_pages = ei_from->num_change_pages;
1131   ei_to->current_change_page = ei_from->current_change_page;
1132
1133   setElementChangePages(ei_to, ei_to->num_change_pages);
1134
1135   for (i = 0; i < ei_to->num_change_pages; i++)
1136     ei_to->change_page[i] = ei_from->change_page[i];
1137
1138   /* ---------- copy group element info ---------- */
1139   if (ei_from->group != NULL && ei_to->group != NULL)   /* group or internal */
1140     *ei_to->group = *ei_from->group;
1141
1142   /* mark this custom element as modified */
1143   ei_to->modified_settings = TRUE;
1144 }
1145 #endif
1146
1147 void setElementChangePages(struct ElementInfo *ei, int change_pages)
1148 {
1149   int change_page_size = sizeof(struct ElementChangeInfo);
1150
1151   ei->num_change_pages = MAX(1, change_pages);
1152
1153   ei->change_page =
1154     checked_realloc(ei->change_page, ei->num_change_pages * change_page_size);
1155
1156   if (ei->current_change_page >= ei->num_change_pages)
1157     ei->current_change_page = ei->num_change_pages - 1;
1158
1159   ei->change = &ei->change_page[ei->current_change_page];
1160 }
1161
1162 void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
1163 {
1164 #if 0
1165   int i, x, y;
1166 #endif
1167
1168 #if 1
1169   xx_change = *change;          /* copy change data into temporary buffer */
1170   xx_num_contents = 1;
1171
1172   setConfigToDefaultsFromConfigList(custom_element_change_conf);
1173
1174   *change = xx_change;
1175
1176   resetEventFlags(change);
1177 #endif
1178
1179 #if 0
1180   change->can_change = FALSE;
1181
1182   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
1183     change->has_event[i] = FALSE;
1184
1185   change->trigger_player = CH_PLAYER_ANY;
1186   change->trigger_side = CH_SIDE_ANY;
1187   change->trigger_page = CH_PAGE_ANY;
1188
1189   change->target_element = EL_EMPTY_SPACE;
1190
1191   change->delay_fixed = 0;
1192   change->delay_random = 0;
1193   change->delay_frames = FRAMES_PER_SECOND;
1194
1195   change->trigger_element = EL_EMPTY_SPACE;
1196
1197   change->explode = FALSE;
1198   change->use_target_content = FALSE;
1199   change->only_if_complete = FALSE;
1200   change->use_random_replace = FALSE;
1201   change->random_percentage = 100;
1202   change->replace_when = CP_WHEN_EMPTY;
1203
1204   change->has_action = FALSE;
1205   change->action_type = CA_NO_ACTION;
1206   change->action_mode = CA_MODE_UNDEFINED;
1207   change->action_arg = CA_ARG_UNDEFINED;
1208
1209   for (x = 0; x < 3; x++)
1210     for (y = 0; y < 3; y++)
1211       change->target_content.e[x][y] = EL_EMPTY_SPACE;
1212 #endif
1213
1214   change->direct_action = 0;
1215   change->other_action = 0;
1216
1217   change->pre_change_function = NULL;
1218   change->change_function = NULL;
1219   change->post_change_function = NULL;
1220 }
1221
1222 static void setLevelInfoToDefaults(struct LevelInfo *level)
1223 {
1224   static boolean clipboard_elements_initialized = FALSE;
1225 #if 0
1226   int i, j, x, y;
1227 #else
1228   int i, x, y;
1229 #endif
1230
1231 #if 1
1232   InitElementPropertiesStatic();
1233 #endif
1234
1235 #if 1
1236   li = *level;          /* copy level data into temporary buffer */
1237
1238   setConfigToDefaultsFromConfigList(element_conf);
1239
1240   *level = li;          /* copy temporary buffer back to level data */
1241 #endif
1242
1243   setLevelInfoToDefaults_EM();
1244
1245   level->native_em_level = &native_em_level;
1246
1247   level->game_engine_type = GAME_ENGINE_TYPE_RND;
1248
1249   level->file_version = FILE_VERSION_ACTUAL;
1250   level->game_version = GAME_VERSION_ACTUAL;
1251
1252   level->encoding_16bit_field  = FALSE; /* default: only 8-bit elements */
1253   level->encoding_16bit_yamyam = FALSE; /* default: only 8-bit elements */
1254   level->encoding_16bit_amoeba = FALSE; /* default: only 8-bit elements */
1255
1256   level->fieldx = STD_LEV_FIELDX;
1257   level->fieldy = STD_LEV_FIELDY;
1258
1259   for (x = 0; x < MAX_LEV_FIELDX; x++)
1260     for (y = 0; y < MAX_LEV_FIELDY; y++)
1261       level->field[x][y] = EL_SAND;
1262
1263   level->time = 100;
1264   level->gems_needed = 0;
1265
1266   level->amoeba_speed = 10;
1267
1268   level->time_magic_wall = 10;
1269   level->time_wheel = 10;
1270 #if 0
1271   level->time_light = 10;
1272   level->time_timegate = 10;
1273 #endif
1274
1275   level->amoeba_content = EL_DIAMOND;
1276
1277 #if 0
1278   level->game_of_life[0] = 2;
1279   level->game_of_life[1] = 3;
1280   level->game_of_life[2] = 3;
1281   level->game_of_life[3] = 3;
1282
1283   level->biomaze[0] = 2;
1284   level->biomaze[1] = 3;
1285   level->biomaze[2] = 3;
1286   level->biomaze[3] = 3;
1287 #endif
1288
1289 #if 0
1290   level->double_speed = FALSE;
1291 #endif
1292   level->initial_gravity = FALSE;
1293   level->em_slippery_gems = FALSE;
1294   level->instant_relocation = FALSE;
1295   level->can_pass_to_walkable = FALSE;
1296   level->grow_into_diggable = TRUE;
1297
1298 #if 0
1299   level->block_snap_field = TRUE;
1300 #endif
1301
1302   level->block_last_field = FALSE;      /* EM does not block by default */
1303   level->sp_block_last_field = TRUE;    /* SP blocks the last field */
1304
1305   level->can_move_into_acid_bits = ~0;  /* everything can move into acid */
1306   level->dont_collide_with_bits = ~0;   /* always deadly when colliding */
1307
1308   level->use_spring_bug = FALSE;
1309   level->use_time_orb_bug = FALSE;
1310
1311   level->use_step_counter = FALSE;
1312
1313   /* values for the new EMC elements */
1314 #if 0
1315   level->android_move_time = 10;
1316   level->android_clone_time = 10;
1317   level->ball_time = 10;
1318   level->lenses_score = 10;
1319   level->lenses_time = 10;
1320   level->magnify_score = 10;
1321   level->magnify_time = 10;
1322   level->slurp_score = 10;
1323   level->wind_direction_initial = MV_NONE;
1324   level->ball_random = FALSE;
1325   level->ball_state_initial = FALSE;
1326
1327   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
1328     for (x = 0; x < 3; x++)
1329       for (y = 0; y < 3; y++)
1330         level->ball_content[i].e[x][y] = EL_EMPTY;
1331
1332   for (i = 0; i < 16; i++)
1333     level->android_array[i] = FALSE;
1334 #endif
1335
1336   level->use_custom_template = FALSE;
1337
1338   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
1339     level->name[i] = '\0';
1340   for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
1341     level->author[i] = '\0';
1342
1343   strcpy(level->name, NAMELESS_LEVEL_NAME);
1344   strcpy(level->author, ANONYMOUS_NAME);
1345
1346   for (i = 0; i < 4; i++)
1347   {
1348     level->envelope_text[i][0] = '\0';
1349     level->envelope_xsize[i] = MAX_ENVELOPE_XSIZE;
1350     level->envelope_ysize[i] = MAX_ENVELOPE_YSIZE;
1351   }
1352
1353   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
1354     level->score[i] = (i == SC_TIME_BONUS ? 1 : 10);
1355
1356   level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
1357   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
1358     for (x = 0; x < 3; x++)
1359       for (y = 0; y < 3; y++)
1360         level->yamyam_content[i].e[x][y] =
1361           (i < STD_ELEMENT_CONTENTS ? EL_ROCK : EL_EMPTY);
1362
1363   level->field[0][0] = EL_PLAYER_1;
1364   level->field[STD_LEV_FIELDX - 1][STD_LEV_FIELDY - 1] = EL_EXIT_CLOSED;
1365
1366   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1367   {
1368     int element = i;
1369     struct ElementInfo *ei = &element_info[element];
1370
1371 #if 1
1372     if (IS_CUSTOM_ELEMENT(element) ||
1373         IS_GROUP_ELEMENT(element) ||
1374         IS_INTERNAL_ELEMENT(element))
1375     {
1376       xx_ei = *ei;      /* copy element data into temporary buffer */
1377
1378       setConfigToDefaultsFromConfigList(custom_element_conf);
1379
1380       *ei = xx_ei;
1381     }
1382 #endif
1383
1384     /* never initialize clipboard elements after the very first time */
1385     /* (to be able to use clipboard elements between several levels) */
1386     if (IS_CLIPBOARD_ELEMENT(element) && clipboard_elements_initialized)
1387       continue;
1388
1389     setElementChangePages(ei, 1);
1390     setElementChangeInfoToDefaults(ei->change);
1391
1392     if (IS_CUSTOM_ELEMENT(element) ||
1393         IS_GROUP_ELEMENT(element) ||
1394         IS_INTERNAL_ELEMENT(element))
1395     {
1396 #if 1
1397       setElementDescriptionToDefault(ei);
1398 #else
1399       for (j = 0; j < MAX_ELEMENT_NAME_LEN + 1; j++)
1400         ei->description[j] = '\0';
1401
1402       if (ei->custom_description != NULL)
1403         strncpy(ei->description, ei->custom_description,MAX_ELEMENT_NAME_LEN);
1404       else
1405         strcpy(ei->description, ei->editor_description);
1406 #endif
1407
1408 #if 0
1409       ei->use_gfx_element = FALSE;
1410       ei->gfx_element = EL_EMPTY_SPACE;
1411 #endif
1412
1413       ei->modified_settings = FALSE;
1414     }
1415
1416     if (IS_CUSTOM_ELEMENT(element) ||
1417         IS_INTERNAL_ELEMENT(element))
1418     {
1419 #if 0
1420       ei->access_direction = MV_ALL_DIRECTIONS;
1421
1422       ei->collect_score_initial = 10;   /* special default */
1423       ei->collect_count_initial = 1;    /* special default */
1424
1425       ei->ce_value_fixed_initial = 0;
1426       ei->ce_value_random_initial = 0;
1427       ei->use_last_ce_value = FALSE;
1428
1429       ei->push_delay_fixed = -1;        /* initialize later */
1430       ei->push_delay_random = -1;       /* initialize later */
1431       ei->drop_delay_fixed = 0;
1432       ei->drop_delay_random = 0;
1433       ei->move_delay_fixed = 0;
1434       ei->move_delay_random = 0;
1435
1436       ei->move_pattern = MV_ALL_DIRECTIONS;
1437       ei->move_direction_initial = MV_START_AUTOMATIC;
1438       ei->move_stepsize = TILEX / 8;
1439
1440       ei->move_enter_element = EL_EMPTY_SPACE;
1441       ei->move_leave_element = EL_EMPTY_SPACE;
1442       ei->move_leave_type = LEAVE_TYPE_UNLIMITED;
1443
1444       ei->slippery_type = SLIPPERY_ANY_RANDOM;
1445
1446       ei->explosion_type = EXPLODES_3X3;
1447       ei->explosion_delay = 16;
1448       ei->ignition_delay = 8;
1449
1450       for (x = 0; x < 3; x++)
1451         for (y = 0; y < 3; y++)
1452           ei->content.e[x][y] = EL_EMPTY_SPACE;
1453 #endif
1454
1455       ei->access_type = 0;
1456       ei->access_layer = 0;
1457       ei->access_protected = 0;
1458       ei->walk_to_action = 0;
1459       ei->smash_targets = 0;
1460       ei->deadliness = 0;
1461
1462       ei->can_explode_by_fire = FALSE;
1463       ei->can_explode_smashed = FALSE;
1464       ei->can_explode_impact = FALSE;
1465
1466       ei->current_change_page = 0;
1467
1468 #if 0
1469       /* !!! now done in InitElementPropertiesStatic() (see above) !!! */
1470       /* !!! (else properties set there will be overwritten here)  !!! */
1471       /* start with no properties at all */
1472 #if 1
1473       for (j = 0; j < NUM_EP_BITFIELDS; j++)
1474         ei->properties[j] = EP_BITMASK_DEFAULT;
1475 #else
1476       for (j = 0; j < NUM_EP_BITFIELDS; j++)
1477         Properties[element][j] = EP_BITMASK_DEFAULT;
1478 #endif
1479 #endif
1480
1481 #if 0
1482       /* now set default properties */
1483       SET_PROPERTY(element, EP_CAN_MOVE_INTO_ACID, TRUE);
1484 #endif
1485     }
1486
1487     if (IS_GROUP_ELEMENT(element) ||
1488         IS_INTERNAL_ELEMENT(element))
1489     {
1490       struct ElementGroupInfo *group;
1491
1492       /* initialize memory for list of elements in group */
1493       if (ei->group == NULL)
1494         ei->group = checked_malloc(sizeof(struct ElementGroupInfo));
1495
1496       group = ei->group;
1497
1498 #if 1
1499       xx_group = *group;        /* copy group data into temporary buffer */
1500
1501       setConfigToDefaultsFromConfigList(group_element_conf);
1502
1503       *group = xx_group;
1504 #endif
1505
1506 #if 0
1507       for (j = 0; j < MAX_ELEMENTS_IN_GROUP; j++)
1508         group->element[j] = EL_EMPTY_SPACE;
1509
1510       /* default: only one element in group */
1511       group->num_elements = 1;
1512
1513       group->choice_mode = ANIM_RANDOM;
1514 #endif
1515     }
1516   }
1517
1518   clipboard_elements_initialized = TRUE;
1519
1520   BorderElement = EL_STEELWALL;
1521
1522   level->no_valid_file = FALSE;
1523
1524   level->changed = FALSE;
1525
1526   if (leveldir_current == NULL)         /* only when dumping level */
1527     return;
1528
1529   /* try to determine better author name than 'anonymous' */
1530   if (!strEqual(leveldir_current->author, ANONYMOUS_NAME))
1531   {
1532     strncpy(level->author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN);
1533     level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
1534   }
1535   else
1536   {
1537     switch (LEVELCLASS(leveldir_current))
1538     {
1539       case LEVELCLASS_TUTORIAL:
1540         strcpy(level->author, PROGRAM_AUTHOR_STRING);
1541         break;
1542
1543       case LEVELCLASS_CONTRIB:
1544         strncpy(level->author, leveldir_current->name, MAX_LEVEL_AUTHOR_LEN);
1545         level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
1546         break;
1547
1548       case LEVELCLASS_PRIVATE:
1549         strncpy(level->author, getRealName(), MAX_LEVEL_AUTHOR_LEN);
1550         level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
1551         break;
1552
1553       default:
1554         /* keep default value */
1555         break;
1556     }
1557   }
1558 }
1559
1560 static void setFileInfoToDefaults(struct LevelFileInfo *level_file_info)
1561 {
1562   level_file_info->nr = 0;
1563   level_file_info->type = LEVEL_FILE_TYPE_UNKNOWN;
1564   level_file_info->packed = FALSE;
1565   level_file_info->basename = NULL;
1566   level_file_info->filename = NULL;
1567 }
1568
1569 static void ActivateLevelTemplate()
1570 {
1571 #if 1
1572   /* Currently there is no special action needed to activate the template
1573      data, because 'element_info' property settings overwrite the original
1574      level data, while all other variables do not change. */
1575 #else
1576   /* Currently there is no special action needed to activate the template
1577      data, because 'element_info' and 'Properties' overwrite the original
1578      level data, while all other variables do not change. */
1579 #endif
1580 }
1581
1582 static char *getLevelFilenameFromBasename(char *basename)
1583 {
1584   static char *filename = NULL;
1585
1586   checked_free(filename);
1587
1588   filename = getPath2(getCurrentLevelDir(), basename);
1589
1590   return filename;
1591 }
1592
1593 static int getFileTypeFromBasename(char *basename)
1594 {
1595   static char *filename = NULL;
1596   struct stat file_status;
1597
1598   /* ---------- try to determine file type from filename ---------- */
1599
1600   /* check for typical filename of a Supaplex level package file */
1601   if (strlen(basename) == 10 && (strncmp(basename, "levels.d", 8) == 0 ||
1602                                  strncmp(basename, "LEVELS.D", 8) == 0))
1603     return LEVEL_FILE_TYPE_SP;
1604
1605   /* ---------- try to determine file type from filesize ---------- */
1606
1607   checked_free(filename);
1608   filename = getPath2(getCurrentLevelDir(), basename);
1609
1610   if (stat(filename, &file_status) == 0)
1611   {
1612     /* check for typical filesize of a Supaplex level package file */
1613     if (file_status.st_size == 170496)
1614       return LEVEL_FILE_TYPE_SP;
1615   }
1616
1617   return LEVEL_FILE_TYPE_UNKNOWN;
1618 }
1619
1620 static char *getSingleLevelBasename(int nr)
1621 {
1622   static char basename[MAX_FILENAME_LEN];
1623
1624   if (nr < 0)
1625     sprintf(basename, "template.%s", LEVELFILE_EXTENSION);
1626   else
1627     sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION);
1628
1629   return basename;
1630 }
1631
1632 static char *getPackedLevelBasename(int type)
1633 {
1634   static char basename[MAX_FILENAME_LEN];
1635   char *directory = getCurrentLevelDir();
1636   DIR *dir;
1637   struct dirent *dir_entry;
1638
1639   strcpy(basename, UNDEFINED_FILENAME);         /* default: undefined file */
1640
1641   if ((dir = opendir(directory)) == NULL)
1642   {
1643     Error(ERR_WARN, "cannot read current level directory '%s'", directory);
1644
1645     return basename;
1646   }
1647
1648   while ((dir_entry = readdir(dir)) != NULL)    /* loop until last dir entry */
1649   {
1650     char *entry_basename = dir_entry->d_name;
1651     int entry_type = getFileTypeFromBasename(entry_basename);
1652
1653     if (entry_type != LEVEL_FILE_TYPE_UNKNOWN)  /* found valid level package */
1654     {
1655       if (type == LEVEL_FILE_TYPE_UNKNOWN ||
1656           type == entry_type)
1657       {
1658         strcpy(basename, entry_basename);
1659
1660         break;
1661       }
1662     }
1663   }
1664
1665   closedir(dir);
1666
1667   return basename;
1668 }
1669
1670 static char *getSingleLevelFilename(int nr)
1671 {
1672   return getLevelFilenameFromBasename(getSingleLevelBasename(nr));
1673 }
1674
1675 #if 0
1676 static char *getPackedLevelFilename(int type)
1677 {
1678   return getLevelFilenameFromBasename(getPackedLevelBasename(type));
1679 }
1680 #endif
1681
1682 char *getDefaultLevelFilename(int nr)
1683 {
1684   return getSingleLevelFilename(nr);
1685 }
1686
1687 #if 0
1688 static void setLevelFileInfo_SingleLevelFilename(struct LevelFileInfo *lfi,
1689                                                  int type)
1690 {
1691   lfi->type = type;
1692   lfi->packed = FALSE;
1693   lfi->basename = getSingleLevelBasename(lfi->nr, lfi->type);
1694   lfi->filename = getLevelFilenameFromBasename(lfi->basename);
1695 }
1696 #endif
1697
1698 static void setLevelFileInfo_FormatLevelFilename(struct LevelFileInfo *lfi,
1699                                                  int type, char *format, ...)
1700 {
1701   static char basename[MAX_FILENAME_LEN];
1702   va_list ap;
1703
1704   va_start(ap, format);
1705   vsprintf(basename, format, ap);
1706   va_end(ap);
1707
1708   lfi->type = type;
1709   lfi->packed = FALSE;
1710   lfi->basename = basename;
1711   lfi->filename = getLevelFilenameFromBasename(lfi->basename);
1712 }
1713
1714 static void setLevelFileInfo_PackedLevelFilename(struct LevelFileInfo *lfi,
1715                                                  int type)
1716 {
1717   lfi->type = type;
1718   lfi->packed = TRUE;
1719   lfi->basename = getPackedLevelBasename(lfi->type);
1720   lfi->filename = getLevelFilenameFromBasename(lfi->basename);
1721 }
1722
1723 static int getFiletypeFromID(char *filetype_id)
1724 {
1725   char *filetype_id_lower;
1726   int filetype = LEVEL_FILE_TYPE_UNKNOWN;
1727   int i;
1728
1729   if (filetype_id == NULL)
1730     return LEVEL_FILE_TYPE_UNKNOWN;
1731
1732   filetype_id_lower = getStringToLower(filetype_id);
1733
1734   for (i = 0; filetype_id_list[i].id != NULL; i++)
1735   {
1736     char *id_lower = getStringToLower(filetype_id_list[i].id);
1737     
1738     if (strEqual(filetype_id_lower, id_lower))
1739       filetype = filetype_id_list[i].filetype;
1740
1741     free(id_lower);
1742
1743     if (filetype != LEVEL_FILE_TYPE_UNKNOWN)
1744       break;
1745   }
1746
1747   free(filetype_id_lower);
1748
1749   return filetype;
1750 }
1751
1752 static void determineLevelFileInfo_Filename(struct LevelFileInfo *lfi)
1753 {
1754   int nr = lfi->nr;
1755
1756   /* special case: level number is negative => check for level template file */
1757   if (nr < 0)
1758   {
1759     setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
1760                                          "template.%s", LEVELFILE_EXTENSION);
1761
1762     /* no fallback if template file not existing */
1763     return;
1764   }
1765
1766   /* special case: check for file name/pattern specified in "levelinfo.conf" */
1767   if (leveldir_current->level_filename != NULL)
1768   {
1769     int filetype = getFiletypeFromID(leveldir_current->level_filetype);
1770
1771     setLevelFileInfo_FormatLevelFilename(lfi, filetype,
1772                                          leveldir_current->level_filename, nr);
1773     if (fileExists(lfi->filename))
1774       return;
1775   }
1776
1777   /* check for native Rocks'n'Diamonds level file */
1778   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
1779                                        "%03d.%s", nr, LEVELFILE_EXTENSION);
1780   if (fileExists(lfi->filename))
1781     return;
1782
1783   /* check for Emerald Mine level file (V1) */
1784   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "a%c%c",
1785                                        'a' + (nr / 10) % 26, '0' + nr % 10);
1786   if (fileExists(lfi->filename))
1787     return;
1788   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "A%c%c",
1789                                        'A' + (nr / 10) % 26, '0' + nr % 10);
1790   if (fileExists(lfi->filename))
1791     return;
1792
1793   /* check for Emerald Mine level file (V2 to V5) */
1794   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%d", nr);
1795   if (fileExists(lfi->filename))
1796     return;
1797
1798   /* check for Emerald Mine level file (V6 / single mode) */
1799   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02ds", nr);
1800   if (fileExists(lfi->filename))
1801     return;
1802   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dS", nr);
1803   if (fileExists(lfi->filename))
1804     return;
1805
1806   /* check for Emerald Mine level file (V6 / teamwork mode) */
1807   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dt", nr);
1808   if (fileExists(lfi->filename))
1809     return;
1810   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dT", nr);
1811   if (fileExists(lfi->filename))
1812     return;
1813
1814   /* check for various packed level file formats */
1815   setLevelFileInfo_PackedLevelFilename(lfi, LEVEL_FILE_TYPE_UNKNOWN);
1816   if (fileExists(lfi->filename))
1817     return;
1818
1819   /* no known level file found -- use default values (and fail later) */
1820   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
1821                                        "%03d.%s", nr, LEVELFILE_EXTENSION);
1822 }
1823
1824 static void determineLevelFileInfo_Filetype(struct LevelFileInfo *lfi)
1825 {
1826   if (lfi->type == LEVEL_FILE_TYPE_UNKNOWN)
1827     lfi->type = getFileTypeFromBasename(lfi->basename);
1828 }
1829
1830 static void setLevelFileInfo(struct LevelFileInfo *level_file_info, int nr)
1831 {
1832   /* always start with reliable default values */
1833   setFileInfoToDefaults(level_file_info);
1834
1835   level_file_info->nr = nr;     /* set requested level number */
1836
1837   determineLevelFileInfo_Filename(level_file_info);
1838   determineLevelFileInfo_Filetype(level_file_info);
1839 }
1840
1841 /* ------------------------------------------------------------------------- */
1842 /* functions for loading R'n'D level                                         */
1843 /* ------------------------------------------------------------------------- */
1844
1845 int getMappedElement(int element)
1846 {
1847   /* remap some (historic, now obsolete) elements */
1848
1849   switch (element)
1850   {
1851     case EL_PLAYER_OBSOLETE:
1852       element = EL_PLAYER_1;
1853       break;
1854
1855     case EL_KEY_OBSOLETE:
1856       element = EL_KEY_1;
1857
1858     case EL_EM_KEY_1_FILE_OBSOLETE:
1859       element = EL_EM_KEY_1;
1860       break;
1861
1862     case EL_EM_KEY_2_FILE_OBSOLETE:
1863       element = EL_EM_KEY_2;
1864       break;
1865
1866     case EL_EM_KEY_3_FILE_OBSOLETE:
1867       element = EL_EM_KEY_3;
1868       break;
1869
1870     case EL_EM_KEY_4_FILE_OBSOLETE:
1871       element = EL_EM_KEY_4;
1872       break;
1873
1874     case EL_ENVELOPE_OBSOLETE:
1875       element = EL_ENVELOPE_1;
1876       break;
1877
1878     case EL_SP_EMPTY:
1879       element = EL_EMPTY;
1880       break;
1881
1882     default:
1883       if (element >= NUM_FILE_ELEMENTS)
1884       {
1885         Error(ERR_WARN, "invalid level element %d", element);
1886
1887         element = EL_UNKNOWN;
1888       }
1889       break;
1890   }
1891
1892   return element;
1893 }
1894
1895 int getMappedElementByVersion(int element, int game_version)
1896 {
1897   /* remap some elements due to certain game version */
1898
1899   if (game_version <= VERSION_IDENT(2,2,0,0))
1900   {
1901     /* map game font elements */
1902     element = (element == EL_CHAR('[')  ? EL_CHAR_AUMLAUT :
1903                element == EL_CHAR('\\') ? EL_CHAR_OUMLAUT :
1904                element == EL_CHAR(']')  ? EL_CHAR_UUMLAUT :
1905                element == EL_CHAR('^')  ? EL_CHAR_COPYRIGHT : element);
1906   }
1907
1908   if (game_version < VERSION_IDENT(3,0,0,0))
1909   {
1910     /* map Supaplex gravity tube elements */
1911     element = (element == EL_SP_GRAVITY_PORT_LEFT  ? EL_SP_PORT_LEFT  :
1912                element == EL_SP_GRAVITY_PORT_RIGHT ? EL_SP_PORT_RIGHT :
1913                element == EL_SP_GRAVITY_PORT_UP    ? EL_SP_PORT_UP    :
1914                element == EL_SP_GRAVITY_PORT_DOWN  ? EL_SP_PORT_DOWN  :
1915                element);
1916   }
1917
1918   return element;
1919 }
1920
1921 static int LoadLevel_VERS(FILE *file, int chunk_size, struct LevelInfo *level)
1922 {
1923   level->file_version = getFileVersion(file);
1924   level->game_version = getFileVersion(file);
1925
1926   return chunk_size;
1927 }
1928
1929 static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
1930 {
1931   int i, x, y;
1932
1933   level->fieldx = getFile8Bit(file);
1934   level->fieldy = getFile8Bit(file);
1935
1936   level->time           = getFile16BitBE(file);
1937   level->gems_needed    = getFile16BitBE(file);
1938
1939   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
1940     level->name[i] = getFile8Bit(file);
1941   level->name[MAX_LEVEL_NAME_LEN] = 0;
1942
1943   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
1944     level->score[i] = getFile8Bit(file);
1945
1946   level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
1947   for (i = 0; i < STD_ELEMENT_CONTENTS; i++)
1948     for (y = 0; y < 3; y++)
1949       for (x = 0; x < 3; x++)
1950         level->yamyam_content[i].e[x][y] = getMappedElement(getFile8Bit(file));
1951
1952   level->amoeba_speed           = getFile8Bit(file);
1953   level->time_magic_wall        = getFile8Bit(file);
1954   level->time_wheel             = getFile8Bit(file);
1955   level->amoeba_content         = getMappedElement(getFile8Bit(file));
1956
1957   level->initial_player_stepsize = (getFile8Bit(file) == 1 ? STEPSIZE_FAST :
1958                                     STEPSIZE_NORMAL);
1959
1960   level->initial_gravity        = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1961   level->encoding_16bit_field   = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1962   level->em_slippery_gems       = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1963
1964   level->use_custom_template    = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1965
1966   level->block_last_field       = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1967   level->sp_block_last_field    = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1968   level->can_move_into_acid_bits = getFile32BitBE(file);
1969   level->dont_collide_with_bits = getFile8Bit(file);
1970
1971   level->use_spring_bug         = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1972   level->use_step_counter       = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1973
1974   level->instant_relocation     = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1975   level->can_pass_to_walkable   = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1976   level->grow_into_diggable     = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1977
1978   level->game_engine_type       = getFile8Bit(file);
1979
1980   ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED);
1981
1982   return chunk_size;
1983 }
1984
1985 static int LoadLevel_AUTH(FILE *file, int chunk_size, struct LevelInfo *level)
1986 {
1987   int i;
1988
1989   for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
1990     level->author[i] = getFile8Bit(file);
1991   level->author[MAX_LEVEL_NAME_LEN] = 0;
1992
1993   return chunk_size;
1994 }
1995
1996 static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level)
1997 {
1998   int x, y;
1999   int chunk_size_expected = level->fieldx * level->fieldy;
2000
2001   /* Note: "chunk_size" was wrong before version 2.0 when elements are
2002      stored with 16-bit encoding (and should be twice as big then).
2003      Even worse, playfield data was stored 16-bit when only yamyam content
2004      contained 16-bit elements and vice versa. */
2005
2006   if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
2007     chunk_size_expected *= 2;
2008
2009   if (chunk_size_expected != chunk_size)
2010   {
2011     ReadUnusedBytesFromFile(file, chunk_size);
2012     return chunk_size_expected;
2013   }
2014
2015   for (y = 0; y < level->fieldy; y++)
2016     for (x = 0; x < level->fieldx; x++)
2017       level->field[x][y] =
2018         getMappedElement(level->encoding_16bit_field ? getFile16BitBE(file) :
2019                          getFile8Bit(file));
2020   return chunk_size;
2021 }
2022
2023 static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
2024 {
2025   int i, x, y;
2026   int header_size = 4;
2027   int content_size = MAX_ELEMENT_CONTENTS * 3 * 3;
2028   int chunk_size_expected = header_size + content_size;
2029
2030   /* Note: "chunk_size" was wrong before version 2.0 when elements are
2031      stored with 16-bit encoding (and should be twice as big then).
2032      Even worse, playfield data was stored 16-bit when only yamyam content
2033      contained 16-bit elements and vice versa. */
2034
2035   if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
2036     chunk_size_expected += content_size;
2037
2038   if (chunk_size_expected != chunk_size)
2039   {
2040     ReadUnusedBytesFromFile(file, chunk_size);
2041     return chunk_size_expected;
2042   }
2043
2044   getFile8Bit(file);
2045   level->num_yamyam_contents = getFile8Bit(file);
2046   getFile8Bit(file);
2047   getFile8Bit(file);
2048
2049   /* correct invalid number of content fields -- should never happen */
2050   if (level->num_yamyam_contents < 1 ||
2051       level->num_yamyam_contents > MAX_ELEMENT_CONTENTS)
2052     level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
2053
2054   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
2055     for (y = 0; y < 3; y++)
2056       for (x = 0; x < 3; x++)
2057         level->yamyam_content[i].e[x][y] =
2058           getMappedElement(level->encoding_16bit_field ?
2059                            getFile16BitBE(file) : getFile8Bit(file));
2060   return chunk_size;
2061 }
2062
2063 static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
2064 {
2065   int i, x, y;
2066   int element;
2067   int num_contents, content_xsize, content_ysize;
2068   int content_array[MAX_ELEMENT_CONTENTS][3][3];
2069
2070   element = getMappedElement(getFile16BitBE(file));
2071   num_contents = getFile8Bit(file);
2072   content_xsize = getFile8Bit(file);
2073   content_ysize = getFile8Bit(file);
2074
2075   ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED);
2076
2077   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
2078     for (y = 0; y < 3; y++)
2079       for (x = 0; x < 3; x++)
2080         content_array[i][x][y] = getMappedElement(getFile16BitBE(file));
2081
2082   /* correct invalid number of content fields -- should never happen */
2083   if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS)
2084     num_contents = STD_ELEMENT_CONTENTS;
2085
2086   if (element == EL_YAMYAM)
2087   {
2088     level->num_yamyam_contents = num_contents;
2089
2090     for (i = 0; i < num_contents; i++)
2091       for (y = 0; y < 3; y++)
2092         for (x = 0; x < 3; x++)
2093           level->yamyam_content[i].e[x][y] = content_array[i][x][y];
2094   }
2095   else if (element == EL_BD_AMOEBA)
2096   {
2097     level->amoeba_content = content_array[0][0][0];
2098   }
2099   else
2100   {
2101     Error(ERR_WARN, "cannot load content for element '%d'", element);
2102   }
2103
2104   return chunk_size;
2105 }
2106
2107 static int LoadLevel_CNT3(FILE *file, int chunk_size, struct LevelInfo *level)
2108 {
2109   int i;
2110   int element;
2111   int envelope_nr;
2112   int envelope_len;
2113   int chunk_size_expected;
2114
2115   element = getMappedElement(getFile16BitBE(file));
2116   if (!IS_ENVELOPE(element))
2117     element = EL_ENVELOPE_1;
2118
2119   envelope_nr = element - EL_ENVELOPE_1;
2120
2121   envelope_len = getFile16BitBE(file);
2122
2123   level->envelope_xsize[envelope_nr] = getFile8Bit(file);
2124   level->envelope_ysize[envelope_nr] = getFile8Bit(file);
2125
2126   ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT3_UNUSED);
2127
2128   chunk_size_expected = LEVEL_CHUNK_CNT3_SIZE(envelope_len);
2129   if (chunk_size_expected != chunk_size)
2130   {
2131     ReadUnusedBytesFromFile(file, chunk_size - LEVEL_CHUNK_CNT3_HEADER);
2132     return chunk_size_expected;
2133   }
2134
2135   for (i = 0; i < envelope_len; i++)
2136     level->envelope_text[envelope_nr][i] = getFile8Bit(file);
2137
2138   return chunk_size;
2139 }
2140
2141 static int LoadLevel_CUS1(FILE *file, int chunk_size, struct LevelInfo *level)
2142 {
2143   int num_changed_custom_elements = getFile16BitBE(file);
2144   int chunk_size_expected = 2 + num_changed_custom_elements * 6;
2145   int i;
2146
2147   if (chunk_size_expected != chunk_size)
2148   {
2149     ReadUnusedBytesFromFile(file, chunk_size - 2);
2150     return chunk_size_expected;
2151   }
2152
2153   for (i = 0; i < num_changed_custom_elements; i++)
2154   {
2155     int element = getFile16BitBE(file);
2156     int properties = getFile32BitBE(file);
2157
2158 #if 1
2159     if (IS_CUSTOM_ELEMENT(element))
2160       element_info[element].properties[EP_BITFIELD_BASE_NR] = properties;
2161     else
2162       Error(ERR_WARN, "invalid custom element number %d", element);
2163 #else
2164     if (IS_CUSTOM_ELEMENT(element))
2165       Properties[element][EP_BITFIELD_BASE_NR] = properties;
2166     else
2167       Error(ERR_WARN, "invalid custom element number %d", element);
2168 #endif
2169   }
2170
2171   return chunk_size;
2172 }
2173
2174 static int LoadLevel_CUS2(FILE *file, int chunk_size, struct LevelInfo *level)
2175 {
2176   int num_changed_custom_elements = getFile16BitBE(file);
2177   int chunk_size_expected = 2 + num_changed_custom_elements * 4;
2178   int i;
2179
2180   if (chunk_size_expected != chunk_size)
2181   {
2182     ReadUnusedBytesFromFile(file, chunk_size - 2);
2183     return chunk_size_expected;
2184   }
2185
2186   for (i = 0; i < num_changed_custom_elements; i++)
2187   {
2188     int element = getFile16BitBE(file);
2189     int custom_target_element = getFile16BitBE(file);
2190
2191     if (IS_CUSTOM_ELEMENT(element))
2192       element_info[element].change->target_element = custom_target_element;
2193     else
2194       Error(ERR_WARN, "invalid custom element number %d", element);
2195   }
2196
2197   return chunk_size;
2198 }
2199
2200 static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level)
2201 {
2202   int num_changed_custom_elements = getFile16BitBE(file);
2203   int chunk_size_expected = LEVEL_CHUNK_CUS3_SIZE(num_changed_custom_elements);
2204   int i, j, x, y;
2205
2206   if (chunk_size_expected != chunk_size)
2207   {
2208     ReadUnusedBytesFromFile(file, chunk_size - 2);
2209     return chunk_size_expected;
2210   }
2211
2212   for (i = 0; i < num_changed_custom_elements; i++)
2213   {
2214     int element = getFile16BitBE(file);
2215     struct ElementInfo *ei = &element_info[element];
2216     unsigned int event_bits;
2217
2218     if (!IS_CUSTOM_ELEMENT(element))
2219     {
2220       Error(ERR_WARN, "invalid custom element number %d", element);
2221
2222       element = EL_INTERNAL_DUMMY;
2223     }
2224
2225     for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++)
2226       ei->description[j] = getFile8Bit(file);
2227     ei->description[MAX_ELEMENT_NAME_LEN] = 0;
2228
2229 #if 1
2230     ei->properties[EP_BITFIELD_BASE_NR] = getFile32BitBE(file);
2231 #else
2232     Properties[element][EP_BITFIELD_BASE_NR] = getFile32BitBE(file);
2233 #endif
2234
2235     /* some free bytes for future properties and padding */
2236     ReadUnusedBytesFromFile(file, 7);
2237
2238     ei->use_gfx_element = getFile8Bit(file);
2239     ei->gfx_element = getMappedElement(getFile16BitBE(file));
2240
2241     ei->collect_score_initial = getFile8Bit(file);
2242     ei->collect_count_initial = getFile8Bit(file);
2243
2244     ei->push_delay_fixed = getFile16BitBE(file);
2245     ei->push_delay_random = getFile16BitBE(file);
2246     ei->move_delay_fixed = getFile16BitBE(file);
2247     ei->move_delay_random = getFile16BitBE(file);
2248
2249     ei->move_pattern = getFile16BitBE(file);
2250     ei->move_direction_initial = getFile8Bit(file);
2251     ei->move_stepsize = getFile8Bit(file);
2252
2253     for (y = 0; y < 3; y++)
2254       for (x = 0; x < 3; x++)
2255         ei->content.e[x][y] = getMappedElement(getFile16BitBE(file));
2256
2257     event_bits = getFile32BitBE(file);
2258     for (j = 0; j < NUM_CHANGE_EVENTS; j++)
2259       if (event_bits & (1 << j))
2260         ei->change->has_event[j] = TRUE;
2261
2262     ei->change->target_element = getMappedElement(getFile16BitBE(file));
2263
2264     ei->change->delay_fixed = getFile16BitBE(file);
2265     ei->change->delay_random = getFile16BitBE(file);
2266     ei->change->delay_frames = getFile16BitBE(file);
2267
2268     ei->change->trigger_element = getMappedElement(getFile16BitBE(file));
2269
2270     ei->change->explode = getFile8Bit(file);
2271     ei->change->use_target_content = getFile8Bit(file);
2272     ei->change->only_if_complete = getFile8Bit(file);
2273     ei->change->use_random_replace = getFile8Bit(file);
2274
2275     ei->change->random_percentage = getFile8Bit(file);
2276     ei->change->replace_when = getFile8Bit(file);
2277
2278     for (y = 0; y < 3; y++)
2279       for (x = 0; x < 3; x++)
2280         ei->change->target_content.e[x][y] =
2281           getMappedElement(getFile16BitBE(file));
2282
2283     ei->slippery_type = getFile8Bit(file);
2284
2285     /* some free bytes for future properties and padding */
2286     ReadUnusedBytesFromFile(file, LEVEL_CPART_CUS3_UNUSED);
2287
2288     /* mark that this custom element has been modified */
2289     ei->modified_settings = TRUE;
2290   }
2291
2292   return chunk_size;
2293 }
2294
2295 static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
2296 {
2297   struct ElementInfo *ei;
2298   int chunk_size_expected;
2299   int element;
2300   int i, j, x, y;
2301
2302   /* ---------- custom element base property values (96 bytes) ------------- */
2303
2304   element = getFile16BitBE(file);
2305
2306   if (!IS_CUSTOM_ELEMENT(element))
2307   {
2308     Error(ERR_WARN, "invalid custom element number %d", element);
2309
2310     ReadUnusedBytesFromFile(file, chunk_size - 2);
2311     return chunk_size;
2312   }
2313
2314   ei = &element_info[element];
2315
2316   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
2317     ei->description[i] = getFile8Bit(file);
2318   ei->description[MAX_ELEMENT_NAME_LEN] = 0;
2319
2320 #if 1
2321   ei->properties[EP_BITFIELD_BASE_NR] = getFile32BitBE(file);
2322 #else
2323   Properties[element][EP_BITFIELD_BASE_NR] = getFile32BitBE(file);
2324 #endif
2325   ReadUnusedBytesFromFile(file, 4);     /* reserved for more base properties */
2326
2327   ei->num_change_pages = getFile8Bit(file);
2328
2329   chunk_size_expected = LEVEL_CHUNK_CUS4_SIZE(ei->num_change_pages);
2330   if (chunk_size_expected != chunk_size)
2331   {
2332     ReadUnusedBytesFromFile(file, chunk_size - 43);
2333     return chunk_size_expected;
2334   }
2335
2336   ei->ce_value_fixed_initial = getFile16BitBE(file);
2337   ei->ce_value_random_initial = getFile16BitBE(file);
2338   ei->use_last_ce_value = getFile8Bit(file);
2339
2340   ei->use_gfx_element = getFile8Bit(file);
2341   ei->gfx_element = getMappedElement(getFile16BitBE(file));
2342
2343   ei->collect_score_initial = getFile8Bit(file);
2344   ei->collect_count_initial = getFile8Bit(file);
2345
2346   ei->drop_delay_fixed = getFile8Bit(file);
2347   ei->push_delay_fixed = getFile8Bit(file);
2348   ei->drop_delay_random = getFile8Bit(file);
2349   ei->push_delay_random = getFile8Bit(file);
2350   ei->move_delay_fixed = getFile16BitBE(file);
2351   ei->move_delay_random = getFile16BitBE(file);
2352
2353   /* bits 0 - 15 of "move_pattern" ... */
2354   ei->move_pattern = getFile16BitBE(file);
2355   ei->move_direction_initial = getFile8Bit(file);
2356   ei->move_stepsize = getFile8Bit(file);
2357
2358   ei->slippery_type = getFile8Bit(file);
2359
2360   for (y = 0; y < 3; y++)
2361     for (x = 0; x < 3; x++)
2362       ei->content.e[x][y] = getMappedElement(getFile16BitBE(file));
2363
2364   ei->move_enter_element = getMappedElement(getFile16BitBE(file));
2365   ei->move_leave_element = getMappedElement(getFile16BitBE(file));
2366   ei->move_leave_type = getFile8Bit(file);
2367
2368   /* ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible) */
2369   ei->move_pattern |= (getFile16BitBE(file) << 16);
2370
2371   ei->access_direction = getFile8Bit(file);
2372
2373   ei->explosion_delay = getFile8Bit(file);
2374   ei->ignition_delay = getFile8Bit(file);
2375   ei->explosion_type = getFile8Bit(file);
2376
2377   /* some free bytes for future custom property values and padding */
2378   ReadUnusedBytesFromFile(file, 1);
2379
2380   /* ---------- change page property values (48 bytes) --------------------- */
2381
2382   setElementChangePages(ei, ei->num_change_pages);
2383
2384   for (i = 0; i < ei->num_change_pages; i++)
2385   {
2386     struct ElementChangeInfo *change = &ei->change_page[i];
2387     unsigned int event_bits;
2388
2389     /* always start with reliable default values */
2390     setElementChangeInfoToDefaults(change);
2391
2392     /* bits 0 - 31 of "has_event[]" ... */
2393     event_bits = getFile32BitBE(file);
2394     for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
2395       if (event_bits & (1 << j))
2396         change->has_event[j] = TRUE;
2397
2398     change->target_element = getMappedElement(getFile16BitBE(file));
2399
2400     change->delay_fixed = getFile16BitBE(file);
2401     change->delay_random = getFile16BitBE(file);
2402     change->delay_frames = getFile16BitBE(file);
2403
2404     change->trigger_element = getMappedElement(getFile16BitBE(file));
2405
2406     change->explode = getFile8Bit(file);
2407     change->use_target_content = getFile8Bit(file);
2408     change->only_if_complete = getFile8Bit(file);
2409     change->use_random_replace = getFile8Bit(file);
2410
2411     change->random_percentage = getFile8Bit(file);
2412     change->replace_when = getFile8Bit(file);
2413
2414     for (y = 0; y < 3; y++)
2415       for (x = 0; x < 3; x++)
2416         change->target_content.e[x][y]= getMappedElement(getFile16BitBE(file));
2417
2418     change->can_change = getFile8Bit(file);
2419
2420     change->trigger_side = getFile8Bit(file);
2421
2422     change->trigger_player = getFile8Bit(file);
2423     change->trigger_page = getFile8Bit(file);
2424
2425     change->trigger_page = (change->trigger_page == CH_PAGE_ANY_FILE ?
2426                             CH_PAGE_ANY : (1 << change->trigger_page));
2427
2428     change->has_action = getFile8Bit(file);
2429     change->action_type = getFile8Bit(file);
2430     change->action_mode = getFile8Bit(file);
2431     change->action_arg = getFile16BitBE(file);
2432
2433     /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */
2434     event_bits = getFile8Bit(file);
2435     for (j = 32; j < NUM_CHANGE_EVENTS; j++)
2436       if (event_bits & (1 << (j - 32)))
2437         change->has_event[j] = TRUE;
2438   }
2439
2440   /* mark this custom element as modified */
2441   ei->modified_settings = TRUE;
2442
2443   return chunk_size;
2444 }
2445
2446 static int LoadLevel_GRP1(FILE *file, int chunk_size, struct LevelInfo *level)
2447 {
2448   struct ElementInfo *ei;
2449   struct ElementGroupInfo *group;
2450   int element;
2451   int i;
2452
2453   element = getFile16BitBE(file);
2454
2455   if (!IS_GROUP_ELEMENT(element))
2456   {
2457     Error(ERR_WARN, "invalid group element number %d", element);
2458
2459     ReadUnusedBytesFromFile(file, chunk_size - 2);
2460     return chunk_size;
2461   }
2462
2463   ei = &element_info[element];
2464
2465   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
2466     ei->description[i] = getFile8Bit(file);
2467   ei->description[MAX_ELEMENT_NAME_LEN] = 0;
2468
2469   group = element_info[element].group;
2470
2471   group->num_elements = getFile8Bit(file);
2472
2473   ei->use_gfx_element = getFile8Bit(file);
2474   ei->gfx_element = getMappedElement(getFile16BitBE(file));
2475
2476   group->choice_mode = getFile8Bit(file);
2477
2478   /* some free bytes for future values and padding */
2479   ReadUnusedBytesFromFile(file, 3);
2480
2481   for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
2482     group->element[i] = getMappedElement(getFile16BitBE(file));
2483
2484   /* mark this group element as modified */
2485   element_info[element].modified_settings = TRUE;
2486
2487   return chunk_size;
2488 }
2489
2490 static int LoadLevel_MicroChunk(FILE *file, struct ElementFileConfig *config,
2491                                 int element)
2492 {
2493   int micro_chunk_size = 0;
2494   int conf_type = getFile8Bit(file);
2495   int byte_mask = conf_type & CONF_MASK_BYTES;
2496   boolean element_found = FALSE;
2497   int i;
2498
2499   micro_chunk_size += 1;
2500
2501   if (byte_mask == CONF_MASK_MULTI_BYTES)
2502   {
2503     int num_bytes = getFile16BitBE(file);
2504     byte *buffer = checked_malloc(num_bytes);
2505
2506 #if 0
2507     printf("::: - found multi bytes\n");
2508 #endif
2509
2510     ReadBytesFromFile(file, buffer, num_bytes);
2511
2512     for (i = 0; config[i].data_type != -1; i++)
2513     {
2514       if (config[i].element == element &&
2515           config[i].conf_type == conf_type)
2516       {
2517         int data_type = config[i].data_type;
2518         int num_entities = num_bytes / CONF_ENTITY_NUM_BYTES(data_type);
2519         int max_num_entities = config[i].max_num_entities;
2520
2521         if (num_entities > max_num_entities)
2522         {
2523           Error(ERR_WARN,
2524                 "truncating number of entities for element %d from %d to %d",
2525                 element, num_entities, max_num_entities);
2526
2527           num_entities = max_num_entities;
2528         }
2529
2530         *(int *)(config[i].num_entities) = num_entities;
2531
2532         element_found = TRUE;
2533
2534         if (data_type == TYPE_STRING)
2535         {
2536           char *string = (char *)(config[i].value);
2537           int j;
2538
2539           for (j = 0; j < max_num_entities; j++)
2540             string[j] = (j < num_entities ? buffer[j] : '\0');
2541         }
2542         else if (data_type == TYPE_ELEMENT_LIST)
2543         {
2544           int *element_array = (int *)(config[i].value);
2545           int j;
2546
2547           for (j = 0; j < num_entities; j++)
2548             element_array[j] =
2549               getMappedElement(CONF_ELEMENTS_ELEMENT(buffer, j));
2550         }
2551         else if (data_type == TYPE_CONTENT_LIST)
2552         {
2553           struct Content *content= (struct Content *)(config[i].value);
2554           int c, x, y;
2555
2556           for (c = 0; c < num_entities; c++)
2557             for (y = 0; y < 3; y++)
2558               for (x = 0; x < 3; x++)
2559                 content[c].e[x][y] =
2560                   getMappedElement(CONF_CONTENTS_ELEMENT(buffer, c, x, y));
2561         }
2562         else
2563           element_found = FALSE;
2564
2565         break;
2566       }
2567     }
2568
2569     checked_free(buffer);
2570
2571     micro_chunk_size += 2 + num_bytes;
2572   }
2573   else          /* constant size configuration data (1, 2 or 4 bytes) */
2574   {
2575     int value = (byte_mask == CONF_MASK_1_BYTE ? getFile8Bit   (file) :
2576                  byte_mask == CONF_MASK_2_BYTE ? getFile16BitBE(file) :
2577                  byte_mask == CONF_MASK_4_BYTE ? getFile32BitBE(file) : 0);
2578
2579 #if 0
2580     printf("::: - found single bytes\n");
2581 #endif
2582
2583     for (i = 0; config[i].data_type != -1; i++)
2584     {
2585       if (config[i].element == element &&
2586           config[i].conf_type == conf_type)
2587       {
2588         int data_type = config[i].data_type;
2589
2590         if (data_type == TYPE_BOOLEAN)
2591           *(boolean *)(config[i].value) = value;
2592         else
2593           *(int *)    (config[i].value) = value;
2594
2595         element_found = TRUE;
2596
2597         break;
2598       }
2599     }
2600
2601     micro_chunk_size += CONF_VALUE_NUM_BYTES(byte_mask);
2602   }
2603
2604   if (!element_found)
2605     Error(ERR_WARN, "cannot load micro chunk value for element %d", element);
2606
2607   return micro_chunk_size;
2608 }
2609
2610 static int LoadLevel_CONF(FILE *file, int chunk_size, struct LevelInfo *level)
2611 {
2612   int real_chunk_size = 0;
2613
2614 #if 1
2615   li = *level;          /* copy level data into temporary buffer */
2616 #endif
2617
2618   while (!feof(file))
2619   {
2620     int element = getFile16BitBE(file);
2621 #if 1
2622     real_chunk_size += 2;
2623     real_chunk_size += LoadLevel_MicroChunk(file, element_conf, element);
2624 #else
2625     int conf_type = getFile8Bit(file);
2626     int byte_mask = conf_type & CONF_MASK_BYTES;
2627     boolean element_found = FALSE;
2628     int i;
2629
2630     real_chunk_size += 3;
2631
2632 #if 0
2633     li = *level;        /* copy level data into temporary buffer */
2634 #endif
2635
2636     if (byte_mask == CONF_MASK_MULTI_BYTES)
2637     {
2638       int num_bytes = getFile16BitBE(file);
2639       byte *buffer = checked_malloc(num_bytes);
2640
2641       ReadBytesFromFile(file, buffer, num_bytes);
2642
2643       for (i = 0; element_conf[i].data_type != -1; i++)
2644       {
2645         if (element_conf[i].element == element &&
2646             element_conf[i].conf_type == conf_type)
2647         {
2648           int data_type = element_conf[i].data_type;
2649           int num_entities = num_bytes / CONF_ENTITY_NUM_BYTES(data_type);
2650           int max_num_entities = element_conf[i].max_num_entities;
2651
2652           if (num_entities > max_num_entities)
2653           {
2654             Error(ERR_WARN,
2655                   "truncating number of entities for element %d from %d to %d",
2656                   element, num_entities, max_num_entities);
2657
2658             num_entities = max_num_entities;
2659           }
2660
2661           *(int *)(element_conf[i].num_entities) = num_entities;
2662
2663           element_found = TRUE;
2664
2665           if (data_type == TYPE_ELEMENT_LIST)
2666           {
2667             int *element_array = (int *)(element_conf[i].value);
2668             int j;
2669
2670             for (j = 0; j < num_entities; j++)
2671               element_array[j] =
2672                 getMappedElement(CONF_ELEMENTS_ELEMENT(buffer, j));
2673           }
2674           else if (data_type == TYPE_CONTENT_LIST)
2675           {
2676             struct Content *content= (struct Content *)(element_conf[i].value);
2677             int c, x, y;
2678
2679             for (c = 0; c < num_entities; c++)
2680               for (y = 0; y < 3; y++)
2681                 for (x = 0; x < 3; x++)
2682                   content[c].e[x][y] =
2683                     getMappedElement(CONF_CONTENTS_ELEMENT(buffer, c, x, y));
2684           }
2685           else
2686             element_found = FALSE;
2687
2688           break;
2689         }
2690       }
2691
2692       checked_free(buffer);
2693
2694       real_chunk_size += 2 + num_bytes;
2695     }
2696     else        /* constant size configuration data (1, 2 or 4 bytes) */
2697     {
2698       int value = (byte_mask == CONF_MASK_1_BYTE ? getFile8Bit   (file) :
2699                    byte_mask == CONF_MASK_2_BYTE ? getFile16BitBE(file) :
2700                    byte_mask == CONF_MASK_4_BYTE ? getFile32BitBE(file) : 0);
2701
2702       for (i = 0; element_conf[i].data_type != -1; i++)
2703       {
2704         if (element_conf[i].element == element &&
2705             element_conf[i].conf_type == conf_type)
2706         {
2707           int data_type = element_conf[i].data_type;
2708
2709           if (data_type == TYPE_BOOLEAN)
2710             *(boolean *)(element_conf[i].value) = value;
2711           else
2712             *(int *)    (element_conf[i].value) = value;
2713
2714           element_found = TRUE;
2715
2716           break;
2717         }
2718       }
2719
2720       real_chunk_size += CONF_VALUE_NUM_BYTES(byte_mask);
2721     }
2722
2723     if (!element_found)
2724       Error(ERR_WARN, "cannot load CONF value for element %d", element);
2725 #endif
2726
2727 #if 0
2728     *level = li;        /* copy temporary buffer back to level data */
2729 #endif
2730
2731 #if 1
2732     if (real_chunk_size >= chunk_size)
2733       break;
2734 #else
2735     if (conf_type == CONF_LAST_ENTRY || real_chunk_size >= chunk_size)
2736       break;
2737 #endif
2738   }
2739
2740 #if 1
2741   *level = li;          /* copy temporary buffer back to level data */
2742 #endif
2743
2744   return real_chunk_size;
2745 }
2746
2747 static int LoadLevel_CUSX(FILE *file, int chunk_size, struct LevelInfo *level)
2748 {
2749   int element = getFile16BitBE(file);
2750   int real_chunk_size = 2;
2751   struct ElementInfo *ei = &element_info[element];
2752   int i;
2753
2754 #if 0
2755   printf("::: CUSX: loading element '%s' ...\n", EL_NAME(element));
2756 #endif
2757
2758   xx_ei = *ei;          /* copy element data into temporary buffer */
2759
2760   xx_ei.num_change_pages = -1;
2761
2762   while (!feof(file))
2763   {
2764     real_chunk_size += LoadLevel_MicroChunk(file, custom_element_conf, -1);
2765
2766 #if 0
2767     printf("::: - real_chunk_size now %d\n", real_chunk_size);
2768 #endif
2769
2770     if (xx_ei.num_change_pages != -1)
2771       break;
2772
2773     if (real_chunk_size >= chunk_size)
2774       break;
2775   }
2776
2777   *ei = xx_ei;
2778
2779   if (ei->num_change_pages == -1)
2780   {
2781     Error(ERR_WARN, "LoadLevel_CUSX(): missing 'num_change_pages' for '%s'",
2782           EL_NAME(element));
2783
2784     ei->num_change_pages = 1;
2785
2786     setElementChangePages(ei, 1);
2787     setElementChangeInfoToDefaults(ei->change);
2788
2789     return real_chunk_size;
2790   }
2791
2792   /* initialize number of change pages stored for this custom element */
2793   setElementChangePages(ei, ei->num_change_pages);
2794   for (i = 0; i < ei->num_change_pages; i++)
2795     setElementChangeInfoToDefaults(&ei->change_page[i]);
2796
2797   /* start with reading properties for the first change page */
2798   xx_current_change_page = 0;
2799
2800   while (!feof(file))
2801   {
2802     struct ElementChangeInfo *change = &ei->change_page[xx_current_change_page];
2803
2804     xx_change = *change;        /* copy change data into temporary buffer */
2805
2806     resetEventBits();           /* reset bits; change page might have changed */
2807
2808     real_chunk_size += LoadLevel_MicroChunk(file,custom_element_change_conf,-1);
2809
2810     *change = xx_change;
2811
2812     setEventFlagsFromEventBits(change);
2813
2814     if (real_chunk_size >= chunk_size)
2815       break;
2816   }
2817
2818   return real_chunk_size;
2819 }
2820
2821 static int LoadLevel_GRPX(FILE *file, int chunk_size, struct LevelInfo *level)
2822 {
2823   int element = getFile16BitBE(file);
2824   int real_chunk_size = 2;
2825   struct ElementInfo *ei = &element_info[element];
2826   struct ElementGroupInfo *group = ei->group;
2827
2828   xx_ei = *ei;          /* copy element data into temporary buffer */
2829   xx_group = *group;    /* copy group data into temporary buffer */
2830
2831   while (!feof(file))
2832   {
2833     real_chunk_size += LoadLevel_MicroChunk(file, group_element_conf, -1);
2834
2835     if (real_chunk_size >= chunk_size)
2836       break;
2837   }
2838
2839   *ei = xx_ei;
2840   *group = xx_group;
2841
2842   return real_chunk_size;
2843 }
2844
2845 static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
2846                                       struct LevelFileInfo *level_file_info)
2847 {
2848   char *filename = level_file_info->filename;
2849   char cookie[MAX_LINE_LEN];
2850   char chunk_name[CHUNK_ID_LEN + 1];
2851   int chunk_size;
2852   FILE *file;
2853
2854   if (!(file = fopen(filename, MODE_READ)))
2855   {
2856     level->no_valid_file = TRUE;
2857
2858     if (level != &level_template)
2859       Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
2860
2861     return;
2862   }
2863
2864   getFileChunkBE(file, chunk_name, NULL);
2865   if (strEqual(chunk_name, "RND1"))
2866   {
2867     getFile32BitBE(file);               /* not used */
2868
2869     getFileChunkBE(file, chunk_name, NULL);
2870     if (!strEqual(chunk_name, "CAVE"))
2871     {
2872       level->no_valid_file = TRUE;
2873
2874       Error(ERR_WARN, "unknown format of level file '%s'", filename);
2875       fclose(file);
2876       return;
2877     }
2878   }
2879   else  /* check for pre-2.0 file format with cookie string */
2880   {
2881     strcpy(cookie, chunk_name);
2882     fgets(&cookie[4], MAX_LINE_LEN - 4, file);
2883     if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
2884       cookie[strlen(cookie) - 1] = '\0';
2885
2886     if (!checkCookieString(cookie, LEVEL_COOKIE_TMPL))
2887     {
2888       level->no_valid_file = TRUE;
2889
2890       Error(ERR_WARN, "unknown format of level file '%s'", filename);
2891       fclose(file);
2892       return;
2893     }
2894
2895     if ((level->file_version = getFileVersionFromCookieString(cookie)) == -1)
2896     {
2897       level->no_valid_file = TRUE;
2898
2899       Error(ERR_WARN, "unsupported version of level file '%s'", filename);
2900       fclose(file);
2901       return;
2902     }
2903
2904     /* pre-2.0 level files have no game version, so use file version here */
2905     level->game_version = level->file_version;
2906   }
2907
2908   if (level->file_version < FILE_VERSION_1_2)
2909   {
2910     /* level files from versions before 1.2.0 without chunk structure */
2911     LoadLevel_HEAD(file, LEVEL_HEADER_SIZE,             level);
2912     LoadLevel_BODY(file, level->fieldx * level->fieldy, level);
2913   }
2914   else
2915   {
2916     static struct
2917     {
2918       char *name;
2919       int size;
2920       int (*loader)(FILE *, int, struct LevelInfo *);
2921     }
2922     chunk_info[] =
2923     {
2924       { "VERS", FILE_VERS_CHUNK_SIZE,   LoadLevel_VERS },
2925       { "HEAD", LEVEL_HEADER_SIZE,      LoadLevel_HEAD },
2926       { "AUTH", MAX_LEVEL_AUTHOR_LEN,   LoadLevel_AUTH },
2927       { "BODY", -1,                     LoadLevel_BODY },
2928       { "CONT", -1,                     LoadLevel_CONT },
2929       { "CNT2", LEVEL_CHUNK_CNT2_SIZE,  LoadLevel_CNT2 },
2930       { "CNT3", -1,                     LoadLevel_CNT3 },
2931       { "CUS1", -1,                     LoadLevel_CUS1 },
2932       { "CUS2", -1,                     LoadLevel_CUS2 },
2933       { "CUS3", -1,                     LoadLevel_CUS3 },
2934       { "CUS4", -1,                     LoadLevel_CUS4 },
2935       { "GRP1", -1,                     LoadLevel_GRP1 },
2936       { "CONF", -1,                     LoadLevel_CONF },
2937 #if 1
2938       { "CUSX", -1,                     LoadLevel_CUSX },
2939       { "GRPX", -1,                     LoadLevel_GRPX },
2940 #endif
2941
2942       {  NULL,  0,                      NULL }
2943     };
2944
2945     while (getFileChunkBE(file, chunk_name, &chunk_size))
2946     {
2947       int i = 0;
2948
2949       while (chunk_info[i].name != NULL &&
2950              !strEqual(chunk_name, chunk_info[i].name))
2951         i++;
2952
2953       if (chunk_info[i].name == NULL)
2954       {
2955         Error(ERR_WARN, "unknown chunk '%s' in level file '%s'",
2956               chunk_name, filename);
2957         ReadUnusedBytesFromFile(file, chunk_size);
2958       }
2959       else if (chunk_info[i].size != -1 &&
2960                chunk_info[i].size != chunk_size)
2961       {
2962         Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
2963               chunk_size, chunk_name, filename);
2964         ReadUnusedBytesFromFile(file, chunk_size);
2965       }
2966       else
2967       {
2968         /* call function to load this level chunk */
2969         int chunk_size_expected =
2970           (chunk_info[i].loader)(file, chunk_size, level);
2971
2972         /* the size of some chunks cannot be checked before reading other
2973            chunks first (like "HEAD" and "BODY") that contain some header
2974            information, so check them here */
2975         if (chunk_size_expected != chunk_size)
2976         {
2977           Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
2978                 chunk_size, chunk_name, filename);
2979         }
2980       }
2981     }
2982   }
2983
2984   fclose(file);
2985 }
2986
2987 /* ------------------------------------------------------------------------- */
2988 /* functions for loading EM level                                            */
2989 /* ------------------------------------------------------------------------- */
2990
2991 #if 0
2992
2993 static int map_em_element_yam(int element)
2994 {
2995   switch (element)
2996   {
2997     case 0x00:  return EL_EMPTY;
2998     case 0x01:  return EL_EMERALD;
2999     case 0x02:  return EL_DIAMOND;
3000     case 0x03:  return EL_ROCK;
3001     case 0x04:  return EL_ROBOT;
3002     case 0x05:  return EL_SPACESHIP_UP;
3003     case 0x06:  return EL_BOMB;
3004     case 0x07:  return EL_BUG_UP;
3005     case 0x08:  return EL_AMOEBA_DROP;
3006     case 0x09:  return EL_NUT;
3007     case 0x0a:  return EL_YAMYAM;
3008     case 0x0b:  return EL_QUICKSAND_FULL;
3009     case 0x0c:  return EL_SAND;
3010     case 0x0d:  return EL_WALL_SLIPPERY;
3011     case 0x0e:  return EL_STEELWALL;
3012     case 0x0f:  return EL_WALL;
3013     case 0x10:  return EL_EM_KEY_1;
3014     case 0x11:  return EL_EM_KEY_2;
3015     case 0x12:  return EL_EM_KEY_4;
3016     case 0x13:  return EL_EM_KEY_3;
3017     case 0x14:  return EL_MAGIC_WALL;
3018     case 0x15:  return EL_ROBOT_WHEEL;
3019     case 0x16:  return EL_DYNAMITE;
3020
3021     case 0x17:  return EL_EM_KEY_1;                     /* EMC */
3022     case 0x18:  return EL_BUG_UP;                       /* EMC */
3023     case 0x1a:  return EL_DIAMOND;                      /* EMC */
3024     case 0x1b:  return EL_EMERALD;                      /* EMC */
3025     case 0x25:  return EL_NUT;                          /* EMC */
3026     case 0x80:  return EL_EMPTY;                        /* EMC */
3027     case 0x85:  return EL_EM_KEY_1;                     /* EMC */
3028     case 0x86:  return EL_EM_KEY_2;                     /* EMC */
3029     case 0x87:  return EL_EM_KEY_4;                     /* EMC */
3030     case 0x88:  return EL_EM_KEY_3;                     /* EMC */
3031     case 0x94:  return EL_QUICKSAND_EMPTY;              /* EMC */
3032     case 0x9a:  return EL_AMOEBA_WET;                   /* EMC */
3033     case 0xaf:  return EL_DYNAMITE;                     /* EMC */
3034     case 0xbd:  return EL_SAND;                         /* EMC */
3035
3036     default:
3037       Error(ERR_WARN, "invalid level element %d", element);
3038       return EL_UNKNOWN;
3039   }
3040 }
3041
3042 static int map_em_element_field(int element)
3043 {
3044   if (element >= 0xc8 && element <= 0xe1)
3045     return EL_CHAR_A + (element - 0xc8);
3046   else if (element >= 0xe2 && element <= 0xeb)
3047     return EL_CHAR_0 + (element - 0xe2);
3048
3049   switch (element)
3050   {
3051     case 0x00:  return EL_ROCK;
3052     case 0x01:  return EL_ROCK;                         /* EMC */
3053     case 0x02:  return EL_DIAMOND;
3054     case 0x03:  return EL_DIAMOND;
3055     case 0x04:  return EL_ROBOT;
3056     case 0x05:  return EL_ROBOT;                        /* EMC */
3057     case 0x06:  return EL_EMPTY_SPACE;                  /* EMC */
3058     case 0x07:  return EL_EMPTY_SPACE;                  /* EMC */
3059     case 0x08:  return EL_SPACESHIP_UP;
3060     case 0x09:  return EL_SPACESHIP_RIGHT;
3061     case 0x0a:  return EL_SPACESHIP_DOWN;
3062     case 0x0b:  return EL_SPACESHIP_LEFT;
3063     case 0x0c:  return EL_SPACESHIP_UP;
3064     case 0x0d:  return EL_SPACESHIP_RIGHT;
3065     case 0x0e:  return EL_SPACESHIP_DOWN;
3066     case 0x0f:  return EL_SPACESHIP_LEFT;
3067
3068     case 0x10:  return EL_BOMB;
3069     case 0x11:  return EL_BOMB;                         /* EMC */
3070     case 0x12:  return EL_EMERALD;
3071     case 0x13:  return EL_EMERALD;
3072     case 0x14:  return EL_BUG_UP;
3073     case 0x15:  return EL_BUG_RIGHT;
3074     case 0x16:  return EL_BUG_DOWN;
3075     case 0x17:  return EL_BUG_LEFT;
3076     case 0x18:  return EL_BUG_UP;
3077     case 0x19:  return EL_BUG_RIGHT;
3078     case 0x1a:  return EL_BUG_DOWN;
3079     case 0x1b:  return EL_BUG_LEFT;
3080     case 0x1c:  return EL_AMOEBA_DROP;
3081     case 0x1d:  return EL_AMOEBA_DROP;                  /* EMC */
3082     case 0x1e:  return EL_AMOEBA_DROP;                  /* EMC */
3083     case 0x1f:  return EL_AMOEBA_DROP;                  /* EMC */
3084
3085     case 0x20:  return EL_ROCK;
3086     case 0x21:  return EL_BOMB;                         /* EMC */
3087     case 0x22:  return EL_DIAMOND;                      /* EMC */
3088     case 0x23:  return EL_EMERALD;                      /* EMC */
3089     case 0x24:  return EL_MAGIC_WALL;
3090     case 0x25:  return EL_NUT;
3091     case 0x26:  return EL_NUT;                          /* EMC */
3092     case 0x27:  return EL_NUT;                          /* EMC */
3093
3094       /* looks like magic wheel, but is _always_ activated */
3095     case 0x28:  return EL_ROBOT_WHEEL;                  /* EMC */
3096
3097     case 0x29:  return EL_YAMYAM;       /* up */
3098     case 0x2a:  return EL_YAMYAM;       /* down */
3099     case 0x2b:  return EL_YAMYAM;       /* left */      /* EMC */
3100     case 0x2c:  return EL_YAMYAM;       /* right */     /* EMC */
3101     case 0x2d:  return EL_QUICKSAND_FULL;
3102     case 0x2e:  return EL_EMPTY_SPACE;                  /* EMC */
3103     case 0x2f:  return EL_EMPTY_SPACE;                  /* EMC */
3104
3105     case 0x30:  return EL_EMPTY_SPACE;                  /* EMC */
3106     case 0x31:  return EL_SAND;                         /* EMC */
3107     case 0x32:  return EL_SAND;                         /* EMC */
3108     case 0x33:  return EL_SAND;                         /* EMC */
3109     case 0x34:  return EL_QUICKSAND_FULL;               /* EMC */
3110     case 0x35:  return EL_QUICKSAND_FULL;               /* EMC */
3111     case 0x36:  return EL_QUICKSAND_FULL;               /* EMC */
3112     case 0x37:  return EL_SAND;                         /* EMC */
3113     case 0x38:  return EL_ROCK;                         /* EMC */
3114     case 0x39:  return EL_EXPANDABLE_WALL_HORIZONTAL;   /* EMC */
3115     case 0x3a:  return EL_EXPANDABLE_WALL_VERTICAL;     /* EMC */
3116     case 0x3b:  return EL_DYNAMITE_ACTIVE;      /* 1 */
3117     case 0x3c:  return EL_DYNAMITE_ACTIVE;      /* 2 */
3118     case 0x3d:  return EL_DYNAMITE_ACTIVE;      /* 3 */
3119     case 0x3e:  return EL_DYNAMITE_ACTIVE;      /* 4 */
3120     case 0x3f:  return EL_ACID_POOL_BOTTOM;
3121
3122     case 0x40:  return EL_EXIT_OPEN;    /* 1 */
3123     case 0x41:  return EL_EXIT_OPEN;    /* 2 */
3124     case 0x42:  return EL_EXIT_OPEN;    /* 3 */
3125     case 0x43:  return EL_BALLOON;                      /* EMC */
3126     case 0x44:  return EL_UNKNOWN;                      /* EMC ("plant") */
3127     case 0x45:  return EL_SPRING;                       /* EMC */
3128     case 0x46:  return EL_SPRING;       /* falling */   /* EMC */
3129     case 0x47:  return EL_SPRING;       /* left */      /* EMC */
3130     case 0x48:  return EL_SPRING;       /* right */     /* EMC */
3131     case 0x49:  return EL_UNKNOWN;                      /* EMC ("ball 1") */
3132     case 0x4a:  return EL_UNKNOWN;                      /* EMC ("ball 2") */
3133     case 0x4b:  return EL_UNKNOWN;                      /* EMC ("android") */
3134     case 0x4c:  return EL_EMPTY_SPACE;                  /* EMC */
3135     case 0x4d:  return EL_UNKNOWN;                      /* EMC ("android") */
3136     case 0x4e:  return EL_INVISIBLE_WALL;               /* EMC (? "android") */
3137     case 0x4f:  return EL_UNKNOWN;                      /* EMC ("android") */
3138
3139     case 0x50:  return EL_UNKNOWN;                      /* EMC ("android") */
3140     case 0x51:  return EL_UNKNOWN;                      /* EMC ("android") */
3141     case 0x52:  return EL_UNKNOWN;                      /* EMC ("android") */
3142     case 0x53:  return EL_UNKNOWN;                      /* EMC ("android") */
3143     case 0x54:  return EL_UNKNOWN;                      /* EMC ("android") */
3144     case 0x55:  return EL_EMPTY_SPACE;                  /* EMC */
3145     case 0x56:  return EL_EMPTY_SPACE;                  /* EMC */
3146     case 0x57:  return EL_EMPTY_SPACE;                  /* EMC */
3147     case 0x58:  return EL_EMPTY_SPACE;                  /* EMC */
3148     case 0x59:  return EL_EMPTY_SPACE;                  /* EMC */
3149     case 0x5a:  return EL_EMPTY_SPACE;                  /* EMC */
3150     case 0x5b:  return EL_EMPTY_SPACE;                  /* EMC */
3151     case 0x5c:  return EL_EMPTY_SPACE;                  /* EMC */
3152     case 0x5d:  return EL_EMPTY_SPACE;                  /* EMC */
3153     case 0x5e:  return EL_EMPTY_SPACE;                  /* EMC */
3154     case 0x5f:  return EL_EMPTY_SPACE;                  /* EMC */
3155
3156     case 0x60:  return EL_EMPTY_SPACE;                  /* EMC */
3157     case 0x61:  return EL_EMPTY_SPACE;                  /* EMC */
3158     case 0x62:  return EL_EMPTY_SPACE;                  /* EMC */
3159     case 0x63:  return EL_SPRING;       /* left */      /* EMC */
3160     case 0x64:  return EL_SPRING;       /* right */     /* EMC */
3161     case 0x65:  return EL_ACID;         /* 1 */         /* EMC */
3162     case 0x66:  return EL_ACID;         /* 2 */         /* EMC */
3163     case 0x67:  return EL_ACID;         /* 3 */         /* EMC */
3164     case 0x68:  return EL_ACID;         /* 4 */         /* EMC */
3165     case 0x69:  return EL_ACID;         /* 5 */         /* EMC */
3166     case 0x6a:  return EL_ACID;         /* 6 */         /* EMC */
3167     case 0x6b:  return EL_ACID;         /* 7 */         /* EMC */
3168     case 0x6c:  return EL_ACID;         /* 8 */         /* EMC */
3169     case 0x6d:  return EL_EMPTY_SPACE;                  /* EMC */
3170     case 0x6e:  return EL_EMPTY_SPACE;                  /* EMC */
3171     case 0x6f:  return EL_EMPTY_SPACE;                  /* EMC */
3172
3173     case 0x70:  return EL_EMPTY_SPACE;                  /* EMC */
3174     case 0x71:  return EL_EMPTY_SPACE;                  /* EMC */
3175     case 0x72:  return EL_NUT;          /* left */      /* EMC */
3176     case 0x73:  return EL_SAND;                         /* EMC (? "nut") */
3177     case 0x74:  return EL_STEELWALL;
3178     case 0x75:  return EL_EMPTY_SPACE;                  /* EMC */
3179     case 0x76:  return EL_EMPTY_SPACE;                  /* EMC */
3180     case 0x77:  return EL_BOMB;         /* left */      /* EMC */
3181     case 0x78:  return EL_BOMB;         /* right */     /* EMC */
3182     case 0x79:  return EL_ROCK;         /* left */      /* EMC */
3183     case 0x7a:  return EL_ROCK;         /* right */     /* EMC */
3184     case 0x7b:  return EL_ACID;                         /* (? EMC "blank") */
3185     case 0x7c:  return EL_EMPTY_SPACE;                  /* EMC */
3186     case 0x7d:  return EL_EMPTY_SPACE;                  /* EMC */
3187     case 0x7e:  return EL_EMPTY_SPACE;                  /* EMC */
3188     case 0x7f:  return EL_EMPTY_SPACE;                  /* EMC */
3189
3190     case 0x80:  return EL_EMPTY;
3191     case 0x81:  return EL_WALL_SLIPPERY;
3192     case 0x82:  return EL_SAND;
3193     case 0x83:  return EL_STEELWALL;
3194     case 0x84:  return EL_WALL;
3195     case 0x85:  return EL_EM_KEY_1;
3196     case 0x86:  return EL_EM_KEY_2;
3197     case 0x87:  return EL_EM_KEY_4;
3198     case 0x88:  return EL_EM_KEY_3;
3199     case 0x89:  return EL_EM_GATE_1;
3200     case 0x8a:  return EL_EM_GATE_2;
3201     case 0x8b:  return EL_EM_GATE_4;
3202     case 0x8c:  return EL_EM_GATE_3;
3203     case 0x8d:  return EL_INVISIBLE_WALL;               /* EMC (? "dripper") */
3204     case 0x8e:  return EL_EM_GATE_1_GRAY;
3205     case 0x8f:  return EL_EM_GATE_2_GRAY;
3206
3207     case 0x90:  return EL_EM_GATE_4_GRAY;
3208     case 0x91:  return EL_EM_GATE_3_GRAY;
3209     case 0x92:  return EL_MAGIC_WALL;
3210     case 0x93:  return EL_ROBOT_WHEEL;
3211     case 0x94:  return EL_QUICKSAND_EMPTY;              /* (? EMC "sand") */
3212     case 0x95:  return EL_ACID_POOL_TOPLEFT;
3213     case 0x96:  return EL_ACID_POOL_TOPRIGHT;
3214     case 0x97:  return EL_ACID_POOL_BOTTOMLEFT;
3215     case 0x98:  return EL_ACID_POOL_BOTTOMRIGHT;
3216     case 0x99:  return EL_ACID;                 /* (? EMC "fake blank") */
3217     case 0x9a:  return EL_AMOEBA_DEAD;          /* 1 */
3218     case 0x9b:  return EL_AMOEBA_DEAD;          /* 2 */
3219     case 0x9c:  return EL_AMOEBA_DEAD;          /* 3 */
3220     case 0x9d:  return EL_AMOEBA_DEAD;          /* 4 */
3221     case 0x9e:  return EL_EXIT_CLOSED;
3222     case 0x9f:  return EL_CHAR_LESS;            /* arrow left */
3223
3224       /* looks like normal sand, but behaves like wall */
3225     case 0xa0:  return EL_UNKNOWN;              /* EMC ("fake grass") */
3226     case 0xa1:  return EL_UNKNOWN;              /* EMC ("lenses") */
3227     case 0xa2:  return EL_UNKNOWN;              /* EMC ("magnify") */
3228     case 0xa3:  return EL_UNKNOWN;              /* EMC ("fake blank") */
3229     case 0xa4:  return EL_UNKNOWN;              /* EMC ("fake grass") */
3230     case 0xa5:  return EL_UNKNOWN;              /* EMC ("switch") */
3231     case 0xa6:  return EL_UNKNOWN;              /* EMC ("switch") */
3232     case 0xa7:  return EL_EMPTY_SPACE;                  /* EMC */
3233     case 0xa8:  return EL_EMC_WALL_1;                   /* EMC ("decor 8") */
3234     case 0xa9:  return EL_EMC_WALL_2;                   /* EMC ("decor 9") */
3235     case 0xaa:  return EL_EMC_WALL_3;                   /* EMC ("decor 10") */
3236     case 0xab:  return EL_EMC_WALL_7;                   /* EMC ("decor 5") */
3237     case 0xac:  return EL_CHAR_COMMA;                   /* EMC */
3238     case 0xad:  return EL_CHAR_QUOTEDBL;                /* EMC */
3239     case 0xae:  return EL_CHAR_MINUS;                   /* EMC */
3240     case 0xaf:  return EL_DYNAMITE;
3241
3242     case 0xb0:  return EL_EMC_STEELWALL_1;              /* EMC ("steel 3") */
3243     case 0xb1:  return EL_EMC_WALL_8;                   /* EMC ("decor 6") */
3244     case 0xb2:  return EL_UNKNOWN;                      /* EMC ("decor 7") */
3245     case 0xb3:  return EL_STEELWALL;            /* 2 */ /* EMC */
3246     case 0xb4:  return EL_WALL_SLIPPERY;        /* 2 */ /* EMC */
3247     case 0xb5:  return EL_EMC_WALL_6;                   /* EMC ("decor 2") */
3248     case 0xb6:  return EL_EMC_WALL_5;                   /* EMC ("decor 4") */
3249     case 0xb7:  return EL_EMC_WALL_4;                   /* EMC ("decor 3") */
3250     case 0xb8:  return EL_BALLOON_SWITCH_ANY;           /* EMC */
3251     case 0xb9:  return EL_BALLOON_SWITCH_RIGHT;         /* EMC */
3252     case 0xba:  return EL_BALLOON_SWITCH_DOWN;          /* EMC */
3253     case 0xbb:  return EL_BALLOON_SWITCH_LEFT;          /* EMC */
3254     case 0xbc:  return EL_BALLOON_SWITCH_UP;            /* EMC */
3255     case 0xbd:  return EL_SAND;                         /* EMC ("dirt") */
3256     case 0xbe:  return EL_UNKNOWN;                      /* EMC ("plant") */
3257     case 0xbf:  return EL_UNKNOWN;                      /* EMC ("key 5") */
3258
3259     case 0xc0:  return EL_UNKNOWN;                      /* EMC ("key 6") */
3260     case 0xc1:  return EL_UNKNOWN;                      /* EMC ("key 7") */
3261     case 0xc2:  return EL_UNKNOWN;                      /* EMC ("key 8") */
3262     case 0xc3:  return EL_UNKNOWN;                      /* EMC ("door 5") */
3263     case 0xc4:  return EL_UNKNOWN;                      /* EMC ("door 6") */
3264     case 0xc5:  return EL_UNKNOWN;                      /* EMC ("door 7") */
3265     case 0xc6:  return EL_UNKNOWN;                      /* EMC ("door 8") */
3266     case 0xc7:  return EL_UNKNOWN;                      /* EMC ("bumper") */
3267
3268       /* characters: see above */
3269
3270     case 0xec:  return EL_CHAR_PERIOD;
3271     case 0xed:  return EL_CHAR_EXCLAM;
3272     case 0xee:  return EL_CHAR_COLON;
3273     case 0xef:  return EL_CHAR_QUESTION;
3274
3275     case 0xf0:  return EL_CHAR_GREATER;                 /* arrow right */
3276     case 0xf1:  return EL_CHAR_COPYRIGHT;               /* EMC: "decor 1" */
3277     case 0xf2:  return EL_UNKNOWN;              /* EMC ("fake door 5") */
3278     case 0xf3:  return EL_UNKNOWN;              /* EMC ("fake door 6") */
3279     case 0xf4:  return EL_UNKNOWN;              /* EMC ("fake door 7") */
3280     case 0xf5:  return EL_UNKNOWN;              /* EMC ("fake door 8") */
3281     case 0xf6:  return EL_EMPTY_SPACE;                  /* EMC */
3282     case 0xf7:  return EL_EMPTY_SPACE;                  /* EMC */
3283
3284     case 0xf8:  return EL_EMPTY_SPACE;                  /* EMC */
3285     case 0xf9:  return EL_EMPTY_SPACE;                  /* EMC */
3286     case 0xfa:  return EL_EMPTY_SPACE;                  /* EMC */
3287     case 0xfb:  return EL_EMPTY_SPACE;                  /* EMC */
3288     case 0xfc:  return EL_EMPTY_SPACE;                  /* EMC */
3289     case 0xfd:  return EL_EMPTY_SPACE;                  /* EMC */
3290
3291     case 0xfe:  return EL_PLAYER_1;                     /* EMC: "blank" */
3292     case 0xff:  return EL_PLAYER_2;                     /* EMC: "blank" */
3293
3294     default:
3295       /* should never happen (all 8-bit value cases should be handled) */
3296       Error(ERR_WARN, "invalid level element %d", element);
3297       return EL_UNKNOWN;
3298   }
3299 }
3300
3301 #define EM_LEVEL_SIZE                   2106
3302 #define EM_LEVEL_XSIZE                  64
3303 #define EM_LEVEL_YSIZE                  32
3304
3305 static void OLD_LoadLevelFromFileInfo_EM(struct LevelInfo *level,
3306                                          struct LevelFileInfo *level_file_info)
3307 {
3308   char *filename = level_file_info->filename;
3309   FILE *file;
3310   unsigned char leveldata[EM_LEVEL_SIZE];
3311   unsigned char *header = &leveldata[EM_LEVEL_XSIZE * EM_LEVEL_YSIZE];
3312   int nr = level_file_info->nr;
3313   int i, x, y;
3314
3315   if (!(file = fopen(filename, MODE_READ)))
3316   {
3317     level->no_valid_file = TRUE;
3318
3319     Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
3320
3321     return;
3322   }
3323
3324   for (i = 0; i < EM_LEVEL_SIZE; i++)
3325     leveldata[i] = fgetc(file);
3326
3327   fclose(file);
3328
3329   /* check if level data is crypted by testing against known starting bytes
3330      of the few existing crypted level files (from Emerald Mine 1 + 2) */
3331
3332   if ((leveldata[0] == 0xf1 ||
3333        leveldata[0] == 0xf5) && leveldata[2] == 0xe7 && leveldata[3] == 0xee)
3334   {
3335     unsigned char code0 = 0x65;
3336     unsigned char code1 = 0x11;
3337
3338     if (leveldata[0] == 0xf5)   /* error in crypted Emerald Mine 2 levels */
3339       leveldata[0] = 0xf1;
3340
3341     /* decode crypted level data */
3342
3343     for (i = 0; i < EM_LEVEL_SIZE; i++)
3344     {
3345       leveldata[i] ^= code0;
3346       leveldata[i] -= code1;
3347
3348       code0 = (code0 + 7) & 0xff;
3349     }
3350   }
3351
3352   level->fieldx = EM_LEVEL_XSIZE;
3353   level->fieldy = EM_LEVEL_YSIZE;
3354
3355   level->time           = header[46] * 10;
3356   level->gems_needed    = header[47];
3357
3358   /* The original Emerald Mine levels have their level number stored
3359      at the second byte of the level file...
3360      Do not trust this information at other level files, e.g. EMC,
3361      but correct it anyway (normally the first row is completely
3362      steel wall, so the correction does not hurt anyway). */
3363
3364   if (leveldata[1] == nr)
3365     leveldata[1] = leveldata[2];        /* correct level number field */
3366
3367   sprintf(level->name, "Level %d", nr);         /* set level name */
3368
3369   level->score[SC_EMERALD]      = header[36];
3370   level->score[SC_DIAMOND]      = header[37];
3371   level->score[SC_ROBOT]        = header[38];
3372   level->score[SC_SPACESHIP]    = header[39];
3373   level->score[SC_BUG]          = header[40];
3374   level->score[SC_YAMYAM]       = header[41];
3375   level->score[SC_NUT]          = header[42];
3376   level->score[SC_DYNAMITE]     = header[43];
3377   level->score[SC_TIME_BONUS]   = header[44];
3378
3379   level->num_yamyam_contents = 4;
3380
3381   for (i = 0; i < level->num_yamyam_contents; i++)
3382     for (y = 0; y < 3; y++)
3383       for (x = 0; x < 3; x++)
3384         level->yamyam_content[i].e[x][y] =
3385           map_em_element_yam(header[i * 9 + y * 3 + x]);
3386
3387   level->amoeba_speed           = (header[52] * 256 + header[53]) % 256;
3388   level->time_magic_wall        = (header[54] * 256 + header[55]) * 16 / 100;
3389   level->time_wheel             = (header[56] * 256 + header[57]) * 16 / 100;
3390   level->amoeba_content         = EL_DIAMOND;
3391
3392   for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
3393   {
3394     int new_element = map_em_element_field(leveldata[y * EM_LEVEL_XSIZE + x]);
3395
3396     if (new_element == EL_AMOEBA_DEAD && level->amoeba_speed)
3397       new_element = EL_AMOEBA_WET;
3398
3399     level->field[x][y] = new_element;
3400   }
3401
3402   x = (header[48] * 256 + header[49]) % EM_LEVEL_XSIZE;
3403   y = (header[48] * 256 + header[49]) / EM_LEVEL_XSIZE;
3404   level->field[x][y] = EL_PLAYER_1;
3405
3406   x = (header[50] * 256 + header[51]) % EM_LEVEL_XSIZE;
3407   y = (header[50] * 256 + header[51]) / EM_LEVEL_XSIZE;
3408   level->field[x][y] = EL_PLAYER_2;
3409 }
3410
3411 #endif
3412
3413 void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
3414 {
3415   static int ball_xy[8][2] =
3416   {
3417     { 0, 0 },
3418     { 1, 0 },
3419     { 2, 0 },
3420     { 0, 1 },
3421     { 2, 1 },
3422     { 0, 2 },
3423     { 1, 2 },
3424     { 2, 2 },
3425   };
3426   struct LevelInfo_EM *level_em = level->native_em_level;
3427   struct LEVEL *lev = level_em->lev;
3428   struct PLAYER **ply = level_em->ply;
3429   int i, j, x, y;
3430
3431 #if 0
3432   printf("::: A\n");
3433   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3434     for (j = 0; j < 8; j++)
3435       printf("::: ball %d, %d: %d\n", i, j,
3436              level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
3437 #endif
3438
3439   lev->width  = MIN(level->fieldx, EM_MAX_CAVE_WIDTH);
3440   lev->height = MIN(level->fieldy, EM_MAX_CAVE_HEIGHT);
3441
3442   lev->time_seconds     = level->time;
3443   lev->required_initial = level->gems_needed;
3444
3445   lev->emerald_score    = level->score[SC_EMERALD];
3446   lev->diamond_score    = level->score[SC_DIAMOND];
3447   lev->alien_score      = level->score[SC_ROBOT];
3448   lev->tank_score       = level->score[SC_SPACESHIP];
3449   lev->bug_score        = level->score[SC_BUG];
3450   lev->eater_score      = level->score[SC_YAMYAM];
3451   lev->nut_score        = level->score[SC_NUT];
3452   lev->dynamite_score   = level->score[SC_DYNAMITE];
3453   lev->key_score        = level->score[SC_KEY];
3454   lev->exit_score       = level->score[SC_TIME_BONUS];
3455
3456   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3457     for (y = 0; y < 3; y++)
3458       for (x = 0; x < 3; x++)
3459         lev->eater_array[i][y * 3 + x] =
3460           map_element_RND_to_EM(level->yamyam_content[i].e[x][y]);
3461
3462   lev->amoeba_time              = level->amoeba_speed;
3463   lev->wonderwall_time_initial  = level->time_magic_wall;
3464   lev->wheel_time               = level->time_wheel;
3465
3466   lev->android_move_time        = level->android_move_time;
3467   lev->android_clone_time       = level->android_clone_time;
3468   lev->ball_random              = level->ball_random;
3469   lev->ball_state_initial       = level->ball_state_initial;
3470   lev->ball_time                = level->ball_time;
3471   lev->num_ball_arrays          = level->num_ball_contents;
3472
3473   lev->lenses_score             = level->lenses_score;
3474   lev->magnify_score            = level->magnify_score;
3475   lev->slurp_score              = level->slurp_score;
3476
3477   lev->lenses_time              = level->lenses_time;
3478   lev->magnify_time             = level->magnify_time;
3479
3480   lev->wind_direction_initial =
3481     map_direction_RND_to_EM(level->wind_direction_initial);
3482   lev->wind_cnt_initial = (level->wind_direction_initial != MV_NONE ?
3483                            lev->wind_time : 0);
3484
3485   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3486     for (j = 0; j < 8; j++)
3487       lev->ball_array[i][j] =
3488         map_element_RND_to_EM(level->
3489                               ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
3490
3491 #if 0
3492   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3493     for (j = 0; j < 8; j++)
3494       printf("::: ball %d, %d: %d\n", i, j,
3495              level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
3496 #endif
3497
3498   map_android_clone_elements_RND_to_EM(level);
3499
3500 #if 0
3501   for (i = 0; i < 16; i++)
3502     lev->android_array[i] = FALSE;      /* !!! YET TO COME !!! */
3503 #endif
3504
3505   /* first fill the complete playfield with the default border element */
3506   for (y = 0; y < EM_MAX_CAVE_HEIGHT; y++)
3507     for (x = 0; x < EM_MAX_CAVE_WIDTH; x++)
3508       level_em->cave[x][y] = ZBORDER;
3509
3510 #if 1
3511
3512 #if 0
3513 #if 1
3514   LoadLevel_InitPlayfield();
3515 #else
3516   lev_fieldx = lev->width;      /* !!! also in LoadLevel_InitPlayfield() !!! */
3517   lev_fieldy = lev->height;     /* !!! also in LoadLevel_InitPlayfield() !!! */
3518   SetBorderElement();           /* !!! also in LoadLevel_InitPlayfield() !!! */
3519 #endif
3520 #endif
3521
3522 #if 0
3523   printf("::: BorderElement == %d\n", BorderElement);
3524 #endif
3525
3526   if (BorderElement == EL_STEELWALL)
3527   {
3528     for (y = 0; y < lev->height + 2; y++)
3529       for (x = 0; x < lev->width + 2; x++)
3530         level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_STEELWALL);
3531   }
3532
3533   /* then copy the real level contents from level file into the playfield */
3534   for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
3535   {
3536     int new_element = map_element_RND_to_EM(level->field[x][y]);
3537     int offset = (BorderElement == EL_STEELWALL ? 1 : 0);
3538     int xx = x + 1 + offset;
3539     int yy = y + 1 + offset;
3540
3541     if (level->field[x][y] == EL_AMOEBA_DEAD)
3542       new_element = map_element_RND_to_EM(EL_AMOEBA_WET);
3543
3544     level_em->cave[xx][yy] = new_element;
3545   }
3546
3547 #else
3548
3549   /* then copy the real level contents from level file into the playfield */
3550   for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
3551   {
3552     int new_element = map_element_RND_to_EM(level->field[x][y]);
3553
3554     if (level->field[x][y] == EL_AMOEBA_DEAD)
3555       new_element = map_element_RND_to_EM(EL_AMOEBA_WET);
3556
3557     level_em->cave[x + 1][y + 1] = new_element;
3558   }
3559
3560 #endif
3561
3562 #if 1
3563
3564   for (i = 0; i < MAX_PLAYERS; i++)
3565   {
3566     ply[i]->x_initial = 0;
3567     ply[i]->y_initial = 0;
3568   }
3569
3570 #else
3571
3572   ply1->x_initial = 0;
3573   ply1->y_initial = 0;
3574
3575   ply2->x_initial = 0;
3576   ply2->y_initial = 0;
3577
3578 #endif
3579
3580   /* initialize player positions and delete players from the playfield */
3581   for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
3582   {
3583
3584 #if 1
3585     if (ELEM_IS_PLAYER(level->field[x][y]))
3586     {
3587       int player_nr = GET_PLAYER_NR(level->field[x][y]);
3588       int offset = (BorderElement == EL_STEELWALL ? 1 : 0);
3589       int xx = x + 1 + offset;
3590       int yy = y + 1 + offset;
3591
3592       ply[player_nr]->x_initial = xx;
3593       ply[player_nr]->y_initial = yy;
3594
3595       level_em->cave[xx][yy] = map_element_RND_to_EM(EL_EMPTY);
3596     }
3597
3598 #else
3599
3600 #if 1
3601     /* !!! CURRENTLY ONLY SUPPORT FOR ONE PLAYER !!! */
3602     if (ELEM_IS_PLAYER(level->field[x][y]))
3603     {
3604       ply1->x_initial = x + 1;
3605       ply1->y_initial = y + 1;
3606       level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_EMPTY);
3607     }
3608 #else
3609     /* !!! ADD SUPPORT FOR MORE THAN ONE PLAYER !!! */
3610     if (level->field[x][y] == EL_PLAYER_1)
3611     {
3612       ply1->x_initial = x + 1;
3613       ply1->y_initial = y + 1;
3614       level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_EMPTY);
3615     }
3616     else if (level->field[x][y] == EL_PLAYER_2)
3617     {
3618       ply2->x_initial = x + 1;
3619       ply2->y_initial = y + 1;
3620       level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_EMPTY);
3621     }
3622 #endif
3623
3624 #endif
3625
3626   }
3627
3628   if (BorderElement == EL_STEELWALL)
3629   {
3630 #if 1
3631     lev->width  += 2;
3632     lev->height += 2;
3633 #endif
3634   }
3635 }
3636
3637 void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
3638 {
3639   static int ball_xy[8][2] =
3640   {
3641     { 0, 0 },
3642     { 1, 0 },
3643     { 2, 0 },
3644     { 0, 1 },
3645     { 2, 1 },
3646     { 0, 2 },
3647     { 1, 2 },
3648     { 2, 2 },
3649   };
3650   struct LevelInfo_EM *level_em = level->native_em_level;
3651   struct LEVEL *lev = level_em->lev;
3652   struct PLAYER **ply = level_em->ply;
3653   int i, j, x, y;
3654
3655   level->fieldx = MIN(lev->width,  MAX_LEV_FIELDX);
3656   level->fieldy = MIN(lev->height, MAX_LEV_FIELDY);
3657
3658   level->time        = lev->time_seconds;
3659   level->gems_needed = lev->required_initial;
3660
3661   sprintf(level->name, "Level %d", level->file_info.nr);
3662
3663   level->score[SC_EMERALD]      = lev->emerald_score;
3664   level->score[SC_DIAMOND]      = lev->diamond_score;
3665   level->score[SC_ROBOT]        = lev->alien_score;
3666   level->score[SC_SPACESHIP]    = lev->tank_score;
3667   level->score[SC_BUG]          = lev->bug_score;
3668   level->score[SC_YAMYAM]       = lev->eater_score;
3669   level->score[SC_NUT]          = lev->nut_score;
3670   level->score[SC_DYNAMITE]     = lev->dynamite_score;
3671   level->score[SC_KEY]          = lev->key_score;
3672   level->score[SC_TIME_BONUS]   = lev->exit_score;
3673
3674   level->num_yamyam_contents = MAX_ELEMENT_CONTENTS;
3675
3676   for (i = 0; i < level->num_yamyam_contents; i++)
3677     for (y = 0; y < 3; y++)
3678       for (x = 0; x < 3; x++)
3679         level->yamyam_content[i].e[x][y] =
3680           map_element_EM_to_RND(lev->eater_array[i][y * 3 + x]);
3681
3682   level->amoeba_speed           = lev->amoeba_time;
3683   level->time_magic_wall        = lev->wonderwall_time_initial;
3684   level->time_wheel             = lev->wheel_time;
3685
3686   level->android_move_time      = lev->android_move_time;
3687   level->android_clone_time     = lev->android_clone_time;
3688   level->ball_random            = lev->ball_random;
3689   level->ball_state_initial     = lev->ball_state_initial;
3690   level->ball_time              = lev->ball_time;
3691   level->num_ball_contents      = lev->num_ball_arrays;
3692
3693   level->lenses_score           = lev->lenses_score;
3694   level->magnify_score          = lev->magnify_score;
3695   level->slurp_score            = lev->slurp_score;
3696
3697   level->lenses_time            = lev->lenses_time;
3698   level->magnify_time           = lev->magnify_time;
3699
3700   level->wind_direction_initial =
3701     map_direction_EM_to_RND(lev->wind_direction_initial);
3702
3703 #if 0
3704   printf("::: foo\n");
3705   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3706     for (j = 0; j < 8; j++)
3707       printf("::: ball %d, %d: %d\n", i, j,
3708              level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
3709 #endif
3710
3711   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3712     for (j = 0; j < 8; j++)
3713       level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]] =
3714         map_element_EM_to_RND(lev->ball_array[i][j]);
3715
3716 #if 0
3717   printf("::: bar\n");
3718   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3719     for (j = 0; j < 8; j++)
3720       printf("::: ball %d, %d: %d\n", i, j,
3721              level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
3722 #endif
3723
3724   map_android_clone_elements_EM_to_RND(level);
3725
3726 #if 0
3727   for (i = 0; i < 16; i++)
3728     level->android_array[i] = FALSE;    /* !!! YET TO COME !!! */
3729 #endif
3730
3731   /* convert the playfield (some elements need special treatment) */
3732   for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
3733   {
3734     int new_element = map_element_EM_to_RND(level_em->cave[x + 1][y + 1]);
3735
3736     if (new_element == EL_AMOEBA_WET && level->amoeba_speed == 0)
3737       new_element = EL_AMOEBA_DEAD;
3738
3739     level->field[x][y] = new_element;
3740   }
3741
3742 #if 0
3743   printf("::: bar 0\n");
3744   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3745     for (j = 0; j < 8; j++)
3746       printf("::: ball %d, %d: %d\n", i, j,
3747              level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
3748 #endif
3749
3750 #if 1
3751
3752   for (i = 0; i < MAX_PLAYERS; i++)
3753   {
3754     /* in case of all players set to the same field, use the first player */
3755     int nr = MAX_PLAYERS - i - 1;
3756     int jx = ply[nr]->x_initial - 1;
3757     int jy = ply[nr]->y_initial - 1;
3758
3759 #if 0
3760     printf("::: player %d: %d, %d\n", nr, jx, jy);
3761 #endif
3762
3763     if (jx != -1 && jy != -1)
3764       level->field[jx][jy] = EL_PLAYER_1 + nr;
3765   }
3766
3767 #else
3768
3769   /* in case of both players set to the same field, use the first player */
3770   level->field[ply2->x_initial - 1][ply2->y_initial - 1] = EL_PLAYER_2;
3771   level->field[ply1->x_initial - 1][ply1->y_initial - 1] = EL_PLAYER_1;
3772
3773 #endif
3774
3775 #if 0
3776   printf("::: native Emerald Mine file version: %d\n", level_em->file_version);
3777 #endif
3778
3779 #if 0
3780   printf("::: bar 2\n");
3781   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3782     for (j = 0; j < 8; j++)
3783       printf("::: ball %d, %d: %d\n", i, j,
3784              level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
3785 #endif
3786 }
3787
3788 static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,
3789                                      struct LevelFileInfo *level_file_info)
3790 {
3791   if (!LoadNativeLevel_EM(level_file_info->filename))
3792     level->no_valid_file = TRUE;
3793 }
3794
3795 void CopyNativeLevel_RND_to_Native(struct LevelInfo *level)
3796 {
3797   if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
3798     CopyNativeLevel_RND_to_EM(level);
3799 }
3800
3801 void CopyNativeLevel_Native_to_RND(struct LevelInfo *level)
3802 {
3803
3804 #if 0
3805   {
3806     static int ball_xy[8][2] =
3807       {
3808         { 0, 0 },
3809         { 1, 0 },
3810         { 2, 0 },
3811         { 0, 1 },
3812         { 2, 1 },
3813         { 0, 2 },
3814         { 1, 2 },
3815         { 2, 2 },
3816       };
3817     int i, j;
3818
3819     printf("::: A6\n");
3820     for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3821       for (j = 0; j < 8; j++)
3822         printf("::: ball %d, %d: %d\n", i, j,
3823                level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
3824   }
3825 #endif
3826
3827   if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
3828     CopyNativeLevel_EM_to_RND(level);
3829 }
3830
3831
3832 /* ------------------------------------------------------------------------- */
3833 /* functions for loading SP level                                            */
3834 /* ------------------------------------------------------------------------- */
3835
3836 #define NUM_SUPAPLEX_LEVELS_PER_PACKAGE 111
3837 #define SP_LEVEL_SIZE                   1536
3838 #define SP_LEVEL_XSIZE                  60
3839 #define SP_LEVEL_YSIZE                  24
3840 #define SP_LEVEL_NAME_LEN               23
3841
3842 static void LoadLevelFromFileStream_SP(FILE *file, struct LevelInfo *level,
3843                                        int nr)
3844 {
3845   int num_special_ports;
3846   int i, x, y;
3847
3848   /* for details of the Supaplex level format, see Herman Perk's Supaplex
3849      documentation file "SPFIX63.DOC" from his Supaplex "SpeedFix" package */
3850
3851   /* read level body (width * height == 60 * 24 tiles == 1440 bytes) */
3852   for (y = 0; y < SP_LEVEL_YSIZE; y++)
3853   {
3854     for (x = 0; x < SP_LEVEL_XSIZE; x++)
3855     {
3856       int element_old = fgetc(file);
3857       int element_new;
3858
3859       if (element_old <= 0x27)
3860         element_new = getMappedElement(EL_SP_START + element_old);
3861       else if (element_old == 0x28)
3862         element_new = EL_INVISIBLE_WALL;
3863       else
3864       {
3865         Error(ERR_WARN, "in level %d, at position %d, %d:", nr, x, y);
3866         Error(ERR_WARN, "invalid level element %d", element_old);
3867
3868         element_new = EL_UNKNOWN;
3869       }
3870
3871       level->field[x][y] = element_new;
3872     }
3873   }
3874
3875   ReadUnusedBytesFromFile(file, 4);     /* (not used by Supaplex engine) */
3876
3877   /* initial gravity: 1 == "on", anything else (0) == "off" */
3878   level->initial_gravity = (fgetc(file) == 1 ? TRUE : FALSE);
3879
3880   ReadUnusedBytesFromFile(file, 1);     /* (not used by Supaplex engine) */
3881
3882   /* level title in uppercase letters, padded with dashes ("-") (23 bytes) */
3883   for (i = 0; i < SP_LEVEL_NAME_LEN; i++)
3884     level->name[i] = fgetc(file);
3885   level->name[SP_LEVEL_NAME_LEN] = '\0';
3886
3887   /* initial "freeze zonks": 2 == "on", anything else (0, 1) == "off" */
3888   ReadUnusedBytesFromFile(file, 1);     /* (not used by R'n'D engine) */
3889
3890   /* number of infotrons needed; 0 means that Supaplex will count the total
3891      amount of infotrons in the level and use the low byte of that number
3892      (a multiple of 256 infotrons will result in "0 infotrons needed"!) */
3893   level->gems_needed = fgetc(file);
3894
3895   /* number of special ("gravity") port entries below (maximum 10 allowed) */
3896   num_special_ports = fgetc(file);
3897
3898   /* database of properties of up to 10 special ports (6 bytes per port) */
3899   for (i = 0; i < 10; i++)
3900   {
3901     int port_location, port_x, port_y, port_element;
3902     int gravity;
3903
3904     /* high and low byte of the location of a special port; if (x, y) are the
3905        coordinates of a port in the field and (0, 0) is the top-left corner,
3906        the 16 bit value here calculates as 2 * (x + (y * 60)) (this is twice
3907        of what may be expected: Supaplex works with a game field in memory
3908        which is 2 bytes per tile) */
3909     port_location = getFile16BitBE(file);
3910
3911     /* change gravity: 1 == "turn on", anything else (0) == "turn off" */
3912     gravity = fgetc(file);
3913
3914     /* "freeze zonks": 2 == "turn on", anything else (0, 1) == "turn off" */
3915     ReadUnusedBytesFromFile(file, 1);   /* (not used by R'n'D engine) */
3916
3917     /* "freeze enemies": 1 == "turn on", anything else (0) == "turn off" */
3918     ReadUnusedBytesFromFile(file, 1);   /* (not used by R'n'D engine) */
3919
3920     ReadUnusedBytesFromFile(file, 1);   /* (not used by Supaplex engine) */
3921
3922     if (i >= num_special_ports)
3923       continue;
3924
3925     port_x = (port_location / 2) % SP_LEVEL_XSIZE;
3926     port_y = (port_location / 2) / SP_LEVEL_XSIZE;
3927
3928     if (port_x < 0 || port_x >= SP_LEVEL_XSIZE ||
3929         port_y < 0 || port_y >= SP_LEVEL_YSIZE)
3930     {
3931       Error(ERR_WARN, "special port position (%d, %d) out of bounds",
3932             port_x, port_y);
3933
3934       continue;
3935     }
3936
3937     port_element = level->field[port_x][port_y];
3938
3939     if (port_element < EL_SP_GRAVITY_PORT_RIGHT ||
3940         port_element > EL_SP_GRAVITY_PORT_UP)
3941     {
3942       Error(ERR_WARN, "no special port at position (%d, %d)", port_x, port_y);
3943
3944       continue;
3945     }
3946
3947     /* change previous (wrong) gravity inverting special port to either
3948        gravity enabling special port or gravity disabling special port */
3949     level->field[port_x][port_y] +=
3950       (gravity == 1 ? EL_SP_GRAVITY_ON_PORT_RIGHT :
3951        EL_SP_GRAVITY_OFF_PORT_RIGHT) - EL_SP_GRAVITY_PORT_RIGHT;
3952   }
3953
3954   ReadUnusedBytesFromFile(file, 4);     /* (not used by Supaplex engine) */
3955
3956   /* change special gravity ports without database entries to normal ports */
3957   for (y = 0; y < SP_LEVEL_YSIZE; y++)
3958     for (x = 0; x < SP_LEVEL_XSIZE; x++)
3959       if (level->field[x][y] >= EL_SP_GRAVITY_PORT_RIGHT &&
3960           level->field[x][y] <= EL_SP_GRAVITY_PORT_UP)
3961         level->field[x][y] += EL_SP_PORT_RIGHT - EL_SP_GRAVITY_PORT_RIGHT;
3962
3963   /* auto-determine number of infotrons if it was stored as "0" -- see above */
3964   if (level->gems_needed == 0)
3965   {
3966     for (y = 0; y < SP_LEVEL_YSIZE; y++)
3967       for (x = 0; x < SP_LEVEL_XSIZE; x++)
3968         if (level->field[x][y] == EL_SP_INFOTRON)
3969           level->gems_needed++;
3970
3971     level->gems_needed &= 0xff;         /* only use low byte -- see above */
3972   }
3973
3974   level->fieldx = SP_LEVEL_XSIZE;
3975   level->fieldy = SP_LEVEL_YSIZE;
3976
3977   level->time = 0;                      /* no time limit */
3978   level->amoeba_speed = 0;
3979   level->time_magic_wall = 0;
3980   level->time_wheel = 0;
3981   level->amoeba_content = EL_EMPTY;
3982
3983 #if 1
3984   /* original Supaplex does not use score values -- use default values */
3985 #else
3986   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
3987     level->score[i] = 0;                /* !!! CORRECT THIS !!! */
3988 #endif
3989
3990   /* there are no yamyams in supaplex levels */
3991   for (i = 0; i < level->num_yamyam_contents; i++)
3992     for (y = 0; y < 3; y++)
3993       for (x = 0; x < 3; x++)
3994         level->yamyam_content[i].e[x][y] = EL_EMPTY;
3995 }
3996
3997 static void LoadLevelFromFileInfo_SP(struct LevelInfo *level,
3998                                      struct LevelFileInfo *level_file_info)
3999 {
4000   char *filename = level_file_info->filename;
4001   FILE *file;
4002   int nr = level_file_info->nr - leveldir_current->first_level;
4003   int i, l, x, y;
4004   char name_first, name_last;
4005   struct LevelInfo multipart_level;
4006   int multipart_xpos, multipart_ypos;
4007   boolean is_multipart_level;
4008   boolean is_first_part;
4009   boolean reading_multipart_level = FALSE;
4010   boolean use_empty_level = FALSE;
4011
4012   if (!(file = fopen(filename, MODE_READ)))
4013   {
4014     level->no_valid_file = TRUE;
4015
4016     Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
4017
4018     return;
4019   }
4020
4021   /* position file stream to the requested level inside the level package */
4022   if (fseek(file, nr * SP_LEVEL_SIZE, SEEK_SET) != 0)
4023   {
4024     level->no_valid_file = TRUE;
4025
4026     Error(ERR_WARN, "cannot fseek level '%s' -- using empty level", filename);
4027
4028     return;
4029   }
4030
4031   /* there exist Supaplex level package files with multi-part levels which
4032      can be detected as follows: instead of leading and trailing dashes ('-')
4033      to pad the level name, they have leading and trailing numbers which are
4034      the x and y coordinations of the current part of the multi-part level;
4035      if there are '?' characters instead of numbers on the left or right side
4036      of the level name, the multi-part level consists of only horizontal or
4037      vertical parts */
4038
4039   for (l = nr; l < NUM_SUPAPLEX_LEVELS_PER_PACKAGE; l++)
4040   {
4041     LoadLevelFromFileStream_SP(file, level, l);
4042
4043     /* check if this level is a part of a bigger multi-part level */
4044
4045     name_first = level->name[0];
4046     name_last  = level->name[SP_LEVEL_NAME_LEN - 1];
4047
4048     is_multipart_level =
4049       ((name_first == '?' || (name_first >= '0' && name_first <= '9')) &&
4050        (name_last  == '?' || (name_last  >= '0' && name_last  <= '9')));
4051
4052     is_first_part =
4053       ((name_first == '?' || name_first == '1') &&
4054        (name_last  == '?' || name_last  == '1'));
4055
4056     /* correct leading multipart level meta information in level name */
4057     for (i = 0; i < SP_LEVEL_NAME_LEN && level->name[i] == name_first; i++)
4058       level->name[i] = '-';
4059
4060     /* correct trailing multipart level meta information in level name */
4061     for (i = SP_LEVEL_NAME_LEN - 1; i>=0 && level->name[i] == name_last; i--)
4062       level->name[i] = '-';
4063
4064     /* ---------- check for normal single level ---------- */
4065
4066     if (!reading_multipart_level && !is_multipart_level)
4067     {
4068       /* the current level is simply a normal single-part level, and we are
4069          not reading a multi-part level yet, so return the level as it is */
4070
4071       break;
4072     }
4073
4074     /* ---------- check for empty level (unused multi-part) ---------- */
4075
4076     if (!reading_multipart_level && is_multipart_level && !is_first_part)
4077     {
4078       /* this is a part of a multi-part level, but not the first part
4079          (and we are not already reading parts of a multi-part level);
4080          in this case, use an empty level instead of the single part */
4081
4082       use_empty_level = TRUE;
4083
4084       break;
4085     }
4086
4087     /* ---------- check for finished multi-part level ---------- */
4088
4089     if (reading_multipart_level &&
4090         (!is_multipart_level ||
4091          !strEqual(level->name, multipart_level.name)))
4092     {
4093       /* we are already reading parts of a multi-part level, but this level is
4094          either not a multi-part level, or a part of a different multi-part
4095          level; in both cases, the multi-part level seems to be complete */
4096
4097       break;
4098     }
4099
4100     /* ---------- here we have one part of a multi-part level ---------- */
4101
4102     reading_multipart_level = TRUE;
4103
4104     if (is_first_part)  /* start with first part of new multi-part level */
4105     {
4106       /* copy level info structure from first part */
4107       multipart_level = *level;
4108
4109       /* clear playfield of new multi-part level */
4110       for (y = 0; y < MAX_LEV_FIELDY; y++)
4111         for (x = 0; x < MAX_LEV_FIELDX; x++)
4112           multipart_level.field[x][y] = EL_EMPTY;
4113     }
4114
4115     if (name_first == '?')
4116       name_first = '1';
4117     if (name_last == '?')
4118       name_last = '1';
4119
4120     multipart_xpos = (int)(name_first - '0');
4121     multipart_ypos = (int)(name_last  - '0');
4122
4123 #if 0
4124     printf("----------> part (%d/%d) of multi-part level '%s'\n",
4125            multipart_xpos, multipart_ypos, multipart_level.name);
4126 #endif
4127
4128     if (multipart_xpos * SP_LEVEL_XSIZE > MAX_LEV_FIELDX ||
4129         multipart_ypos * SP_LEVEL_YSIZE > MAX_LEV_FIELDY)
4130     {
4131       Error(ERR_WARN, "multi-part level is too big -- ignoring part of it");
4132
4133       break;
4134     }
4135
4136     multipart_level.fieldx = MAX(multipart_level.fieldx,
4137                                  multipart_xpos * SP_LEVEL_XSIZE);
4138     multipart_level.fieldy = MAX(multipart_level.fieldy,
4139                                  multipart_ypos * SP_LEVEL_YSIZE);
4140
4141     /* copy level part at the right position of multi-part level */
4142     for (y = 0; y < SP_LEVEL_YSIZE; y++)
4143     {
4144       for (x = 0; x < SP_LEVEL_XSIZE; x++)
4145       {
4146         int start_x = (multipart_xpos - 1) * SP_LEVEL_XSIZE;
4147         int start_y = (multipart_ypos - 1) * SP_LEVEL_YSIZE;
4148
4149         multipart_level.field[start_x + x][start_y + y] = level->field[x][y];
4150       }
4151     }
4152   }
4153
4154   fclose(file);
4155
4156   if (use_empty_level)
4157   {
4158     setLevelInfoToDefaults(level);
4159
4160     level->fieldx = SP_LEVEL_XSIZE;
4161     level->fieldy = SP_LEVEL_YSIZE;
4162
4163     for (y = 0; y < SP_LEVEL_YSIZE; y++)
4164       for (x = 0; x < SP_LEVEL_XSIZE; x++)
4165         level->field[x][y] = EL_EMPTY;
4166
4167     strcpy(level->name, "-------- EMPTY --------");
4168
4169     Error(ERR_WARN, "single part of multi-part level -- using empty level");
4170   }
4171
4172   if (reading_multipart_level)
4173     *level = multipart_level;
4174 }
4175
4176 /* ------------------------------------------------------------------------- */
4177 /* functions for loading generic level                                       */
4178 /* ------------------------------------------------------------------------- */
4179
4180 void LoadLevelFromFileInfo(struct LevelInfo *level,
4181                            struct LevelFileInfo *level_file_info)
4182 {
4183   /* always start with reliable default values */
4184   setLevelInfoToDefaults(level);
4185
4186   switch (level_file_info->type)
4187   {
4188     case LEVEL_FILE_TYPE_RND:
4189       LoadLevelFromFileInfo_RND(level, level_file_info);
4190       break;
4191
4192     case LEVEL_FILE_TYPE_EM:
4193       LoadLevelFromFileInfo_EM(level, level_file_info);
4194       level->game_engine_type = GAME_ENGINE_TYPE_EM;
4195       break;
4196
4197     case LEVEL_FILE_TYPE_SP:
4198       LoadLevelFromFileInfo_SP(level, level_file_info);
4199       break;
4200
4201     default:
4202       LoadLevelFromFileInfo_RND(level, level_file_info);
4203       break;
4204   }
4205
4206   /* if level file is invalid, restore level structure to default values */
4207   if (level->no_valid_file)
4208     setLevelInfoToDefaults(level);
4209
4210   if (level->game_engine_type == GAME_ENGINE_TYPE_UNKNOWN)
4211     level->game_engine_type = GAME_ENGINE_TYPE_RND;
4212
4213 #if 1
4214   if (level_file_info->type != LEVEL_FILE_TYPE_RND)
4215     CopyNativeLevel_Native_to_RND(level);
4216 #else
4217   if (level_file_info->type == LEVEL_FILE_TYPE_RND)
4218     CopyNativeLevel_RND_to_Native(level);
4219   else
4220     CopyNativeLevel_Native_to_RND(level);
4221 #endif
4222 }
4223
4224 void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
4225 {
4226   static struct LevelFileInfo level_file_info;
4227
4228   /* always start with reliable default values */
4229   setFileInfoToDefaults(&level_file_info);
4230
4231   level_file_info.nr = 0;                       /* unknown level number */
4232   level_file_info.type = LEVEL_FILE_TYPE_RND;   /* no others supported yet */
4233   level_file_info.filename = filename;
4234
4235   LoadLevelFromFileInfo(level, &level_file_info);
4236 }
4237
4238 static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
4239 {
4240   if (leveldir_current == NULL)         /* only when dumping level */
4241     return;
4242
4243   /* all engine modifications also valid for levels which use latest engine */
4244 #if 1
4245   if (level->game_version < VERSION_IDENT(3,2,0,5))
4246   {
4247     /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */
4248     level->score[SC_TIME_BONUS] /= 10;
4249   }
4250 #endif
4251
4252 #if 0
4253   leveldir_current->latest_engine = TRUE;       /* !!! TEST ONLY !!! */
4254 #endif
4255
4256   if (leveldir_current->latest_engine)
4257   {
4258     /* ---------- use latest game engine ----------------------------------- */
4259
4260     /* For all levels which are forced to use the latest game engine version
4261        (normally all but user contributed, private and undefined levels), set
4262        the game engine version to the actual version; this allows for actual
4263        corrections in the game engine to take effect for existing, converted
4264        levels (from "classic" or other existing games) to make the emulation
4265        of the corresponding game more accurate, while (hopefully) not breaking
4266        existing levels created from other players. */
4267
4268     level->game_version = GAME_VERSION_ACTUAL;
4269
4270     /* Set special EM style gems behaviour: EM style gems slip down from
4271        normal, steel and growing wall. As this is a more fundamental change,
4272        it seems better to set the default behaviour to "off" (as it is more
4273        natural) and make it configurable in the level editor (as a property
4274        of gem style elements). Already existing converted levels (neither
4275        private nor contributed levels) are changed to the new behaviour. */
4276
4277     if (level->file_version < FILE_VERSION_2_0)
4278       level->em_slippery_gems = TRUE;
4279
4280     return;
4281   }
4282
4283   /* ---------- use game engine the level was created with ----------------- */
4284
4285   /* For all levels which are not forced to use the latest game engine
4286      version (normally user contributed, private and undefined levels),
4287      use the version of the game engine the levels were created for.
4288
4289      Since 2.0.1, the game engine version is now directly stored
4290      in the level file (chunk "VERS"), so there is no need anymore
4291      to set the game version from the file version (except for old,
4292      pre-2.0 levels, where the game version is still taken from the
4293      file format version used to store the level -- see above). */
4294
4295   /* player was faster than enemies in 1.0.0 and before */
4296   if (level->file_version == FILE_VERSION_1_0)
4297     level->initial_player_stepsize = STEPSIZE_FAST;
4298
4299   /* default behaviour for EM style gems was "slippery" only in 2.0.1 */
4300   if (level->game_version == VERSION_IDENT(2,0,1,0))
4301     level->em_slippery_gems = TRUE;
4302
4303   /* springs could be pushed over pits before (pre-release version) 2.2.0 */
4304   if (level->game_version < VERSION_IDENT(2,2,0,0))
4305     level->use_spring_bug = TRUE;
4306
4307   if (level->game_version < VERSION_IDENT(3,2,0,5))
4308   {
4309     /* time orb caused limited time in endless time levels before 3.2.0-5 */
4310     level->use_time_orb_bug = TRUE;
4311
4312     /* default behaviour for snapping was "no snap delay" before 3.2.0-5 */
4313     level->block_snap_field = FALSE;
4314
4315     /* extra time score was same value as time left score before 3.2.0-5 */
4316     level->extra_time_score = level->score[SC_TIME_BONUS];
4317
4318 #if 0
4319     /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */
4320     level->score[SC_TIME_BONUS] /= 10;
4321 #endif
4322   }
4323
4324   if (level->game_version < VERSION_IDENT(3,2,0,7))
4325   {
4326     /* default behaviour for snapping was "not continuous" before 3.2.0-7 */
4327     level->continuous_snapping = FALSE;
4328   }
4329
4330   /* only few elements were able to actively move into acid before 3.1.0 */
4331   /* trigger settings did not exist before 3.1.0; set to default "any" */
4332   if (level->game_version < VERSION_IDENT(3,1,0,0))
4333   {
4334     int i, j;
4335
4336     /* correct "can move into acid" settings (all zero in old levels) */
4337
4338     level->can_move_into_acid_bits = 0; /* nothing can move into acid */
4339     level->dont_collide_with_bits = 0; /* nothing is deadly when colliding */
4340
4341     setMoveIntoAcidProperty(level, EL_ROBOT,     TRUE);
4342     setMoveIntoAcidProperty(level, EL_SATELLITE, TRUE);
4343     setMoveIntoAcidProperty(level, EL_PENGUIN,   TRUE);
4344     setMoveIntoAcidProperty(level, EL_BALLOON,   TRUE);
4345
4346     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4347       SET_PROPERTY(EL_CUSTOM_START + i, EP_CAN_MOVE_INTO_ACID, TRUE);
4348
4349     /* correct trigger settings (stored as zero == "none" in old levels) */
4350
4351     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4352     {
4353       int element = EL_CUSTOM_START + i;
4354       struct ElementInfo *ei = &element_info[element];
4355
4356       for (j = 0; j < ei->num_change_pages; j++)
4357       {
4358         struct ElementChangeInfo *change = &ei->change_page[j];
4359
4360         change->trigger_player = CH_PLAYER_ANY;
4361         change->trigger_page = CH_PAGE_ANY;
4362       }
4363     }
4364   }
4365 }
4366
4367 static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
4368 {
4369   int i, j, x, y;
4370
4371   /* map custom element change events that have changed in newer versions
4372      (these following values were accidentally changed in version 3.0.1)
4373      (this seems to be needed only for 'ab_levelset3' and 'ab_levelset4') */
4374   if (level->game_version <= VERSION_IDENT(3,0,0,0))
4375   {
4376     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4377     {
4378       int element = EL_CUSTOM_START + i;
4379
4380       /* order of checking and copying events to be mapped is important */
4381       /* (do not change the start and end value -- they are constant) */
4382       for (j = CE_BY_OTHER_ACTION; j >= CE_VALUE_GETS_ZERO; j--)
4383       {
4384         if (HAS_CHANGE_EVENT(element, j - 2))
4385         {
4386           SET_CHANGE_EVENT(element, j - 2, FALSE);
4387           SET_CHANGE_EVENT(element, j, TRUE);
4388         }
4389       }
4390
4391       /* order of checking and copying events to be mapped is important */
4392       /* (do not change the start and end value -- they are constant) */
4393       for (j = CE_PLAYER_COLLECTS_X; j >= CE_HITTING_SOMETHING; j--)
4394       {
4395         if (HAS_CHANGE_EVENT(element, j - 1))
4396         {
4397           SET_CHANGE_EVENT(element, j - 1, FALSE);
4398           SET_CHANGE_EVENT(element, j, TRUE);
4399         }
4400       }
4401     }
4402   }
4403
4404   /* initialize "can_change" field for old levels with only one change page */
4405   if (level->game_version <= VERSION_IDENT(3,0,2,0))
4406   {
4407     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4408     {
4409       int element = EL_CUSTOM_START + i;
4410
4411       if (CAN_CHANGE(element))
4412         element_info[element].change->can_change = TRUE;
4413     }
4414   }
4415
4416   /* correct custom element values (for old levels without these options) */
4417   if (level->game_version < VERSION_IDENT(3,1,1,0))
4418   {
4419     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4420     {
4421       int element = EL_CUSTOM_START + i;
4422       struct ElementInfo *ei = &element_info[element];
4423
4424       if (ei->access_direction == MV_NO_DIRECTION)
4425         ei->access_direction = MV_ALL_DIRECTIONS;
4426
4427 #if 0
4428       for (j = 0; j < ei->num_change_pages; j++)
4429       {
4430         struct ElementChangeInfo *change = &ei->change_page[j];
4431
4432         if (change->trigger_side == CH_SIDE_NONE)
4433           change->trigger_side = CH_SIDE_ANY;
4434       }
4435 #endif
4436     }
4437   }
4438
4439 #if 1
4440   /* correct custom element values (fix invalid values for all versions) */
4441   if (1)
4442   {
4443     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4444     {
4445       int element = EL_CUSTOM_START + i;
4446       struct ElementInfo *ei = &element_info[element];
4447
4448       for (j = 0; j < ei->num_change_pages; j++)
4449       {
4450         struct ElementChangeInfo *change = &ei->change_page[j];
4451
4452         if (change->trigger_player == CH_PLAYER_NONE)
4453           change->trigger_player = CH_PLAYER_ANY;
4454
4455         if (change->trigger_side == CH_SIDE_NONE)
4456           change->trigger_side = CH_SIDE_ANY;
4457       }
4458     }
4459   }
4460 #endif
4461
4462   /* initialize "can_explode" field for old levels which did not store this */
4463   /* !!! CHECK THIS -- "<= 3,1,0,0" IS PROBABLY WRONG !!! */
4464   if (level->game_version <= VERSION_IDENT(3,1,0,0))
4465   {
4466     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4467     {
4468       int element = EL_CUSTOM_START + i;
4469
4470       if (EXPLODES_1X1_OLD(element))
4471         element_info[element].explosion_type = EXPLODES_1X1;
4472
4473       SET_PROPERTY(element, EP_CAN_EXPLODE, (EXPLODES_BY_FIRE(element) ||
4474                                              EXPLODES_SMASHED(element) ||
4475                                              EXPLODES_IMPACT(element)));
4476     }
4477   }
4478
4479   /* correct previously hard-coded move delay values for maze runner style */
4480   if (level->game_version < VERSION_IDENT(3,1,1,0))
4481   {
4482     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4483     {
4484       int element = EL_CUSTOM_START + i;
4485
4486       if (element_info[element].move_pattern & MV_MAZE_RUNNER_STYLE)
4487       {
4488         /* previously hard-coded and therefore ignored */
4489         element_info[element].move_delay_fixed = 9;
4490         element_info[element].move_delay_random = 0;
4491       }
4492     }
4493   }
4494
4495   /* map elements that have changed in newer versions */
4496   level->amoeba_content = getMappedElementByVersion(level->amoeba_content,
4497                                                     level->game_version);
4498   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
4499     for (x = 0; x < 3; x++)
4500       for (y = 0; y < 3; y++)
4501         level->yamyam_content[i].e[x][y] =
4502           getMappedElementByVersion(level->yamyam_content[i].e[x][y],
4503                                     level->game_version);
4504
4505   /* initialize element properties for level editor etc. */
4506   InitElementPropertiesEngine(level->game_version);
4507 }
4508
4509 static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
4510 {
4511   int x, y;
4512
4513   /* map elements that have changed in newer versions */
4514   for (y = 0; y < level->fieldy; y++)
4515     for (x = 0; x < level->fieldx; x++)
4516       level->field[x][y] = getMappedElementByVersion(level->field[x][y],
4517                                                      level->game_version);
4518
4519   /* copy elements to runtime playfield array */
4520   for (x = 0; x < MAX_LEV_FIELDX; x++)
4521     for (y = 0; y < MAX_LEV_FIELDY; y++)
4522       Feld[x][y] = level->field[x][y];
4523
4524   /* initialize level size variables for faster access */
4525   lev_fieldx = level->fieldx;
4526   lev_fieldy = level->fieldy;
4527
4528   /* determine border element for this level */
4529   SetBorderElement();
4530 }
4531
4532 static void LoadLevel_InitNativeEngines(struct LevelInfo *level,char *filename)
4533 {
4534   struct LevelFileInfo *level_file_info = &level->file_info;
4535
4536 #if 1
4537   if (level_file_info->type == LEVEL_FILE_TYPE_RND)
4538     CopyNativeLevel_RND_to_Native(level);
4539 #else
4540   if (level_file_info->type == LEVEL_FILE_TYPE_RND)
4541     CopyNativeLevel_RND_to_Native(level);
4542   else
4543     CopyNativeLevel_Native_to_RND(level);
4544 #endif
4545 }
4546
4547 void LoadLevelTemplate(int nr)
4548 {
4549   char *filename;
4550
4551   setLevelFileInfo(&level_template.file_info, nr);
4552   filename = level_template.file_info.filename;
4553
4554   LoadLevelFromFileInfo(&level_template, &level_template.file_info);
4555
4556   LoadLevel_InitVersion(&level_template, filename);
4557   LoadLevel_InitElements(&level_template, filename);
4558
4559   ActivateLevelTemplate();
4560 }
4561
4562 void LoadLevel(int nr)
4563 {
4564   char *filename;
4565
4566   setLevelFileInfo(&level.file_info, nr);
4567   filename = level.file_info.filename;
4568
4569   LoadLevelFromFileInfo(&level, &level.file_info);
4570
4571   if (level.use_custom_template)
4572     LoadLevelTemplate(-1);
4573
4574   LoadLevel_InitVersion(&level, filename);
4575   LoadLevel_InitElements(&level, filename);
4576   LoadLevel_InitPlayfield(&level, filename);
4577
4578   LoadLevel_InitNativeEngines(&level, filename);
4579 }
4580
4581 static void SaveLevel_VERS(FILE *file, struct LevelInfo *level)
4582 {
4583   putFileVersion(file, level->file_version);
4584   putFileVersion(file, level->game_version);
4585 }
4586
4587 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
4588 {
4589   int i, x, y;
4590
4591   putFile8Bit(file, level->fieldx);
4592   putFile8Bit(file, level->fieldy);
4593
4594   putFile16BitBE(file, level->time);
4595   putFile16BitBE(file, level->gems_needed);
4596
4597   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
4598     putFile8Bit(file, level->name[i]);
4599
4600   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
4601     putFile8Bit(file, level->score[i]);
4602
4603   for (i = 0; i < STD_ELEMENT_CONTENTS; i++)
4604     for (y = 0; y < 3; y++)
4605       for (x = 0; x < 3; x++)
4606         putFile8Bit(file, (level->encoding_16bit_yamyam ? EL_EMPTY :
4607                            level->yamyam_content[i].e[x][y]));
4608   putFile8Bit(file, level->amoeba_speed);
4609   putFile8Bit(file, level->time_magic_wall);
4610   putFile8Bit(file, level->time_wheel);
4611   putFile8Bit(file, (level->encoding_16bit_amoeba ? EL_EMPTY :
4612                      level->amoeba_content));
4613   putFile8Bit(file, (level->initial_player_stepsize == STEPSIZE_FAST ? 1 : 0));
4614   putFile8Bit(file, (level->initial_gravity ? 1 : 0));
4615   putFile8Bit(file, (level->encoding_16bit_field ? 1 : 0));
4616   putFile8Bit(file, (level->em_slippery_gems ? 1 : 0));
4617
4618   putFile8Bit(file, (level->use_custom_template ? 1 : 0));
4619
4620   putFile8Bit(file, (level->block_last_field ? 1 : 0));
4621   putFile8Bit(file, (level->sp_block_last_field ? 1 : 0));
4622   putFile32BitBE(file, level->can_move_into_acid_bits);
4623   putFile8Bit(file, level->dont_collide_with_bits);
4624
4625   putFile8Bit(file, (level->use_spring_bug ? 1 : 0));
4626   putFile8Bit(file, (level->use_step_counter ? 1 : 0));
4627
4628   putFile8Bit(file, (level->instant_relocation ? 1 : 0));
4629   putFile8Bit(file, (level->can_pass_to_walkable ? 1 : 0));
4630   putFile8Bit(file, (level->grow_into_diggable ? 1 : 0));
4631
4632   putFile8Bit(file, level->game_engine_type);
4633
4634   WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
4635 }
4636
4637 static void SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
4638 {
4639   int i;
4640
4641   for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
4642     putFile8Bit(file, level->author[i]);
4643 }
4644
4645 static void SaveLevel_BODY(FILE *file, struct LevelInfo *level)
4646 {
4647   int x, y;
4648
4649   for (y = 0; y < level->fieldy; y++) 
4650     for (x = 0; x < level->fieldx; x++) 
4651       if (level->encoding_16bit_field)
4652         putFile16BitBE(file, level->field[x][y]);
4653       else
4654         putFile8Bit(file, level->field[x][y]);
4655 }
4656
4657 #if 0
4658 static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
4659 {
4660   int i, x, y;
4661
4662   putFile8Bit(file, EL_YAMYAM);
4663   putFile8Bit(file, level->num_yamyam_contents);
4664   putFile8Bit(file, 0);
4665   putFile8Bit(file, 0);
4666
4667   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
4668     for (y = 0; y < 3; y++)
4669       for (x = 0; x < 3; x++)
4670         if (level->encoding_16bit_field)
4671           putFile16BitBE(file, level->yamyam_content[i].e[x][y]);
4672         else
4673           putFile8Bit(file, level->yamyam_content[i].e[x][y]);
4674 }
4675 #endif
4676
4677 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
4678 {
4679   int i, x, y;
4680   int num_contents, content_xsize, content_ysize;
4681   int content_array[MAX_ELEMENT_CONTENTS][3][3];
4682
4683   if (element == EL_YAMYAM)
4684   {
4685     num_contents = level->num_yamyam_contents;
4686     content_xsize = 3;
4687     content_ysize = 3;
4688
4689     for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
4690       for (y = 0; y < 3; y++)
4691         for (x = 0; x < 3; x++)
4692           content_array[i][x][y] = level->yamyam_content[i].e[x][y];
4693   }
4694   else if (element == EL_BD_AMOEBA)
4695   {
4696     num_contents = 1;
4697     content_xsize = 1;
4698     content_ysize = 1;
4699
4700     for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
4701       for (y = 0; y < 3; y++)
4702         for (x = 0; x < 3; x++)
4703           content_array[i][x][y] = EL_EMPTY;
4704     content_array[0][0][0] = level->amoeba_content;
4705   }
4706   else
4707   {
4708     /* chunk header already written -- write empty chunk data */
4709     WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_SIZE);
4710
4711     Error(ERR_WARN, "cannot save content for element '%d'", element);
4712     return;
4713   }
4714
4715   putFile16BitBE(file, element);
4716   putFile8Bit(file, num_contents);
4717   putFile8Bit(file, content_xsize);
4718   putFile8Bit(file, content_ysize);
4719
4720   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED);
4721
4722   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
4723     for (y = 0; y < 3; y++)
4724       for (x = 0; x < 3; x++)
4725         putFile16BitBE(file, content_array[i][x][y]);
4726 }
4727
4728 static void SaveLevel_CNT3(FILE *file, struct LevelInfo *level, int element)
4729 {
4730   int i;
4731   int envelope_nr = element - EL_ENVELOPE_1;
4732   int envelope_len = strlen(level->envelope_text[envelope_nr]) + 1;
4733
4734   putFile16BitBE(file, element);
4735   putFile16BitBE(file, envelope_len);
4736   putFile8Bit(file, level->envelope_xsize[envelope_nr]);
4737   putFile8Bit(file, level->envelope_ysize[envelope_nr]);
4738
4739   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT3_UNUSED);
4740
4741   for (i = 0; i < envelope_len; i++)
4742     putFile8Bit(file, level->envelope_text[envelope_nr][i]);
4743 }
4744
4745 #if 0
4746 static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level,
4747                            int num_changed_custom_elements)
4748 {
4749   int i, check = 0;
4750
4751   putFile16BitBE(file, num_changed_custom_elements);
4752
4753   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4754   {
4755     int element = EL_CUSTOM_START + i;
4756
4757 #if 1
4758     struct ElementInfo *ei = &element_info[element];
4759
4760     if (ei->properties[EP_BITFIELD_BASE_NR] != EP_BITMASK_DEFAULT)
4761     {
4762       if (check < num_changed_custom_elements)
4763       {
4764         putFile16BitBE(file, element);
4765         putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
4766       }
4767
4768       check++;
4769     }
4770 #else
4771     if (Properties[element][EP_BITFIELD_BASE_NR] != EP_BITMASK_DEFAULT)
4772     {
4773       if (check < num_changed_custom_elements)
4774       {
4775         putFile16BitBE(file, element);
4776         putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE_NR]);
4777       }
4778
4779       check++;
4780     }
4781 #endif
4782   }
4783
4784   if (check != num_changed_custom_elements)     /* should not happen */
4785     Error(ERR_WARN, "inconsistent number of custom element properties");
4786 }
4787 #endif
4788
4789 #if 0
4790 static void SaveLevel_CUS2(FILE *file, struct LevelInfo *level,
4791                            int num_changed_custom_elements)
4792 {
4793   int i, check = 0;
4794
4795   putFile16BitBE(file, num_changed_custom_elements);
4796
4797   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4798   {
4799     int element = EL_CUSTOM_START + i;
4800
4801     if (element_info[element].change->target_element != EL_EMPTY_SPACE)
4802     {
4803       if (check < num_changed_custom_elements)
4804       {
4805         putFile16BitBE(file, element);
4806         putFile16BitBE(file, element_info[element].change->target_element);
4807       }
4808
4809       check++;
4810     }
4811   }
4812
4813   if (check != num_changed_custom_elements)     /* should not happen */
4814     Error(ERR_WARN, "inconsistent number of custom target elements");
4815 }
4816 #endif
4817
4818 #if 0
4819 static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
4820                            int num_changed_custom_elements)
4821 {
4822   int i, j, x, y, check = 0;
4823
4824   putFile16BitBE(file, num_changed_custom_elements);
4825
4826   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4827   {
4828     int element = EL_CUSTOM_START + i;
4829     struct ElementInfo *ei = &element_info[element];
4830
4831     if (ei->modified_settings)
4832     {
4833       if (check < num_changed_custom_elements)
4834       {
4835         putFile16BitBE(file, element);
4836
4837         for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++)
4838           putFile8Bit(file, ei->description[j]);
4839
4840 #if 1
4841         putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
4842 #else
4843         putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE_NR]);
4844 #endif
4845
4846         /* some free bytes for future properties and padding */
4847         WriteUnusedBytesToFile(file, 7);
4848
4849         putFile8Bit(file, ei->use_gfx_element);
4850         putFile16BitBE(file, ei->gfx_element);
4851
4852         putFile8Bit(file, ei->collect_score_initial);
4853         putFile8Bit(file, ei->collect_count_initial);
4854
4855         putFile16BitBE(file, ei->push_delay_fixed);
4856         putFile16BitBE(file, ei->push_delay_random);
4857         putFile16BitBE(file, ei->move_delay_fixed);
4858         putFile16BitBE(file, ei->move_delay_random);
4859
4860         putFile16BitBE(file, ei->move_pattern);
4861         putFile8Bit(file, ei->move_direction_initial);
4862         putFile8Bit(file, ei->move_stepsize);
4863
4864         for (y = 0; y < 3; y++)
4865           for (x = 0; x < 3; x++)
4866             putFile16BitBE(file, ei->content.e[x][y]);
4867
4868         putFile32BitBE(file, ei->change->events);
4869
4870         putFile16BitBE(file, ei->change->target_element);
4871
4872         putFile16BitBE(file, ei->change->delay_fixed);
4873         putFile16BitBE(file, ei->change->delay_random);
4874         putFile16BitBE(file, ei->change->delay_frames);
4875
4876         putFile16BitBE(file, ei->change->trigger_element);
4877
4878         putFile8Bit(file, ei->change->explode);
4879         putFile8Bit(file, ei->change->use_target_content);
4880         putFile8Bit(file, ei->change->only_if_complete);
4881         putFile8Bit(file, ei->change->use_random_replace);
4882
4883         putFile8Bit(file, ei->change->random_percentage);
4884         putFile8Bit(file, ei->change->replace_when);
4885
4886         for (y = 0; y < 3; y++)
4887           for (x = 0; x < 3; x++)
4888             putFile16BitBE(file, ei->change->content.e[x][y]);
4889
4890         putFile8Bit(file, ei->slippery_type);
4891
4892         /* some free bytes for future properties and padding */
4893         WriteUnusedBytesToFile(file, LEVEL_CPART_CUS3_UNUSED);
4894       }
4895
4896       check++;
4897     }
4898   }
4899
4900   if (check != num_changed_custom_elements)     /* should not happen */
4901     Error(ERR_WARN, "inconsistent number of custom element properties");
4902 }
4903 #endif
4904
4905 #if 0
4906 static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
4907 {
4908   struct ElementInfo *ei = &element_info[element];
4909   int i, j, x, y;
4910
4911   /* ---------- custom element base property values (96 bytes) ------------- */
4912
4913   putFile16BitBE(file, element);
4914
4915   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
4916     putFile8Bit(file, ei->description[i]);
4917
4918 #if 1
4919   putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
4920 #else
4921   putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE_NR]);
4922 #endif
4923   WriteUnusedBytesToFile(file, 4);      /* reserved for more base properties */
4924
4925   putFile8Bit(file, ei->num_change_pages);
4926
4927   putFile16BitBE(file, ei->ce_value_fixed_initial);
4928   putFile16BitBE(file, ei->ce_value_random_initial);
4929   putFile8Bit(file, ei->use_last_ce_value);
4930
4931   putFile8Bit(file, ei->use_gfx_element);
4932   putFile16BitBE(file, ei->gfx_element);
4933
4934   putFile8Bit(file, ei->collect_score_initial);
4935   putFile8Bit(file, ei->collect_count_initial);
4936
4937   putFile8Bit(file, ei->drop_delay_fixed);
4938   putFile8Bit(file, ei->push_delay_fixed);
4939   putFile8Bit(file, ei->drop_delay_random);
4940   putFile8Bit(file, ei->push_delay_random);
4941   putFile16BitBE(file, ei->move_delay_fixed);
4942   putFile16BitBE(file, ei->move_delay_random);
4943
4944   /* bits 0 - 15 of "move_pattern" ... */
4945   putFile16BitBE(file, ei->move_pattern & 0xffff);
4946   putFile8Bit(file, ei->move_direction_initial);
4947   putFile8Bit(file, ei->move_stepsize);
4948
4949   putFile8Bit(file, ei->slippery_type);
4950
4951   for (y = 0; y < 3; y++)
4952     for (x = 0; x < 3; x++)
4953       putFile16BitBE(file, ei->content.e[x][y]);
4954
4955   putFile16BitBE(file, ei->move_enter_element);
4956   putFile16BitBE(file, ei->move_leave_element);
4957   putFile8Bit(file, ei->move_leave_type);
4958
4959   /* ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible) */
4960   putFile16BitBE(file, (ei->move_pattern >> 16) & 0xffff);
4961
4962   putFile8Bit(file, ei->access_direction);
4963
4964   putFile8Bit(file, ei->explosion_delay);
4965   putFile8Bit(file, ei->ignition_delay);
4966   putFile8Bit(file, ei->explosion_type);
4967
4968   /* some free bytes for future custom property values and padding */
4969   WriteUnusedBytesToFile(file, 1);
4970
4971   /* ---------- change page property values (48 bytes) --------------------- */
4972
4973   for (i = 0; i < ei->num_change_pages; i++)
4974   {
4975     struct ElementChangeInfo *change = &ei->change_page[i];
4976     unsigned int event_bits;
4977
4978     /* bits 0 - 31 of "has_event[]" ... */
4979     event_bits = 0;
4980     for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
4981       if (change->has_event[j])
4982         event_bits |= (1 << j);
4983     putFile32BitBE(file, event_bits);
4984
4985     putFile16BitBE(file, change->target_element);
4986
4987     putFile16BitBE(file, change->delay_fixed);
4988     putFile16BitBE(file, change->delay_random);
4989     putFile16BitBE(file, change->delay_frames);
4990
4991     putFile16BitBE(file, change->trigger_element);
4992
4993     putFile8Bit(file, change->explode);
4994     putFile8Bit(file, change->use_target_content);
4995     putFile8Bit(file, change->only_if_complete);
4996     putFile8Bit(file, change->use_random_replace);
4997
4998     putFile8Bit(file, change->random_percentage);
4999     putFile8Bit(file, change->replace_when);
5000
5001     for (y = 0; y < 3; y++)
5002       for (x = 0; x < 3; x++)
5003         putFile16BitBE(file, change->target_content.e[x][y]);
5004
5005     putFile8Bit(file, change->can_change);
5006
5007     putFile8Bit(file, change->trigger_side);
5008
5009     putFile8Bit(file, change->trigger_player);
5010     putFile8Bit(file, (change->trigger_page == CH_PAGE_ANY ? CH_PAGE_ANY_FILE :
5011                        log_2(change->trigger_page)));
5012
5013     putFile8Bit(file, change->has_action);
5014     putFile8Bit(file, change->action_type);
5015     putFile8Bit(file, change->action_mode);
5016     putFile16BitBE(file, change->action_arg);
5017
5018     /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */
5019     event_bits = 0;
5020     for (j = 32; j < NUM_CHANGE_EVENTS; j++)
5021       if (change->has_event[j])
5022         event_bits |= (1 << (j - 32));
5023     putFile8Bit(file, event_bits);
5024   }
5025 }
5026 #endif
5027
5028 #if 0
5029 static void SaveLevel_GRP1(FILE *file, struct LevelInfo *level, int element)
5030 {
5031   struct ElementInfo *ei = &element_info[element];
5032   struct ElementGroupInfo *group = ei->group;
5033   int i;
5034
5035   putFile16BitBE(file, element);
5036
5037   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
5038     putFile8Bit(file, ei->description[i]);
5039
5040   putFile8Bit(file, group->num_elements);
5041
5042   putFile8Bit(file, ei->use_gfx_element);
5043   putFile16BitBE(file, ei->gfx_element);
5044
5045   putFile8Bit(file, group->choice_mode);
5046
5047   /* some free bytes for future values and padding */
5048   WriteUnusedBytesToFile(file, 3);
5049
5050   for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
5051     putFile16BitBE(file, group->element[i]);
5052 }
5053 #endif
5054
5055 static int SaveLevel_MicroChunk(FILE *file, struct ElementFileConfig *entry)
5056 {
5057   int data_type = entry->data_type;
5058   int conf_type = entry->conf_type;
5059   int byte_mask = conf_type & CONF_MASK_BYTES;
5060   int element = entry->element;
5061   int default_value = entry->default_value;
5062   int num_bytes = 0;
5063   boolean modified = FALSE;
5064
5065   if (byte_mask != CONF_MASK_MULTI_BYTES)
5066   {
5067     void *value_ptr = entry->value;
5068     int value = (data_type == TYPE_BOOLEAN ? *(boolean *)value_ptr :
5069                  *(int *)value_ptr);
5070
5071     /* check if any settings have been modified before saving them */
5072     if (value != default_value)
5073       modified = TRUE;
5074
5075     if (!modified)              /* do not save unmodified default settings */
5076       return 0;
5077
5078     if (element != -1)
5079       num_bytes += putFile16BitBE(file, element);
5080
5081     num_bytes += putFile8Bit(file, conf_type);
5082     num_bytes += (byte_mask == CONF_MASK_1_BYTE ? putFile8Bit   (file, value) :
5083                   byte_mask == CONF_MASK_2_BYTE ? putFile16BitBE(file, value) :
5084                   byte_mask == CONF_MASK_4_BYTE ? putFile32BitBE(file, value) :
5085                   0);
5086
5087     return num_bytes;
5088   }
5089   else if (data_type == TYPE_STRING)
5090   {
5091     char *default_string = entry->default_string;
5092     char *string = (char *)(entry->value);
5093     int string_length = strlen(string);
5094     int i;
5095
5096     /* check if any settings have been modified before saving them */
5097     if (!strEqual(string, default_string))
5098       modified = TRUE;
5099
5100     if (!modified)              /* do not save unmodified default settings */
5101       return 0;
5102
5103     if (element != -1)
5104       num_bytes += putFile16BitBE(file, element);
5105
5106     num_bytes += putFile8Bit(file, conf_type);
5107     num_bytes += putFile16BitBE(file, string_length);
5108
5109     for (i = 0; i < string_length; i++)
5110       num_bytes += putFile8Bit(file, string[i]);
5111
5112     return num_bytes;
5113   }
5114   else if (data_type == TYPE_ELEMENT_LIST)
5115   {
5116     int *element_array = (int *)(entry->value);
5117     int num_elements = *(int *)(entry->num_entities);
5118     int i;
5119
5120     /* check if any settings have been modified before saving them */
5121     for (i = 0; i < num_elements; i++)
5122       if (element_array[i] != default_value)
5123         modified = TRUE;
5124
5125     if (!modified)              /* do not save unmodified default settings */
5126       return 0;
5127
5128     if (element != -1)
5129       num_bytes += putFile16BitBE(file, element);
5130
5131     num_bytes += putFile8Bit(file, conf_type);
5132     num_bytes += putFile16BitBE(file, num_elements * CONF_ELEMENT_NUM_BYTES);
5133
5134     for (i = 0; i < num_elements; i++)
5135       num_bytes += putFile16BitBE(file, element_array[i]);
5136
5137     return num_bytes;
5138   }
5139   else if (data_type == TYPE_CONTENT_LIST)
5140   {
5141     struct Content *content = (struct Content *)(entry->value);
5142     int num_contents = *(int *)(entry->num_entities);
5143     int i, x, y;
5144
5145     /* check if any settings have been modified before saving them */
5146     for (i = 0; i < num_contents; i++)
5147       for (y = 0; y < 3; y++)
5148         for (x = 0; x < 3; x++)
5149           if (content[i].e[x][y] != default_value)
5150             modified = TRUE;
5151
5152     if (!modified)              /* do not save unmodified default settings */
5153       return 0;
5154
5155     if (element != -1)
5156       num_bytes += putFile16BitBE(file, element);
5157
5158     num_bytes += putFile8Bit(file, conf_type);
5159     num_bytes += putFile16BitBE(file, num_contents * CONF_CONTENT_NUM_BYTES);
5160
5161     for (i = 0; i < num_contents; i++)
5162       for (y = 0; y < 3; y++)
5163         for (x = 0; x < 3; x++)
5164           num_bytes += putFile16BitBE(file, content[i].e[x][y]);
5165
5166     return num_bytes;
5167   }
5168
5169   return 0;
5170 }
5171
5172 #if 0
5173
5174 static int SaveLevel_MicroChunk_SingleValue(FILE *file,
5175                                             struct ElementFileConfig *entry)
5176 {
5177   int default_value = entry->default_value;
5178   int element = entry->element;
5179   int data_type = entry->data_type;
5180   int conf_type = entry->conf_type;
5181   int byte_mask = conf_type & CONF_MASK_BYTES;
5182   void *value_ptr = entry->value;
5183   int value = (data_type == TYPE_BOOLEAN ? *(boolean *)value_ptr :
5184                *(int *)value_ptr);
5185   int num_bytes = 0;
5186   boolean modified = FALSE;
5187
5188   /* check if any settings have been modified before saving them */
5189   if (value != default_value)
5190     modified = TRUE;
5191
5192   if (!modified)                /* do not save unmodified default settings */
5193     return 0;
5194
5195 #if 0
5196   printf("::: %02x, %d: %d != %d\n",
5197          byte_mask, conf_type & CONF_MASK_TOKEN,
5198          value, default_value);
5199 #endif
5200
5201   if (element != -1)
5202     num_bytes += putFile16BitBE(file, element);
5203
5204   num_bytes += putFile8Bit(file, conf_type);
5205   num_bytes += (byte_mask == CONF_MASK_1_BYTE ? putFile8Bit   (file, value) :
5206                 byte_mask == CONF_MASK_2_BYTE ? putFile16BitBE(file, value) :
5207                 byte_mask == CONF_MASK_4_BYTE ? putFile32BitBE(file, value) :0);
5208
5209   return num_bytes;
5210 }
5211
5212 static int SaveLevel_MicroChunk_ElementList(FILE *file,
5213                                             struct ElementFileConfig *entry)
5214 {
5215   int *element_array = (int *)(entry->value);
5216   int num_elements = *(int *)(entry->num_entities);
5217   int default_value = entry->default_value;
5218   int element = entry->element;
5219   int conf_type = entry->conf_type;
5220   int num_bytes = 0;
5221   boolean modified = FALSE;
5222   int i;
5223
5224   /* check if any settings have been modified before saving them */
5225   for (i = 0; i < num_elements; i++)
5226     if (element_array[i] != default_value)
5227       modified = TRUE;
5228
5229   if (!modified)                /* do not save unmodified default settings */
5230     return 0;
5231
5232   if (element != -1)
5233     num_bytes += putFile16BitBE(file, element);
5234
5235   num_bytes += putFile8Bit(file, conf_type);
5236   num_bytes += putFile16BitBE(file, num_elements * CONF_ELEMENT_NUM_BYTES);
5237
5238   for (i = 0; i < num_elements; i++)
5239     num_bytes += putFile16BitBE(file, element_array[i]);
5240
5241   return num_bytes;
5242 }
5243
5244 static int SaveLevel_MicroChunk_ContentList(FILE *file,
5245                                             struct ElementFileConfig *entry)
5246 {
5247   struct Content *content = (struct Content *)(entry->value);
5248   int num_contents = *(int *)(entry->num_entities);
5249   int default_value = entry->default_value;
5250   int element = entry->element;
5251   int conf_type = entry->conf_type;
5252   int num_bytes = 0;
5253   boolean modified = FALSE;
5254   int i, x, y;
5255
5256   /* check if any settings have been modified before saving them */
5257   for (i = 0; i < num_contents; i++)
5258     for (y = 0; y < 3; y++)
5259       for (x = 0; x < 3; x++)
5260         if (content[i].e[x][y] != default_value)
5261           modified = TRUE;
5262
5263   if (!modified)                /* do not save unmodified default settings */
5264     return 0;
5265
5266   if (element != -1)
5267     num_bytes += putFile16BitBE(file, element);
5268
5269   num_bytes += putFile8Bit(file, conf_type);
5270   num_bytes += putFile16BitBE(file, num_contents * CONF_CONTENT_NUM_BYTES);
5271
5272   for (i = 0; i < num_contents; i++)
5273     for (y = 0; y < 3; y++)
5274       for (x = 0; x < 3; x++)
5275         num_bytes += putFile16BitBE(file, content[i].e[x][y]);
5276
5277   return num_bytes;
5278 }
5279
5280 #endif
5281
5282 static int SaveLevel_CONF(FILE *file, struct LevelInfo *level)
5283 {
5284   int chunk_size = 0;
5285   int i;
5286
5287   li = *level;          /* copy level data into temporary buffer */
5288
5289   for (i = 0; element_conf[i].data_type != -1; i++)
5290   {
5291 #if 1
5292     chunk_size += SaveLevel_MicroChunk(file, &element_conf[i]);
5293 #else
5294     struct ElementFileConfig *config = &element_conf[i];
5295     int data_type = config->data_type;
5296     int conf_type = config->conf_type;
5297     int byte_mask = conf_type & CONF_MASK_BYTES;
5298
5299     if (byte_mask != CONF_MASK_MULTI_BYTES)
5300       chunk_size += SaveLevel_MicroChunk_SingleValue(file, config);
5301     else if (data_type == TYPE_ELEMENT_LIST)
5302       chunk_size += SaveLevel_MicroChunk_ElementList(file, config);
5303     else if (data_type == TYPE_CONTENT_LIST)
5304       chunk_size += SaveLevel_MicroChunk_ContentList(file, config);
5305 #endif
5306   }
5307
5308   return chunk_size;
5309 }
5310
5311 static int SaveLevel_CUSX(FILE *file, struct LevelInfo *level, int element)
5312 {
5313   struct ElementInfo *ei = &element_info[element];
5314   int chunk_size = 0;
5315   int i, j;
5316
5317   chunk_size += putFile16BitBE(file, element);
5318
5319   xx_ei = *ei;          /* copy element data into temporary buffer */
5320
5321   /* set default description string for this specific element */
5322   strcpy(xx_default_description, getDefaultElementDescription(ei));
5323
5324   /* set (fixed) number of content areas (may have been overwritten earlier) */
5325   xx_num_contents = 1;
5326
5327 #if 0
5328   printf("::: - element config\n");
5329 #endif
5330
5331   for (i = 0; custom_element_conf[i].data_type != -1; i++)
5332     chunk_size += SaveLevel_MicroChunk(file, &custom_element_conf[i]);
5333
5334 #if 0
5335   printf("::: - change pages\n");
5336 #endif
5337
5338   for (i = 0; i < ei->num_change_pages; i++)
5339   {
5340     struct ElementChangeInfo *change = &ei->change_page[i];
5341
5342     xx_current_change_page = i;
5343
5344     xx_change = *change;        /* copy change data into temporary buffer */
5345
5346 #if 0
5347     printf(":::   %d: xx_change.action_mode == %d\n",
5348            i, xx_change.action_mode);
5349     printf(":::   %d: xx_change.action_arg == %d\n",
5350            i, xx_change.action_arg);
5351 #endif
5352
5353     resetEventBits();
5354     setEventBitsFromEventFlags(change);
5355
5356     for (j = 0; custom_element_change_conf[j].data_type != -1; j++)
5357       chunk_size += SaveLevel_MicroChunk(file, &custom_element_change_conf[j]);
5358
5359 #if 0
5360     if (element == EL_CUSTOM_START)
5361       printf("::: - saving change page %d / %d (%d bytes)\n",
5362              i, ei->num_change_pages, chunk_size);
5363 #endif
5364   }
5365
5366   return chunk_size;
5367 }
5368
5369 static int SaveLevel_GRPX(FILE *file, struct LevelInfo *level, int element)
5370 {
5371   struct ElementInfo *ei = &element_info[element];
5372   struct ElementGroupInfo *group = ei->group;
5373   int chunk_size = 0;
5374   int i;
5375
5376   chunk_size += putFile16BitBE(file, element);
5377
5378   xx_ei = *ei;          /* copy element data into temporary buffer */
5379   xx_group = *group;    /* copy group data into temporary buffer */
5380
5381   /* set default description string for this specific element */
5382   strcpy(xx_default_description, getDefaultElementDescription(ei));
5383
5384   for (i = 0; group_element_conf[i].data_type != -1; i++)
5385     chunk_size += SaveLevel_MicroChunk(file, &group_element_conf[i]);
5386
5387   return chunk_size;
5388 }
5389
5390 static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
5391 {
5392   int body_chunk_size, conf_chunk_size;
5393   int i, x, y;
5394   FILE *file;
5395
5396   if (!(file = fopen(filename, MODE_WRITE)))
5397   {
5398     Error(ERR_WARN, "cannot save level file '%s'", filename);
5399     return;
5400   }
5401
5402   level->file_version = FILE_VERSION_ACTUAL;
5403   level->game_version = GAME_VERSION_ACTUAL;
5404
5405   /* check level field for 16-bit elements */
5406   level->encoding_16bit_field = FALSE;
5407   for (y = 0; y < level->fieldy; y++) 
5408     for (x = 0; x < level->fieldx; x++) 
5409       if (level->field[x][y] > 255)
5410         level->encoding_16bit_field = TRUE;
5411
5412   /* check yamyam content for 16-bit elements */
5413   level->encoding_16bit_yamyam = FALSE;
5414   for (i = 0; i < level->num_yamyam_contents; i++)
5415     for (y = 0; y < 3; y++)
5416       for (x = 0; x < 3; x++)
5417         if (level->yamyam_content[i].e[x][y] > 255)
5418           level->encoding_16bit_yamyam = TRUE;
5419
5420   /* check amoeba content for 16-bit elements */
5421   level->encoding_16bit_amoeba = FALSE;
5422   if (level->amoeba_content > 255)
5423     level->encoding_16bit_amoeba = TRUE;
5424
5425   /* calculate size of "BODY" chunk */
5426   body_chunk_size =
5427     level->fieldx * level->fieldy * (level->encoding_16bit_field ? 2 : 1);
5428
5429   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
5430   putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
5431
5432   putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
5433   SaveLevel_VERS(file, level);
5434
5435   putFileChunkBE(file, "HEAD", LEVEL_HEADER_SIZE);
5436   SaveLevel_HEAD(file, level);
5437
5438   putFileChunkBE(file, "AUTH", MAX_LEVEL_AUTHOR_LEN);
5439   SaveLevel_AUTH(file, level);
5440
5441   putFileChunkBE(file, "BODY", body_chunk_size);
5442   SaveLevel_BODY(file, level);
5443
5444   if (level->encoding_16bit_yamyam ||
5445       level->num_yamyam_contents != STD_ELEMENT_CONTENTS)
5446   {
5447     putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
5448     SaveLevel_CNT2(file, level, EL_YAMYAM);
5449   }
5450
5451   if (level->encoding_16bit_amoeba)
5452   {
5453     putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
5454     SaveLevel_CNT2(file, level, EL_BD_AMOEBA);
5455   }
5456
5457   /* check for envelope content */
5458   for (i = 0; i < 4; i++)
5459   {
5460     if (strlen(level->envelope_text[i]) > 0)
5461     {
5462       int envelope_len = strlen(level->envelope_text[i]) + 1;
5463
5464       putFileChunkBE(file, "CNT3", LEVEL_CHUNK_CNT3_SIZE(envelope_len));
5465       SaveLevel_CNT3(file, level, EL_ENVELOPE_1 + i);
5466     }
5467   }
5468
5469   /* if not using template level, check for non-default custom/group elements */
5470   if (!level->use_custom_template)
5471   {
5472 #if 0
5473     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
5474     {
5475       int element = EL_CUSTOM_START + i;
5476
5477       if (element_info[element].modified_settings)
5478       {
5479         int num_change_pages = element_info[element].num_change_pages;
5480
5481         putFileChunkBE(file, "CUS4", LEVEL_CHUNK_CUS4_SIZE(num_change_pages));
5482         SaveLevel_CUS4(file, level, element);
5483       }
5484     }
5485
5486     for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
5487     {
5488       int element = EL_GROUP_START + i;
5489
5490       if (element_info[element].modified_settings)
5491       {
5492         putFileChunkBE(file, "GRP1", LEVEL_CHUNK_GRP1_SIZE);
5493         SaveLevel_GRP1(file, level, element);
5494       }
5495     }
5496 #endif
5497   }
5498
5499   conf_chunk_size = SaveLevel_CONF(NULL, level);
5500
5501   /* check if non-default element settings need to be saved */
5502   if (conf_chunk_size > 0)
5503   {
5504     putFileChunkBE(file, "CONF", conf_chunk_size);
5505     SaveLevel_CONF(file, level);
5506   }
5507
5508   /* if not using template level, check for non-default custom/group elements */
5509   if (!level->use_custom_template)
5510   {
5511     /* (element number, number of change pages, change page number) */
5512     int cusx_chunk_size_no_changes = (2) + (1 + 1) + (1 + 1);
5513     /* (element number only) */
5514     int grpx_chunk_size_no_changes = (2);
5515
5516 #if 1
5517     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
5518     {
5519       int element = EL_CUSTOM_START + i;
5520       int cusx_chunk_size = SaveLevel_CUSX(NULL, level, element);
5521
5522       /* check if non-default element settings need to be saved */
5523       if (cusx_chunk_size > cusx_chunk_size_no_changes)
5524       {
5525 #if 1
5526         printf("::: SAVING CE %d\n", i + 1);
5527 #endif
5528
5529         putFileChunkBE(file, "CUSX", cusx_chunk_size);
5530         SaveLevel_CUSX(file, level, element);
5531       }
5532     }
5533
5534     for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
5535     {
5536       int element = EL_GROUP_START + i;
5537       int grpx_chunk_size = SaveLevel_GRPX(NULL, level, element);
5538
5539       /* check if non-default element settings need to be saved */
5540       if (grpx_chunk_size > grpx_chunk_size_no_changes)
5541       {
5542 #if 1
5543         printf("::: SAVING GE %d\n", i + 1);
5544 #endif
5545
5546         putFileChunkBE(file, "GRPX", grpx_chunk_size);
5547         SaveLevel_GRPX(file, level, element);
5548       }
5549     }
5550 #endif
5551   }
5552
5553   fclose(file);
5554
5555   SetFilePermissions(filename, PERMS_PRIVATE);
5556 }
5557
5558 void SaveLevel(int nr)
5559 {
5560   char *filename = getDefaultLevelFilename(nr);
5561
5562   SaveLevelFromFilename(&level, filename);
5563 }
5564
5565 void SaveLevelTemplate()
5566 {
5567   char *filename = getDefaultLevelFilename(-1);
5568
5569   SaveLevelFromFilename(&level, filename);
5570 }
5571
5572 void DumpLevel(struct LevelInfo *level)
5573 {
5574   if (level->no_valid_file)
5575   {
5576     Error(ERR_WARN, "cannot dump -- no valid level file found");
5577
5578     return;
5579   }
5580
5581   printf_line("-", 79);
5582   printf("Level xxx (file version %08d, game version %08d)\n",
5583          level->file_version, level->game_version);
5584   printf_line("-", 79);
5585
5586   printf("Level author: '%s'\n", level->author);
5587   printf("Level title:  '%s'\n", level->name);
5588   printf("\n");
5589   printf("Playfield size: %d x %d\n", level->fieldx, level->fieldy);
5590   printf("\n");
5591   printf("Level time:  %d seconds\n", level->time);
5592   printf("Gems needed: %d\n", level->gems_needed);
5593   printf("\n");
5594   printf("Time for magic wall: %d seconds\n", level->time_magic_wall);
5595   printf("Time for wheel:      %d seconds\n", level->time_wheel);
5596   printf("Time for light:      %d seconds\n", level->time_light);
5597   printf("Time for timegate:   %d seconds\n", level->time_timegate);
5598   printf("\n");
5599   printf("Amoeba speed: %d\n", level->amoeba_speed);
5600   printf("\n");
5601   printf("Initial gravity:             %s\n", (level->initial_gravity ? "yes" : "no"));
5602   printf("Initial player stepsize:     %d\n", level->initial_player_stepsize);
5603   printf("EM style slippery gems:      %s\n", (level->em_slippery_gems ? "yes" : "no"));
5604   printf("Player blocks last field:    %s\n", (level->block_last_field ? "yes" : "no"));
5605   printf("SP player blocks last field: %s\n", (level->sp_block_last_field ? "yes" : "no"));
5606   printf("use spring bug: %s\n", (level->use_spring_bug ? "yes" : "no"));
5607   printf("use step counter: %s\n", (level->use_step_counter ? "yes" : "no"));
5608
5609   printf_line("-", 79);
5610 }
5611
5612
5613 /* ========================================================================= */
5614 /* tape file functions                                                       */
5615 /* ========================================================================= */
5616
5617 static void setTapeInfoToDefaults()
5618 {
5619   int i;
5620
5621   /* always start with reliable default values (empty tape) */
5622   TapeErase();
5623
5624   /* default values (also for pre-1.2 tapes) with only the first player */
5625   tape.player_participates[0] = TRUE;
5626   for (i = 1; i < MAX_PLAYERS; i++)
5627     tape.player_participates[i] = FALSE;
5628
5629   /* at least one (default: the first) player participates in every tape */
5630   tape.num_participating_players = 1;
5631
5632   tape.level_nr = level_nr;
5633   tape.counter = 0;
5634   tape.changed = FALSE;
5635
5636   tape.recording = FALSE;
5637   tape.playing = FALSE;
5638   tape.pausing = FALSE;
5639
5640   tape.no_valid_file = FALSE;
5641 }
5642
5643 static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
5644 {
5645   tape->file_version = getFileVersion(file);
5646   tape->game_version = getFileVersion(file);
5647
5648   return chunk_size;
5649 }
5650
5651 static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
5652 {
5653   int i;
5654
5655   tape->random_seed = getFile32BitBE(file);
5656   tape->date        = getFile32BitBE(file);
5657   tape->length      = getFile32BitBE(file);
5658
5659   /* read header fields that are new since version 1.2 */
5660   if (tape->file_version >= FILE_VERSION_1_2)
5661   {
5662     byte store_participating_players = getFile8Bit(file);
5663     int engine_version;
5664
5665     /* since version 1.2, tapes store which players participate in the tape */
5666     tape->num_participating_players = 0;
5667     for (i = 0; i < MAX_PLAYERS; i++)
5668     {
5669       tape->player_participates[i] = FALSE;
5670
5671       if (store_participating_players & (1 << i))
5672       {
5673         tape->player_participates[i] = TRUE;
5674         tape->num_participating_players++;
5675       }
5676     }
5677
5678     ReadUnusedBytesFromFile(file, TAPE_HEADER_UNUSED);
5679
5680     engine_version = getFileVersion(file);
5681     if (engine_version > 0)
5682       tape->engine_version = engine_version;
5683     else
5684       tape->engine_version = tape->game_version;
5685   }
5686
5687   return chunk_size;
5688 }
5689
5690 static int LoadTape_INFO(FILE *file, int chunk_size, struct TapeInfo *tape)
5691 {
5692   int level_identifier_size;
5693   int i;
5694
5695   level_identifier_size = getFile16BitBE(file);
5696
5697   tape->level_identifier =
5698     checked_realloc(tape->level_identifier, level_identifier_size);
5699
5700   for (i = 0; i < level_identifier_size; i++)
5701     tape->level_identifier[i] = getFile8Bit(file);
5702
5703   tape->level_nr = getFile16BitBE(file);
5704
5705   chunk_size = 2 + level_identifier_size + 2;
5706
5707   return chunk_size;
5708 }
5709
5710 static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
5711 {
5712   int i, j;
5713   int chunk_size_expected =
5714     (tape->num_participating_players + 1) * tape->length;
5715
5716   if (chunk_size_expected != chunk_size)
5717   {
5718     ReadUnusedBytesFromFile(file, chunk_size);
5719     return chunk_size_expected;
5720   }
5721
5722   for (i = 0; i < tape->length; i++)
5723   {
5724     if (i >= MAX_TAPE_LEN)
5725       break;
5726
5727     for (j = 0; j < MAX_PLAYERS; j++)
5728     {
5729       tape->pos[i].action[j] = MV_NONE;
5730
5731       if (tape->player_participates[j])
5732         tape->pos[i].action[j] = getFile8Bit(file);
5733     }
5734
5735     tape->pos[i].delay = getFile8Bit(file);
5736
5737     if (tape->file_version == FILE_VERSION_1_0)
5738     {
5739       /* eliminate possible diagonal moves in old tapes */
5740       /* this is only for backward compatibility */
5741
5742       byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
5743       byte action = tape->pos[i].action[0];
5744       int k, num_moves = 0;
5745
5746       for (k = 0; k<4; k++)
5747       {
5748         if (action & joy_dir[k])
5749         {
5750           tape->pos[i + num_moves].action[0] = joy_dir[k];
5751           if (num_moves > 0)
5752             tape->pos[i + num_moves].delay = 0;
5753           num_moves++;
5754         }
5755       }
5756
5757       if (num_moves > 1)
5758       {
5759         num_moves--;
5760         i += num_moves;
5761         tape->length += num_moves;
5762       }
5763     }
5764     else if (tape->file_version < FILE_VERSION_2_0)
5765     {
5766       /* convert pre-2.0 tapes to new tape format */
5767
5768       if (tape->pos[i].delay > 1)
5769       {
5770         /* action part */
5771         tape->pos[i + 1] = tape->pos[i];
5772         tape->pos[i + 1].delay = 1;
5773
5774         /* delay part */
5775         for (j = 0; j < MAX_PLAYERS; j++)
5776           tape->pos[i].action[j] = MV_NONE;
5777         tape->pos[i].delay--;
5778
5779         i++;
5780         tape->length++;
5781       }
5782     }
5783
5784     if (feof(file))
5785       break;
5786   }
5787
5788   if (i != tape->length)
5789     chunk_size = (tape->num_participating_players + 1) * i;
5790
5791   return chunk_size;
5792 }
5793
5794 void LoadTapeFromFilename(char *filename)
5795 {
5796   char cookie[MAX_LINE_LEN];
5797   char chunk_name[CHUNK_ID_LEN + 1];
5798   FILE *file;
5799   int chunk_size;
5800
5801   /* always start with reliable default values */
5802   setTapeInfoToDefaults();
5803
5804   if (!(file = fopen(filename, MODE_READ)))
5805   {
5806     tape.no_valid_file = TRUE;
5807
5808     return;
5809   }
5810
5811   getFileChunkBE(file, chunk_name, NULL);
5812   if (strEqual(chunk_name, "RND1"))
5813   {
5814     getFile32BitBE(file);               /* not used */
5815
5816     getFileChunkBE(file, chunk_name, NULL);
5817     if (!strEqual(chunk_name, "TAPE"))
5818     {
5819       tape.no_valid_file = TRUE;
5820
5821       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
5822       fclose(file);
5823       return;
5824     }
5825   }
5826   else  /* check for pre-2.0 file format with cookie string */
5827   {
5828     strcpy(cookie, chunk_name);
5829     fgets(&cookie[4], MAX_LINE_LEN - 4, file);
5830     if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
5831       cookie[strlen(cookie) - 1] = '\0';
5832
5833     if (!checkCookieString(cookie, TAPE_COOKIE_TMPL))
5834     {
5835       tape.no_valid_file = TRUE;
5836
5837       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
5838       fclose(file);
5839       return;
5840     }
5841
5842     if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1)
5843     {
5844       tape.no_valid_file = TRUE;
5845
5846       Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
5847       fclose(file);
5848       return;
5849     }
5850
5851     /* pre-2.0 tape files have no game version, so use file version here */
5852     tape.game_version = tape.file_version;
5853   }
5854
5855   if (tape.file_version < FILE_VERSION_1_2)
5856   {
5857     /* tape files from versions before 1.2.0 without chunk structure */
5858     LoadTape_HEAD(file, TAPE_HEADER_SIZE, &tape);
5859     LoadTape_BODY(file, 2 * tape.length,  &tape);
5860   }
5861   else
5862   {
5863     static struct
5864     {
5865       char *name;
5866       int size;
5867       int (*loader)(FILE *, int, struct TapeInfo *);
5868     }
5869     chunk_info[] =
5870     {
5871       { "VERS", FILE_VERS_CHUNK_SIZE,   LoadTape_VERS },
5872       { "HEAD", TAPE_HEADER_SIZE,       LoadTape_HEAD },
5873       { "INFO", -1,                     LoadTape_INFO },
5874       { "BODY", -1,                     LoadTape_BODY },
5875       {  NULL,  0,                      NULL }
5876     };
5877
5878     while (getFileChunkBE(file, chunk_name, &chunk_size))
5879     {
5880       int i = 0;
5881
5882       while (chunk_info[i].name != NULL &&
5883              !strEqual(chunk_name, chunk_info[i].name))
5884         i++;
5885
5886       if (chunk_info[i].name == NULL)
5887       {
5888         Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'",
5889               chunk_name, filename);
5890         ReadUnusedBytesFromFile(file, chunk_size);
5891       }
5892       else if (chunk_info[i].size != -1 &&
5893                chunk_info[i].size != chunk_size)
5894       {
5895         Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
5896               chunk_size, chunk_name, filename);
5897         ReadUnusedBytesFromFile(file, chunk_size);
5898       }
5899       else
5900       {
5901         /* call function to load this tape chunk */
5902         int chunk_size_expected =
5903           (chunk_info[i].loader)(file, chunk_size, &tape);
5904
5905         /* the size of some chunks cannot be checked before reading other
5906            chunks first (like "HEAD" and "BODY") that contain some header
5907            information, so check them here */
5908         if (chunk_size_expected != chunk_size)
5909         {
5910           Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
5911                 chunk_size, chunk_name, filename);
5912         }
5913       }
5914     }
5915   }
5916
5917   fclose(file);
5918
5919   tape.length_seconds = GetTapeLength();
5920
5921 #if 0
5922   printf("::: tape game version: %d\n", tape.game_version);
5923   printf("::: tape engine version: %d\n", tape.engine_version);
5924 #endif
5925 }
5926
5927 void LoadTape(int nr)
5928 {
5929   char *filename = getTapeFilename(nr);
5930
5931   LoadTapeFromFilename(filename);
5932 }
5933
5934 void LoadSolutionTape(int nr)
5935 {
5936   char *filename = getSolutionTapeFilename(nr);
5937
5938   LoadTapeFromFilename(filename);
5939 }
5940
5941 static void SaveTape_VERS(FILE *file, struct TapeInfo *tape)
5942 {
5943   putFileVersion(file, tape->file_version);
5944   putFileVersion(file, tape->game_version);
5945 }
5946
5947 static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
5948 {
5949   int i;
5950   byte store_participating_players = 0;
5951
5952   /* set bits for participating players for compact storage */
5953   for (i = 0; i < MAX_PLAYERS; i++)
5954     if (tape->player_participates[i])
5955       store_participating_players |= (1 << i);
5956
5957   putFile32BitBE(file, tape->random_seed);
5958   putFile32BitBE(file, tape->date);
5959   putFile32BitBE(file, tape->length);
5960
5961   putFile8Bit(file, store_participating_players);
5962
5963   /* unused bytes not at the end here for 4-byte alignment of engine_version */
5964   WriteUnusedBytesToFile(file, TAPE_HEADER_UNUSED);
5965
5966   putFileVersion(file, tape->engine_version);
5967 }
5968
5969 static void SaveTape_INFO(FILE *file, struct TapeInfo *tape)
5970 {
5971   int level_identifier_size = strlen(tape->level_identifier) + 1;
5972   int i;
5973
5974   putFile16BitBE(file, level_identifier_size);
5975
5976   for (i = 0; i < level_identifier_size; i++)
5977     putFile8Bit(file, tape->level_identifier[i]);
5978
5979   putFile16BitBE(file, tape->level_nr);
5980 }
5981
5982 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
5983 {
5984   int i, j;
5985
5986   for (i = 0; i < tape->length; i++)
5987   {
5988     for (j = 0; j < MAX_PLAYERS; j++)
5989       if (tape->player_participates[j])
5990         putFile8Bit(file, tape->pos[i].action[j]);
5991
5992     putFile8Bit(file, tape->pos[i].delay);
5993   }
5994 }
5995
5996 void SaveTape(int nr)
5997 {
5998   char *filename = getTapeFilename(nr);
5999   FILE *file;
6000   boolean new_tape = TRUE;
6001   int num_participating_players = 0;
6002   int info_chunk_size;
6003   int body_chunk_size;
6004   int i;
6005
6006   InitTapeDirectory(leveldir_current->subdir);
6007
6008   /* if a tape still exists, ask to overwrite it */
6009   if (fileExists(filename))
6010   {
6011     new_tape = FALSE;
6012     if (!Request("Replace old tape ?", REQ_ASK))
6013       return;
6014   }
6015
6016   if (!(file = fopen(filename, MODE_WRITE)))
6017   {
6018     Error(ERR_WARN, "cannot save level recording file '%s'", filename);
6019     return;
6020   }
6021
6022   tape.file_version = FILE_VERSION_ACTUAL;
6023   tape.game_version = GAME_VERSION_ACTUAL;
6024
6025   /* count number of participating players  */
6026   for (i = 0; i < MAX_PLAYERS; i++)
6027     if (tape.player_participates[i])
6028       num_participating_players++;
6029
6030   info_chunk_size = 2 + (strlen(tape.level_identifier) + 1) + 2;
6031   body_chunk_size = (num_participating_players + 1) * tape.length;
6032
6033   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
6034   putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
6035
6036   putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
6037   SaveTape_VERS(file, &tape);
6038
6039   putFileChunkBE(file, "HEAD", TAPE_HEADER_SIZE);
6040   SaveTape_HEAD(file, &tape);
6041
6042   putFileChunkBE(file, "INFO", info_chunk_size);
6043   SaveTape_INFO(file, &tape);
6044
6045   putFileChunkBE(file, "BODY", body_chunk_size);
6046   SaveTape_BODY(file, &tape);
6047
6048   fclose(file);
6049
6050   SetFilePermissions(filename, PERMS_PRIVATE);
6051
6052   tape.changed = FALSE;
6053
6054   if (new_tape)
6055     Request("Tape saved !", REQ_CONFIRM);
6056 }
6057
6058 void DumpTape(struct TapeInfo *tape)
6059 {
6060   int tape_frame_counter;
6061   int i, j;
6062
6063   if (tape->no_valid_file)
6064   {
6065     Error(ERR_WARN, "cannot dump -- no valid tape file found");
6066
6067     return;
6068   }
6069
6070   printf_line("-", 79);
6071   printf("Tape of Level %03d (file version %08d, game version %08d)\n",
6072          tape->level_nr, tape->file_version, tape->game_version);
6073   printf("                  (effective engine version %08d)\n",
6074          tape->engine_version);
6075   printf("Level series identifier: '%s'\n", tape->level_identifier);
6076   printf_line("-", 79);
6077
6078   tape_frame_counter = 0;
6079
6080   for (i = 0; i < tape->length; i++)
6081   {
6082     if (i >= MAX_TAPE_LEN)
6083       break;
6084
6085     printf("%04d: ", i);
6086
6087     for (j = 0; j < MAX_PLAYERS; j++)
6088     {
6089       if (tape->player_participates[j])
6090       {
6091         int action = tape->pos[i].action[j];
6092
6093         printf("%d:%02x ", j, action);
6094         printf("[%c%c%c%c|%c%c] - ",
6095                (action & JOY_LEFT ? '<' : ' '),
6096                (action & JOY_RIGHT ? '>' : ' '),
6097                (action & JOY_UP ? '^' : ' '),
6098                (action & JOY_DOWN ? 'v' : ' '),
6099                (action & JOY_BUTTON_1 ? '1' : ' '),
6100                (action & JOY_BUTTON_2 ? '2' : ' '));
6101       }
6102     }
6103
6104     printf("(%03d) ", tape->pos[i].delay);
6105     printf("[%05d]\n", tape_frame_counter);
6106
6107     tape_frame_counter += tape->pos[i].delay;
6108   }
6109
6110   printf_line("-", 79);
6111 }
6112
6113
6114 /* ========================================================================= */
6115 /* score file functions                                                      */
6116 /* ========================================================================= */
6117
6118 void LoadScore(int nr)
6119 {
6120   int i;
6121   char *filename = getScoreFilename(nr);
6122   char cookie[MAX_LINE_LEN];
6123   char line[MAX_LINE_LEN];
6124   char *line_ptr;
6125   FILE *file;
6126
6127   /* always start with reliable default values */
6128   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
6129   {
6130     strcpy(highscore[i].Name, EMPTY_PLAYER_NAME);
6131     highscore[i].Score = 0;
6132   }
6133
6134   if (!(file = fopen(filename, MODE_READ)))
6135     return;
6136
6137   /* check file identifier */
6138   fgets(cookie, MAX_LINE_LEN, file);
6139   if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
6140     cookie[strlen(cookie) - 1] = '\0';
6141
6142   if (!checkCookieString(cookie, SCORE_COOKIE))
6143   {
6144     Error(ERR_WARN, "unknown format of score file '%s'", filename);
6145     fclose(file);
6146     return;
6147   }
6148
6149   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
6150   {
6151     fscanf(file, "%d", &highscore[i].Score);
6152     fgets(line, MAX_LINE_LEN, file);
6153
6154     if (line[strlen(line) - 1] == '\n')
6155       line[strlen(line) - 1] = '\0';
6156
6157     for (line_ptr = line; *line_ptr; line_ptr++)
6158     {
6159       if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
6160       {
6161         strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN);
6162         highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0';
6163         break;
6164       }
6165     }
6166   }
6167
6168   fclose(file);
6169 }
6170
6171 void SaveScore(int nr)
6172 {
6173   int i;
6174   char *filename = getScoreFilename(nr);
6175   FILE *file;
6176
6177   InitScoreDirectory(leveldir_current->subdir);
6178
6179   if (!(file = fopen(filename, MODE_WRITE)))
6180   {
6181     Error(ERR_WARN, "cannot save score for level %d", nr);
6182     return;
6183   }
6184
6185   fprintf(file, "%s\n\n", SCORE_COOKIE);
6186
6187   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
6188     fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name);
6189
6190   fclose(file);
6191
6192   SetFilePermissions(filename, PERMS_PUBLIC);
6193 }
6194
6195
6196 /* ========================================================================= */
6197 /* setup file functions                                                      */
6198 /* ========================================================================= */
6199
6200 #define TOKEN_STR_PLAYER_PREFIX                 "player_"
6201
6202 /* global setup */
6203 #define SETUP_TOKEN_PLAYER_NAME                 0
6204 #define SETUP_TOKEN_SOUND                       1
6205 #define SETUP_TOKEN_SOUND_LOOPS                 2
6206 #define SETUP_TOKEN_SOUND_MUSIC                 3
6207 #define SETUP_TOKEN_SOUND_SIMPLE                4
6208 #define SETUP_TOKEN_TOONS                       5
6209 #define SETUP_TOKEN_SCROLL_DELAY                6
6210 #define SETUP_TOKEN_SOFT_SCROLLING              7
6211 #define SETUP_TOKEN_FADING                      8
6212 #define SETUP_TOKEN_AUTORECORD                  9
6213 #define SETUP_TOKEN_SHOW_TITLESCREEN            10
6214 #define SETUP_TOKEN_QUICK_DOORS                 11
6215 #define SETUP_TOKEN_TEAM_MODE                   12
6216 #define SETUP_TOKEN_HANDICAP                    13
6217 #define SETUP_TOKEN_SKIP_LEVELS                 14
6218 #define SETUP_TOKEN_TIME_LIMIT                  15
6219 #define SETUP_TOKEN_FULLSCREEN                  16
6220 #define SETUP_TOKEN_ASK_ON_ESCAPE               17
6221 #define SETUP_TOKEN_ASK_ON_ESCAPE_EDITOR        18
6222 #define SETUP_TOKEN_QUICK_SWITCH                19
6223 #define SETUP_TOKEN_INPUT_ON_FOCUS              20
6224 #define SETUP_TOKEN_PREFER_AGA_GRAPHICS         21
6225 #define SETUP_TOKEN_GRAPHICS_SET                22
6226 #define SETUP_TOKEN_SOUNDS_SET                  23
6227 #define SETUP_TOKEN_MUSIC_SET                   24
6228 #define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS     25
6229 #define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS       26
6230 #define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC        27
6231
6232 #define NUM_GLOBAL_SETUP_TOKENS                 28
6233
6234 /* editor setup */
6235 #define SETUP_TOKEN_EDITOR_EL_BOULDERDASH       0
6236 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE      1
6237 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE_CLUB 2
6238 #define SETUP_TOKEN_EDITOR_EL_MORE              3
6239 #define SETUP_TOKEN_EDITOR_EL_SOKOBAN           4
6240 #define SETUP_TOKEN_EDITOR_EL_SUPAPLEX          5
6241 #define SETUP_TOKEN_EDITOR_EL_DIAMOND_CAVES     6
6242 #define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH    7
6243 #define SETUP_TOKEN_EDITOR_EL_CHARS             8
6244 #define SETUP_TOKEN_EDITOR_EL_CUSTOM            9
6245 #define SETUP_TOKEN_EDITOR_EL_HEADLINES         10
6246 #define SETUP_TOKEN_EDITOR_EL_USER_DEFINED      11
6247 #define SETUP_TOKEN_EDITOR_EL_DYNAMIC           12
6248 #define SETUP_TOKEN_EDITOR_SHOW_ELEMENT_TOKEN   13
6249
6250 #define NUM_EDITOR_SETUP_TOKENS                 14
6251
6252 /* editor cascade setup */
6253 #define SETUP_TOKEN_EDITOR_CASCADE_BD           0
6254 #define SETUP_TOKEN_EDITOR_CASCADE_EM           1
6255 #define SETUP_TOKEN_EDITOR_CASCADE_EMC          2
6256 #define SETUP_TOKEN_EDITOR_CASCADE_RND          3
6257 #define SETUP_TOKEN_EDITOR_CASCADE_SB           4
6258 #define SETUP_TOKEN_EDITOR_CASCADE_SP           5
6259 #define SETUP_TOKEN_EDITOR_CASCADE_DC           6
6260 #define SETUP_TOKEN_EDITOR_CASCADE_DX           7
6261 #define SETUP_TOKEN_EDITOR_CASCADE_TEXT         8
6262 #define SETUP_TOKEN_EDITOR_CASCADE_CE           9
6263 #define SETUP_TOKEN_EDITOR_CASCADE_GE           10
6264 #define SETUP_TOKEN_EDITOR_CASCADE_USER         11
6265 #define SETUP_TOKEN_EDITOR_CASCADE_GENERIC      12
6266 #define SETUP_TOKEN_EDITOR_CASCADE_DYNAMIC      13
6267
6268 #define NUM_EDITOR_CASCADE_SETUP_TOKENS         14
6269
6270 /* shortcut setup */
6271 #define SETUP_TOKEN_SHORTCUT_SAVE_GAME          0
6272 #define SETUP_TOKEN_SHORTCUT_LOAD_GAME          1
6273 #define SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE       2
6274 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_1     3
6275 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_2     4
6276 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_3     5
6277 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_4     6
6278 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_ALL   7
6279
6280 #define NUM_SHORTCUT_SETUP_TOKENS               8
6281
6282 /* player setup */
6283 #define SETUP_TOKEN_PLAYER_USE_JOYSTICK         0
6284 #define SETUP_TOKEN_PLAYER_JOY_DEVICE_NAME      1
6285 #define SETUP_TOKEN_PLAYER_JOY_XLEFT            2
6286 #define SETUP_TOKEN_PLAYER_JOY_XMIDDLE          3
6287 #define SETUP_TOKEN_PLAYER_JOY_XRIGHT           4
6288 #define SETUP_TOKEN_PLAYER_JOY_YUPPER           5
6289 #define SETUP_TOKEN_PLAYER_JOY_YMIDDLE          6
6290 #define SETUP_TOKEN_PLAYER_JOY_YLOWER           7
6291 #define SETUP_TOKEN_PLAYER_JOY_SNAP             8
6292 #define SETUP_TOKEN_PLAYER_JOY_DROP             9
6293 #define SETUP_TOKEN_PLAYER_KEY_LEFT             10
6294 #define SETUP_TOKEN_PLAYER_KEY_RIGHT            11
6295 #define SETUP_TOKEN_PLAYER_KEY_UP               12
6296 #define SETUP_TOKEN_PLAYER_KEY_DOWN             13
6297 #define SETUP_TOKEN_PLAYER_KEY_SNAP             14
6298 #define SETUP_TOKEN_PLAYER_KEY_DROP             15
6299
6300 #define NUM_PLAYER_SETUP_TOKENS                 16
6301
6302 /* system setup */
6303 #define SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER      0
6304 #define SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE  1
6305
6306 #define NUM_SYSTEM_SETUP_TOKENS                 2
6307
6308 /* options setup */
6309 #define SETUP_TOKEN_OPTIONS_VERBOSE             0
6310
6311 #define NUM_OPTIONS_SETUP_TOKENS                1
6312
6313
6314 static struct SetupInfo si;
6315 static struct SetupEditorInfo sei;
6316 static struct SetupEditorCascadeInfo seci;
6317 static struct SetupShortcutInfo ssi;
6318 static struct SetupInputInfo sii;
6319 static struct SetupSystemInfo syi;
6320 static struct OptionInfo soi;
6321
6322 static struct TokenInfo global_setup_tokens[] =
6323 {
6324   { TYPE_STRING, &si.player_name,       "player_name"                   },
6325   { TYPE_SWITCH, &si.sound,             "sound"                         },
6326   { TYPE_SWITCH, &si.sound_loops,       "repeating_sound_loops"         },
6327   { TYPE_SWITCH, &si.sound_music,       "background_music"              },
6328   { TYPE_SWITCH, &si.sound_simple,      "simple_sound_effects"          },
6329   { TYPE_SWITCH, &si.toons,             "toons"                         },
6330   { TYPE_SWITCH, &si.scroll_delay,      "scroll_delay"                  },
6331   { TYPE_SWITCH, &si.soft_scrolling,    "soft_scrolling"                },
6332   { TYPE_SWITCH, &si.fading,            "screen_fading"                 },
6333   { TYPE_SWITCH, &si.autorecord,        "automatic_tape_recording"      },
6334   { TYPE_SWITCH, &si.show_titlescreen,  "show_titlescreen"              },
6335   { TYPE_SWITCH, &si.quick_doors,       "quick_doors"                   },
6336   { TYPE_SWITCH, &si.team_mode,         "team_mode"                     },
6337   { TYPE_SWITCH, &si.handicap,          "handicap"                      },
6338   { TYPE_SWITCH, &si.skip_levels,       "skip_levels"                   },
6339   { TYPE_SWITCH, &si.time_limit,        "time_limit"                    },
6340   { TYPE_SWITCH, &si.fullscreen,        "fullscreen"                    },
6341   { TYPE_SWITCH, &si.ask_on_escape,     "ask_on_escape"                 },
6342   { TYPE_SWITCH, &si.ask_on_escape_editor, "ask_on_escape_editor"       },
6343   { TYPE_SWITCH, &si.quick_switch,      "quick_player_switch"           },
6344   { TYPE_SWITCH, &si.input_on_focus,    "input_on_focus"                },
6345   { TYPE_SWITCH, &si.prefer_aga_graphics, "prefer_aga_graphics"         },
6346   { TYPE_STRING, &si.graphics_set,      "graphics_set"                  },
6347   { TYPE_STRING, &si.sounds_set,        "sounds_set"                    },
6348   { TYPE_STRING, &si.music_set,         "music_set"                     },
6349   { TYPE_SWITCH, &si.override_level_graphics, "override_level_graphics" },
6350   { TYPE_SWITCH, &si.override_level_sounds,   "override_level_sounds"   },
6351   { TYPE_SWITCH, &si.override_level_music,    "override_level_music"    },
6352 };
6353
6354 static struct TokenInfo editor_setup_tokens[] =
6355 {
6356   { TYPE_SWITCH, &sei.el_boulderdash,   "editor.el_boulderdash"         },
6357   { TYPE_SWITCH, &sei.el_emerald_mine,  "editor.el_emerald_mine"        },
6358   { TYPE_SWITCH, &sei.el_emerald_mine_club,"editor.el_emerald_mine_club"},
6359   { TYPE_SWITCH, &sei.el_more,          "editor.el_more"                },
6360   { TYPE_SWITCH, &sei.el_sokoban,       "editor.el_sokoban"             },
6361   { TYPE_SWITCH, &sei.el_supaplex,      "editor.el_supaplex"            },
6362   { TYPE_SWITCH, &sei.el_diamond_caves, "editor.el_diamond_caves"       },
6363   { TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash"      },
6364   { TYPE_SWITCH, &sei.el_chars,         "editor.el_chars"               },
6365   { TYPE_SWITCH, &sei.el_custom,        "editor.el_custom"              },
6366   { TYPE_SWITCH, &sei.el_headlines,     "editor.el_headlines"           },
6367   { TYPE_SWITCH, &sei.el_user_defined,  "editor.el_user_defined"        },
6368   { TYPE_SWITCH, &sei.el_dynamic,       "editor.el_dynamic"             },
6369   { TYPE_SWITCH, &sei.show_element_token,"editor.show_element_token"    },
6370 };
6371
6372 static struct TokenInfo editor_cascade_setup_tokens[] =
6373 {
6374   { TYPE_SWITCH, &seci.el_bd,           "editor.cascade.el_bd"          },
6375   { TYPE_SWITCH, &seci.el_em,           "editor.cascade.el_em"          },
6376   { TYPE_SWITCH, &seci.el_emc,          "editor.cascade.el_emc"         },
6377   { TYPE_SWITCH, &seci.el_rnd,          "editor.cascade.el_rnd"         },
6378   { TYPE_SWITCH, &seci.el_sb,           "editor.cascade.el_sb"          },
6379   { TYPE_SWITCH, &seci.el_sp,           "editor.cascade.el_sp"          },
6380   { TYPE_SWITCH, &seci.el_dc,           "editor.cascade.el_dc"          },
6381   { TYPE_SWITCH, &seci.el_dx,           "editor.cascade.el_dx"          },
6382   { TYPE_SWITCH, &seci.el_chars,        "editor.cascade.el_chars"       },
6383   { TYPE_SWITCH, &seci.el_ce,           "editor.cascade.el_ce"          },
6384   { TYPE_SWITCH, &seci.el_ge,           "editor.cascade.el_ge"          },
6385   { TYPE_SWITCH, &seci.el_user,         "editor.cascade.el_user"        },
6386   { TYPE_SWITCH, &seci.el_dynamic,      "editor.cascade.el_dynamic"     },
6387 };
6388
6389 static struct TokenInfo shortcut_setup_tokens[] =
6390 {
6391   { TYPE_KEY_X11, &ssi.save_game,       "shortcut.save_game"            },
6392   { TYPE_KEY_X11, &ssi.load_game,       "shortcut.load_game"            },
6393   { TYPE_KEY_X11, &ssi.toggle_pause,    "shortcut.toggle_pause"         },
6394   { TYPE_KEY_X11, &ssi.focus_player[0], "shortcut.focus_player_1"       },
6395   { TYPE_KEY_X11, &ssi.focus_player[1], "shortcut.focus_player_2"       },
6396   { TYPE_KEY_X11, &ssi.focus_player[2], "shortcut.focus_player_3"       },
6397   { TYPE_KEY_X11, &ssi.focus_player[3], "shortcut.focus_player_4"       },
6398   { TYPE_KEY_X11, &ssi.focus_player_all,"shortcut.focus_player_all"     },
6399 };
6400
6401 static struct TokenInfo player_setup_tokens[] =
6402 {
6403   { TYPE_BOOLEAN, &sii.use_joystick,    ".use_joystick"                 },
6404   { TYPE_STRING,  &sii.joy.device_name, ".joy.device_name"              },
6405   { TYPE_INTEGER, &sii.joy.xleft,       ".joy.xleft"                    },
6406   { TYPE_INTEGER, &sii.joy.xmiddle,     ".joy.xmiddle"                  },
6407   { TYPE_INTEGER, &sii.joy.xright,      ".joy.xright"                   },
6408   { TYPE_INTEGER, &sii.joy.yupper,      ".joy.yupper"                   },
6409   { TYPE_INTEGER, &sii.joy.ymiddle,     ".joy.ymiddle"                  },
6410   { TYPE_INTEGER, &sii.joy.ylower,      ".joy.ylower"                   },
6411   { TYPE_INTEGER, &sii.joy.snap,        ".joy.snap_field"               },
6412   { TYPE_INTEGER, &sii.joy.drop,        ".joy.place_bomb"               },
6413   { TYPE_KEY_X11, &sii.key.left,        ".key.move_left"                },
6414   { TYPE_KEY_X11, &sii.key.right,       ".key.move_right"               },
6415   { TYPE_KEY_X11, &sii.key.up,          ".key.move_up"                  },
6416   { TYPE_KEY_X11, &sii.key.down,        ".key.move_down"                },
6417   { TYPE_KEY_X11, &sii.key.snap,        ".key.snap_field"               },
6418   { TYPE_KEY_X11, &sii.key.drop,        ".key.place_bomb"               },
6419 };
6420
6421 static struct TokenInfo system_setup_tokens[] =
6422 {
6423   { TYPE_STRING,  &syi.sdl_audiodriver, "system.sdl_audiodriver"        },
6424   { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size" },
6425 };
6426
6427 static struct TokenInfo options_setup_tokens[] =
6428 {
6429   { TYPE_BOOLEAN, &soi.verbose,         "options.verbose"               },
6430 };
6431
6432 static char *get_corrected_login_name(char *login_name)
6433 {
6434   /* needed because player name must be a fixed length string */
6435   char *login_name_new = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
6436
6437   strncpy(login_name_new, login_name, MAX_PLAYER_NAME_LEN);
6438   login_name_new[MAX_PLAYER_NAME_LEN] = '\0';
6439
6440   if (strlen(login_name) > MAX_PLAYER_NAME_LEN)         /* name has been cut */
6441     if (strchr(login_name_new, ' '))
6442       *strchr(login_name_new, ' ') = '\0';
6443
6444   return login_name_new;
6445 }
6446
6447 static void setSetupInfoToDefaults(struct SetupInfo *si)
6448 {
6449   int i;
6450
6451   si->player_name = get_corrected_login_name(getLoginName());
6452
6453   si->sound = TRUE;
6454   si->sound_loops = TRUE;
6455   si->sound_music = TRUE;
6456   si->sound_simple = TRUE;
6457   si->toons = TRUE;
6458   si->double_buffering = TRUE;
6459   si->direct_draw = !si->double_buffering;
6460   si->scroll_delay = TRUE;
6461   si->soft_scrolling = TRUE;
6462   si->fading = FALSE;
6463   si->autorecord = TRUE;
6464   si->show_titlescreen = TRUE;
6465   si->quick_doors = FALSE;
6466   si->team_mode = FALSE;
6467   si->handicap = TRUE;
6468   si->skip_levels = TRUE;
6469   si->time_limit = TRUE;
6470   si->fullscreen = FALSE;
6471   si->ask_on_escape = TRUE;
6472   si->ask_on_escape_editor = TRUE;
6473   si->quick_switch = FALSE;
6474   si->input_on_focus = FALSE;
6475   si->prefer_aga_graphics = TRUE;
6476
6477   si->graphics_set = getStringCopy(GFX_CLASSIC_SUBDIR);
6478   si->sounds_set = getStringCopy(SND_CLASSIC_SUBDIR);
6479   si->music_set = getStringCopy(MUS_CLASSIC_SUBDIR);
6480   si->override_level_graphics = FALSE;
6481   si->override_level_sounds = FALSE;
6482   si->override_level_music = FALSE;
6483
6484   si->editor.el_boulderdash       = TRUE;
6485   si->editor.el_emerald_mine      = TRUE;
6486   si->editor.el_emerald_mine_club = TRUE;
6487   si->editor.el_more              = TRUE;
6488   si->editor.el_sokoban           = TRUE;
6489   si->editor.el_supaplex          = TRUE;
6490   si->editor.el_diamond_caves     = TRUE;
6491   si->editor.el_dx_boulderdash    = TRUE;
6492   si->editor.el_chars             = TRUE;
6493   si->editor.el_custom            = TRUE;
6494
6495   si->editor.el_headlines = TRUE;
6496   si->editor.el_user_defined = FALSE;
6497   si->editor.el_dynamic = TRUE;
6498
6499   si->editor.show_element_token = FALSE;
6500
6501   si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
6502   si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME;
6503   si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE;
6504
6505   si->shortcut.focus_player[0] = DEFAULT_KEY_FOCUS_PLAYER_1;
6506   si->shortcut.focus_player[1] = DEFAULT_KEY_FOCUS_PLAYER_2;
6507   si->shortcut.focus_player[2] = DEFAULT_KEY_FOCUS_PLAYER_3;
6508   si->shortcut.focus_player[3] = DEFAULT_KEY_FOCUS_PLAYER_4;
6509   si->shortcut.focus_player_all = DEFAULT_KEY_FOCUS_PLAYER_ALL;
6510
6511   for (i = 0; i < MAX_PLAYERS; i++)
6512   {
6513     si->input[i].use_joystick = FALSE;
6514     si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
6515     si->input[i].joy.xleft   = JOYSTICK_XLEFT;
6516     si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
6517     si->input[i].joy.xright  = JOYSTICK_XRIGHT;
6518     si->input[i].joy.yupper  = JOYSTICK_YUPPER;
6519     si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
6520     si->input[i].joy.ylower  = JOYSTICK_YLOWER;
6521     si->input[i].joy.snap  = (i == 0 ? JOY_BUTTON_1 : 0);
6522     si->input[i].joy.drop  = (i == 0 ? JOY_BUTTON_2 : 0);
6523     si->input[i].key.left  = (i == 0 ? DEFAULT_KEY_LEFT  : KSYM_UNDEFINED);
6524     si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
6525     si->input[i].key.up    = (i == 0 ? DEFAULT_KEY_UP    : KSYM_UNDEFINED);
6526     si->input[i].key.down  = (i == 0 ? DEFAULT_KEY_DOWN  : KSYM_UNDEFINED);
6527     si->input[i].key.snap  = (i == 0 ? DEFAULT_KEY_SNAP  : KSYM_UNDEFINED);
6528     si->input[i].key.drop  = (i == 0 ? DEFAULT_KEY_DROP  : KSYM_UNDEFINED);
6529   }
6530
6531   si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT);
6532   si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
6533
6534   si->options.verbose = FALSE;
6535 }
6536
6537 static void setSetupInfoToDefaults_EditorCascade(struct SetupInfo *si)
6538 {
6539   si->editor_cascade.el_bd      = TRUE;
6540   si->editor_cascade.el_em      = TRUE;
6541   si->editor_cascade.el_emc     = TRUE;
6542   si->editor_cascade.el_rnd     = TRUE;
6543   si->editor_cascade.el_sb      = TRUE;
6544   si->editor_cascade.el_sp      = TRUE;
6545   si->editor_cascade.el_dc      = TRUE;
6546   si->editor_cascade.el_dx      = TRUE;
6547
6548   si->editor_cascade.el_chars   = FALSE;
6549   si->editor_cascade.el_ce      = FALSE;
6550   si->editor_cascade.el_ge      = FALSE;
6551   si->editor_cascade.el_user    = FALSE;
6552   si->editor_cascade.el_dynamic = FALSE;
6553 }
6554
6555 static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
6556 {
6557   int i, pnr;
6558
6559   if (!setup_file_hash)
6560     return;
6561
6562   /* global setup */
6563   si = setup;
6564   for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
6565     setSetupInfo(global_setup_tokens, i,
6566                  getHashEntry(setup_file_hash, global_setup_tokens[i].text));
6567   setup = si;
6568
6569   /* editor setup */
6570   sei = setup.editor;
6571   for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
6572     setSetupInfo(editor_setup_tokens, i,
6573                  getHashEntry(setup_file_hash,editor_setup_tokens[i].text));
6574   setup.editor = sei;
6575
6576   /* shortcut setup */
6577   ssi = setup.shortcut;
6578   for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
6579     setSetupInfo(shortcut_setup_tokens, i,
6580                  getHashEntry(setup_file_hash,shortcut_setup_tokens[i].text));
6581   setup.shortcut = ssi;
6582
6583   /* player setup */
6584   for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
6585   {
6586     char prefix[30];
6587
6588     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
6589
6590     sii = setup.input[pnr];
6591     for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
6592     {
6593       char full_token[100];
6594
6595       sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
6596       setSetupInfo(player_setup_tokens, i,
6597                    getHashEntry(setup_file_hash, full_token));
6598     }
6599     setup.input[pnr] = sii;
6600   }
6601
6602   /* system setup */
6603   syi = setup.system;
6604   for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
6605     setSetupInfo(system_setup_tokens, i,
6606                  getHashEntry(setup_file_hash, system_setup_tokens[i].text));
6607   setup.system = syi;
6608
6609   /* options setup */
6610   soi = setup.options;
6611   for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
6612     setSetupInfo(options_setup_tokens, i,
6613                  getHashEntry(setup_file_hash, options_setup_tokens[i].text));
6614   setup.options = soi;
6615 }
6616
6617 static void decodeSetupFileHash_EditorCascade(SetupFileHash *setup_file_hash)
6618 {
6619   int i;
6620
6621   if (!setup_file_hash)
6622     return;
6623
6624   /* editor cascade setup */
6625   seci = setup.editor_cascade;
6626   for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
6627     setSetupInfo(editor_cascade_setup_tokens, i,
6628                  getHashEntry(setup_file_hash,
6629                               editor_cascade_setup_tokens[i].text));
6630   setup.editor_cascade = seci;
6631 }
6632
6633 void LoadSetup()
6634 {
6635   char *filename = getSetupFilename();
6636   SetupFileHash *setup_file_hash = NULL;
6637
6638   /* always start with reliable default values */
6639   setSetupInfoToDefaults(&setup);
6640
6641   setup_file_hash = loadSetupFileHash(filename);
6642
6643   if (setup_file_hash)
6644   {
6645     char *player_name_new;
6646
6647     checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP"));
6648     decodeSetupFileHash(setup_file_hash);
6649
6650     setup.direct_draw = !setup.double_buffering;
6651
6652     freeSetupFileHash(setup_file_hash);
6653
6654     /* needed to work around problems with fixed length strings */
6655     player_name_new = get_corrected_login_name(setup.player_name);
6656     free(setup.player_name);
6657     setup.player_name = player_name_new;
6658   }
6659   else
6660     Error(ERR_WARN, "using default setup values");
6661 }
6662
6663 void LoadSetup_EditorCascade()
6664 {
6665   char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
6666   SetupFileHash *setup_file_hash = NULL;
6667
6668   /* always start with reliable default values */
6669   setSetupInfoToDefaults_EditorCascade(&setup);
6670
6671   setup_file_hash = loadSetupFileHash(filename);
6672
6673   if (setup_file_hash)
6674   {
6675     checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP"));
6676     decodeSetupFileHash_EditorCascade(setup_file_hash);
6677
6678     freeSetupFileHash(setup_file_hash);
6679   }
6680
6681   free(filename);
6682 }
6683
6684 void SaveSetup()
6685 {
6686   char *filename = getSetupFilename();
6687   FILE *file;
6688   int i, pnr;
6689
6690   InitUserDataDirectory();
6691
6692   if (!(file = fopen(filename, MODE_WRITE)))
6693   {
6694     Error(ERR_WARN, "cannot write setup file '%s'", filename);
6695     return;
6696   }
6697
6698   fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
6699                                                getCookie("SETUP")));
6700   fprintf(file, "\n");
6701
6702   /* global setup */
6703   si = setup;
6704   for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
6705   {
6706     /* just to make things nicer :) */
6707     if (i == SETUP_TOKEN_PLAYER_NAME + 1 ||
6708         i == SETUP_TOKEN_GRAPHICS_SET)
6709       fprintf(file, "\n");
6710
6711     fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
6712   }
6713
6714   /* editor setup */
6715   sei = setup.editor;
6716   fprintf(file, "\n");
6717   for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
6718     fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i));
6719
6720   /* shortcut setup */
6721   ssi = setup.shortcut;
6722   fprintf(file, "\n");
6723   for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
6724     fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
6725
6726   /* player setup */
6727   for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
6728   {
6729     char prefix[30];
6730
6731     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
6732     fprintf(file, "\n");
6733
6734     sii = setup.input[pnr];
6735     for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
6736       fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
6737   }
6738
6739   /* system setup */
6740   syi = setup.system;
6741   fprintf(file, "\n");
6742   for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
6743     fprintf(file, "%s\n", getSetupLine(system_setup_tokens, "", i));
6744
6745   /* options setup */
6746   soi = setup.options;
6747   fprintf(file, "\n");
6748   for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
6749     fprintf(file, "%s\n", getSetupLine(options_setup_tokens, "", i));
6750
6751   fclose(file);
6752
6753   SetFilePermissions(filename, PERMS_PRIVATE);
6754 }
6755
6756 void SaveSetup_EditorCascade()
6757 {
6758   char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
6759   FILE *file;
6760   int i;
6761
6762   InitUserDataDirectory();
6763
6764   if (!(file = fopen(filename, MODE_WRITE)))
6765   {
6766     Error(ERR_WARN, "cannot write editor cascade state file '%s'", filename);
6767     free(filename);
6768     return;
6769   }
6770
6771   fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
6772                                                getCookie("SETUP")));
6773   fprintf(file, "\n");
6774
6775   seci = setup.editor_cascade;
6776   fprintf(file, "\n");
6777   for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
6778     fprintf(file, "%s\n", getSetupLine(editor_cascade_setup_tokens, "", i));
6779
6780   fclose(file);
6781
6782   SetFilePermissions(filename, PERMS_PRIVATE);
6783
6784   free(filename);
6785 }
6786
6787 void LoadCustomElementDescriptions()
6788 {
6789   char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
6790   SetupFileHash *setup_file_hash;
6791   int i;
6792
6793   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6794   {
6795     if (element_info[i].custom_description != NULL)
6796     {
6797       free(element_info[i].custom_description);
6798       element_info[i].custom_description = NULL;
6799     }
6800   }
6801
6802   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
6803     return;
6804
6805   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6806   {
6807     char *token = getStringCat2(element_info[i].token_name, ".name");
6808     char *value = getHashEntry(setup_file_hash, token);
6809
6810     if (value != NULL)
6811       element_info[i].custom_description = getStringCopy(value);
6812
6813     free(token);
6814   }
6815
6816   freeSetupFileHash(setup_file_hash);
6817 }
6818
6819 static void LoadSpecialMenuDesignSettingsFromFilename(char *filename)
6820 {
6821   SetupFileHash *setup_file_hash;
6822   int i;
6823
6824 #if 0
6825   printf("LoadSpecialMenuDesignSettings from file '%s' ...\n", filename);
6826 #endif
6827
6828   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
6829     return;
6830
6831   /* special case: initialize with default values that may be overwritten */
6832   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
6833   {
6834     char *value_x = getHashEntry(setup_file_hash, "menu.draw_xoffset");
6835     char *value_y = getHashEntry(setup_file_hash, "menu.draw_yoffset");
6836     char *list_size = getHashEntry(setup_file_hash, "menu.list_size");
6837
6838     if (value_x != NULL)
6839       menu.draw_xoffset[i] = get_integer_from_string(value_x);
6840     if (value_y != NULL)
6841       menu.draw_yoffset[i] = get_integer_from_string(value_y);
6842     if (list_size != NULL)
6843       menu.list_size[i] = get_integer_from_string(list_size);
6844   }
6845
6846   /* read (and overwrite with) values that may be specified in config file */
6847   for (i = 0; image_config_vars[i].token != NULL; i++)
6848   {
6849     char *value = getHashEntry(setup_file_hash, image_config_vars[i].token);
6850
6851     if (value != NULL)
6852       *image_config_vars[i].value =
6853         get_auto_parameter_value(image_config_vars[i].token, value);
6854   }
6855
6856   freeSetupFileHash(setup_file_hash);
6857 }
6858
6859 void LoadSpecialMenuDesignSettings()
6860 {
6861   char *filename_base = UNDEFINED_FILENAME, *filename_local;
6862   int i, j;
6863
6864   /* always start with reliable default values from default config */
6865   for (i = 0; image_config_vars[i].token != NULL; i++)
6866     for (j = 0; image_config[j].token != NULL; j++)
6867       if (strEqual(image_config_vars[i].token, image_config[j].token))
6868         *image_config_vars[i].value =
6869           get_auto_parameter_value(image_config_vars[i].token,
6870                                    image_config[j].value);
6871
6872 #if 1
6873   if (!SETUP_OVERRIDE_ARTWORK(setup, ARTWORK_TYPE_GRAPHICS))
6874   {
6875     /* first look for special settings configured in level series config */
6876     filename_base = getCustomArtworkLevelConfigFilename(ARTWORK_TYPE_GRAPHICS);
6877
6878     if (fileExists(filename_base))
6879       LoadSpecialMenuDesignSettingsFromFilename(filename_base);
6880   }
6881
6882   filename_local = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
6883
6884   if (filename_local != NULL && !strEqual(filename_base, filename_local))
6885     LoadSpecialMenuDesignSettingsFromFilename(filename_local);
6886
6887 #else
6888
6889   filename_local = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
6890
6891   LoadSpecialMenuDesignSettingsFromFilename(filename_local);
6892 #endif
6893 }
6894
6895 void LoadUserDefinedEditorElementList(int **elements, int *num_elements)
6896 {
6897   char *filename = getEditorSetupFilename();
6898   SetupFileList *setup_file_list, *list;
6899   SetupFileHash *element_hash;
6900   int num_unknown_tokens = 0;
6901   int i;
6902
6903   if ((setup_file_list = loadSetupFileList(filename)) == NULL)
6904     return;
6905
6906   element_hash = newSetupFileHash();
6907
6908   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6909     setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
6910
6911   /* determined size may be larger than needed (due to unknown elements) */
6912   *num_elements = 0;
6913   for (list = setup_file_list; list != NULL; list = list->next)
6914     (*num_elements)++;
6915
6916   /* add space for up to 3 more elements for padding that may be needed */
6917   *num_elements += 3;
6918
6919   /* free memory for old list of elements, if needed */
6920   checked_free(*elements);
6921
6922   /* allocate memory for new list of elements */
6923   *elements = checked_malloc(*num_elements * sizeof(int));
6924
6925   *num_elements = 0;
6926   for (list = setup_file_list; list != NULL; list = list->next)
6927   {
6928     char *value = getHashEntry(element_hash, list->token);
6929
6930     if (value == NULL)          /* try to find obsolete token mapping */
6931     {
6932       char *mapped_token = get_mapped_token(list->token);
6933
6934       if (mapped_token != NULL)
6935       {
6936         value = getHashEntry(element_hash, mapped_token);
6937
6938         free(mapped_token);
6939       }
6940     }
6941
6942     if (value != NULL)
6943     {
6944       (*elements)[(*num_elements)++] = atoi(value);
6945     }
6946     else
6947     {
6948       if (num_unknown_tokens == 0)
6949       {
6950         Error(ERR_RETURN_LINE, "-");
6951         Error(ERR_RETURN, "warning: unknown token(s) found in config file:");
6952         Error(ERR_RETURN, "- config file: '%s'", filename);
6953
6954         num_unknown_tokens++;
6955       }
6956
6957       Error(ERR_RETURN, "- token: '%s'", list->token);
6958     }
6959   }
6960
6961   if (num_unknown_tokens > 0)
6962     Error(ERR_RETURN_LINE, "-");
6963
6964   while (*num_elements % 4)     /* pad with empty elements, if needed */
6965     (*elements)[(*num_elements)++] = EL_EMPTY;
6966
6967   freeSetupFileList(setup_file_list);
6968   freeSetupFileHash(element_hash);
6969
6970 #if 0
6971   for (i = 0; i < *num_elements; i++)
6972     printf("editor: element '%s' [%d]\n",
6973            element_info[(*elements)[i]].token_name, (*elements)[i]);
6974 #endif
6975 }
6976
6977 static struct MusicFileInfo *get_music_file_info_ext(char *basename, int music,
6978                                                      boolean is_sound)
6979 {
6980   SetupFileHash *setup_file_hash = NULL;
6981   struct MusicFileInfo tmp_music_file_info, *new_music_file_info;
6982   char *filename_music, *filename_prefix, *filename_info;
6983   struct
6984   {
6985     char *token;
6986     char **value_ptr;
6987   }
6988   token_to_value_ptr[] =
6989   {
6990     { "title_header",   &tmp_music_file_info.title_header       },
6991     { "artist_header",  &tmp_music_file_info.artist_header      },
6992     { "album_header",   &tmp_music_file_info.album_header       },
6993     { "year_header",    &tmp_music_file_info.year_header        },
6994
6995     { "title",          &tmp_music_file_info.title              },
6996     { "artist",         &tmp_music_file_info.artist             },
6997     { "album",          &tmp_music_file_info.album              },
6998     { "year",           &tmp_music_file_info.year               },
6999
7000     { NULL,             NULL                                    },
7001   };
7002   int i;
7003
7004   filename_music = (is_sound ? getCustomSoundFilename(basename) :
7005                     getCustomMusicFilename(basename));
7006
7007   if (filename_music == NULL)
7008     return NULL;
7009
7010   /* ---------- try to replace file extension ---------- */
7011
7012   filename_prefix = getStringCopy(filename_music);
7013   if (strrchr(filename_prefix, '.') != NULL)
7014     *strrchr(filename_prefix, '.') = '\0';
7015   filename_info = getStringCat2(filename_prefix, ".txt");
7016
7017 #if 0
7018   printf("trying to load file '%s'...\n", filename_info);
7019 #endif
7020
7021   if (fileExists(filename_info))
7022     setup_file_hash = loadSetupFileHash(filename_info);
7023
7024   free(filename_prefix);
7025   free(filename_info);
7026
7027   if (setup_file_hash == NULL)
7028   {
7029     /* ---------- try to add file extension ---------- */
7030
7031     filename_prefix = getStringCopy(filename_music);
7032     filename_info = getStringCat2(filename_prefix, ".txt");
7033
7034 #if 0
7035     printf("trying to load file '%s'...\n", filename_info);
7036 #endif
7037
7038     if (fileExists(filename_info))
7039       setup_file_hash = loadSetupFileHash(filename_info);
7040
7041     free(filename_prefix);
7042     free(filename_info);
7043   }
7044
7045   if (setup_file_hash == NULL)
7046     return NULL;
7047
7048   /* ---------- music file info found ---------- */
7049
7050   memset(&tmp_music_file_info, 0, sizeof(struct MusicFileInfo));
7051
7052   for (i = 0; token_to_value_ptr[i].token != NULL; i++)
7053   {
7054     char *value = getHashEntry(setup_file_hash, token_to_value_ptr[i].token);
7055
7056     *token_to_value_ptr[i].value_ptr =
7057       getStringCopy(value != NULL && *value != '\0' ? value : UNKNOWN_NAME);
7058   }
7059
7060   tmp_music_file_info.basename = getStringCopy(basename);
7061   tmp_music_file_info.music = music;
7062   tmp_music_file_info.is_sound = is_sound;
7063
7064   new_music_file_info = checked_malloc(sizeof(struct MusicFileInfo));
7065   *new_music_file_info = tmp_music_file_info;
7066
7067   return new_music_file_info;
7068 }
7069
7070 static struct MusicFileInfo *get_music_file_info(char *basename, int music)
7071 {
7072   return get_music_file_info_ext(basename, music, FALSE);
7073 }
7074
7075 static struct MusicFileInfo *get_sound_file_info(char *basename, int sound)
7076 {
7077   return get_music_file_info_ext(basename, sound, TRUE);
7078 }
7079
7080 static boolean music_info_listed_ext(struct MusicFileInfo *list,
7081                                      char *basename, boolean is_sound)
7082 {
7083   for (; list != NULL; list = list->next)
7084     if (list->is_sound == is_sound && strEqual(list->basename, basename))
7085       return TRUE;
7086
7087   return FALSE;
7088 }
7089
7090 static boolean music_info_listed(struct MusicFileInfo *list, char *basename)
7091 {
7092   return music_info_listed_ext(list, basename, FALSE);
7093 }
7094
7095 static boolean sound_info_listed(struct MusicFileInfo *list, char *basename)
7096 {
7097   return music_info_listed_ext(list, basename, TRUE);
7098 }
7099
7100 void LoadMusicInfo()
7101 {
7102   char *music_directory = getCustomMusicDirectory();
7103   int num_music = getMusicListSize();
7104   int num_music_noconf = 0;
7105   int num_sounds = getSoundListSize();
7106   DIR *dir;
7107   struct dirent *dir_entry;
7108   struct FileInfo *music, *sound;
7109   struct MusicFileInfo *next, **new;
7110   int i;
7111
7112   while (music_file_info != NULL)
7113   {
7114     next = music_file_info->next;
7115
7116     checked_free(music_file_info->basename);
7117
7118     checked_free(music_file_info->title_header);
7119     checked_free(music_file_info->artist_header);
7120     checked_free(music_file_info->album_header);
7121     checked_free(music_file_info->year_header);
7122
7123     checked_free(music_file_info->title);
7124     checked_free(music_file_info->artist);
7125     checked_free(music_file_info->album);
7126     checked_free(music_file_info->year);
7127
7128     free(music_file_info);
7129
7130     music_file_info = next;
7131   }
7132
7133   new = &music_file_info;
7134
7135   for (i = 0; i < num_music; i++)
7136   {
7137     music = getMusicListEntry(i);
7138
7139     if (music->filename == NULL)
7140       continue;
7141
7142     if (strEqual(music->filename, UNDEFINED_FILENAME))
7143       continue;
7144
7145     /* a configured file may be not recognized as music */
7146     if (!FileIsMusic(music->filename))
7147       continue;
7148
7149 #if 0
7150     printf("::: -> '%s' (configured)\n", music->filename);
7151 #endif
7152
7153     if (!music_info_listed(music_file_info, music->filename))
7154     {
7155       *new = get_music_file_info(music->filename, i);
7156       if (*new != NULL)
7157         new = &(*new)->next;
7158     }
7159   }
7160
7161   if ((dir = opendir(music_directory)) == NULL)
7162   {
7163     Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
7164     return;
7165   }
7166
7167   while ((dir_entry = readdir(dir)) != NULL)    /* loop until last dir entry */
7168   {
7169     char *basename = dir_entry->d_name;
7170     boolean music_already_used = FALSE;
7171     int i;
7172
7173     /* skip all music files that are configured in music config file */
7174     for (i = 0; i < num_music; i++)
7175     {
7176       music = getMusicListEntry(i);
7177
7178       if (music->filename == NULL)
7179         continue;
7180
7181       if (strEqual(basename, music->filename))
7182       {
7183         music_already_used = TRUE;
7184         break;
7185       }
7186     }
7187
7188     if (music_already_used)
7189       continue;
7190
7191     if (!FileIsMusic(basename))
7192       continue;
7193
7194 #if 0
7195     printf("::: -> '%s' (found in directory)\n", basename);
7196 #endif
7197
7198     if (!music_info_listed(music_file_info, basename))
7199     {
7200       *new = get_music_file_info(basename, MAP_NOCONF_MUSIC(num_music_noconf));
7201       if (*new != NULL)
7202         new = &(*new)->next;
7203     }
7204
7205     num_music_noconf++;
7206   }
7207
7208   closedir(dir);
7209
7210   for (i = 0; i < num_sounds; i++)
7211   {
7212     sound = getSoundListEntry(i);
7213
7214     if (sound->filename == NULL)
7215       continue;
7216
7217     if (strEqual(sound->filename, UNDEFINED_FILENAME))
7218       continue;
7219
7220     /* a configured file may be not recognized as sound */
7221     if (!FileIsSound(sound->filename))
7222       continue;
7223
7224 #if 0
7225     printf("::: -> '%s' (configured)\n", sound->filename);
7226 #endif
7227
7228     if (!sound_info_listed(music_file_info, sound->filename))
7229     {
7230       *new = get_sound_file_info(sound->filename, i);
7231       if (*new != NULL)
7232         new = &(*new)->next;
7233     }
7234   }
7235
7236 #if 0
7237   for (next = music_file_info; next != NULL; next = next->next)
7238     printf("::: title == '%s'\n", next->title);
7239 #endif
7240 }
7241
7242 void add_helpanim_entry(int element, int action, int direction, int delay,
7243                         int *num_list_entries)
7244 {
7245   struct HelpAnimInfo *new_list_entry;
7246   (*num_list_entries)++;
7247
7248   helpanim_info =
7249     checked_realloc(helpanim_info,
7250                     *num_list_entries * sizeof(struct HelpAnimInfo));
7251   new_list_entry = &helpanim_info[*num_list_entries - 1];
7252
7253   new_list_entry->element = element;
7254   new_list_entry->action = action;
7255   new_list_entry->direction = direction;
7256   new_list_entry->delay = delay;
7257 }
7258
7259 void print_unknown_token(char *filename, char *token, int token_nr)
7260 {
7261   if (token_nr == 0)
7262   {
7263     Error(ERR_RETURN_LINE, "-");
7264     Error(ERR_RETURN, "warning: unknown token(s) found in config file:");
7265     Error(ERR_RETURN, "- config file: '%s'", filename);
7266   }
7267
7268   Error(ERR_RETURN, "- token: '%s'", token);
7269 }
7270
7271 void print_unknown_token_end(int token_nr)
7272 {
7273   if (token_nr > 0)
7274     Error(ERR_RETURN_LINE, "-");
7275 }
7276
7277 void LoadHelpAnimInfo()
7278 {
7279   char *filename = getHelpAnimFilename();
7280   SetupFileList *setup_file_list = NULL, *list;
7281   SetupFileHash *element_hash, *action_hash, *direction_hash;
7282   int num_list_entries = 0;
7283   int num_unknown_tokens = 0;
7284   int i;
7285
7286   if (fileExists(filename))
7287     setup_file_list = loadSetupFileList(filename);
7288
7289   if (setup_file_list == NULL)
7290   {
7291     /* use reliable default values from static configuration */
7292     SetupFileList *insert_ptr;
7293
7294     insert_ptr = setup_file_list =
7295       newSetupFileList(helpanim_config[0].token,
7296                        helpanim_config[0].value);
7297
7298     for (i = 1; helpanim_config[i].token; i++)
7299       insert_ptr = addListEntry(insert_ptr,
7300                                 helpanim_config[i].token,
7301                                 helpanim_config[i].value);
7302   }
7303
7304   element_hash   = newSetupFileHash();
7305   action_hash    = newSetupFileHash();
7306   direction_hash = newSetupFileHash();
7307
7308   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
7309     setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
7310
7311   for (i = 0; i < NUM_ACTIONS; i++)
7312     setHashEntry(action_hash, element_action_info[i].suffix,
7313                  i_to_a(element_action_info[i].value));
7314
7315   /* do not store direction index (bit) here, but direction value! */
7316   for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
7317     setHashEntry(direction_hash, element_direction_info[i].suffix,
7318                  i_to_a(1 << element_direction_info[i].value));
7319
7320   for (list = setup_file_list; list != NULL; list = list->next)
7321   {
7322     char *element_token, *action_token, *direction_token;
7323     char *element_value, *action_value, *direction_value;
7324     int delay = atoi(list->value);
7325
7326     if (strEqual(list->token, "end"))
7327     {
7328       add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
7329
7330       continue;
7331     }
7332
7333     /* first try to break element into element/action/direction parts;
7334        if this does not work, also accept combined "element[.act][.dir]"
7335        elements (like "dynamite.active"), which are unique elements */
7336
7337     if (strchr(list->token, '.') == NULL)       /* token contains no '.' */
7338     {
7339       element_value = getHashEntry(element_hash, list->token);
7340       if (element_value != NULL)        /* element found */
7341         add_helpanim_entry(atoi(element_value), -1, -1, delay,
7342                            &num_list_entries);
7343       else
7344       {
7345         /* no further suffixes found -- this is not an element */
7346         print_unknown_token(filename, list->token, num_unknown_tokens++);
7347       }
7348
7349       continue;
7350     }
7351
7352     /* token has format "<prefix>.<something>" */
7353
7354     action_token = strchr(list->token, '.');    /* suffix may be action ... */
7355     direction_token = action_token;             /* ... or direction */
7356
7357     element_token = getStringCopy(list->token);
7358     *strchr(element_token, '.') = '\0';
7359
7360     element_value = getHashEntry(element_hash, element_token);
7361
7362     if (element_value == NULL)          /* this is no element */
7363     {
7364       element_value = getHashEntry(element_hash, list->token);
7365       if (element_value != NULL)        /* combined element found */
7366         add_helpanim_entry(atoi(element_value), -1, -1, delay,
7367                            &num_list_entries);
7368       else
7369         print_unknown_token(filename, list->token, num_unknown_tokens++);
7370
7371       free(element_token);
7372
7373       continue;
7374     }
7375
7376     action_value = getHashEntry(action_hash, action_token);
7377
7378     if (action_value != NULL)           /* action found */
7379     {
7380       add_helpanim_entry(atoi(element_value), atoi(action_value), -1, delay,
7381                     &num_list_entries);
7382
7383       free(element_token);
7384
7385       continue;
7386     }
7387
7388     direction_value = getHashEntry(direction_hash, direction_token);
7389
7390     if (direction_value != NULL)        /* direction found */
7391     {
7392       add_helpanim_entry(atoi(element_value), -1, atoi(direction_value), delay,
7393                          &num_list_entries);
7394
7395       free(element_token);
7396
7397       continue;
7398     }
7399
7400     if (strchr(action_token + 1, '.') == NULL)
7401     {
7402       /* no further suffixes found -- this is not an action nor direction */
7403
7404       element_value = getHashEntry(element_hash, list->token);
7405       if (element_value != NULL)        /* combined element found */
7406         add_helpanim_entry(atoi(element_value), -1, -1, delay,
7407                            &num_list_entries);
7408       else
7409         print_unknown_token(filename, list->token, num_unknown_tokens++);
7410
7411       free(element_token);
7412
7413       continue;
7414     }
7415
7416     /* token has format "<prefix>.<suffix>.<something>" */
7417
7418     direction_token = strchr(action_token + 1, '.');
7419
7420     action_token = getStringCopy(action_token);
7421     *strchr(action_token + 1, '.') = '\0';
7422
7423     action_value = getHashEntry(action_hash, action_token);
7424
7425     if (action_value == NULL)           /* this is no action */
7426     {
7427       element_value = getHashEntry(element_hash, list->token);
7428       if (element_value != NULL)        /* combined element found */
7429         add_helpanim_entry(atoi(element_value), -1, -1, delay,
7430                            &num_list_entries);
7431       else
7432         print_unknown_token(filename, list->token, num_unknown_tokens++);
7433
7434       free(element_token);
7435       free(action_token);
7436
7437       continue;
7438     }
7439
7440     direction_value = getHashEntry(direction_hash, direction_token);
7441
7442     if (direction_value != NULL)        /* direction found */
7443     {
7444       add_helpanim_entry(atoi(element_value), atoi(action_value),
7445                          atoi(direction_value), delay, &num_list_entries);
7446
7447       free(element_token);
7448       free(action_token);
7449
7450       continue;
7451     }
7452
7453     /* this is no direction */
7454
7455     element_value = getHashEntry(element_hash, list->token);
7456     if (element_value != NULL)          /* combined element found */
7457       add_helpanim_entry(atoi(element_value), -1, -1, delay,
7458                          &num_list_entries);
7459     else
7460       print_unknown_token(filename, list->token, num_unknown_tokens++);
7461
7462     free(element_token);
7463     free(action_token);
7464   }
7465
7466   print_unknown_token_end(num_unknown_tokens);
7467
7468   add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
7469   add_helpanim_entry(HELPANIM_LIST_END,  -1, -1, -1, &num_list_entries);
7470
7471   freeSetupFileList(setup_file_list);
7472   freeSetupFileHash(element_hash);
7473   freeSetupFileHash(action_hash);
7474   freeSetupFileHash(direction_hash);
7475
7476 #if 0
7477   for (i = 0; i < num_list_entries; i++)
7478     printf("::: '%s': %d, %d, %d => %d\n",
7479            EL_NAME(helpanim_info[i].element),
7480            helpanim_info[i].element,
7481            helpanim_info[i].action,
7482            helpanim_info[i].direction,
7483            helpanim_info[i].delay);
7484 #endif
7485 }
7486
7487 void LoadHelpTextInfo()
7488 {
7489   char *filename = getHelpTextFilename();
7490   int i;
7491
7492   if (helptext_info != NULL)
7493   {
7494     freeSetupFileHash(helptext_info);
7495     helptext_info = NULL;
7496   }
7497
7498   if (fileExists(filename))
7499     helptext_info = loadSetupFileHash(filename);
7500
7501   if (helptext_info == NULL)
7502   {
7503     /* use reliable default values from static configuration */
7504     helptext_info = newSetupFileHash();
7505
7506     for (i = 0; helptext_config[i].token; i++)
7507       setHashEntry(helptext_info,
7508                    helptext_config[i].token,
7509                    helptext_config[i].value);
7510   }
7511
7512 #if 0
7513   BEGIN_HASH_ITERATION(helptext_info, itr)
7514   {
7515     printf("::: '%s' => '%s'\n",
7516            HASH_ITERATION_TOKEN(itr), HASH_ITERATION_VALUE(itr));
7517   }
7518   END_HASH_ITERATION(hash, itr)
7519 #endif
7520 }
7521
7522
7523 /* ------------------------------------------------------------------------- *
7524  * convert levels
7525  * ------------------------------------------------------------------------- */
7526
7527 #define MAX_NUM_CONVERT_LEVELS          1000
7528
7529 void ConvertLevels()
7530 {
7531   static LevelDirTree *convert_leveldir = NULL;
7532   static int convert_level_nr = -1;
7533   static int num_levels_handled = 0;
7534   static int num_levels_converted = 0;
7535   static boolean levels_failed[MAX_NUM_CONVERT_LEVELS];
7536   int i;
7537
7538   convert_leveldir = getTreeInfoFromIdentifier(leveldir_first,
7539                                                global.convert_leveldir);
7540
7541   if (convert_leveldir == NULL)
7542     Error(ERR_EXIT, "no such level identifier: '%s'",
7543           global.convert_leveldir);
7544
7545   leveldir_current = convert_leveldir;
7546
7547   if (global.convert_level_nr != -1)
7548   {
7549     convert_leveldir->first_level = global.convert_level_nr;
7550     convert_leveldir->last_level  = global.convert_level_nr;
7551   }
7552
7553   convert_level_nr = convert_leveldir->first_level;
7554
7555   printf_line("=", 79);
7556   printf("Converting levels\n");
7557   printf_line("-", 79);
7558   printf("Level series identifier: '%s'\n", convert_leveldir->identifier);
7559   printf("Level series name:       '%s'\n", convert_leveldir->name);
7560   printf("Level series author:     '%s'\n", convert_leveldir->author);
7561   printf("Number of levels:        %d\n",   convert_leveldir->levels);
7562   printf_line("=", 79);
7563   printf("\n");
7564
7565   for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++)
7566     levels_failed[i] = FALSE;
7567
7568   while (convert_level_nr <= convert_leveldir->last_level)
7569   {
7570     char *level_filename;
7571     boolean new_level;
7572
7573     level_nr = convert_level_nr++;
7574
7575     printf("Level %03d: ", level_nr);
7576
7577     LoadLevel(level_nr);
7578     if (level.no_valid_file)
7579     {
7580       printf("(no level)\n");
7581       continue;
7582     }
7583
7584     printf("converting level ... ");
7585
7586     level_filename = getDefaultLevelFilename(level_nr);
7587     new_level = !fileExists(level_filename);
7588
7589     if (new_level)
7590     {
7591       SaveLevel(level_nr);
7592
7593       num_levels_converted++;
7594
7595       printf("converted.\n");
7596     }
7597     else
7598     {
7599       if (level_nr >= 0 && level_nr < MAX_NUM_CONVERT_LEVELS)
7600         levels_failed[level_nr] = TRUE;
7601
7602       printf("NOT CONVERTED -- LEVEL ALREADY EXISTS.\n");
7603     }
7604
7605     num_levels_handled++;
7606   }
7607
7608   printf("\n");
7609   printf_line("=", 79);
7610   printf("Number of levels handled: %d\n", num_levels_handled);
7611   printf("Number of levels converted: %d (%d%%)\n", num_levels_converted,
7612          (num_levels_handled ?
7613           num_levels_converted * 100 / num_levels_handled : 0));
7614   printf_line("-", 79);
7615   printf("Summary (for automatic parsing by scripts):\n");
7616   printf("LEVELDIR '%s', CONVERTED %d/%d (%d%%)",
7617          convert_leveldir->identifier, num_levels_converted,
7618          num_levels_handled,
7619          (num_levels_handled ?
7620           num_levels_converted * 100 / num_levels_handled : 0));
7621
7622   if (num_levels_handled != num_levels_converted)
7623   {
7624     printf(", FAILED:");
7625     for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++)
7626       if (levels_failed[i])
7627         printf(" %03d", i);
7628   }
7629
7630   printf("\n");
7631   printf_line("=", 79);
7632
7633   CloseAllAndExit(0);
7634 }