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