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