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