changed filename string handling for level file info structure
[rocksndiamonds.git] / src / files.c
1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
5 //                  Holger Schemel
6 //                  info@artsoft.org
7 //                  http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
9 // files.c
10 // ============================================================================
11
12 #include <ctype.h>
13 #include <sys/stat.h>
14 #include <dirent.h>
15 #include <math.h>
16
17 #include "libgame/libgame.h"
18
19 #include "files.h"
20 #include "init.h"
21 #include "screens.h"
22 #include "tools.h"
23 #include "tape.h"
24 #include "config.h"
25
26 #define ENABLE_UNUSED_CODE      0       /* currently unused functions */
27 #define ENABLE_HISTORIC_CHUNKS  0       /* only for historic reference */
28 #define ENABLE_RESERVED_CODE    0       /* reserved for later use */
29
30 #define CHUNK_ID_LEN            4       /* IFF style chunk id length  */
31 #define CHUNK_SIZE_UNDEFINED    0       /* undefined chunk size == 0  */
32 #define CHUNK_SIZE_NONE         -1      /* do not write chunk size    */
33
34 #define LEVEL_CHUNK_NAME_SIZE   MAX_LEVEL_NAME_LEN
35 #define LEVEL_CHUNK_AUTH_SIZE   MAX_LEVEL_AUTHOR_LEN
36
37 #define LEVEL_CHUNK_VERS_SIZE   8       /* size of file version chunk */
38 #define LEVEL_CHUNK_DATE_SIZE   4       /* size of file date chunk    */
39 #define LEVEL_CHUNK_HEAD_SIZE   80      /* size of level file header  */
40 #define LEVEL_CHUNK_HEAD_UNUSED 0       /* unused level header bytes  */
41 #define LEVEL_CHUNK_CNT2_SIZE   160     /* size of level CNT2 chunk   */
42 #define LEVEL_CHUNK_CNT2_UNUSED 11      /* unused CNT2 chunk bytes    */
43 #define LEVEL_CHUNK_CNT3_HEADER 16      /* size of level CNT3 header  */
44 #define LEVEL_CHUNK_CNT3_UNUSED 10      /* unused CNT3 chunk bytes    */
45 #define LEVEL_CPART_CUS3_SIZE   134     /* size of CUS3 chunk part    */
46 #define LEVEL_CPART_CUS3_UNUSED 15      /* unused CUS3 bytes / part   */
47 #define LEVEL_CHUNK_GRP1_SIZE   74      /* size of level GRP1 chunk   */
48
49 /* (element number, number of change pages, change page number) */
50 #define LEVEL_CHUNK_CUSX_UNCHANGED      (2 + (1 + 1) + (1 + 1))
51
52 /* (element number only) */
53 #define LEVEL_CHUNK_GRPX_UNCHANGED      2
54 #define LEVEL_CHUNK_NOTE_UNCHANGED      2
55
56 /* (nothing at all if unchanged) */
57 #define LEVEL_CHUNK_ELEM_UNCHANGED      0
58
59 #define TAPE_CHUNK_VERS_SIZE    8       /* size of file version chunk */
60 #define TAPE_CHUNK_HEAD_SIZE    20      /* size of tape file header   */
61 #define TAPE_CHUNK_HEAD_UNUSED  2       /* unused tape header bytes   */
62
63 #define LEVEL_CHUNK_CNT3_SIZE(x)         (LEVEL_CHUNK_CNT3_HEADER + (x))
64 #define LEVEL_CHUNK_CUS3_SIZE(x)         (2 + (x) * LEVEL_CPART_CUS3_SIZE)
65 #define LEVEL_CHUNK_CUS4_SIZE(x)         (96 + (x) * 48)
66
67 /* file identifier strings */
68 #define LEVEL_COOKIE_TMPL               "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x"
69 #define TAPE_COOKIE_TMPL                "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
70 #define SCORE_COOKIE                    "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
71
72 /* values for deciding when (not) to save configuration data */
73 #define SAVE_CONF_NEVER                 0
74 #define SAVE_CONF_ALWAYS                1
75 #define SAVE_CONF_WHEN_CHANGED          -1
76
77 /* values for chunks using micro chunks */
78 #define CONF_MASK_1_BYTE                0x00
79 #define CONF_MASK_2_BYTE                0x40
80 #define CONF_MASK_4_BYTE                0x80
81 #define CONF_MASK_MULTI_BYTES           0xc0
82
83 #define CONF_MASK_BYTES                 0xc0
84 #define CONF_MASK_TOKEN                 0x3f
85
86 #define CONF_VALUE_1_BYTE(x)            (CONF_MASK_1_BYTE       | (x))
87 #define CONF_VALUE_2_BYTE(x)            (CONF_MASK_2_BYTE       | (x))
88 #define CONF_VALUE_4_BYTE(x)            (CONF_MASK_4_BYTE       | (x))
89 #define CONF_VALUE_MULTI_BYTES(x)       (CONF_MASK_MULTI_BYTES  | (x))
90
91 /* these definitions are just for convenience of use and readability */
92 #define CONF_VALUE_8_BIT(x)             CONF_VALUE_1_BYTE(x)
93 #define CONF_VALUE_16_BIT(x)            CONF_VALUE_2_BYTE(x)
94 #define CONF_VALUE_32_BIT(x)            CONF_VALUE_4_BYTE(x)
95 #define CONF_VALUE_BYTES(x)             CONF_VALUE_MULTI_BYTES(x)
96
97 #define CONF_VALUE_NUM_BYTES(x)         ((x) == CONF_MASK_1_BYTE ? 1 :  \
98                                          (x) == CONF_MASK_2_BYTE ? 2 :  \
99                                          (x) == CONF_MASK_4_BYTE ? 4 : 0)
100
101 #define CONF_CONTENT_NUM_ELEMENTS       (3 * 3)
102 #define CONF_CONTENT_NUM_BYTES          (CONF_CONTENT_NUM_ELEMENTS * 2)
103 #define CONF_ELEMENT_NUM_BYTES          (2)
104
105 #define CONF_ENTITY_NUM_BYTES(t)        ((t) == TYPE_ELEMENT ||         \
106                                          (t) == TYPE_ELEMENT_LIST ?     \
107                                          CONF_ELEMENT_NUM_BYTES :       \
108                                          (t) == TYPE_CONTENT ||         \
109                                          (t) == TYPE_CONTENT_LIST ?     \
110                                          CONF_CONTENT_NUM_BYTES : 1)
111
112 #define CONF_ELEMENT_BYTE_POS(i)        ((i) * CONF_ELEMENT_NUM_BYTES)
113 #define CONF_ELEMENTS_ELEMENT(b,i)     ((b[CONF_ELEMENT_BYTE_POS(i)] << 8) |  \
114                                         (b[CONF_ELEMENT_BYTE_POS(i) + 1]))
115
116 #define CONF_CONTENT_ELEMENT_POS(c,x,y) ((c) * CONF_CONTENT_NUM_ELEMENTS +    \
117                                          (y) * 3 + (x))
118 #define CONF_CONTENT_BYTE_POS(c,x,y)    (CONF_CONTENT_ELEMENT_POS(c,x,y) *    \
119                                          CONF_ELEMENT_NUM_BYTES)
120 #define CONF_CONTENTS_ELEMENT(b,c,x,y) ((b[CONF_CONTENT_BYTE_POS(c,x,y)]<< 8)|\
121                                         (b[CONF_CONTENT_BYTE_POS(c,x,y) + 1]))
122
123 /* temporary variables used to store pointers to structure members */
124 static struct LevelInfo li;
125 static struct ElementInfo xx_ei, yy_ei;
126 static struct ElementChangeInfo xx_change;
127 static struct ElementGroupInfo xx_group;
128 static struct EnvelopeInfo xx_envelope;
129 static unsigned int xx_event_bits[NUM_CE_BITFIELDS];
130 static char xx_default_description[MAX_ELEMENT_NAME_LEN + 1];
131 static int xx_num_contents;
132 static int xx_current_change_page;
133 static char xx_default_string_empty[1] = "";
134 static int xx_string_length_unused;
135
136 struct LevelFileConfigInfo
137 {
138   int element;                  /* element for which data is to be stored */
139   int save_type;                /* save data always, never or when changed */
140   int data_type;                /* data type (used internally, not stored) */
141   int conf_type;                /* micro chunk identifier (stored in file) */
142
143   /* (mandatory) */
144   void *value;                  /* variable that holds the data to be stored */
145   int default_value;            /* initial default value for this variable */
146
147   /* (optional) */
148   void *value_copy;             /* variable that holds the data to be copied */
149   void *num_entities;           /* number of entities for multi-byte data */
150   int default_num_entities;     /* default number of entities for this data */
151   int max_num_entities;         /* maximal number of entities for this data */
152   char *default_string;         /* optional default string for string data */
153 };
154
155 static struct LevelFileConfigInfo chunk_config_INFO[] =
156 {
157   /* ---------- values not related to single elements ----------------------- */
158
159   {
160     -1,                                 SAVE_CONF_ALWAYS,
161     TYPE_INTEGER,                       CONF_VALUE_8_BIT(1),
162     &li.game_engine_type,               GAME_ENGINE_TYPE_RND
163   },
164
165   {
166     -1,                                 SAVE_CONF_ALWAYS,
167     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
168     &li.fieldx,                         STD_LEV_FIELDX
169   },
170   {
171     -1,                                 SAVE_CONF_ALWAYS,
172     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
173     &li.fieldy,                         STD_LEV_FIELDY
174   },
175
176   {
177     -1,                                 SAVE_CONF_ALWAYS,
178     TYPE_INTEGER,                       CONF_VALUE_16_BIT(3),
179     &li.time,                           100
180   },
181
182   {
183     -1,                                 SAVE_CONF_ALWAYS,
184     TYPE_INTEGER,                       CONF_VALUE_16_BIT(4),
185     &li.gems_needed,                    0
186   },
187
188   {
189     -1,                                 -1,
190     TYPE_INTEGER,                       CONF_VALUE_32_BIT(2),
191     &li.random_seed,                    0
192   },
193
194   {
195     -1,                                 -1,
196     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(2),
197     &li.use_step_counter,               FALSE
198   },
199
200   {
201     -1,                                 -1,
202     TYPE_BITFIELD,                      CONF_VALUE_8_BIT(4),
203     &li.wind_direction_initial,         MV_NONE
204   },
205
206   {
207     -1,                                 -1,
208     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(5),
209     &li.em_slippery_gems,               FALSE
210   },
211
212   {
213     -1,                                 -1,
214     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(6),
215     &li.use_custom_template,            FALSE
216   },
217
218   {
219     -1,                                 -1,
220     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(1),
221     &li.can_move_into_acid_bits,        ~0      /* default: everything can */
222   },
223
224   {
225     -1,                                 -1,
226     TYPE_BITFIELD,                      CONF_VALUE_8_BIT(7),
227     &li.dont_collide_with_bits,         ~0      /* default: always deadly */
228   },
229
230   {
231     -1,                                 -1,
232     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(8),
233     &li.em_explodes_by_fire,            FALSE
234   },
235
236   {
237     -1,                                 -1,
238     TYPE_INTEGER,                       CONF_VALUE_16_BIT(5),
239     &li.score[SC_TIME_BONUS],           1
240   },
241
242   {
243     -1,                                 -1,
244     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(9),
245     &li.auto_exit_sokoban,              FALSE
246   },
247
248   {
249     -1,                                 -1,
250     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(10),
251     &li.auto_count_gems,                FALSE
252   },
253
254   {
255     -1,                                 -1,
256     -1,                                 -1,
257     NULL,                               -1
258   }
259 };
260
261 static struct LevelFileConfigInfo chunk_config_ELEM[] =
262 {
263   /* (these values are the same for each player) */
264   {
265     EL_PLAYER_1,                        -1,
266     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
267     &li.block_last_field,               FALSE   /* default case for EM levels */
268   },
269   {
270     EL_PLAYER_1,                        -1,
271     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(2),
272     &li.sp_block_last_field,            TRUE    /* default case for SP levels */
273   },
274   {
275     EL_PLAYER_1,                        -1,
276     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(3),
277     &li.instant_relocation,             FALSE
278   },
279   {
280     EL_PLAYER_1,                        -1,
281     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(4),
282     &li.can_pass_to_walkable,           FALSE
283   },
284   {
285     EL_PLAYER_1,                        -1,
286     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(5),
287     &li.block_snap_field,               TRUE
288   },
289   {
290     EL_PLAYER_1,                        -1,
291     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(6),
292     &li.continuous_snapping,            TRUE
293   },
294   {
295     EL_PLAYER_1,                        -1,
296     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(12),
297     &li.shifted_relocation,             FALSE
298   },
299   {
300     EL_PLAYER_1,                        -1,
301     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(15),
302     &li.lazy_relocation,                FALSE
303   },
304
305   /* (these values are different for each player) */
306   {
307     EL_PLAYER_1,                        -1,
308     TYPE_INTEGER,                       CONF_VALUE_8_BIT(7),
309     &li.initial_player_stepsize[0],     STEPSIZE_NORMAL
310   },
311   {
312     EL_PLAYER_1,                        -1,
313     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(8),
314     &li.initial_player_gravity[0],      FALSE
315   },
316   {
317     EL_PLAYER_1,                        -1,
318     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(9),
319     &li.use_start_element[0],           FALSE
320   },
321   {
322     EL_PLAYER_1,                        -1,
323     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
324     &li.start_element[0],               EL_PLAYER_1
325   },
326   {
327     EL_PLAYER_1,                        -1,
328     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(10),
329     &li.use_artwork_element[0],         FALSE
330   },
331   {
332     EL_PLAYER_1,                        -1,
333     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(2),
334     &li.artwork_element[0],             EL_PLAYER_1
335   },
336   {
337     EL_PLAYER_1,                        -1,
338     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(11),
339     &li.use_explosion_element[0],       FALSE
340   },
341   {
342     EL_PLAYER_1,                        -1,
343     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(3),
344     &li.explosion_element[0],           EL_PLAYER_1
345   },
346   {
347     EL_PLAYER_1,                        -1,
348     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(13),
349     &li.use_initial_inventory[0],       FALSE
350   },
351   {
352     EL_PLAYER_1,                        -1,
353     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(14),
354     &li.initial_inventory_size[0],      1
355   },
356   {
357     EL_PLAYER_1,                        -1,
358     TYPE_ELEMENT_LIST,                  CONF_VALUE_BYTES(1),
359     &li.initial_inventory_content[0][0],EL_EMPTY, NULL,
360     &li.initial_inventory_size[0],      1, MAX_INITIAL_INVENTORY_SIZE
361   },
362
363   {
364     EL_PLAYER_2,                        -1,
365     TYPE_INTEGER,                       CONF_VALUE_8_BIT(7),
366     &li.initial_player_stepsize[1],     STEPSIZE_NORMAL
367   },
368   {
369     EL_PLAYER_2,                        -1,
370     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(8),
371     &li.initial_player_gravity[1],      FALSE
372   },
373   {
374     EL_PLAYER_2,                        -1,
375     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(9),
376     &li.use_start_element[1],           FALSE
377   },
378   {
379     EL_PLAYER_2,                        -1,
380     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
381     &li.start_element[1],               EL_PLAYER_2
382   },
383   {
384     EL_PLAYER_2,                        -1,
385     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(10),
386     &li.use_artwork_element[1],         FALSE
387   },
388   {
389     EL_PLAYER_2,                        -1,
390     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(2),
391     &li.artwork_element[1],             EL_PLAYER_2
392   },
393   {
394     EL_PLAYER_2,                        -1,
395     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(11),
396     &li.use_explosion_element[1],       FALSE
397   },
398   {
399     EL_PLAYER_2,                        -1,
400     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(3),
401     &li.explosion_element[1],           EL_PLAYER_2
402   },
403   {
404     EL_PLAYER_2,                        -1,
405     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(13),
406     &li.use_initial_inventory[1],       FALSE
407   },
408   {
409     EL_PLAYER_2,                        -1,
410     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(14),
411     &li.initial_inventory_size[1],      1
412   },
413   {
414     EL_PLAYER_2,                        -1,
415     TYPE_ELEMENT_LIST,                  CONF_VALUE_BYTES(1),
416     &li.initial_inventory_content[1][0],EL_EMPTY, NULL,
417     &li.initial_inventory_size[1],      1, MAX_INITIAL_INVENTORY_SIZE
418   },
419
420   {
421     EL_PLAYER_3,                        -1,
422     TYPE_INTEGER,                       CONF_VALUE_8_BIT(7),
423     &li.initial_player_stepsize[2],     STEPSIZE_NORMAL
424   },
425   {
426     EL_PLAYER_3,                        -1,
427     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(8),
428     &li.initial_player_gravity[2],      FALSE
429   },
430   {
431     EL_PLAYER_3,                        -1,
432     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(9),
433     &li.use_start_element[2],           FALSE
434   },
435   {
436     EL_PLAYER_3,                        -1,
437     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
438     &li.start_element[2],               EL_PLAYER_3
439   },
440   {
441     EL_PLAYER_3,                        -1,
442     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(10),
443     &li.use_artwork_element[2],         FALSE
444   },
445   {
446     EL_PLAYER_3,                        -1,
447     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(2),
448     &li.artwork_element[2],             EL_PLAYER_3
449   },
450   {
451     EL_PLAYER_3,                        -1,
452     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(11),
453     &li.use_explosion_element[2],       FALSE
454   },
455   {
456     EL_PLAYER_3,                        -1,
457     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(3),
458     &li.explosion_element[2],           EL_PLAYER_3
459   },
460   {
461     EL_PLAYER_3,                        -1,
462     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(13),
463     &li.use_initial_inventory[2],       FALSE
464   },
465   {
466     EL_PLAYER_3,                        -1,
467     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(14),
468     &li.initial_inventory_size[2],      1
469   },
470   {
471     EL_PLAYER_3,                        -1,
472     TYPE_ELEMENT_LIST,                  CONF_VALUE_BYTES(1),
473     &li.initial_inventory_content[2][0],EL_EMPTY, NULL,
474     &li.initial_inventory_size[2],      1, MAX_INITIAL_INVENTORY_SIZE
475   },
476
477   {
478     EL_PLAYER_4,                        -1,
479     TYPE_INTEGER,                       CONF_VALUE_8_BIT(7),
480     &li.initial_player_stepsize[3],     STEPSIZE_NORMAL
481   },
482   {
483     EL_PLAYER_4,                        -1,
484     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(8),
485     &li.initial_player_gravity[3],      FALSE
486   },
487   {
488     EL_PLAYER_4,                        -1,
489     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(9),
490     &li.use_start_element[3],           FALSE
491   },
492   {
493     EL_PLAYER_4,                        -1,
494     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
495     &li.start_element[3],               EL_PLAYER_4
496   },
497   {
498     EL_PLAYER_4,                        -1,
499     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(10),
500     &li.use_artwork_element[3],         FALSE
501   },
502   {
503     EL_PLAYER_4,                        -1,
504     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(2),
505     &li.artwork_element[3],             EL_PLAYER_4
506   },
507   {
508     EL_PLAYER_4,                        -1,
509     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(11),
510     &li.use_explosion_element[3],       FALSE
511   },
512   {
513     EL_PLAYER_4,                        -1,
514     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(3),
515     &li.explosion_element[3],           EL_PLAYER_4
516   },
517   {
518     EL_PLAYER_4,                        -1,
519     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(13),
520     &li.use_initial_inventory[3],       FALSE
521   },
522   {
523     EL_PLAYER_4,                        -1,
524     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(14),
525     &li.initial_inventory_size[3],      1
526   },
527   {
528     EL_PLAYER_4,                        -1,
529     TYPE_ELEMENT_LIST,                  CONF_VALUE_BYTES(1),
530     &li.initial_inventory_content[3][0],EL_EMPTY, NULL,
531     &li.initial_inventory_size[3],      1, MAX_INITIAL_INVENTORY_SIZE
532   },
533
534   {
535     EL_EMERALD,                         -1,
536     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
537     &li.score[SC_EMERALD],              10
538   },
539
540   {
541     EL_DIAMOND,                         -1,
542     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
543     &li.score[SC_DIAMOND],              10
544   },
545
546   {
547     EL_BUG,                             -1,
548     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
549     &li.score[SC_BUG],                  10
550   },
551
552   {
553     EL_SPACESHIP,                       -1,
554     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
555     &li.score[SC_SPACESHIP],            10
556   },
557
558   {
559     EL_PACMAN,                          -1,
560     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
561     &li.score[SC_PACMAN],               10
562   },
563
564   {
565     EL_NUT,                             -1,
566     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
567     &li.score[SC_NUT],                  10
568   },
569
570   {
571     EL_DYNAMITE,                        -1,
572     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
573     &li.score[SC_DYNAMITE],             10
574   },
575
576   {
577     EL_KEY_1,                           -1,
578     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
579     &li.score[SC_KEY],                  10
580   },
581
582   {
583     EL_PEARL,                           -1,
584     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
585     &li.score[SC_PEARL],                10
586   },
587
588   {
589     EL_CRYSTAL,                         -1,
590     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
591     &li.score[SC_CRYSTAL],              10
592   },
593
594   {
595     EL_BD_AMOEBA,                       -1,
596     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
597     &li.amoeba_content,                 EL_DIAMOND
598   },
599   {
600     EL_BD_AMOEBA,                       -1,
601     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
602     &li.amoeba_speed,                   10
603   },
604   {
605     EL_BD_AMOEBA,                       -1,
606     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
607     &li.grow_into_diggable,             TRUE
608   },
609
610   {
611     EL_YAMYAM,                          -1,
612     TYPE_CONTENT_LIST,                  CONF_VALUE_BYTES(1),
613     &li.yamyam_content,                 EL_ROCK, NULL,
614     &li.num_yamyam_contents,            4, MAX_ELEMENT_CONTENTS
615   },
616   {
617     EL_YAMYAM,                          -1,
618     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
619     &li.score[SC_YAMYAM],               10
620   },
621
622   {
623     EL_ROBOT,                           -1,
624     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
625     &li.score[SC_ROBOT],                10
626   },
627   {
628     EL_ROBOT,                           -1,
629     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
630     &li.slurp_score,                    10
631   },
632
633   {
634     EL_ROBOT_WHEEL,                     -1,
635     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
636     &li.time_wheel,                     10
637   },
638
639   {
640     EL_MAGIC_WALL,                      -1,
641     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
642     &li.time_magic_wall,                10
643   },
644
645   {
646     EL_GAME_OF_LIFE,                    -1,
647     TYPE_INTEGER,                       CONF_VALUE_8_BIT(1),
648     &li.game_of_life[0],                2
649   },
650   {
651     EL_GAME_OF_LIFE,                    -1,
652     TYPE_INTEGER,                       CONF_VALUE_8_BIT(2),
653     &li.game_of_life[1],                3
654   },
655   {
656     EL_GAME_OF_LIFE,                    -1,
657     TYPE_INTEGER,                       CONF_VALUE_8_BIT(3),
658     &li.game_of_life[2],                3
659   },
660   {
661     EL_GAME_OF_LIFE,                    -1,
662     TYPE_INTEGER,                       CONF_VALUE_8_BIT(4),
663     &li.game_of_life[3],                3
664   },
665
666   {
667     EL_BIOMAZE,                         -1,
668     TYPE_INTEGER,                       CONF_VALUE_8_BIT(1),
669     &li.biomaze[0],                     2
670   },
671   {
672     EL_BIOMAZE,                         -1,
673     TYPE_INTEGER,                       CONF_VALUE_8_BIT(2),
674     &li.biomaze[1],                     3
675   },
676   {
677     EL_BIOMAZE,                         -1,
678     TYPE_INTEGER,                       CONF_VALUE_8_BIT(3),
679     &li.biomaze[2],                     3
680   },
681   {
682     EL_BIOMAZE,                         -1,
683     TYPE_INTEGER,                       CONF_VALUE_8_BIT(4),
684     &li.biomaze[3],                     3
685   },
686
687   {
688     EL_TIMEGATE_SWITCH,                 -1,
689     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
690     &li.time_timegate,                  10
691   },
692
693   {
694     EL_LIGHT_SWITCH_ACTIVE,             -1,
695     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
696     &li.time_light,                     10
697   },
698
699   {
700     EL_SHIELD_NORMAL,                   -1,
701     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
702     &li.shield_normal_time,             10
703   },
704   {
705     EL_SHIELD_NORMAL,                   -1,
706     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
707     &li.score[SC_SHIELD],               10
708   },
709
710   {
711     EL_SHIELD_DEADLY,                   -1,
712     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
713     &li.shield_deadly_time,             10
714   },
715   {
716     EL_SHIELD_DEADLY,                   -1,
717     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
718     &li.score[SC_SHIELD],               10
719   },
720
721   {
722     EL_EXTRA_TIME,                      -1,
723     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
724     &li.extra_time,                     10
725   },
726   {
727     EL_EXTRA_TIME,                      -1,
728     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
729     &li.extra_time_score,               10
730   },
731
732   {
733     EL_TIME_ORB_FULL,                   -1,
734     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
735     &li.time_orb_time,                  10
736   },
737   {
738     EL_TIME_ORB_FULL,                   -1,
739     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
740     &li.use_time_orb_bug,               FALSE
741   },
742
743   {
744     EL_SPRING,                          -1,
745     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
746     &li.use_spring_bug,                 FALSE
747   },
748
749   {
750     EL_EMC_ANDROID,                     -1,
751     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
752     &li.android_move_time,              10
753   },
754   {
755     EL_EMC_ANDROID,                     -1,
756     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
757     &li.android_clone_time,             10
758   },
759   {
760     EL_EMC_ANDROID,                     -1,
761     TYPE_ELEMENT_LIST,                  CONF_VALUE_BYTES(1),
762     &li.android_clone_element[0],       EL_EMPTY, NULL,
763     &li.num_android_clone_elements,     1, MAX_ANDROID_ELEMENTS
764   },
765
766   {
767     EL_EMC_LENSES,                      -1,
768     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
769     &li.lenses_score,                   10
770   },
771   {
772     EL_EMC_LENSES,                      -1,
773     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
774     &li.lenses_time,                    10
775   },
776
777   {
778     EL_EMC_MAGNIFIER,                   -1,
779     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
780     &li.magnify_score,                  10
781   },
782   {
783     EL_EMC_MAGNIFIER,                   -1,
784     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
785     &li.magnify_time,                   10
786   },
787
788   {
789     EL_EMC_MAGIC_BALL,                  -1,
790     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
791     &li.ball_time,                      10
792   },
793   {
794     EL_EMC_MAGIC_BALL,                  -1,
795     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
796     &li.ball_random,                    FALSE
797   },
798   {
799     EL_EMC_MAGIC_BALL,                  -1,
800     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(2),
801     &li.ball_state_initial,             FALSE
802   },
803   {
804     EL_EMC_MAGIC_BALL,                  -1,
805     TYPE_CONTENT_LIST,                  CONF_VALUE_BYTES(1),
806     &li.ball_content,                   EL_EMPTY, NULL,
807     &li.num_ball_contents,              4, MAX_ELEMENT_CONTENTS
808   },
809
810   {
811     EL_MM_MCDUFFIN,                     -1,
812     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
813     &li.mm_laser_red,                   FALSE
814   },
815   {
816     EL_MM_MCDUFFIN,                     -1,
817     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(2),
818     &li.mm_laser_green,                 FALSE
819   },
820   {
821     EL_MM_MCDUFFIN,                     -1,
822     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(3),
823     &li.mm_laser_blue,                  TRUE
824   },
825
826   {
827     EL_DF_LASER,                        -1,
828     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
829     &li.df_laser_red,                   TRUE
830   },
831   {
832     EL_DF_LASER,                        -1,
833     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(2),
834     &li.df_laser_green,                 TRUE
835   },
836   {
837     EL_DF_LASER,                        -1,
838     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(3),
839     &li.df_laser_blue,                  FALSE
840   },
841
842   {
843     EL_MM_FUSE_ACTIVE,                  -1,
844     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
845     &li.mm_time_fuse,                   25
846   },
847   {
848     EL_MM_BOMB,                         -1,
849     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
850     &li.mm_time_bomb,                   75
851   },
852   {
853     EL_MM_GRAY_BALL,                    -1,
854     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
855     &li.mm_time_ball,                   75
856   },
857   {
858     EL_MM_STEEL_BLOCK,                  -1,
859     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
860     &li.mm_time_block,                  75
861   },
862   {
863     EL_MM_LIGHTBALL,                    -1,
864     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
865     &li.score[SC_ELEM_BONUS],           10
866   },
867
868   /* ---------- unused values ----------------------------------------------- */
869
870   {
871     EL_UNKNOWN,                         SAVE_CONF_NEVER,
872     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
873     &li.score[SC_UNKNOWN_15],           10
874   },
875
876   {
877     -1,                                 -1,
878     -1,                                 -1,
879     NULL,                               -1
880   }
881 };
882
883 static struct LevelFileConfigInfo chunk_config_NOTE[] =
884 {
885   {
886     -1,                                 -1,
887     TYPE_INTEGER,                       CONF_VALUE_8_BIT(1),
888     &xx_envelope.xsize,                 MAX_ENVELOPE_XSIZE,
889   },
890   {
891     -1,                                 -1,
892     TYPE_INTEGER,                       CONF_VALUE_8_BIT(2),
893     &xx_envelope.ysize,                 MAX_ENVELOPE_YSIZE,
894   },
895
896   {
897     -1,                                 -1,
898     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(3),
899     &xx_envelope.autowrap,              FALSE
900   },
901   {
902     -1,                                 -1,
903     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(4),
904     &xx_envelope.centered,              FALSE
905   },
906
907   {
908     -1,                                 -1,
909     TYPE_STRING,                        CONF_VALUE_BYTES(1),
910     &xx_envelope.text,                  -1, NULL,
911     &xx_string_length_unused,           -1, MAX_ENVELOPE_TEXT_LEN,
912     &xx_default_string_empty[0]
913   },
914
915   {
916     -1,                                 -1,
917     -1,                                 -1,
918     NULL,                               -1
919   }
920 };
921
922 static struct LevelFileConfigInfo chunk_config_CUSX_base[] =
923 {
924   {
925     -1,                                 -1,
926     TYPE_STRING,                        CONF_VALUE_BYTES(1),
927     &xx_ei.description[0],              -1,
928     &yy_ei.description[0],
929     &xx_string_length_unused,           -1, MAX_ELEMENT_NAME_LEN,
930     &xx_default_description[0]
931   },
932
933   {
934     -1,                                 -1,
935     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(1),
936     &xx_ei.properties[EP_BITFIELD_BASE_NR], EP_BITMASK_BASE_DEFAULT,
937     &yy_ei.properties[EP_BITFIELD_BASE_NR]
938   },
939 #if ENABLE_RESERVED_CODE
940   /* (reserved for later use) */
941   {
942     -1,                                 -1,
943     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(2),
944     &xx_ei.properties[EP_BITFIELD_BASE_NR + 1], EP_BITMASK_DEFAULT,
945     &yy_ei.properties[EP_BITFIELD_BASE_NR + 1]
946   },
947 #endif
948
949   {
950     -1,                                 -1,
951     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
952     &xx_ei.use_gfx_element,             FALSE,
953     &yy_ei.use_gfx_element
954   },
955   {
956     -1,                                 -1,
957     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
958     &xx_ei.gfx_element_initial,         EL_EMPTY_SPACE,
959     &yy_ei.gfx_element_initial
960   },
961
962   {
963     -1,                                 -1,
964     TYPE_BITFIELD,                      CONF_VALUE_8_BIT(2),
965     &xx_ei.access_direction,            MV_ALL_DIRECTIONS,
966     &yy_ei.access_direction
967   },
968
969   {
970     -1,                                 -1,
971     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
972     &xx_ei.collect_score_initial,       10,
973     &yy_ei.collect_score_initial
974   },
975   {
976     -1,                                 -1,
977     TYPE_INTEGER,                       CONF_VALUE_16_BIT(3),
978     &xx_ei.collect_count_initial,       1,
979     &yy_ei.collect_count_initial
980   },
981
982   {
983     -1,                                 -1,
984     TYPE_INTEGER,                       CONF_VALUE_16_BIT(4),
985     &xx_ei.ce_value_fixed_initial,      0,
986     &yy_ei.ce_value_fixed_initial
987   },
988   {
989     -1,                                 -1,
990     TYPE_INTEGER,                       CONF_VALUE_16_BIT(5),
991     &xx_ei.ce_value_random_initial,     0,
992     &yy_ei.ce_value_random_initial
993   },
994   {
995     -1,                                 -1,
996     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(3),
997     &xx_ei.use_last_ce_value,           FALSE,
998     &yy_ei.use_last_ce_value
999   },
1000
1001   {
1002     -1,                                 -1,
1003     TYPE_INTEGER,                       CONF_VALUE_16_BIT(6),
1004     &xx_ei.push_delay_fixed,            8,
1005     &yy_ei.push_delay_fixed
1006   },
1007   {
1008     -1,                                 -1,
1009     TYPE_INTEGER,                       CONF_VALUE_16_BIT(7),
1010     &xx_ei.push_delay_random,           8,
1011     &yy_ei.push_delay_random
1012   },
1013   {
1014     -1,                                 -1,
1015     TYPE_INTEGER,                       CONF_VALUE_16_BIT(8),
1016     &xx_ei.drop_delay_fixed,            0,
1017     &yy_ei.drop_delay_fixed
1018   },
1019   {
1020     -1,                                 -1,
1021     TYPE_INTEGER,                       CONF_VALUE_16_BIT(9),
1022     &xx_ei.drop_delay_random,           0,
1023     &yy_ei.drop_delay_random
1024   },
1025   {
1026     -1,                                 -1,
1027     TYPE_INTEGER,                       CONF_VALUE_16_BIT(10),
1028     &xx_ei.move_delay_fixed,            0,
1029     &yy_ei.move_delay_fixed
1030   },
1031   {
1032     -1,                                 -1,
1033     TYPE_INTEGER,                       CONF_VALUE_16_BIT(11),
1034     &xx_ei.move_delay_random,           0,
1035     &yy_ei.move_delay_random
1036   },
1037
1038   {
1039     -1,                                 -1,
1040     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(3),
1041     &xx_ei.move_pattern,                MV_ALL_DIRECTIONS,
1042     &yy_ei.move_pattern
1043   },
1044   {
1045     -1,                                 -1,
1046     TYPE_BITFIELD,                      CONF_VALUE_8_BIT(4),
1047     &xx_ei.move_direction_initial,      MV_START_AUTOMATIC,
1048     &yy_ei.move_direction_initial
1049   },
1050   {
1051     -1,                                 -1,
1052     TYPE_INTEGER,                       CONF_VALUE_8_BIT(5),
1053     &xx_ei.move_stepsize,               TILEX / 8,
1054     &yy_ei.move_stepsize
1055   },
1056
1057   {
1058     -1,                                 -1,
1059     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(12),
1060     &xx_ei.move_enter_element,          EL_EMPTY_SPACE,
1061     &yy_ei.move_enter_element
1062   },
1063   {
1064     -1,                                 -1,
1065     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(13),
1066     &xx_ei.move_leave_element,          EL_EMPTY_SPACE,
1067     &yy_ei.move_leave_element
1068   },
1069   {
1070     -1,                                 -1,
1071     TYPE_INTEGER,                       CONF_VALUE_8_BIT(6),
1072     &xx_ei.move_leave_type,             LEAVE_TYPE_UNLIMITED,
1073     &yy_ei.move_leave_type
1074   },
1075
1076   {
1077     -1,                                 -1,
1078     TYPE_INTEGER,                       CONF_VALUE_8_BIT(7),
1079     &xx_ei.slippery_type,               SLIPPERY_ANY_RANDOM,
1080     &yy_ei.slippery_type
1081   },
1082
1083   {
1084     -1,                                 -1,
1085     TYPE_INTEGER,                       CONF_VALUE_8_BIT(8),
1086     &xx_ei.explosion_type,              EXPLODES_3X3,
1087     &yy_ei.explosion_type
1088   },
1089   {
1090     -1,                                 -1,
1091     TYPE_INTEGER,                       CONF_VALUE_16_BIT(14),
1092     &xx_ei.explosion_delay,             16,
1093     &yy_ei.explosion_delay
1094   },
1095   {
1096     -1,                                 -1,
1097     TYPE_INTEGER,                       CONF_VALUE_16_BIT(15),
1098     &xx_ei.ignition_delay,              8,
1099     &yy_ei.ignition_delay
1100   },
1101
1102   {
1103     -1,                                 -1,
1104     TYPE_CONTENT_LIST,                  CONF_VALUE_BYTES(2),
1105     &xx_ei.content,                     EL_EMPTY_SPACE,
1106     &yy_ei.content,
1107     &xx_num_contents,                   1, 1
1108   },
1109
1110   /* ---------- "num_change_pages" must be the last entry ------------------- */
1111
1112   {
1113     -1,                                 SAVE_CONF_ALWAYS,
1114     TYPE_INTEGER,                       CONF_VALUE_8_BIT(9),
1115     &xx_ei.num_change_pages,            1,
1116     &yy_ei.num_change_pages
1117   },
1118
1119   {
1120     -1,                                 -1,
1121     -1,                                 -1,
1122     NULL,                               -1,
1123     NULL
1124   }
1125 };
1126
1127 static struct LevelFileConfigInfo chunk_config_CUSX_change[] =
1128 {
1129   /* ---------- "current_change_page" must be the first entry --------------- */
1130
1131   {
1132     -1,                                 SAVE_CONF_ALWAYS,
1133     TYPE_INTEGER,                       CONF_VALUE_8_BIT(1),
1134     &xx_current_change_page,            -1
1135   },
1136
1137   /* ---------- (the remaining entries can be in any order) ----------------- */
1138
1139   {
1140     -1,                                 -1,
1141     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(2),
1142     &xx_change.can_change,              FALSE
1143   },
1144
1145   {
1146     -1,                                 -1,
1147     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(1),
1148     &xx_event_bits[0],                  0
1149   },
1150   {
1151     -1,                                 -1,
1152     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(2),
1153     &xx_event_bits[1],                  0
1154   },
1155
1156   {
1157     -1,                                 -1,
1158     TYPE_BITFIELD,                      CONF_VALUE_8_BIT(3),
1159     &xx_change.trigger_player,          CH_PLAYER_ANY
1160   },
1161   {
1162     -1,                                 -1,
1163     TYPE_BITFIELD,                      CONF_VALUE_8_BIT(4),
1164     &xx_change.trigger_side,            CH_SIDE_ANY
1165   },
1166   {
1167     -1,                                 -1,
1168     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(3),
1169     &xx_change.trigger_page,            CH_PAGE_ANY
1170   },
1171
1172   {
1173     -1,                                 -1,
1174     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
1175     &xx_change.target_element,          EL_EMPTY_SPACE
1176   },
1177
1178   {
1179     -1,                                 -1,
1180     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
1181     &xx_change.delay_fixed,             0
1182   },
1183   {
1184     -1,                                 -1,
1185     TYPE_INTEGER,                       CONF_VALUE_16_BIT(3),
1186     &xx_change.delay_random,            0
1187   },
1188   {
1189     -1,                                 -1,
1190     TYPE_INTEGER,                       CONF_VALUE_16_BIT(4),
1191     &xx_change.delay_frames,            FRAMES_PER_SECOND
1192   },
1193
1194   {
1195     -1,                                 -1,
1196     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(5),
1197     &xx_change.initial_trigger_element, EL_EMPTY_SPACE
1198   },
1199
1200   {
1201     -1,                                 -1,
1202     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(6),
1203     &xx_change.explode,                 FALSE
1204   },
1205   {
1206     -1,                                 -1,
1207     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(7),
1208     &xx_change.use_target_content,      FALSE
1209   },
1210   {
1211     -1,                                 -1,
1212     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(8),
1213     &xx_change.only_if_complete,        FALSE
1214   },
1215   {
1216     -1,                                 -1,
1217     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(9),
1218     &xx_change.use_random_replace,      FALSE
1219   },
1220   {
1221     -1,                                 -1,
1222     TYPE_INTEGER,                       CONF_VALUE_8_BIT(10),
1223     &xx_change.random_percentage,       100
1224   },
1225   {
1226     -1,                                 -1,
1227     TYPE_INTEGER,                       CONF_VALUE_8_BIT(11),
1228     &xx_change.replace_when,            CP_WHEN_EMPTY
1229   },
1230
1231   {
1232     -1,                                 -1,
1233     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(12),
1234     &xx_change.has_action,              FALSE
1235   },
1236   {
1237     -1,                                 -1,
1238     TYPE_INTEGER,                       CONF_VALUE_8_BIT(13),
1239     &xx_change.action_type,             CA_NO_ACTION
1240   },
1241   {
1242     -1,                                 -1,
1243     TYPE_INTEGER,                       CONF_VALUE_8_BIT(14),
1244     &xx_change.action_mode,             CA_MODE_UNDEFINED
1245   },
1246   {
1247     -1,                                 -1,
1248     TYPE_INTEGER,                       CONF_VALUE_16_BIT(6),
1249     &xx_change.action_arg,              CA_ARG_UNDEFINED
1250   },
1251
1252   {
1253     -1,                                 -1,
1254     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(7),
1255     &xx_change.action_element,          EL_EMPTY_SPACE
1256   },
1257
1258   {
1259     -1,                                 -1,
1260     TYPE_CONTENT_LIST,                  CONF_VALUE_BYTES(1),
1261     &xx_change.target_content,          EL_EMPTY_SPACE, NULL,
1262     &xx_num_contents,                   1, 1
1263   },
1264
1265   {
1266     -1,                                 -1,
1267     -1,                                 -1,
1268     NULL,                               -1
1269   }
1270 };
1271
1272 static struct LevelFileConfigInfo chunk_config_GRPX[] =
1273 {
1274   {
1275     -1,                                 -1,
1276     TYPE_STRING,                        CONF_VALUE_BYTES(1),
1277     &xx_ei.description[0],              -1, NULL,
1278     &xx_string_length_unused,           -1, MAX_ELEMENT_NAME_LEN,
1279     &xx_default_description[0]
1280   },
1281
1282   {
1283     -1,                                 -1,
1284     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
1285     &xx_ei.use_gfx_element,             FALSE
1286   },
1287   {
1288     -1,                                 -1,
1289     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
1290     &xx_ei.gfx_element_initial,         EL_EMPTY_SPACE
1291   },
1292
1293   {
1294     -1,                                 -1,
1295     TYPE_INTEGER,                       CONF_VALUE_8_BIT(2),
1296     &xx_group.choice_mode,              ANIM_RANDOM
1297   },
1298
1299   {
1300     -1,                                 -1,
1301     TYPE_ELEMENT_LIST,                  CONF_VALUE_BYTES(2),
1302     &xx_group.element[0],               EL_EMPTY_SPACE, NULL,
1303     &xx_group.num_elements,             1, MAX_ELEMENTS_IN_GROUP
1304   },
1305
1306   {
1307     -1,                                 -1,
1308     -1,                                 -1,
1309     NULL,                               -1
1310   }
1311 };
1312
1313 static struct LevelFileConfigInfo chunk_config_CONF[] =         /* (OBSOLETE) */
1314 {
1315   {
1316     EL_PLAYER_1,                        -1,
1317     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(9),
1318     &li.block_snap_field,               TRUE
1319   },
1320   {
1321     EL_PLAYER_1,                        -1,
1322     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(13),
1323     &li.continuous_snapping,            TRUE
1324   },
1325   {
1326     EL_PLAYER_1,                        -1,
1327     TYPE_INTEGER,                       CONF_VALUE_8_BIT(1),
1328     &li.initial_player_stepsize[0],     STEPSIZE_NORMAL
1329   },
1330   {
1331     EL_PLAYER_1,                        -1,
1332     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(10),
1333     &li.use_start_element[0],           FALSE
1334   },
1335   {
1336     EL_PLAYER_1,                        -1,
1337     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
1338     &li.start_element[0],               EL_PLAYER_1
1339   },
1340   {
1341     EL_PLAYER_1,                        -1,
1342     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(11),
1343     &li.use_artwork_element[0],         FALSE
1344   },
1345   {
1346     EL_PLAYER_1,                        -1,
1347     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(2),
1348     &li.artwork_element[0],             EL_PLAYER_1
1349   },
1350   {
1351     EL_PLAYER_1,                        -1,
1352     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(12),
1353     &li.use_explosion_element[0],       FALSE
1354   },
1355   {
1356     EL_PLAYER_1,                        -1,
1357     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(3),
1358     &li.explosion_element[0],           EL_PLAYER_1
1359   },
1360
1361   {
1362     -1,                                 -1,
1363     -1,                                 -1,
1364     NULL,                               -1
1365   }
1366 };
1367
1368 static struct
1369 {
1370   int filetype;
1371   char *id;
1372 }
1373 filetype_id_list[] =
1374 {
1375   { LEVEL_FILE_TYPE_RND,        "RND"   },
1376   { LEVEL_FILE_TYPE_BD,         "BD"    },
1377   { LEVEL_FILE_TYPE_EM,         "EM"    },
1378   { LEVEL_FILE_TYPE_SP,         "SP"    },
1379   { LEVEL_FILE_TYPE_DX,         "DX"    },
1380   { LEVEL_FILE_TYPE_SB,         "SB"    },
1381   { LEVEL_FILE_TYPE_DC,         "DC"    },
1382   { LEVEL_FILE_TYPE_MM,         "MM"    },
1383   { LEVEL_FILE_TYPE_MM,         "DF"    },
1384   { -1,                         NULL    },
1385 };
1386
1387
1388 /* ========================================================================= */
1389 /* level file functions                                                      */
1390 /* ========================================================================= */
1391
1392 static boolean check_special_flags(char *flag)
1393 {
1394   if (strEqual(options.special_flags, flag) ||
1395       strEqual(leveldir_current->special_flags, flag))
1396     return TRUE;
1397
1398   return FALSE;
1399 }
1400
1401 static struct DateInfo getCurrentDate()
1402 {
1403   time_t epoch_seconds = time(NULL);
1404   struct tm *now = localtime(&epoch_seconds);
1405   struct DateInfo date;
1406
1407   date.year  = now->tm_year + 1900;
1408   date.month = now->tm_mon  + 1;
1409   date.day   = now->tm_mday;
1410
1411   date.src   = DATE_SRC_CLOCK;
1412
1413   return date;
1414 }
1415
1416 static void resetEventFlags(struct ElementChangeInfo *change)
1417 {
1418   int i;
1419
1420   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
1421     change->has_event[i] = FALSE;
1422 }
1423
1424 static void resetEventBits()
1425 {
1426   int i;
1427
1428   for (i = 0; i < NUM_CE_BITFIELDS; i++)
1429     xx_event_bits[i] = 0;
1430 }
1431
1432 static void setEventFlagsFromEventBits(struct ElementChangeInfo *change)
1433 {
1434   int i;
1435
1436   /* important: only change event flag if corresponding event bit is set
1437      (this is because all xx_event_bits[] values are loaded separately,
1438      and all xx_event_bits[] values are set back to zero before loading
1439      another value xx_event_bits[x] (each value representing 32 flags)) */
1440
1441   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
1442     if (xx_event_bits[CH_EVENT_BITFIELD_NR(i)] & CH_EVENT_BIT(i))
1443       change->has_event[i] = TRUE;
1444 }
1445
1446 static void setEventBitsFromEventFlags(struct ElementChangeInfo *change)
1447 {
1448   int i;
1449
1450   /* in contrast to the above function setEventFlagsFromEventBits(), it
1451      would also be possible to set all bits in xx_event_bits[] to 0 or 1
1452      depending on the corresponding change->has_event[i] values here, as
1453      all xx_event_bits[] values are reset in resetEventBits() before */
1454
1455   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
1456     if (change->has_event[i])
1457       xx_event_bits[CH_EVENT_BITFIELD_NR(i)] |= CH_EVENT_BIT(i);
1458 }
1459
1460 static char *getDefaultElementDescription(struct ElementInfo *ei)
1461 {
1462   static char description[MAX_ELEMENT_NAME_LEN + 1];
1463   char *default_description = (ei->custom_description != NULL ?
1464                                ei->custom_description :
1465                                ei->editor_description);
1466   int i;
1467
1468   /* always start with reliable default values */
1469   for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++)
1470     description[i] = '\0';
1471
1472   /* truncate element description to MAX_ELEMENT_NAME_LEN bytes */
1473   strncpy(description, default_description, MAX_ELEMENT_NAME_LEN);
1474
1475   return &description[0];
1476 }
1477
1478 static void setElementDescriptionToDefault(struct ElementInfo *ei)
1479 {
1480   char *default_description = getDefaultElementDescription(ei);
1481   int i;
1482
1483   for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++)
1484     ei->description[i] = default_description[i];
1485 }
1486
1487 static void setConfigToDefaultsFromConfigList(struct LevelFileConfigInfo *conf)
1488 {
1489   int i;
1490
1491   for (i = 0; conf[i].data_type != -1; i++)
1492   {
1493     int default_value = conf[i].default_value;
1494     int data_type = conf[i].data_type;
1495     int conf_type = conf[i].conf_type;
1496     int byte_mask = conf_type & CONF_MASK_BYTES;
1497
1498     if (byte_mask == CONF_MASK_MULTI_BYTES)
1499     {
1500       int default_num_entities = conf[i].default_num_entities;
1501       int max_num_entities = conf[i].max_num_entities;
1502
1503       *(int *)(conf[i].num_entities) = default_num_entities;
1504
1505       if (data_type == TYPE_STRING)
1506       {
1507         char *default_string = conf[i].default_string;
1508         char *string = (char *)(conf[i].value);
1509
1510         strncpy(string, default_string, max_num_entities);
1511       }
1512       else if (data_type == TYPE_ELEMENT_LIST)
1513       {
1514         int *element_array = (int *)(conf[i].value);
1515         int j;
1516
1517         for (j = 0; j < max_num_entities; j++)
1518           element_array[j] = default_value;
1519       }
1520       else if (data_type == TYPE_CONTENT_LIST)
1521       {
1522         struct Content *content = (struct Content *)(conf[i].value);
1523         int c, x, y;
1524
1525         for (c = 0; c < max_num_entities; c++)
1526           for (y = 0; y < 3; y++)
1527             for (x = 0; x < 3; x++)
1528               content[c].e[x][y] = default_value;
1529       }
1530     }
1531     else        /* constant size configuration data (1, 2 or 4 bytes) */
1532     {
1533       if (data_type == TYPE_BOOLEAN)
1534         *(boolean *)(conf[i].value) = default_value;
1535       else
1536         *(int *)    (conf[i].value) = default_value;
1537     }
1538   }
1539 }
1540
1541 static void copyConfigFromConfigList(struct LevelFileConfigInfo *conf)
1542 {
1543   int i;
1544
1545   for (i = 0; conf[i].data_type != -1; i++)
1546   {
1547     int data_type = conf[i].data_type;
1548     int conf_type = conf[i].conf_type;
1549     int byte_mask = conf_type & CONF_MASK_BYTES;
1550
1551     if (byte_mask == CONF_MASK_MULTI_BYTES)
1552     {
1553       int max_num_entities = conf[i].max_num_entities;
1554
1555       if (data_type == TYPE_STRING)
1556       {
1557         char *string      = (char *)(conf[i].value);
1558         char *string_copy = (char *)(conf[i].value_copy);
1559
1560         strncpy(string_copy, string, max_num_entities);
1561       }
1562       else if (data_type == TYPE_ELEMENT_LIST)
1563       {
1564         int *element_array      = (int *)(conf[i].value);
1565         int *element_array_copy = (int *)(conf[i].value_copy);
1566         int j;
1567
1568         for (j = 0; j < max_num_entities; j++)
1569           element_array_copy[j] = element_array[j];
1570       }
1571       else if (data_type == TYPE_CONTENT_LIST)
1572       {
1573         struct Content *content      = (struct Content *)(conf[i].value);
1574         struct Content *content_copy = (struct Content *)(conf[i].value_copy);
1575         int c, x, y;
1576
1577         for (c = 0; c < max_num_entities; c++)
1578           for (y = 0; y < 3; y++)
1579             for (x = 0; x < 3; x++)
1580               content_copy[c].e[x][y] = content[c].e[x][y];
1581       }
1582     }
1583     else        /* constant size configuration data (1, 2 or 4 bytes) */
1584     {
1585       if (data_type == TYPE_BOOLEAN)
1586         *(boolean *)(conf[i].value_copy) = *(boolean *)(conf[i].value);
1587       else
1588         *(int *)    (conf[i].value_copy) = *(int *)    (conf[i].value);
1589     }
1590   }
1591 }
1592
1593 void copyElementInfo(struct ElementInfo *ei_from, struct ElementInfo *ei_to)
1594 {
1595   int i;
1596
1597   xx_ei = *ei_from;     /* copy element data into temporary buffer */
1598   yy_ei = *ei_to;       /* copy element data into temporary buffer */
1599
1600   copyConfigFromConfigList(chunk_config_CUSX_base);
1601
1602   *ei_from = xx_ei;
1603   *ei_to   = yy_ei;
1604
1605   /* ---------- reinitialize and copy change pages ---------- */
1606
1607   ei_to->num_change_pages = ei_from->num_change_pages;
1608   ei_to->current_change_page = ei_from->current_change_page;
1609
1610   setElementChangePages(ei_to, ei_to->num_change_pages);
1611
1612   for (i = 0; i < ei_to->num_change_pages; i++)
1613     ei_to->change_page[i] = ei_from->change_page[i];
1614
1615   /* ---------- copy group element info ---------- */
1616   if (ei_from->group != NULL && ei_to->group != NULL)   /* group or internal */
1617     *ei_to->group = *ei_from->group;
1618
1619   /* mark this custom element as modified */
1620   ei_to->modified_settings = TRUE;
1621 }
1622
1623 void setElementChangePages(struct ElementInfo *ei, int change_pages)
1624 {
1625   int change_page_size = sizeof(struct ElementChangeInfo);
1626
1627   ei->num_change_pages = MAX(1, change_pages);
1628
1629   ei->change_page =
1630     checked_realloc(ei->change_page, ei->num_change_pages * change_page_size);
1631
1632   if (ei->current_change_page >= ei->num_change_pages)
1633     ei->current_change_page = ei->num_change_pages - 1;
1634
1635   ei->change = &ei->change_page[ei->current_change_page];
1636 }
1637
1638 void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
1639 {
1640   xx_change = *change;          /* copy change data into temporary buffer */
1641
1642   setConfigToDefaultsFromConfigList(chunk_config_CUSX_change);
1643
1644   *change = xx_change;
1645
1646   resetEventFlags(change);
1647
1648   change->direct_action = 0;
1649   change->other_action = 0;
1650
1651   change->pre_change_function = NULL;
1652   change->change_function = NULL;
1653   change->post_change_function = NULL;
1654 }
1655
1656 static void setLevelInfoToDefaults_Level(struct LevelInfo *level)
1657 {
1658   int i, x, y;
1659
1660   li = *level;          /* copy level data into temporary buffer */
1661   setConfigToDefaultsFromConfigList(chunk_config_INFO);
1662   *level = li;          /* copy temporary buffer back to level data */
1663
1664   setLevelInfoToDefaults_EM();
1665   setLevelInfoToDefaults_SP();
1666   setLevelInfoToDefaults_MM();
1667
1668   level->native_em_level = &native_em_level;
1669   level->native_sp_level = &native_sp_level;
1670   level->native_mm_level = &native_mm_level;
1671
1672   level->file_version = FILE_VERSION_ACTUAL;
1673   level->game_version = GAME_VERSION_ACTUAL;
1674
1675   level->creation_date = getCurrentDate();
1676
1677   level->encoding_16bit_field  = TRUE;
1678   level->encoding_16bit_yamyam = TRUE;
1679   level->encoding_16bit_amoeba = TRUE;
1680
1681   /* clear level name and level author string buffers */
1682   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
1683     level->name[i] = '\0';
1684   for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
1685     level->author[i] = '\0';
1686
1687   /* set level name and level author to default values */
1688   strcpy(level->name, NAMELESS_LEVEL_NAME);
1689   strcpy(level->author, ANONYMOUS_NAME);
1690
1691   /* set level playfield to playable default level with player and exit */
1692   for (x = 0; x < MAX_LEV_FIELDX; x++)
1693     for (y = 0; y < MAX_LEV_FIELDY; y++)
1694       level->field[x][y] = EL_SAND;
1695
1696   level->field[0][0] = EL_PLAYER_1;
1697   level->field[STD_LEV_FIELDX - 1][STD_LEV_FIELDY - 1] = EL_EXIT_CLOSED;
1698
1699   BorderElement = EL_STEELWALL;
1700
1701   /* detect custom elements when loading them */
1702   level->file_has_custom_elements = FALSE;
1703
1704   /* set all bug compatibility flags to "false" => do not emulate this bug */
1705   level->use_action_after_change_bug = FALSE;
1706
1707   if (leveldir_current)
1708   {
1709     /* try to determine better author name than 'anonymous' */
1710     if (!strEqual(leveldir_current->author, ANONYMOUS_NAME))
1711     {
1712       strncpy(level->author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN);
1713       level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
1714     }
1715     else
1716     {
1717       switch (LEVELCLASS(leveldir_current))
1718       {
1719         case LEVELCLASS_TUTORIAL:
1720           strcpy(level->author, PROGRAM_AUTHOR_STRING);
1721           break;
1722
1723         case LEVELCLASS_CONTRIB:
1724           strncpy(level->author, leveldir_current->name, MAX_LEVEL_AUTHOR_LEN);
1725           level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
1726           break;
1727
1728         case LEVELCLASS_PRIVATE:
1729           strncpy(level->author, getRealName(), MAX_LEVEL_AUTHOR_LEN);
1730           level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
1731           break;
1732
1733         default:
1734           /* keep default value */
1735           break;
1736       }
1737     }
1738   }
1739 }
1740
1741 static void setLevelInfoToDefaults_Elements(struct LevelInfo *level)
1742 {
1743   static boolean clipboard_elements_initialized = FALSE;
1744   int i;
1745
1746   InitElementPropertiesStatic();
1747
1748   li = *level;          /* copy level data into temporary buffer */
1749   setConfigToDefaultsFromConfigList(chunk_config_ELEM);
1750   *level = li;          /* copy temporary buffer back to level data */
1751
1752   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1753   {
1754     int element = i;
1755     struct ElementInfo *ei = &element_info[element];
1756
1757     /* never initialize clipboard elements after the very first time */
1758     /* (to be able to use clipboard elements between several levels) */
1759     if (IS_CLIPBOARD_ELEMENT(element) && clipboard_elements_initialized)
1760       continue;
1761
1762     if (IS_ENVELOPE(element))
1763     {
1764       int envelope_nr = element - EL_ENVELOPE_1;
1765
1766       setConfigToDefaultsFromConfigList(chunk_config_NOTE);
1767
1768       level->envelope[envelope_nr] = xx_envelope;
1769     }
1770
1771     if (IS_CUSTOM_ELEMENT(element) ||
1772         IS_GROUP_ELEMENT(element) ||
1773         IS_INTERNAL_ELEMENT(element))
1774     {
1775       xx_ei = *ei;      /* copy element data into temporary buffer */
1776
1777       setConfigToDefaultsFromConfigList(chunk_config_CUSX_base);
1778
1779       *ei = xx_ei;
1780     }
1781
1782     setElementChangePages(ei, 1);
1783     setElementChangeInfoToDefaults(ei->change);
1784
1785     if (IS_CUSTOM_ELEMENT(element) ||
1786         IS_GROUP_ELEMENT(element) ||
1787         IS_INTERNAL_ELEMENT(element))
1788     {
1789       setElementDescriptionToDefault(ei);
1790
1791       ei->modified_settings = FALSE;
1792     }
1793
1794     if (IS_CUSTOM_ELEMENT(element) ||
1795         IS_INTERNAL_ELEMENT(element))
1796     {
1797       /* internal values used in level editor */
1798
1799       ei->access_type = 0;
1800       ei->access_layer = 0;
1801       ei->access_protected = 0;
1802       ei->walk_to_action = 0;
1803       ei->smash_targets = 0;
1804       ei->deadliness = 0;
1805
1806       ei->can_explode_by_fire = FALSE;
1807       ei->can_explode_smashed = FALSE;
1808       ei->can_explode_impact = FALSE;
1809
1810       ei->current_change_page = 0;
1811     }
1812
1813     if (IS_GROUP_ELEMENT(element) ||
1814         IS_INTERNAL_ELEMENT(element))
1815     {
1816       struct ElementGroupInfo *group;
1817
1818       /* initialize memory for list of elements in group */
1819       if (ei->group == NULL)
1820         ei->group = checked_malloc(sizeof(struct ElementGroupInfo));
1821
1822       group = ei->group;
1823
1824       xx_group = *group;        /* copy group data into temporary buffer */
1825
1826       setConfigToDefaultsFromConfigList(chunk_config_GRPX);
1827
1828       *group = xx_group;
1829     }
1830   }
1831
1832   clipboard_elements_initialized = TRUE;
1833 }
1834
1835 static void setLevelInfoToDefaults(struct LevelInfo *level,
1836                                    boolean level_info_only,
1837                                    boolean reset_file_status)
1838 {
1839   setLevelInfoToDefaults_Level(level);
1840
1841   if (!level_info_only)
1842     setLevelInfoToDefaults_Elements(level);
1843
1844   if (reset_file_status)
1845   {
1846     level->no_valid_file = FALSE;
1847     level->no_level_file = FALSE;
1848   }
1849
1850   level->changed = FALSE;
1851 }
1852
1853 static void setFileInfoToDefaults(struct LevelFileInfo *level_file_info)
1854 {
1855   level_file_info->nr = 0;
1856   level_file_info->type = LEVEL_FILE_TYPE_UNKNOWN;
1857   level_file_info->packed = FALSE;
1858
1859   setString(&level_file_info->basename, NULL);
1860   setString(&level_file_info->filename, NULL);
1861 }
1862
1863 int getMappedElement_SB(int, boolean);
1864
1865 static void ActivateLevelTemplate()
1866 {
1867   int x, y;
1868
1869   if (check_special_flags("load_xsb_to_ces"))
1870   {
1871     /* fill smaller playfields with padding "beyond border wall" elements */
1872     if (level.fieldx < level_template.fieldx ||
1873         level.fieldy < level_template.fieldy)
1874     {
1875       short field[level.fieldx][level.fieldy];
1876       int new_fieldx = MAX(level.fieldx, level_template.fieldx);
1877       int new_fieldy = MAX(level.fieldy, level_template.fieldy);
1878       int pos_fieldx = (new_fieldx - level.fieldx) / 2;
1879       int pos_fieldy = (new_fieldy - level.fieldy) / 2;
1880
1881       /* copy old playfield (which is smaller than the visible area) */
1882       for (y = 0; y < level.fieldy; y++) for (x = 0; x < level.fieldx; x++)
1883         field[x][y] = level.field[x][y];
1884
1885       /* fill new, larger playfield with "beyond border wall" elements */
1886       for (y = 0; y < new_fieldy; y++) for (x = 0; x < new_fieldx; x++)
1887         level.field[x][y] = getMappedElement_SB('_', TRUE);
1888
1889       /* copy the old playfield to the middle of the new playfield */
1890       for (y = 0; y < level.fieldy; y++) for (x = 0; x < level.fieldx; x++)
1891         level.field[pos_fieldx + x][pos_fieldy + y] = field[x][y];
1892
1893       level.fieldx = new_fieldx;
1894       level.fieldy = new_fieldy;
1895     }
1896   }
1897
1898   /* Currently there is no special action needed to activate the template
1899      data, because 'element_info' property settings overwrite the original
1900      level data, while all other variables do not change. */
1901
1902   /* Exception: 'from_level_template' elements in the original level playfield
1903      are overwritten with the corresponding elements at the same position in
1904      playfield from the level template. */
1905
1906   for (x = 0; x < level.fieldx; x++)
1907     for (y = 0; y < level.fieldy; y++)
1908       if (level.field[x][y] == EL_FROM_LEVEL_TEMPLATE)
1909         level.field[x][y] = level_template.field[x][y];
1910
1911   if (check_special_flags("load_xsb_to_ces"))
1912   {
1913     struct LevelInfo level_backup = level;
1914
1915     /* overwrite all individual level settings from template level settings */
1916     level = level_template;
1917
1918     /* restore playfield size */
1919     level.fieldx = level_backup.fieldx;
1920     level.fieldy = level_backup.fieldy;
1921
1922     /* restore playfield content */
1923     for (x = 0; x < level.fieldx; x++)
1924       for (y = 0; y < level.fieldy; y++)
1925         level.field[x][y] = level_backup.field[x][y];
1926
1927     /* restore name and author from individual level */
1928     strcpy(level.name,   level_backup.name);
1929     strcpy(level.author, level_backup.author);
1930
1931     /* restore flag "use_custom_template" */
1932     level.use_custom_template = level_backup.use_custom_template;
1933   }
1934 }
1935
1936 static char *getLevelFilenameFromBasename(char *basename)
1937 {
1938   static char *filename[2] = { NULL, NULL };
1939   int pos = (strEqual(basename, LEVELTEMPLATE_FILENAME) ? 0 : 1);
1940
1941   checked_free(filename[pos]);
1942
1943   filename[pos] = getPath2(getCurrentLevelDir(), basename);
1944
1945   return filename[pos];
1946 }
1947
1948 static int getFileTypeFromBasename(char *basename)
1949 {
1950   /* !!! ALSO SEE COMMENT IN checkForPackageFromBasename() !!! */
1951
1952   static char *filename = NULL;
1953   struct stat file_status;
1954
1955   /* ---------- try to determine file type from filename ---------- */
1956
1957   /* check for typical filename of a Supaplex level package file */
1958   if (strlen(basename) == 10 && strPrefixLower(basename, "levels.d"))
1959     return LEVEL_FILE_TYPE_SP;
1960
1961   /* check for typical filename of a Diamond Caves II level package file */
1962   if (strSuffixLower(basename, ".dc") ||
1963       strSuffixLower(basename, ".dc2"))
1964     return LEVEL_FILE_TYPE_DC;
1965
1966   /* check for typical filename of a Sokoban level package file */
1967   if (strSuffixLower(basename, ".xsb") &&
1968       strchr(basename, '%') == NULL)
1969     return LEVEL_FILE_TYPE_SB;
1970
1971   /* ---------- try to determine file type from filesize ---------- */
1972
1973   checked_free(filename);
1974   filename = getPath2(getCurrentLevelDir(), basename);
1975
1976   if (stat(filename, &file_status) == 0)
1977   {
1978     /* check for typical filesize of a Supaplex level package file */
1979     if (file_status.st_size == 170496)
1980       return LEVEL_FILE_TYPE_SP;
1981   }
1982
1983   return LEVEL_FILE_TYPE_UNKNOWN;
1984 }
1985
1986 static int getFileTypeFromMagicBytes(char *filename, int type)
1987 {
1988   File *file;
1989
1990   if ((file = openFile(filename, MODE_READ)))
1991   {
1992     char chunk_name[CHUNK_ID_LEN + 1];
1993
1994     getFileChunkBE(file, chunk_name, NULL);
1995
1996     if (strEqual(chunk_name, "MMII") ||
1997         strEqual(chunk_name, "MIRR"))
1998       type = LEVEL_FILE_TYPE_MM;
1999
2000     closeFile(file);
2001   }
2002
2003   return type;
2004 }
2005
2006 static boolean checkForPackageFromBasename(char *basename)
2007 {
2008   /* !!! WON'T WORK ANYMORE IF getFileTypeFromBasename() ALSO DETECTS !!!
2009      !!! SINGLE LEVELS (CURRENTLY ONLY DETECTS LEVEL PACKAGES         !!! */
2010
2011   return (getFileTypeFromBasename(basename) != LEVEL_FILE_TYPE_UNKNOWN);
2012 }
2013
2014 static char *getSingleLevelBasenameExt(int nr, char *extension)
2015 {
2016   static char basename[MAX_FILENAME_LEN];
2017
2018   if (nr < 0)
2019     sprintf(basename, "%s", LEVELTEMPLATE_FILENAME);
2020   else
2021     sprintf(basename, "%03d.%s", nr, extension);
2022
2023   return basename;
2024 }
2025
2026 static char *getSingleLevelBasename(int nr)
2027 {
2028   return getSingleLevelBasenameExt(nr, LEVELFILE_EXTENSION);
2029 }
2030
2031 static char *getPackedLevelBasename(int type)
2032 {
2033   static char basename[MAX_FILENAME_LEN];
2034   char *directory = getCurrentLevelDir();
2035   Directory *dir;
2036   DirectoryEntry *dir_entry;
2037
2038   strcpy(basename, UNDEFINED_FILENAME);         /* default: undefined file */
2039
2040   if ((dir = openDirectory(directory)) == NULL)
2041   {
2042     Error(ERR_WARN, "cannot read current level directory '%s'", directory);
2043
2044     return basename;
2045   }
2046
2047   while ((dir_entry = readDirectory(dir)) != NULL)      /* loop all entries */
2048   {
2049     char *entry_basename = dir_entry->basename;
2050     int entry_type = getFileTypeFromBasename(entry_basename);
2051
2052     if (entry_type != LEVEL_FILE_TYPE_UNKNOWN)  /* found valid level package */
2053     {
2054       if (type == LEVEL_FILE_TYPE_UNKNOWN ||
2055           type == entry_type)
2056       {
2057         strcpy(basename, entry_basename);
2058
2059         break;
2060       }
2061     }
2062   }
2063
2064   closeDirectory(dir);
2065
2066   return basename;
2067 }
2068
2069 static char *getSingleLevelFilename(int nr)
2070 {
2071   return getLevelFilenameFromBasename(getSingleLevelBasename(nr));
2072 }
2073
2074 #if ENABLE_UNUSED_CODE
2075 static char *getPackedLevelFilename(int type)
2076 {
2077   return getLevelFilenameFromBasename(getPackedLevelBasename(type));
2078 }
2079 #endif
2080
2081 char *getDefaultLevelFilename(int nr)
2082 {
2083   return getSingleLevelFilename(nr);
2084 }
2085
2086 #if ENABLE_UNUSED_CODE
2087 static void setLevelFileInfo_SingleLevelFilename(struct LevelFileInfo *lfi,
2088                                                  int type)
2089 {
2090   lfi->type = type;
2091   lfi->packed = FALSE;
2092
2093   setString(&lfi->basename, getSingleLevelBasename(lfi->nr, lfi->type));
2094   setString(&lfi->filename, getLevelFilenameFromBasename(lfi->basename));
2095 }
2096 #endif
2097
2098 static void setLevelFileInfo_FormatLevelFilename(struct LevelFileInfo *lfi,
2099                                                  int type, char *format, ...)
2100 {
2101   static char basename[MAX_FILENAME_LEN];
2102   va_list ap;
2103
2104   va_start(ap, format);
2105   vsprintf(basename, format, ap);
2106   va_end(ap);
2107
2108   lfi->type = type;
2109   lfi->packed = FALSE;
2110
2111   setString(&lfi->basename, basename);
2112   setString(&lfi->filename, getLevelFilenameFromBasename(lfi->basename));
2113 }
2114
2115 static void setLevelFileInfo_PackedLevelFilename(struct LevelFileInfo *lfi,
2116                                                  int type)
2117 {
2118   lfi->type = type;
2119   lfi->packed = TRUE;
2120
2121   setString(&lfi->basename, getPackedLevelBasename(lfi->type));
2122   setString(&lfi->filename, getLevelFilenameFromBasename(lfi->basename));
2123 }
2124
2125 static int getFiletypeFromID(char *filetype_id)
2126 {
2127   char *filetype_id_lower;
2128   int filetype = LEVEL_FILE_TYPE_UNKNOWN;
2129   int i;
2130
2131   if (filetype_id == NULL)
2132     return LEVEL_FILE_TYPE_UNKNOWN;
2133
2134   filetype_id_lower = getStringToLower(filetype_id);
2135
2136   for (i = 0; filetype_id_list[i].id != NULL; i++)
2137   {
2138     char *id_lower = getStringToLower(filetype_id_list[i].id);
2139     
2140     if (strEqual(filetype_id_lower, id_lower))
2141       filetype = filetype_id_list[i].filetype;
2142
2143     free(id_lower);
2144
2145     if (filetype != LEVEL_FILE_TYPE_UNKNOWN)
2146       break;
2147   }
2148
2149   free(filetype_id_lower);
2150
2151   return filetype;
2152 }
2153
2154 char *getLocalLevelTemplateFilename()
2155 {
2156   return getDefaultLevelFilename(-1);
2157 }
2158
2159 char *getGlobalLevelTemplateFilename()
2160 {
2161   /* global variable "leveldir_current" must be modified in the loop below */
2162   LevelDirTree *leveldir_current_last = leveldir_current;
2163   char *filename = NULL;
2164
2165   /* check for template level in path from current to topmost tree node */
2166
2167   while (leveldir_current != NULL)
2168   {
2169     filename = getDefaultLevelFilename(-1);
2170
2171     if (fileExists(filename))
2172       break;
2173
2174     leveldir_current = leveldir_current->node_parent;
2175   }
2176
2177   /* restore global variable "leveldir_current" modified in above loop */
2178   leveldir_current = leveldir_current_last;
2179
2180   return filename;
2181 }
2182
2183 static void determineLevelFileInfo_Filename(struct LevelFileInfo *lfi)
2184 {
2185   int nr = lfi->nr;
2186
2187   /* special case: level number is negative => check for level template file */
2188   if (nr < 0)
2189   {
2190     setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
2191                                          getSingleLevelBasename(-1));
2192
2193     /* replace local level template filename with global template filename */
2194     setString(&lfi->filename, getGlobalLevelTemplateFilename());
2195
2196     /* no fallback if template file not existing */
2197     return;
2198   }
2199
2200   /* special case: check for file name/pattern specified in "levelinfo.conf" */
2201   if (leveldir_current->level_filename != NULL)
2202   {
2203     int filetype = getFiletypeFromID(leveldir_current->level_filetype);
2204
2205     setLevelFileInfo_FormatLevelFilename(lfi, filetype,
2206                                          leveldir_current->level_filename, nr);
2207
2208     lfi->packed = checkForPackageFromBasename(leveldir_current->level_filename);
2209
2210     if (fileExists(lfi->filename))
2211       return;
2212   }
2213   else if (leveldir_current->level_filetype != NULL)
2214   {
2215     int filetype = getFiletypeFromID(leveldir_current->level_filetype);
2216
2217     /* check for specified native level file with standard file name */
2218     setLevelFileInfo_FormatLevelFilename(lfi, filetype,
2219                                          "%03d.%s", nr, LEVELFILE_EXTENSION);
2220     if (fileExists(lfi->filename))
2221       return;
2222   }
2223
2224   /* check for native Rocks'n'Diamonds level file */
2225   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
2226                                        "%03d.%s", nr, LEVELFILE_EXTENSION);
2227   if (fileExists(lfi->filename))
2228     return;
2229
2230   /* check for Emerald Mine level file (V1) */
2231   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "a%c%c",
2232                                        'a' + (nr / 10) % 26, '0' + nr % 10);
2233   if (fileExists(lfi->filename))
2234     return;
2235   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "A%c%c",
2236                                        'A' + (nr / 10) % 26, '0' + nr % 10);
2237   if (fileExists(lfi->filename))
2238     return;
2239
2240   /* check for Emerald Mine level file (V2 to V5) */
2241   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%d", nr);
2242   if (fileExists(lfi->filename))
2243     return;
2244
2245   /* check for Emerald Mine level file (V6 / single mode) */
2246   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02ds", nr);
2247   if (fileExists(lfi->filename))
2248     return;
2249   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dS", nr);
2250   if (fileExists(lfi->filename))
2251     return;
2252
2253   /* check for Emerald Mine level file (V6 / teamwork mode) */
2254   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dt", nr);
2255   if (fileExists(lfi->filename))
2256     return;
2257   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dT", nr);
2258   if (fileExists(lfi->filename))
2259     return;
2260
2261   /* check for various packed level file formats */
2262   setLevelFileInfo_PackedLevelFilename(lfi, LEVEL_FILE_TYPE_UNKNOWN);
2263   if (fileExists(lfi->filename))
2264     return;
2265
2266   /* no known level file found -- use default values (and fail later) */
2267   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
2268                                        "%03d.%s", nr, LEVELFILE_EXTENSION);
2269 }
2270
2271 static void determineLevelFileInfo_Filetype(struct LevelFileInfo *lfi)
2272 {
2273   if (lfi->type == LEVEL_FILE_TYPE_UNKNOWN)
2274     lfi->type = getFileTypeFromBasename(lfi->basename);
2275
2276   if (lfi->type == LEVEL_FILE_TYPE_RND)
2277     lfi->type = getFileTypeFromMagicBytes(lfi->filename, lfi->type);
2278 }
2279
2280 static void setLevelFileInfo(struct LevelFileInfo *level_file_info, int nr)
2281 {
2282   /* always start with reliable default values */
2283   setFileInfoToDefaults(level_file_info);
2284
2285   level_file_info->nr = nr;     /* set requested level number */
2286
2287   determineLevelFileInfo_Filename(level_file_info);
2288   determineLevelFileInfo_Filetype(level_file_info);
2289 }
2290
2291 /* ------------------------------------------------------------------------- */
2292 /* functions for loading R'n'D level                                         */
2293 /* ------------------------------------------------------------------------- */
2294
2295 int getMappedElement(int element)
2296 {
2297   /* remap some (historic, now obsolete) elements */
2298
2299   switch (element)
2300   {
2301     case EL_PLAYER_OBSOLETE:
2302       element = EL_PLAYER_1;
2303       break;
2304
2305     case EL_KEY_OBSOLETE:
2306       element = EL_KEY_1;
2307       break;
2308
2309     case EL_EM_KEY_1_FILE_OBSOLETE:
2310       element = EL_EM_KEY_1;
2311       break;
2312
2313     case EL_EM_KEY_2_FILE_OBSOLETE:
2314       element = EL_EM_KEY_2;
2315       break;
2316
2317     case EL_EM_KEY_3_FILE_OBSOLETE:
2318       element = EL_EM_KEY_3;
2319       break;
2320
2321     case EL_EM_KEY_4_FILE_OBSOLETE:
2322       element = EL_EM_KEY_4;
2323       break;
2324
2325     case EL_ENVELOPE_OBSOLETE:
2326       element = EL_ENVELOPE_1;
2327       break;
2328
2329     case EL_SP_EMPTY:
2330       element = EL_EMPTY;
2331       break;
2332
2333     default:
2334       if (element >= NUM_FILE_ELEMENTS)
2335       {
2336         Error(ERR_WARN, "invalid level element %d", element);
2337
2338         element = EL_UNKNOWN;
2339       }
2340       break;
2341   }
2342
2343   return element;
2344 }
2345
2346 int getMappedElementByVersion(int element, int game_version)
2347 {
2348   /* remap some elements due to certain game version */
2349
2350   if (game_version <= VERSION_IDENT(2,2,0,0))
2351   {
2352     /* map game font elements */
2353     element = (element == EL_CHAR('[')  ? EL_CHAR_AUMLAUT :
2354                element == EL_CHAR('\\') ? EL_CHAR_OUMLAUT :
2355                element == EL_CHAR(']')  ? EL_CHAR_UUMLAUT :
2356                element == EL_CHAR('^')  ? EL_CHAR_COPYRIGHT : element);
2357   }
2358
2359   if (game_version < VERSION_IDENT(3,0,0,0))
2360   {
2361     /* map Supaplex gravity tube elements */
2362     element = (element == EL_SP_GRAVITY_PORT_LEFT  ? EL_SP_PORT_LEFT  :
2363                element == EL_SP_GRAVITY_PORT_RIGHT ? EL_SP_PORT_RIGHT :
2364                element == EL_SP_GRAVITY_PORT_UP    ? EL_SP_PORT_UP    :
2365                element == EL_SP_GRAVITY_PORT_DOWN  ? EL_SP_PORT_DOWN  :
2366                element);
2367   }
2368
2369   return element;
2370 }
2371
2372 static int LoadLevel_VERS(File *file, int chunk_size, struct LevelInfo *level)
2373 {
2374   level->file_version = getFileVersion(file);
2375   level->game_version = getFileVersion(file);
2376
2377   return chunk_size;
2378 }
2379
2380 static int LoadLevel_DATE(File *file, int chunk_size, struct LevelInfo *level)
2381 {
2382   level->creation_date.year  = getFile16BitBE(file);
2383   level->creation_date.month = getFile8Bit(file);
2384   level->creation_date.day   = getFile8Bit(file);
2385
2386   level->creation_date.src   = DATE_SRC_LEVELFILE;
2387
2388   return chunk_size;
2389 }
2390
2391 static int LoadLevel_HEAD(File *file, int chunk_size, struct LevelInfo *level)
2392 {
2393   int initial_player_stepsize;
2394   int initial_player_gravity;
2395   int i, x, y;
2396
2397   level->fieldx = getFile8Bit(file);
2398   level->fieldy = getFile8Bit(file);
2399
2400   level->time           = getFile16BitBE(file);
2401   level->gems_needed    = getFile16BitBE(file);
2402
2403   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
2404     level->name[i] = getFile8Bit(file);
2405   level->name[MAX_LEVEL_NAME_LEN] = 0;
2406
2407   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
2408     level->score[i] = getFile8Bit(file);
2409
2410   level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
2411   for (i = 0; i < STD_ELEMENT_CONTENTS; i++)
2412     for (y = 0; y < 3; y++)
2413       for (x = 0; x < 3; x++)
2414         level->yamyam_content[i].e[x][y] = getMappedElement(getFile8Bit(file));
2415
2416   level->amoeba_speed           = getFile8Bit(file);
2417   level->time_magic_wall        = getFile8Bit(file);
2418   level->time_wheel             = getFile8Bit(file);
2419   level->amoeba_content         = getMappedElement(getFile8Bit(file));
2420
2421   initial_player_stepsize       = (getFile8Bit(file) == 1 ? STEPSIZE_FAST :
2422                                    STEPSIZE_NORMAL);
2423
2424   for (i = 0; i < MAX_PLAYERS; i++)
2425     level->initial_player_stepsize[i] = initial_player_stepsize;
2426
2427   initial_player_gravity        = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2428
2429   for (i = 0; i < MAX_PLAYERS; i++)
2430     level->initial_player_gravity[i] = initial_player_gravity;
2431
2432   level->encoding_16bit_field   = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2433   level->em_slippery_gems       = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2434
2435   level->use_custom_template    = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2436
2437   level->block_last_field       = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2438   level->sp_block_last_field    = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2439   level->can_move_into_acid_bits = getFile32BitBE(file);
2440   level->dont_collide_with_bits = getFile8Bit(file);
2441
2442   level->use_spring_bug         = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2443   level->use_step_counter       = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2444
2445   level->instant_relocation     = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2446   level->can_pass_to_walkable   = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2447   level->grow_into_diggable     = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2448
2449   level->game_engine_type       = getFile8Bit(file);
2450
2451   ReadUnusedBytesFromFile(file, LEVEL_CHUNK_HEAD_UNUSED);
2452
2453   return chunk_size;
2454 }
2455
2456 static int LoadLevel_NAME(File *file, int chunk_size, struct LevelInfo *level)
2457 {
2458   int i;
2459
2460   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
2461     level->name[i] = getFile8Bit(file);
2462   level->name[MAX_LEVEL_NAME_LEN] = 0;
2463
2464   return chunk_size;
2465 }
2466
2467 static int LoadLevel_AUTH(File *file, int chunk_size, struct LevelInfo *level)
2468 {
2469   int i;
2470
2471   for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
2472     level->author[i] = getFile8Bit(file);
2473   level->author[MAX_LEVEL_AUTHOR_LEN] = 0;
2474
2475   return chunk_size;
2476 }
2477
2478 static int LoadLevel_BODY(File *file, int chunk_size, struct LevelInfo *level)
2479 {
2480   int x, y;
2481   int chunk_size_expected = level->fieldx * level->fieldy;
2482
2483   /* Note: "chunk_size" was wrong before version 2.0 when elements are
2484      stored with 16-bit encoding (and should be twice as big then).
2485      Even worse, playfield data was stored 16-bit when only yamyam content
2486      contained 16-bit elements and vice versa. */
2487
2488   if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
2489     chunk_size_expected *= 2;
2490
2491   if (chunk_size_expected != chunk_size)
2492   {
2493     ReadUnusedBytesFromFile(file, chunk_size);
2494     return chunk_size_expected;
2495   }
2496
2497   for (y = 0; y < level->fieldy; y++)
2498     for (x = 0; x < level->fieldx; x++)
2499       level->field[x][y] =
2500         getMappedElement(level->encoding_16bit_field ? getFile16BitBE(file) :
2501                          getFile8Bit(file));
2502   return chunk_size;
2503 }
2504
2505 static int LoadLevel_CONT(File *file, int chunk_size, struct LevelInfo *level)
2506 {
2507   int i, x, y;
2508   int header_size = 4;
2509   int content_size = MAX_ELEMENT_CONTENTS * 3 * 3;
2510   int chunk_size_expected = header_size + content_size;
2511
2512   /* Note: "chunk_size" was wrong before version 2.0 when elements are
2513      stored with 16-bit encoding (and should be twice as big then).
2514      Even worse, playfield data was stored 16-bit when only yamyam content
2515      contained 16-bit elements and vice versa. */
2516
2517   if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
2518     chunk_size_expected += content_size;
2519
2520   if (chunk_size_expected != chunk_size)
2521   {
2522     ReadUnusedBytesFromFile(file, chunk_size);
2523     return chunk_size_expected;
2524   }
2525
2526   getFile8Bit(file);
2527   level->num_yamyam_contents = getFile8Bit(file);
2528   getFile8Bit(file);
2529   getFile8Bit(file);
2530
2531   /* correct invalid number of content fields -- should never happen */
2532   if (level->num_yamyam_contents < 1 ||
2533       level->num_yamyam_contents > MAX_ELEMENT_CONTENTS)
2534     level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
2535
2536   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
2537     for (y = 0; y < 3; y++)
2538       for (x = 0; x < 3; x++)
2539         level->yamyam_content[i].e[x][y] =
2540           getMappedElement(level->encoding_16bit_field ?
2541                            getFile16BitBE(file) : getFile8Bit(file));
2542   return chunk_size;
2543 }
2544
2545 static int LoadLevel_CNT2(File *file, int chunk_size, struct LevelInfo *level)
2546 {
2547   int i, x, y;
2548   int element;
2549   int num_contents;
2550   int content_array[MAX_ELEMENT_CONTENTS][3][3];
2551
2552   element = getMappedElement(getFile16BitBE(file));
2553   num_contents = getFile8Bit(file);
2554
2555   getFile8Bit(file);    /* content x size (unused) */
2556   getFile8Bit(file);    /* content y size (unused) */
2557
2558   ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED);
2559
2560   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
2561     for (y = 0; y < 3; y++)
2562       for (x = 0; x < 3; x++)
2563         content_array[i][x][y] = getMappedElement(getFile16BitBE(file));
2564
2565   /* correct invalid number of content fields -- should never happen */
2566   if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS)
2567     num_contents = STD_ELEMENT_CONTENTS;
2568
2569   if (element == EL_YAMYAM)
2570   {
2571     level->num_yamyam_contents = num_contents;
2572
2573     for (i = 0; i < num_contents; i++)
2574       for (y = 0; y < 3; y++)
2575         for (x = 0; x < 3; x++)
2576           level->yamyam_content[i].e[x][y] = content_array[i][x][y];
2577   }
2578   else if (element == EL_BD_AMOEBA)
2579   {
2580     level->amoeba_content = content_array[0][0][0];
2581   }
2582   else
2583   {
2584     Error(ERR_WARN, "cannot load content for element '%d'", element);
2585   }
2586
2587   return chunk_size;
2588 }
2589
2590 static int LoadLevel_CNT3(File *file, int chunk_size, struct LevelInfo *level)
2591 {
2592   int i;
2593   int element;
2594   int envelope_nr;
2595   int envelope_len;
2596   int chunk_size_expected;
2597
2598   element = getMappedElement(getFile16BitBE(file));
2599   if (!IS_ENVELOPE(element))
2600     element = EL_ENVELOPE_1;
2601
2602   envelope_nr = element - EL_ENVELOPE_1;
2603
2604   envelope_len = getFile16BitBE(file);
2605
2606   level->envelope[envelope_nr].xsize = getFile8Bit(file);
2607   level->envelope[envelope_nr].ysize = getFile8Bit(file);
2608
2609   ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT3_UNUSED);
2610
2611   chunk_size_expected = LEVEL_CHUNK_CNT3_SIZE(envelope_len);
2612   if (chunk_size_expected != chunk_size)
2613   {
2614     ReadUnusedBytesFromFile(file, chunk_size - LEVEL_CHUNK_CNT3_HEADER);
2615     return chunk_size_expected;
2616   }
2617
2618   for (i = 0; i < envelope_len; i++)
2619     level->envelope[envelope_nr].text[i] = getFile8Bit(file);
2620
2621   return chunk_size;
2622 }
2623
2624 static int LoadLevel_CUS1(File *file, int chunk_size, struct LevelInfo *level)
2625 {
2626   int num_changed_custom_elements = getFile16BitBE(file);
2627   int chunk_size_expected = 2 + num_changed_custom_elements * 6;
2628   int i;
2629
2630   if (chunk_size_expected != chunk_size)
2631   {
2632     ReadUnusedBytesFromFile(file, chunk_size - 2);
2633     return chunk_size_expected;
2634   }
2635
2636   for (i = 0; i < num_changed_custom_elements; i++)
2637   {
2638     int element = getMappedElement(getFile16BitBE(file));
2639     int properties = getFile32BitBE(file);
2640
2641     if (IS_CUSTOM_ELEMENT(element))
2642       element_info[element].properties[EP_BITFIELD_BASE_NR] = properties;
2643     else
2644       Error(ERR_WARN, "invalid custom element number %d", element);
2645
2646     /* older game versions that wrote level files with CUS1 chunks used
2647        different default push delay values (not yet stored in level file) */
2648     element_info[element].push_delay_fixed = 2;
2649     element_info[element].push_delay_random = 8;
2650   }
2651
2652   level->file_has_custom_elements = TRUE;
2653
2654   return chunk_size;
2655 }
2656
2657 static int LoadLevel_CUS2(File *file, int chunk_size, struct LevelInfo *level)
2658 {
2659   int num_changed_custom_elements = getFile16BitBE(file);
2660   int chunk_size_expected = 2 + num_changed_custom_elements * 4;
2661   int i;
2662
2663   if (chunk_size_expected != chunk_size)
2664   {
2665     ReadUnusedBytesFromFile(file, chunk_size - 2);
2666     return chunk_size_expected;
2667   }
2668
2669   for (i = 0; i < num_changed_custom_elements; i++)
2670   {
2671     int element = getMappedElement(getFile16BitBE(file));
2672     int custom_target_element = getMappedElement(getFile16BitBE(file));
2673
2674     if (IS_CUSTOM_ELEMENT(element))
2675       element_info[element].change->target_element = custom_target_element;
2676     else
2677       Error(ERR_WARN, "invalid custom element number %d", element);
2678   }
2679
2680   level->file_has_custom_elements = TRUE;
2681
2682   return chunk_size;
2683 }
2684
2685 static int LoadLevel_CUS3(File *file, int chunk_size, struct LevelInfo *level)
2686 {
2687   int num_changed_custom_elements = getFile16BitBE(file);
2688   int chunk_size_expected = LEVEL_CHUNK_CUS3_SIZE(num_changed_custom_elements);
2689   int i, j, x, y;
2690
2691   if (chunk_size_expected != chunk_size)
2692   {
2693     ReadUnusedBytesFromFile(file, chunk_size - 2);
2694     return chunk_size_expected;
2695   }
2696
2697   for (i = 0; i < num_changed_custom_elements; i++)
2698   {
2699     int element = getMappedElement(getFile16BitBE(file));
2700     struct ElementInfo *ei = &element_info[element];
2701     unsigned int event_bits;
2702
2703     if (!IS_CUSTOM_ELEMENT(element))
2704     {
2705       Error(ERR_WARN, "invalid custom element number %d", element);
2706
2707       element = EL_INTERNAL_DUMMY;
2708     }
2709
2710     for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++)
2711       ei->description[j] = getFile8Bit(file);
2712     ei->description[MAX_ELEMENT_NAME_LEN] = 0;
2713
2714     ei->properties[EP_BITFIELD_BASE_NR] = getFile32BitBE(file);
2715
2716     /* some free bytes for future properties and padding */
2717     ReadUnusedBytesFromFile(file, 7);
2718
2719     ei->use_gfx_element = getFile8Bit(file);
2720     ei->gfx_element_initial = getMappedElement(getFile16BitBE(file));
2721
2722     ei->collect_score_initial = getFile8Bit(file);
2723     ei->collect_count_initial = getFile8Bit(file);
2724
2725     ei->push_delay_fixed = getFile16BitBE(file);
2726     ei->push_delay_random = getFile16BitBE(file);
2727     ei->move_delay_fixed = getFile16BitBE(file);
2728     ei->move_delay_random = getFile16BitBE(file);
2729
2730     ei->move_pattern = getFile16BitBE(file);
2731     ei->move_direction_initial = getFile8Bit(file);
2732     ei->move_stepsize = getFile8Bit(file);
2733
2734     for (y = 0; y < 3; y++)
2735       for (x = 0; x < 3; x++)
2736         ei->content.e[x][y] = getMappedElement(getFile16BitBE(file));
2737
2738     event_bits = getFile32BitBE(file);
2739     for (j = 0; j < NUM_CHANGE_EVENTS; j++)
2740       if (event_bits & (1 << j))
2741         ei->change->has_event[j] = TRUE;
2742
2743     ei->change->target_element = getMappedElement(getFile16BitBE(file));
2744
2745     ei->change->delay_fixed = getFile16BitBE(file);
2746     ei->change->delay_random = getFile16BitBE(file);
2747     ei->change->delay_frames = getFile16BitBE(file);
2748
2749     ei->change->initial_trigger_element= getMappedElement(getFile16BitBE(file));
2750
2751     ei->change->explode = getFile8Bit(file);
2752     ei->change->use_target_content = getFile8Bit(file);
2753     ei->change->only_if_complete = getFile8Bit(file);
2754     ei->change->use_random_replace = getFile8Bit(file);
2755
2756     ei->change->random_percentage = getFile8Bit(file);
2757     ei->change->replace_when = getFile8Bit(file);
2758
2759     for (y = 0; y < 3; y++)
2760       for (x = 0; x < 3; x++)
2761         ei->change->target_content.e[x][y] =
2762           getMappedElement(getFile16BitBE(file));
2763
2764     ei->slippery_type = getFile8Bit(file);
2765
2766     /* some free bytes for future properties and padding */
2767     ReadUnusedBytesFromFile(file, LEVEL_CPART_CUS3_UNUSED);
2768
2769     /* mark that this custom element has been modified */
2770     ei->modified_settings = TRUE;
2771   }
2772
2773   level->file_has_custom_elements = TRUE;
2774
2775   return chunk_size;
2776 }
2777
2778 static int LoadLevel_CUS4(File *file, int chunk_size, struct LevelInfo *level)
2779 {
2780   struct ElementInfo *ei;
2781   int chunk_size_expected;
2782   int element;
2783   int i, j, x, y;
2784
2785   /* ---------- custom element base property values (96 bytes) ------------- */
2786
2787   element = getMappedElement(getFile16BitBE(file));
2788
2789   if (!IS_CUSTOM_ELEMENT(element))
2790   {
2791     Error(ERR_WARN, "invalid custom element number %d", element);
2792
2793     ReadUnusedBytesFromFile(file, chunk_size - 2);
2794     return chunk_size;
2795   }
2796
2797   ei = &element_info[element];
2798
2799   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
2800     ei->description[i] = getFile8Bit(file);
2801   ei->description[MAX_ELEMENT_NAME_LEN] = 0;
2802
2803   ei->properties[EP_BITFIELD_BASE_NR] = getFile32BitBE(file);
2804
2805   ReadUnusedBytesFromFile(file, 4);     /* reserved for more base properties */
2806
2807   ei->num_change_pages = getFile8Bit(file);
2808
2809   chunk_size_expected = LEVEL_CHUNK_CUS4_SIZE(ei->num_change_pages);
2810   if (chunk_size_expected != chunk_size)
2811   {
2812     ReadUnusedBytesFromFile(file, chunk_size - 43);
2813     return chunk_size_expected;
2814   }
2815
2816   ei->ce_value_fixed_initial = getFile16BitBE(file);
2817   ei->ce_value_random_initial = getFile16BitBE(file);
2818   ei->use_last_ce_value = getFile8Bit(file);
2819
2820   ei->use_gfx_element = getFile8Bit(file);
2821   ei->gfx_element_initial = getMappedElement(getFile16BitBE(file));
2822
2823   ei->collect_score_initial = getFile8Bit(file);
2824   ei->collect_count_initial = getFile8Bit(file);
2825
2826   ei->drop_delay_fixed = getFile8Bit(file);
2827   ei->push_delay_fixed = getFile8Bit(file);
2828   ei->drop_delay_random = getFile8Bit(file);
2829   ei->push_delay_random = getFile8Bit(file);
2830   ei->move_delay_fixed = getFile16BitBE(file);
2831   ei->move_delay_random = getFile16BitBE(file);
2832
2833   /* bits 0 - 15 of "move_pattern" ... */
2834   ei->move_pattern = getFile16BitBE(file);
2835   ei->move_direction_initial = getFile8Bit(file);
2836   ei->move_stepsize = getFile8Bit(file);
2837
2838   ei->slippery_type = getFile8Bit(file);
2839
2840   for (y = 0; y < 3; y++)
2841     for (x = 0; x < 3; x++)
2842       ei->content.e[x][y] = getMappedElement(getFile16BitBE(file));
2843
2844   ei->move_enter_element = getMappedElement(getFile16BitBE(file));
2845   ei->move_leave_element = getMappedElement(getFile16BitBE(file));
2846   ei->move_leave_type = getFile8Bit(file);
2847
2848   /* ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible) */
2849   ei->move_pattern |= (getFile16BitBE(file) << 16);
2850
2851   ei->access_direction = getFile8Bit(file);
2852
2853   ei->explosion_delay = getFile8Bit(file);
2854   ei->ignition_delay = getFile8Bit(file);
2855   ei->explosion_type = getFile8Bit(file);
2856
2857   /* some free bytes for future custom property values and padding */
2858   ReadUnusedBytesFromFile(file, 1);
2859
2860   /* ---------- change page property values (48 bytes) --------------------- */
2861
2862   setElementChangePages(ei, ei->num_change_pages);
2863
2864   for (i = 0; i < ei->num_change_pages; i++)
2865   {
2866     struct ElementChangeInfo *change = &ei->change_page[i];
2867     unsigned int event_bits;
2868
2869     /* always start with reliable default values */
2870     setElementChangeInfoToDefaults(change);
2871
2872     /* bits 0 - 31 of "has_event[]" ... */
2873     event_bits = getFile32BitBE(file);
2874     for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
2875       if (event_bits & (1 << j))
2876         change->has_event[j] = TRUE;
2877
2878     change->target_element = getMappedElement(getFile16BitBE(file));
2879
2880     change->delay_fixed = getFile16BitBE(file);
2881     change->delay_random = getFile16BitBE(file);
2882     change->delay_frames = getFile16BitBE(file);
2883
2884     change->initial_trigger_element = getMappedElement(getFile16BitBE(file));
2885
2886     change->explode = getFile8Bit(file);
2887     change->use_target_content = getFile8Bit(file);
2888     change->only_if_complete = getFile8Bit(file);
2889     change->use_random_replace = getFile8Bit(file);
2890
2891     change->random_percentage = getFile8Bit(file);
2892     change->replace_when = getFile8Bit(file);
2893
2894     for (y = 0; y < 3; y++)
2895       for (x = 0; x < 3; x++)
2896         change->target_content.e[x][y]= getMappedElement(getFile16BitBE(file));
2897
2898     change->can_change = getFile8Bit(file);
2899
2900     change->trigger_side = getFile8Bit(file);
2901
2902     change->trigger_player = getFile8Bit(file);
2903     change->trigger_page = getFile8Bit(file);
2904
2905     change->trigger_page = (change->trigger_page == CH_PAGE_ANY_FILE ?
2906                             CH_PAGE_ANY : (1 << change->trigger_page));
2907
2908     change->has_action = getFile8Bit(file);
2909     change->action_type = getFile8Bit(file);
2910     change->action_mode = getFile8Bit(file);
2911     change->action_arg = getFile16BitBE(file);
2912
2913     /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */
2914     event_bits = getFile8Bit(file);
2915     for (j = 32; j < NUM_CHANGE_EVENTS; j++)
2916       if (event_bits & (1 << (j - 32)))
2917         change->has_event[j] = TRUE;
2918   }
2919
2920   /* mark this custom element as modified */
2921   ei->modified_settings = TRUE;
2922
2923   level->file_has_custom_elements = TRUE;
2924
2925   return chunk_size;
2926 }
2927
2928 static int LoadLevel_GRP1(File *file, int chunk_size, struct LevelInfo *level)
2929 {
2930   struct ElementInfo *ei;
2931   struct ElementGroupInfo *group;
2932   int element;
2933   int i;
2934
2935   element = getMappedElement(getFile16BitBE(file));
2936
2937   if (!IS_GROUP_ELEMENT(element))
2938   {
2939     Error(ERR_WARN, "invalid group element number %d", element);
2940
2941     ReadUnusedBytesFromFile(file, chunk_size - 2);
2942     return chunk_size;
2943   }
2944
2945   ei = &element_info[element];
2946
2947   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
2948     ei->description[i] = getFile8Bit(file);
2949   ei->description[MAX_ELEMENT_NAME_LEN] = 0;
2950
2951   group = element_info[element].group;
2952
2953   group->num_elements = getFile8Bit(file);
2954
2955   ei->use_gfx_element = getFile8Bit(file);
2956   ei->gfx_element_initial = getMappedElement(getFile16BitBE(file));
2957
2958   group->choice_mode = getFile8Bit(file);
2959
2960   /* some free bytes for future values and padding */
2961   ReadUnusedBytesFromFile(file, 3);
2962
2963   for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
2964     group->element[i] = getMappedElement(getFile16BitBE(file));
2965
2966   /* mark this group element as modified */
2967   element_info[element].modified_settings = TRUE;
2968
2969   level->file_has_custom_elements = TRUE;
2970
2971   return chunk_size;
2972 }
2973
2974 static int LoadLevel_MicroChunk(File *file, struct LevelFileConfigInfo *conf,
2975                                 int element, int real_element)
2976 {
2977   int micro_chunk_size = 0;
2978   int conf_type = getFile8Bit(file);
2979   int byte_mask = conf_type & CONF_MASK_BYTES;
2980   boolean element_found = FALSE;
2981   int i;
2982
2983   micro_chunk_size += 1;
2984
2985   if (byte_mask == CONF_MASK_MULTI_BYTES)
2986   {
2987     int num_bytes = getFile16BitBE(file);
2988     byte *buffer = checked_malloc(num_bytes);
2989
2990     ReadBytesFromFile(file, buffer, num_bytes);
2991
2992     for (i = 0; conf[i].data_type != -1; i++)
2993     {
2994       if (conf[i].element == element &&
2995           conf[i].conf_type == conf_type)
2996       {
2997         int data_type = conf[i].data_type;
2998         int num_entities = num_bytes / CONF_ENTITY_NUM_BYTES(data_type);
2999         int max_num_entities = conf[i].max_num_entities;
3000
3001         if (num_entities > max_num_entities)
3002         {
3003           Error(ERR_WARN,
3004                 "truncating number of entities for element %d from %d to %d",
3005                 element, num_entities, max_num_entities);
3006
3007           num_entities = max_num_entities;
3008         }
3009
3010         if (num_entities == 0 && (data_type == TYPE_ELEMENT_LIST ||
3011                                   data_type == TYPE_CONTENT_LIST))
3012         {
3013           /* for element and content lists, zero entities are not allowed */
3014           Error(ERR_WARN, "found empty list of entities for element %d",
3015                 element);
3016
3017           /* do not set "num_entities" here to prevent reading behind buffer */
3018
3019           *(int *)(conf[i].num_entities) = 1;   /* at least one is required */
3020         }
3021         else
3022         {
3023           *(int *)(conf[i].num_entities) = num_entities;
3024         }
3025
3026         element_found = TRUE;
3027
3028         if (data_type == TYPE_STRING)
3029         {
3030           char *string = (char *)(conf[i].value);
3031           int j;
3032
3033           for (j = 0; j < max_num_entities; j++)
3034             string[j] = (j < num_entities ? buffer[j] : '\0');
3035         }
3036         else if (data_type == TYPE_ELEMENT_LIST)
3037         {
3038           int *element_array = (int *)(conf[i].value);
3039           int j;
3040
3041           for (j = 0; j < num_entities; j++)
3042             element_array[j] =
3043               getMappedElement(CONF_ELEMENTS_ELEMENT(buffer, j));
3044         }
3045         else if (data_type == TYPE_CONTENT_LIST)
3046         {
3047           struct Content *content= (struct Content *)(conf[i].value);
3048           int c, x, y;
3049
3050           for (c = 0; c < num_entities; c++)
3051             for (y = 0; y < 3; y++)
3052               for (x = 0; x < 3; x++)
3053                 content[c].e[x][y] =
3054                   getMappedElement(CONF_CONTENTS_ELEMENT(buffer, c, x, y));
3055         }
3056         else
3057           element_found = FALSE;
3058
3059         break;
3060       }
3061     }
3062
3063     checked_free(buffer);
3064
3065     micro_chunk_size += 2 + num_bytes;
3066   }
3067   else          /* constant size configuration data (1, 2 or 4 bytes) */
3068   {
3069     int value = (byte_mask == CONF_MASK_1_BYTE ? getFile8Bit   (file) :
3070                  byte_mask == CONF_MASK_2_BYTE ? getFile16BitBE(file) :
3071                  byte_mask == CONF_MASK_4_BYTE ? getFile32BitBE(file) : 0);
3072
3073     for (i = 0; conf[i].data_type != -1; i++)
3074     {
3075       if (conf[i].element == element &&
3076           conf[i].conf_type == conf_type)
3077       {
3078         int data_type = conf[i].data_type;
3079
3080         if (data_type == TYPE_ELEMENT)
3081           value = getMappedElement(value);
3082
3083         if (data_type == TYPE_BOOLEAN)
3084           *(boolean *)(conf[i].value) = value;
3085         else
3086           *(int *)    (conf[i].value) = value;
3087
3088         element_found = TRUE;
3089
3090         break;
3091       }
3092     }
3093
3094     micro_chunk_size += CONF_VALUE_NUM_BYTES(byte_mask);
3095   }
3096
3097   if (!element_found)
3098   {
3099     char *error_conf_chunk_bytes =
3100       (byte_mask == CONF_MASK_1_BYTE ? "CONF_VALUE_8_BIT" :
3101        byte_mask == CONF_MASK_2_BYTE ? "CONF_VALUE_16_BIT" :
3102        byte_mask == CONF_MASK_4_BYTE ? "CONF_VALUE_32_BIT" :"CONF_VALUE_BYTES");
3103     int error_conf_chunk_token = conf_type & CONF_MASK_TOKEN;
3104     int error_element = real_element;
3105
3106     Error(ERR_WARN, "cannot load micro chunk '%s(%d)' value for element %d ['%s']",
3107           error_conf_chunk_bytes, error_conf_chunk_token,
3108           error_element, EL_NAME(error_element));
3109   }
3110
3111   return micro_chunk_size;
3112 }
3113
3114 static int LoadLevel_INFO(File *file, int chunk_size, struct LevelInfo *level)
3115 {
3116   int real_chunk_size = 0;
3117
3118   li = *level;          /* copy level data into temporary buffer */
3119
3120   while (!checkEndOfFile(file))
3121   {
3122     real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_INFO, -1, -1);
3123
3124     if (real_chunk_size >= chunk_size)
3125       break;
3126   }
3127
3128   *level = li;          /* copy temporary buffer back to level data */
3129
3130   return real_chunk_size;
3131 }
3132
3133 static int LoadLevel_CONF(File *file, int chunk_size, struct LevelInfo *level)
3134 {
3135   int real_chunk_size = 0;
3136
3137   li = *level;          /* copy level data into temporary buffer */
3138
3139   while (!checkEndOfFile(file))
3140   {
3141     int element = getMappedElement(getFile16BitBE(file));
3142
3143     real_chunk_size += 2;
3144     real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CONF,
3145                                             element, element);
3146     if (real_chunk_size >= chunk_size)
3147       break;
3148   }
3149
3150   *level = li;          /* copy temporary buffer back to level data */
3151
3152   return real_chunk_size;
3153 }
3154
3155 static int LoadLevel_ELEM(File *file, int chunk_size, struct LevelInfo *level)
3156 {
3157   int real_chunk_size = 0;
3158
3159   li = *level;          /* copy level data into temporary buffer */
3160
3161   while (!checkEndOfFile(file))
3162   {
3163     int element = getMappedElement(getFile16BitBE(file));
3164
3165     real_chunk_size += 2;
3166     real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_ELEM,
3167                                             element, element);
3168     if (real_chunk_size >= chunk_size)
3169       break;
3170   }
3171
3172   *level = li;          /* copy temporary buffer back to level data */
3173
3174   return real_chunk_size;
3175 }
3176
3177 static int LoadLevel_NOTE(File *file, int chunk_size, struct LevelInfo *level)
3178 {
3179   int element = getMappedElement(getFile16BitBE(file));
3180   int envelope_nr = element - EL_ENVELOPE_1;
3181   int real_chunk_size = 2;
3182
3183   xx_envelope = level->envelope[envelope_nr];   /* copy into temporary buffer */
3184
3185   while (!checkEndOfFile(file))
3186   {
3187     real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_NOTE,
3188                                             -1, element);
3189
3190     if (real_chunk_size >= chunk_size)
3191       break;
3192   }
3193
3194   level->envelope[envelope_nr] = xx_envelope;   /* copy from temporary buffer */
3195
3196   return real_chunk_size;
3197 }
3198
3199 static int LoadLevel_CUSX(File *file, int chunk_size, struct LevelInfo *level)
3200 {
3201   int element = getMappedElement(getFile16BitBE(file));
3202   int real_chunk_size = 2;
3203   struct ElementInfo *ei = &element_info[element];
3204   int i;
3205
3206   xx_ei = *ei;          /* copy element data into temporary buffer */
3207
3208   xx_ei.num_change_pages = -1;
3209
3210   while (!checkEndOfFile(file))
3211   {
3212     real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CUSX_base,
3213                                             -1, element);
3214     if (xx_ei.num_change_pages != -1)
3215       break;
3216
3217     if (real_chunk_size >= chunk_size)
3218       break;
3219   }
3220
3221   *ei = xx_ei;
3222
3223   if (ei->num_change_pages == -1)
3224   {
3225     Error(ERR_WARN, "LoadLevel_CUSX(): missing 'num_change_pages' for '%s'",
3226           EL_NAME(element));
3227
3228     ei->num_change_pages = 1;
3229
3230     setElementChangePages(ei, 1);
3231     setElementChangeInfoToDefaults(ei->change);
3232
3233     return real_chunk_size;
3234   }
3235
3236   /* initialize number of change pages stored for this custom element */
3237   setElementChangePages(ei, ei->num_change_pages);
3238   for (i = 0; i < ei->num_change_pages; i++)
3239     setElementChangeInfoToDefaults(&ei->change_page[i]);
3240
3241   /* start with reading properties for the first change page */
3242   xx_current_change_page = 0;
3243
3244   while (!checkEndOfFile(file))
3245   {
3246     struct ElementChangeInfo *change = &ei->change_page[xx_current_change_page];
3247
3248     xx_change = *change;        /* copy change data into temporary buffer */
3249
3250     resetEventBits();           /* reset bits; change page might have changed */
3251
3252     real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CUSX_change,
3253                                             -1, element);
3254
3255     *change = xx_change;
3256
3257     setEventFlagsFromEventBits(change);
3258
3259     if (real_chunk_size >= chunk_size)
3260       break;
3261   }
3262
3263   level->file_has_custom_elements = TRUE;
3264
3265   return real_chunk_size;
3266 }
3267
3268 static int LoadLevel_GRPX(File *file, int chunk_size, struct LevelInfo *level)
3269 {
3270   int element = getMappedElement(getFile16BitBE(file));
3271   int real_chunk_size = 2;
3272   struct ElementInfo *ei = &element_info[element];
3273   struct ElementGroupInfo *group = ei->group;
3274
3275   xx_ei = *ei;          /* copy element data into temporary buffer */
3276   xx_group = *group;    /* copy group data into temporary buffer */
3277
3278   while (!checkEndOfFile(file))
3279   {
3280     real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_GRPX,
3281                                             -1, element);
3282
3283     if (real_chunk_size >= chunk_size)
3284       break;
3285   }
3286
3287   *ei = xx_ei;
3288   *group = xx_group;
3289
3290   level->file_has_custom_elements = TRUE;
3291
3292   return real_chunk_size;
3293 }
3294
3295 static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
3296                                       struct LevelFileInfo *level_file_info,
3297                                       boolean level_info_only)
3298 {
3299   char *filename = level_file_info->filename;
3300   char cookie[MAX_LINE_LEN];
3301   char chunk_name[CHUNK_ID_LEN + 1];
3302   int chunk_size;
3303   File *file;
3304
3305   if (!(file = openFile(filename, MODE_READ)))
3306   {
3307     level->no_valid_file = TRUE;
3308     level->no_level_file = TRUE;
3309
3310     if (level_info_only)
3311       return;
3312
3313     Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
3314
3315     if (!setup.editor.use_template_for_new_levels)
3316       return;
3317
3318     /* if level file not found, try to initialize level data from template */
3319     filename = getGlobalLevelTemplateFilename();
3320
3321     if (!(file = openFile(filename, MODE_READ)))
3322       return;
3323
3324     /* default: for empty levels, use level template for custom elements */
3325     level->use_custom_template = TRUE;
3326
3327     level->no_valid_file = FALSE;
3328   }
3329
3330   getFileChunkBE(file, chunk_name, NULL);
3331   if (strEqual(chunk_name, "RND1"))
3332   {
3333     getFile32BitBE(file);               /* not used */
3334
3335     getFileChunkBE(file, chunk_name, NULL);
3336     if (!strEqual(chunk_name, "CAVE"))
3337     {
3338       level->no_valid_file = TRUE;
3339
3340       Error(ERR_WARN, "unknown format of level file '%s'", filename);
3341
3342       closeFile(file);
3343
3344       return;
3345     }
3346   }
3347   else  /* check for pre-2.0 file format with cookie string */
3348   {
3349     strcpy(cookie, chunk_name);
3350     if (getStringFromFile(file, &cookie[4], MAX_LINE_LEN - 4) == NULL)
3351       cookie[4] = '\0';
3352     if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
3353       cookie[strlen(cookie) - 1] = '\0';
3354
3355     if (!checkCookieString(cookie, LEVEL_COOKIE_TMPL))
3356     {
3357       level->no_valid_file = TRUE;
3358
3359       Error(ERR_WARN, "unknown format of level file '%s'", filename);
3360
3361       closeFile(file);
3362
3363       return;
3364     }
3365
3366     if ((level->file_version = getFileVersionFromCookieString(cookie)) == -1)
3367     {
3368       level->no_valid_file = TRUE;
3369
3370       Error(ERR_WARN, "unsupported version of level file '%s'", filename);
3371
3372       closeFile(file);
3373
3374       return;
3375     }
3376
3377     /* pre-2.0 level files have no game version, so use file version here */
3378     level->game_version = level->file_version;
3379   }
3380
3381   if (level->file_version < FILE_VERSION_1_2)
3382   {
3383     /* level files from versions before 1.2.0 without chunk structure */
3384     LoadLevel_HEAD(file, LEVEL_CHUNK_HEAD_SIZE,         level);
3385     LoadLevel_BODY(file, level->fieldx * level->fieldy, level);
3386   }
3387   else
3388   {
3389     static struct
3390     {
3391       char *name;
3392       int size;
3393       int (*loader)(File *, int, struct LevelInfo *);
3394     }
3395     chunk_info[] =
3396     {
3397       { "VERS", LEVEL_CHUNK_VERS_SIZE,  LoadLevel_VERS },
3398       { "DATE", LEVEL_CHUNK_DATE_SIZE,  LoadLevel_DATE },
3399       { "HEAD", LEVEL_CHUNK_HEAD_SIZE,  LoadLevel_HEAD },
3400       { "NAME", LEVEL_CHUNK_NAME_SIZE,  LoadLevel_NAME },
3401       { "AUTH", LEVEL_CHUNK_AUTH_SIZE,  LoadLevel_AUTH },
3402       { "INFO", -1,                     LoadLevel_INFO },
3403       { "BODY", -1,                     LoadLevel_BODY },
3404       { "CONT", -1,                     LoadLevel_CONT },
3405       { "CNT2", LEVEL_CHUNK_CNT2_SIZE,  LoadLevel_CNT2 },
3406       { "CNT3", -1,                     LoadLevel_CNT3 },
3407       { "CUS1", -1,                     LoadLevel_CUS1 },
3408       { "CUS2", -1,                     LoadLevel_CUS2 },
3409       { "CUS3", -1,                     LoadLevel_CUS3 },
3410       { "CUS4", -1,                     LoadLevel_CUS4 },
3411       { "GRP1", -1,                     LoadLevel_GRP1 },
3412       { "CONF", -1,                     LoadLevel_CONF },
3413       { "ELEM", -1,                     LoadLevel_ELEM },
3414       { "NOTE", -1,                     LoadLevel_NOTE },
3415       { "CUSX", -1,                     LoadLevel_CUSX },
3416       { "GRPX", -1,                     LoadLevel_GRPX },
3417
3418       {  NULL,  0,                      NULL }
3419     };
3420
3421     while (getFileChunkBE(file, chunk_name, &chunk_size))
3422     {
3423       int i = 0;
3424
3425       while (chunk_info[i].name != NULL &&
3426              !strEqual(chunk_name, chunk_info[i].name))
3427         i++;
3428
3429       if (chunk_info[i].name == NULL)
3430       {
3431         Error(ERR_WARN, "unknown chunk '%s' in level file '%s'",
3432               chunk_name, filename);
3433         ReadUnusedBytesFromFile(file, chunk_size);
3434       }
3435       else if (chunk_info[i].size != -1 &&
3436                chunk_info[i].size != chunk_size)
3437       {
3438         Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
3439               chunk_size, chunk_name, filename);
3440         ReadUnusedBytesFromFile(file, chunk_size);
3441       }
3442       else
3443       {
3444         /* call function to load this level chunk */
3445         int chunk_size_expected =
3446           (chunk_info[i].loader)(file, chunk_size, level);
3447
3448         /* the size of some chunks cannot be checked before reading other
3449            chunks first (like "HEAD" and "BODY") that contain some header
3450            information, so check them here */
3451         if (chunk_size_expected != chunk_size)
3452         {
3453           Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
3454                 chunk_size, chunk_name, filename);
3455         }
3456       }
3457     }
3458   }
3459
3460   closeFile(file);
3461 }
3462
3463
3464 /* ------------------------------------------------------------------------- */
3465 /* functions for loading EM level                                            */
3466 /* ------------------------------------------------------------------------- */
3467
3468 void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
3469 {
3470   static int ball_xy[8][2] =
3471   {
3472     { 0, 0 },
3473     { 1, 0 },
3474     { 2, 0 },
3475     { 0, 1 },
3476     { 2, 1 },
3477     { 0, 2 },
3478     { 1, 2 },
3479     { 2, 2 },
3480   };
3481   struct LevelInfo_EM *level_em = level->native_em_level;
3482   struct LEVEL *lev = level_em->lev;
3483   struct PLAYER **ply = level_em->ply;
3484   int i, j, x, y;
3485
3486   lev->width  = MIN(level->fieldx, EM_MAX_CAVE_WIDTH);
3487   lev->height = MIN(level->fieldy, EM_MAX_CAVE_HEIGHT);
3488
3489   lev->time_seconds     = level->time;
3490   lev->required_initial = level->gems_needed;
3491
3492   lev->emerald_score    = level->score[SC_EMERALD];
3493   lev->diamond_score    = level->score[SC_DIAMOND];
3494   lev->alien_score      = level->score[SC_ROBOT];
3495   lev->tank_score       = level->score[SC_SPACESHIP];
3496   lev->bug_score        = level->score[SC_BUG];
3497   lev->eater_score      = level->score[SC_YAMYAM];
3498   lev->nut_score        = level->score[SC_NUT];
3499   lev->dynamite_score   = level->score[SC_DYNAMITE];
3500   lev->key_score        = level->score[SC_KEY];
3501   lev->exit_score       = level->score[SC_TIME_BONUS];
3502
3503   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3504     for (y = 0; y < 3; y++)
3505       for (x = 0; x < 3; x++)
3506         lev->eater_array[i][y * 3 + x] =
3507           map_element_RND_to_EM(level->yamyam_content[i].e[x][y]);
3508
3509   lev->amoeba_time              = level->amoeba_speed;
3510   lev->wonderwall_time_initial  = level->time_magic_wall;
3511   lev->wheel_time               = level->time_wheel;
3512
3513   lev->android_move_time        = level->android_move_time;
3514   lev->android_clone_time       = level->android_clone_time;
3515   lev->ball_random              = level->ball_random;
3516   lev->ball_state_initial       = level->ball_state_initial;
3517   lev->ball_time                = level->ball_time;
3518   lev->num_ball_arrays          = level->num_ball_contents;
3519
3520   lev->lenses_score             = level->lenses_score;
3521   lev->magnify_score            = level->magnify_score;
3522   lev->slurp_score              = level->slurp_score;
3523
3524   lev->lenses_time              = level->lenses_time;
3525   lev->magnify_time             = level->magnify_time;
3526
3527   lev->wind_direction_initial =
3528     map_direction_RND_to_EM(level->wind_direction_initial);
3529   lev->wind_cnt_initial = (level->wind_direction_initial != MV_NONE ?
3530                            lev->wind_time : 0);
3531
3532   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3533     for (j = 0; j < 8; j++)
3534       lev->ball_array[i][j] =
3535         map_element_RND_to_EM(level->
3536                               ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
3537
3538   map_android_clone_elements_RND_to_EM(level);
3539
3540   /* first fill the complete playfield with the default border element */
3541   for (y = 0; y < EM_MAX_CAVE_HEIGHT; y++)
3542     for (x = 0; x < EM_MAX_CAVE_WIDTH; x++)
3543       level_em->cave[x][y] = ZBORDER;
3544
3545   if (BorderElement == EL_STEELWALL)
3546   {
3547     for (y = 0; y < lev->height + 2; y++)
3548       for (x = 0; x < lev->width + 2; x++)
3549         level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_STEELWALL);
3550   }
3551
3552   /* then copy the real level contents from level file into the playfield */
3553   for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
3554   {
3555     int new_element = map_element_RND_to_EM(level->field[x][y]);
3556     int offset = (BorderElement == EL_STEELWALL ? 1 : 0);
3557     int xx = x + 1 + offset;
3558     int yy = y + 1 + offset;
3559
3560     if (level->field[x][y] == EL_AMOEBA_DEAD)
3561       new_element = map_element_RND_to_EM(EL_AMOEBA_WET);
3562
3563     level_em->cave[xx][yy] = new_element;
3564   }
3565
3566   for (i = 0; i < MAX_PLAYERS; i++)
3567   {
3568     ply[i]->x_initial = 0;
3569     ply[i]->y_initial = 0;
3570   }
3571
3572   /* initialize player positions and delete players from the playfield */
3573   for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
3574   {
3575     if (ELEM_IS_PLAYER(level->field[x][y]))
3576     {
3577       int player_nr = GET_PLAYER_NR(level->field[x][y]);
3578       int offset = (BorderElement == EL_STEELWALL ? 1 : 0);
3579       int xx = x + 1 + offset;
3580       int yy = y + 1 + offset;
3581
3582       ply[player_nr]->x_initial = xx;
3583       ply[player_nr]->y_initial = yy;
3584
3585       level_em->cave[xx][yy] = map_element_RND_to_EM(EL_EMPTY);
3586     }
3587   }
3588
3589   if (BorderElement == EL_STEELWALL)
3590   {
3591     lev->width  += 2;
3592     lev->height += 2;
3593   }
3594 }
3595
3596 void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
3597 {
3598   static int ball_xy[8][2] =
3599   {
3600     { 0, 0 },
3601     { 1, 0 },
3602     { 2, 0 },
3603     { 0, 1 },
3604     { 2, 1 },
3605     { 0, 2 },
3606     { 1, 2 },
3607     { 2, 2 },
3608   };
3609   struct LevelInfo_EM *level_em = level->native_em_level;
3610   struct LEVEL *lev = level_em->lev;
3611   struct PLAYER **ply = level_em->ply;
3612   int i, j, x, y;
3613
3614   level->fieldx = MIN(lev->width,  MAX_LEV_FIELDX);
3615   level->fieldy = MIN(lev->height, MAX_LEV_FIELDY);
3616
3617   level->time        = lev->time_seconds;
3618   level->gems_needed = lev->required_initial;
3619
3620   sprintf(level->name, "Level %d", level->file_info.nr);
3621
3622   level->score[SC_EMERALD]      = lev->emerald_score;
3623   level->score[SC_DIAMOND]      = lev->diamond_score;
3624   level->score[SC_ROBOT]        = lev->alien_score;
3625   level->score[SC_SPACESHIP]    = lev->tank_score;
3626   level->score[SC_BUG]          = lev->bug_score;
3627   level->score[SC_YAMYAM]       = lev->eater_score;
3628   level->score[SC_NUT]          = lev->nut_score;
3629   level->score[SC_DYNAMITE]     = lev->dynamite_score;
3630   level->score[SC_KEY]          = lev->key_score;
3631   level->score[SC_TIME_BONUS]   = lev->exit_score;
3632
3633   level->num_yamyam_contents = MAX_ELEMENT_CONTENTS;
3634
3635   for (i = 0; i < level->num_yamyam_contents; i++)
3636     for (y = 0; y < 3; y++)
3637       for (x = 0; x < 3; x++)
3638         level->yamyam_content[i].e[x][y] =
3639           map_element_EM_to_RND(lev->eater_array[i][y * 3 + x]);
3640
3641   level->amoeba_speed           = lev->amoeba_time;
3642   level->time_magic_wall        = lev->wonderwall_time_initial;
3643   level->time_wheel             = lev->wheel_time;
3644
3645   level->android_move_time      = lev->android_move_time;
3646   level->android_clone_time     = lev->android_clone_time;
3647   level->ball_random            = lev->ball_random;
3648   level->ball_state_initial     = lev->ball_state_initial;
3649   level->ball_time              = lev->ball_time;
3650   level->num_ball_contents      = lev->num_ball_arrays;
3651
3652   level->lenses_score           = lev->lenses_score;
3653   level->magnify_score          = lev->magnify_score;
3654   level->slurp_score            = lev->slurp_score;
3655
3656   level->lenses_time            = lev->lenses_time;
3657   level->magnify_time           = lev->magnify_time;
3658
3659   level->wind_direction_initial =
3660     map_direction_EM_to_RND(lev->wind_direction_initial);
3661
3662   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3663     for (j = 0; j < 8; j++)
3664       level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]] =
3665         map_element_EM_to_RND(lev->ball_array[i][j]);
3666
3667   map_android_clone_elements_EM_to_RND(level);
3668
3669   /* convert the playfield (some elements need special treatment) */
3670   for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
3671   {
3672     int new_element = map_element_EM_to_RND(level_em->cave[x + 1][y + 1]);
3673
3674     if (new_element == EL_AMOEBA_WET && level->amoeba_speed == 0)
3675       new_element = EL_AMOEBA_DEAD;
3676
3677     level->field[x][y] = new_element;
3678   }
3679
3680   for (i = 0; i < MAX_PLAYERS; i++)
3681   {
3682     /* in case of all players set to the same field, use the first player */
3683     int nr = MAX_PLAYERS - i - 1;
3684     int jx = ply[nr]->x_initial - 1;
3685     int jy = ply[nr]->y_initial - 1;
3686
3687     if (jx != -1 && jy != -1)
3688       level->field[jx][jy] = EL_PLAYER_1 + nr;
3689   }
3690 }
3691
3692
3693 /* ------------------------------------------------------------------------- */
3694 /* functions for loading SP level                                            */
3695 /* ------------------------------------------------------------------------- */
3696
3697 void CopyNativeLevel_RND_to_SP(struct LevelInfo *level)
3698 {
3699   struct LevelInfo_SP *level_sp = level->native_sp_level;
3700   LevelInfoType *header = &level_sp->header;
3701   int i, x, y;
3702
3703   level_sp->width  = level->fieldx;
3704   level_sp->height = level->fieldy;
3705
3706   for (x = 0; x < level->fieldx; x++)
3707     for (y = 0; y < level->fieldy; y++)
3708       level_sp->playfield[x][y] = map_element_RND_to_SP(level->field[x][y]);
3709
3710   header->InitialGravity = (level->initial_player_gravity[0] ? 1 : 0);
3711
3712   for (i = 0; i < SP_LEVEL_NAME_LEN; i++)
3713     header->LevelTitle[i] = level->name[i];
3714   /* !!! NO STRING TERMINATION IN SUPAPLEX VB CODE YET -- FIX THIS !!! */
3715
3716   header->InfotronsNeeded = level->gems_needed;
3717
3718   header->SpecialPortCount = 0;
3719
3720   for (x = 0; x < level->fieldx; x++) for (y = 0; y < level->fieldy; y++)
3721   {
3722     boolean gravity_port_found = FALSE;