rnd-20080205-1-src
[rocksndiamonds.git] / src / files.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * files.c                                                  *
12 ***********************************************************/
13
14 #include <ctype.h>
15 #include <sys/stat.h>
16 #include <dirent.h>
17 #include <math.h>
18
19 #include "libgame/libgame.h"
20
21 #include "files.h"
22 #include "init.h"
23 #include "tools.h"
24 #include "tape.h"
25
26
27 #define CHUNK_ID_LEN            4       /* IFF style chunk id length  */
28 #define CHUNK_SIZE_UNDEFINED    0       /* undefined chunk size == 0  */
29 #define CHUNK_SIZE_NONE         -1      /* do not write chunk size    */
30
31 #define LEVEL_CHUNK_NAME_SIZE   MAX_LEVEL_NAME_LEN
32 #define LEVEL_CHUNK_AUTH_SIZE   MAX_LEVEL_AUTHOR_LEN
33
34 #define LEVEL_CHUNK_VERS_SIZE   8       /* size of file version chunk */
35 #define LEVEL_CHUNK_DATE_SIZE   4       /* size of file date chunk    */
36 #define LEVEL_CHUNK_HEAD_SIZE   80      /* size of level file header  */
37 #define LEVEL_CHUNK_HEAD_UNUSED 0       /* unused level header bytes  */
38 #define LEVEL_CHUNK_CNT2_SIZE   160     /* size of level CNT2 chunk   */
39 #define LEVEL_CHUNK_CNT2_UNUSED 11      /* unused CNT2 chunk bytes    */
40 #define LEVEL_CHUNK_CNT3_HEADER 16      /* size of level CNT3 header  */
41 #define LEVEL_CHUNK_CNT3_UNUSED 10      /* unused CNT3 chunk bytes    */
42 #define LEVEL_CPART_CUS3_SIZE   134     /* size of CUS3 chunk part    */
43 #define LEVEL_CPART_CUS3_UNUSED 15      /* unused CUS3 bytes / part   */
44 #define LEVEL_CHUNK_GRP1_SIZE   74      /* size of level GRP1 chunk   */
45
46 /* (element number, number of change pages, change page number) */
47 #define LEVEL_CHUNK_CUSX_UNCHANGED      (2 + (1 + 1) + (1 + 1))
48
49 /* (element number only) */
50 #define LEVEL_CHUNK_GRPX_UNCHANGED      2
51 #define LEVEL_CHUNK_NOTE_UNCHANGED      2
52
53 /* (nothing at all if unchanged) */
54 #define LEVEL_CHUNK_ELEM_UNCHANGED      0
55
56 #define TAPE_CHUNK_VERS_SIZE    8       /* size of file version chunk */
57 #define TAPE_CHUNK_HEAD_SIZE    20      /* size of tape file header   */
58 #define TAPE_CHUNK_HEAD_UNUSED  3       /* unused tape header bytes   */
59
60 #define LEVEL_CHUNK_CNT3_SIZE(x)         (LEVEL_CHUNK_CNT3_HEADER + (x))
61 #define LEVEL_CHUNK_CUS3_SIZE(x)         (2 + (x) * LEVEL_CPART_CUS3_SIZE)
62 #define LEVEL_CHUNK_CUS4_SIZE(x)         (96 + (x) * 48)
63
64 /* file identifier strings */
65 #define LEVEL_COOKIE_TMPL               "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x"
66 #define TAPE_COOKIE_TMPL                "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
67 #define SCORE_COOKIE                    "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
68
69 /* values for deciding when (not) to save configuration data */
70 #define SAVE_CONF_NEVER                 0
71 #define SAVE_CONF_ALWAYS                1
72 #define SAVE_CONF_WHEN_CHANGED          -1
73
74 /* values for chunks using micro chunks */
75 #define CONF_MASK_1_BYTE                0x00
76 #define CONF_MASK_2_BYTE                0x40
77 #define CONF_MASK_4_BYTE                0x80
78 #define CONF_MASK_MULTI_BYTES           0xc0
79
80 #define CONF_MASK_BYTES                 0xc0
81 #define CONF_MASK_TOKEN                 0x3f
82
83 #define CONF_VALUE_1_BYTE(x)            (CONF_MASK_1_BYTE       | (x))
84 #define CONF_VALUE_2_BYTE(x)            (CONF_MASK_2_BYTE       | (x))
85 #define CONF_VALUE_4_BYTE(x)            (CONF_MASK_4_BYTE       | (x))
86 #define CONF_VALUE_MULTI_BYTES(x)       (CONF_MASK_MULTI_BYTES  | (x))
87
88 /* these definitions are just for convenience of use and readability */
89 #define CONF_VALUE_8_BIT(x)             CONF_VALUE_1_BYTE(x)
90 #define CONF_VALUE_16_BIT(x)            CONF_VALUE_2_BYTE(x)
91 #define CONF_VALUE_32_BIT(x)            CONF_VALUE_4_BYTE(x)
92 #define CONF_VALUE_BYTES(x)             CONF_VALUE_MULTI_BYTES(x)
93
94 #define CONF_VALUE_NUM_BYTES(x)         ((x) == CONF_MASK_1_BYTE ? 1 :  \
95                                          (x) == CONF_MASK_2_BYTE ? 2 :  \
96                                          (x) == CONF_MASK_4_BYTE ? 4 : 0)
97
98 #define CONF_CONTENT_NUM_ELEMENTS       (3 * 3)
99 #define CONF_CONTENT_NUM_BYTES          (CONF_CONTENT_NUM_ELEMENTS * 2)
100 #define CONF_ELEMENT_NUM_BYTES          (2)
101
102 #define CONF_ENTITY_NUM_BYTES(t)        ((t) == TYPE_ELEMENT ||         \
103                                          (t) == TYPE_ELEMENT_LIST ?     \
104                                          CONF_ELEMENT_NUM_BYTES :       \
105                                          (t) == TYPE_CONTENT ||         \
106                                          (t) == TYPE_CONTENT_LIST ?     \
107                                          CONF_CONTENT_NUM_BYTES : 1)
108
109 #define CONF_ELEMENT_BYTE_POS(i)        ((i) * CONF_ELEMENT_NUM_BYTES)
110 #define CONF_ELEMENTS_ELEMENT(b,i)     ((b[CONF_ELEMENT_BYTE_POS(i)] << 8) |  \
111                                         (b[CONF_ELEMENT_BYTE_POS(i) + 1]))
112
113 #define CONF_CONTENT_ELEMENT_POS(c,x,y) ((c) * CONF_CONTENT_NUM_ELEMENTS +    \
114                                          (y) * 3 + (x))
115 #define CONF_CONTENT_BYTE_POS(c,x,y)    (CONF_CONTENT_ELEMENT_POS(c,x,y) *    \
116                                          CONF_ELEMENT_NUM_BYTES)
117 #define CONF_CONTENTS_ELEMENT(b,c,x,y) ((b[CONF_CONTENT_BYTE_POS(c,x,y)]<< 8)|\
118                                         (b[CONF_CONTENT_BYTE_POS(c,x,y) + 1]))
119
120 /* temporary variables used to store pointers to structure members */
121 static struct LevelInfo li;
122 static struct ElementInfo xx_ei, yy_ei;
123 static struct ElementChangeInfo xx_change;
124 static struct ElementGroupInfo xx_group;
125 static struct EnvelopeInfo xx_envelope;
126 static unsigned int xx_event_bits[NUM_CE_BITFIELDS];
127 static char xx_default_description[MAX_ELEMENT_NAME_LEN + 1];
128 static int xx_num_contents;
129 static int xx_current_change_page;
130 static char xx_default_string_empty[1] = "";
131 static int xx_string_length_unused;
132
133 struct LevelFileConfigInfo
134 {
135   int element;                  /* element for which data is to be stored */
136   int save_type;                /* save data always, never or when changed */
137   int data_type;                /* data type (used internally, not stored) */
138   int conf_type;                /* micro chunk identifier (stored in file) */
139
140   /* (mandatory) */
141   void *value;                  /* variable that holds the data to be stored */
142   int default_value;            /* initial default value for this variable */
143
144   /* (optional) */
145   void *value_copy;             /* variable that holds the data to be copied */
146   void *num_entities;           /* number of entities for multi-byte data */
147   int default_num_entities;     /* default number of entities for this data */
148   int max_num_entities;         /* maximal number of entities for this data */
149   char *default_string;         /* optional default string for string data */
150 };
151
152 static struct LevelFileConfigInfo chunk_config_INFO[] =
153 {
154   /* ---------- values not related to single elements ----------------------- */
155
156   {
157     -1,                                 SAVE_CONF_ALWAYS,
158     TYPE_INTEGER,                       CONF_VALUE_8_BIT(1),
159     &li.game_engine_type,               GAME_ENGINE_TYPE_RND
160   },
161
162   {
163     -1,                                 SAVE_CONF_ALWAYS,
164     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
165     &li.fieldx,                         STD_LEV_FIELDX
166   },
167   {
168     -1,                                 SAVE_CONF_ALWAYS,
169     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
170     &li.fieldy,                         STD_LEV_FIELDY
171   },
172
173   {
174     -1,                                 SAVE_CONF_ALWAYS,
175     TYPE_INTEGER,                       CONF_VALUE_16_BIT(3),
176     &li.time,                           100
177   },
178
179   {
180     -1,                                 SAVE_CONF_ALWAYS,
181     TYPE_INTEGER,                       CONF_VALUE_16_BIT(4),
182     &li.gems_needed,                    0
183   },
184
185   {
186     -1,                                 -1,
187     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(2),
188     &li.use_step_counter,               FALSE
189   },
190
191   {
192     -1,                                 -1,
193     TYPE_BITFIELD,                      CONF_VALUE_8_BIT(4),
194     &li.wind_direction_initial,         MV_NONE
195   },
196
197   {
198     -1,                                 -1,
199     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(5),
200     &li.em_slippery_gems,               FALSE
201   },
202
203   {
204     -1,                                 -1,
205     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(6),
206     &li.use_custom_template,            FALSE
207   },
208
209   {
210     -1,                                 -1,
211     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(1),
212     &li.can_move_into_acid_bits,        ~0      /* default: everything can */
213   },
214
215   {
216     -1,                                 -1,
217     TYPE_BITFIELD,                      CONF_VALUE_8_BIT(7),
218     &li.dont_collide_with_bits,         ~0      /* default: always deadly */
219   },
220
221   {
222     -1,                                 -1,
223     TYPE_INTEGER,                       CONF_VALUE_16_BIT(5),
224     &li.score[SC_TIME_BONUS],           1
225   },
226
227   {
228     -1,                                 -1,
229     -1,                                 -1,
230     NULL,                               -1
231   }
232 };
233
234 static struct LevelFileConfigInfo chunk_config_ELEM[] =
235 {
236   /* (these values are the same for each player) */
237   {
238     EL_PLAYER_1,                        -1,
239     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
240     &li.block_last_field,               FALSE   /* default case for EM levels */
241   },
242   {
243     EL_PLAYER_1,                        -1,
244     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(2),
245     &li.sp_block_last_field,            TRUE    /* default case for SP levels */
246   },
247   {
248     EL_PLAYER_1,                        -1,
249     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(3),
250     &li.instant_relocation,             FALSE
251   },
252   {
253     EL_PLAYER_1,                        -1,
254     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(4),
255     &li.can_pass_to_walkable,           FALSE
256   },
257   {
258     EL_PLAYER_1,                        -1,
259     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(5),
260     &li.block_snap_field,               TRUE
261   },
262   {
263     EL_PLAYER_1,                        -1,
264     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(6),
265     &li.continuous_snapping,            TRUE
266   },
267   {
268     EL_PLAYER_1,                        -1,
269     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(12),
270     &li.shifted_relocation,             FALSE
271   },
272
273   /* (these values are different for each player) */
274   {
275     EL_PLAYER_1,                        -1,
276     TYPE_INTEGER,                       CONF_VALUE_8_BIT(7),
277     &li.initial_player_stepsize[0],     STEPSIZE_NORMAL
278   },
279   {
280     EL_PLAYER_1,                        -1,
281     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(8),
282     &li.initial_player_gravity[0],      FALSE
283   },
284   {
285     EL_PLAYER_1,                        -1,
286     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(9),
287     &li.use_start_element[0],           FALSE
288   },
289   {
290     EL_PLAYER_1,                        -1,
291     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
292     &li.start_element[0],               EL_PLAYER_1
293   },
294   {
295     EL_PLAYER_1,                        -1,
296     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(10),
297     &li.use_artwork_element[0],         FALSE
298   },
299   {
300     EL_PLAYER_1,                        -1,
301     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(2),
302     &li.artwork_element[0],             EL_PLAYER_1
303   },
304   {
305     EL_PLAYER_1,                        -1,
306     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(11),
307     &li.use_explosion_element[0],       FALSE
308   },
309   {
310     EL_PLAYER_1,                        -1,
311     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(3),
312     &li.explosion_element[0],           EL_PLAYER_1
313   },
314   {
315     EL_PLAYER_1,                        -1,
316     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(13),
317     &li.use_initial_inventory[0],       FALSE
318   },
319   {
320     EL_PLAYER_1,                        -1,
321     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(14),
322     &li.initial_inventory_size[0],      1
323   },
324   {
325     EL_PLAYER_1,                        -1,
326     TYPE_ELEMENT_LIST,                  CONF_VALUE_BYTES(1),
327     &li.initial_inventory_content[0][0],EL_EMPTY, NULL,
328     &li.initial_inventory_size[0],      1, MAX_INITIAL_INVENTORY_SIZE
329   },
330
331   {
332     EL_PLAYER_2,                        -1,
333     TYPE_INTEGER,                       CONF_VALUE_8_BIT(7),
334     &li.initial_player_stepsize[1],     STEPSIZE_NORMAL
335   },
336   {
337     EL_PLAYER_2,                        -1,
338     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(8),
339     &li.initial_player_gravity[1],      FALSE
340   },
341   {
342     EL_PLAYER_2,                        -1,
343     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(9),
344     &li.use_start_element[1],           FALSE
345   },
346   {
347     EL_PLAYER_2,                        -1,
348     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
349     &li.start_element[1],               EL_PLAYER_2
350   },
351   {
352     EL_PLAYER_2,                        -1,
353     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(10),
354     &li.use_artwork_element[1],         FALSE
355   },
356   {
357     EL_PLAYER_2,                        -1,
358     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(2),
359     &li.artwork_element[1],             EL_PLAYER_2
360   },
361   {
362     EL_PLAYER_2,                        -1,
363     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(11),
364     &li.use_explosion_element[1],       FALSE
365   },
366   {
367     EL_PLAYER_2,                        -1,
368     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(3),
369     &li.explosion_element[1],           EL_PLAYER_2
370   },
371   {
372     EL_PLAYER_2,                        -1,
373     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(13),
374     &li.use_initial_inventory[1],       FALSE
375   },
376   {
377     EL_PLAYER_2,                        -1,
378     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(14),
379     &li.initial_inventory_size[1],      1
380   },
381   {
382     EL_PLAYER_2,                        -1,
383     TYPE_ELEMENT_LIST,                  CONF_VALUE_BYTES(1),
384     &li.initial_inventory_content[1][0],EL_EMPTY, NULL,
385     &li.initial_inventory_size[1],      1, MAX_INITIAL_INVENTORY_SIZE
386   },
387
388   {
389     EL_PLAYER_3,                        -1,
390     TYPE_INTEGER,                       CONF_VALUE_8_BIT(7),
391     &li.initial_player_stepsize[2],     STEPSIZE_NORMAL
392   },
393   {
394     EL_PLAYER_3,                        -1,
395     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(8),
396     &li.initial_player_gravity[2],      FALSE
397   },
398   {
399     EL_PLAYER_3,                        -1,
400     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(9),
401     &li.use_start_element[2],           FALSE
402   },
403   {
404     EL_PLAYER_3,                        -1,
405     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
406     &li.start_element[2],               EL_PLAYER_3
407   },
408   {
409     EL_PLAYER_3,                        -1,
410     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(10),
411     &li.use_artwork_element[2],         FALSE
412   },
413   {
414     EL_PLAYER_3,                        -1,
415     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(2),
416     &li.artwork_element[2],             EL_PLAYER_3
417   },
418   {
419     EL_PLAYER_3,                        -1,
420     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(11),
421     &li.use_explosion_element[2],       FALSE
422   },
423   {
424     EL_PLAYER_3,                        -1,
425     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(3),
426     &li.explosion_element[2],           EL_PLAYER_3
427   },
428   {
429     EL_PLAYER_3,                        -1,
430     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(13),
431     &li.use_initial_inventory[2],       FALSE
432   },
433   {
434     EL_PLAYER_3,                        -1,
435     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(14),
436     &li.initial_inventory_size[2],      1
437   },
438   {
439     EL_PLAYER_3,                        -1,
440     TYPE_ELEMENT_LIST,                  CONF_VALUE_BYTES(1),
441     &li.initial_inventory_content[2][0],EL_EMPTY, NULL,
442     &li.initial_inventory_size[2],      1, MAX_INITIAL_INVENTORY_SIZE
443   },
444
445   {
446     EL_PLAYER_4,                        -1,
447     TYPE_INTEGER,                       CONF_VALUE_8_BIT(7),
448     &li.initial_player_stepsize[3],     STEPSIZE_NORMAL
449   },
450   {
451     EL_PLAYER_4,                        -1,
452     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(8),
453     &li.initial_player_gravity[3],      FALSE
454   },
455   {
456     EL_PLAYER_4,                        -1,
457     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(9),
458     &li.use_start_element[3],           FALSE
459   },
460   {
461     EL_PLAYER_4,                        -1,
462     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
463     &li.start_element[3],               EL_PLAYER_4
464   },
465   {
466     EL_PLAYER_4,                        -1,
467     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(10),
468     &li.use_artwork_element[3],         FALSE
469   },
470   {
471     EL_PLAYER_4,                        -1,
472     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(2),
473     &li.artwork_element[3],             EL_PLAYER_4
474   },
475   {
476     EL_PLAYER_4,                        -1,
477     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(11),
478     &li.use_explosion_element[3],       FALSE
479   },
480   {
481     EL_PLAYER_4,                        -1,
482     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(3),
483     &li.explosion_element[3],           EL_PLAYER_4
484   },
485   {
486     EL_PLAYER_4,                        -1,
487     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(13),
488     &li.use_initial_inventory[3],       FALSE
489   },
490   {
491     EL_PLAYER_4,                        -1,
492     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(14),
493     &li.initial_inventory_size[3],      1
494   },
495   {
496     EL_PLAYER_4,                        -1,
497     TYPE_ELEMENT_LIST,                  CONF_VALUE_BYTES(1),
498     &li.initial_inventory_content[3][0],EL_EMPTY, NULL,
499     &li.initial_inventory_size[3],      1, MAX_INITIAL_INVENTORY_SIZE
500   },
501
502   {
503     EL_EMERALD,                         -1,
504     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
505     &li.score[SC_EMERALD],              10
506   },
507
508   {
509     EL_DIAMOND,                         -1,
510     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
511     &li.score[SC_DIAMOND],              10
512   },
513
514   {
515     EL_BUG,                             -1,
516     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
517     &li.score[SC_BUG],                  10
518   },
519
520   {
521     EL_SPACESHIP,                       -1,
522     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
523     &li.score[SC_SPACESHIP],            10
524   },
525
526   {
527     EL_PACMAN,                          -1,
528     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
529     &li.score[SC_PACMAN],               10
530   },
531
532   {
533     EL_NUT,                             -1,
534     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
535     &li.score[SC_NUT],                  10
536   },
537
538   {
539     EL_DYNAMITE,                        -1,
540     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
541     &li.score[SC_DYNAMITE],             10
542   },
543
544   {
545     EL_KEY_1,                           -1,
546     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
547     &li.score[SC_KEY],                  10
548   },
549
550   {
551     EL_PEARL,                           -1,
552     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
553     &li.score[SC_PEARL],                10
554   },
555
556   {
557     EL_CRYSTAL,                         -1,
558     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
559     &li.score[SC_CRYSTAL],              10
560   },
561
562   {
563     EL_BD_AMOEBA,                       -1,
564     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
565     &li.amoeba_content,                 EL_DIAMOND
566   },
567   {
568     EL_BD_AMOEBA,                       -1,
569     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
570     &li.amoeba_speed,                   10
571   },
572   {
573     EL_BD_AMOEBA,                       -1,
574     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
575     &li.grow_into_diggable,             TRUE
576   },
577
578   {
579     EL_YAMYAM,                          -1,
580     TYPE_CONTENT_LIST,                  CONF_VALUE_BYTES(1),
581     &li.yamyam_content,                 EL_ROCK, NULL,
582     &li.num_yamyam_contents,            4, MAX_ELEMENT_CONTENTS
583   },
584   {
585     EL_YAMYAM,                          -1,
586     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
587     &li.score[SC_YAMYAM],               10
588   },
589
590   {
591     EL_ROBOT,                           -1,
592     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
593     &li.score[SC_ROBOT],                10
594   },
595   {
596     EL_ROBOT,                           -1,
597     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
598     &li.slurp_score,                    10
599   },
600
601   {
602     EL_ROBOT_WHEEL,                     -1,
603     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
604     &li.time_wheel,                     10
605   },
606
607   {
608     EL_MAGIC_WALL,                      -1,
609     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
610     &li.time_magic_wall,                10
611   },
612
613   {
614     EL_GAME_OF_LIFE,                    -1,
615     TYPE_INTEGER,                       CONF_VALUE_8_BIT(1),
616     &li.game_of_life[0],                2
617   },
618   {
619     EL_GAME_OF_LIFE,                    -1,
620     TYPE_INTEGER,                       CONF_VALUE_8_BIT(2),
621     &li.game_of_life[1],                3
622   },
623   {
624     EL_GAME_OF_LIFE,                    -1,
625     TYPE_INTEGER,                       CONF_VALUE_8_BIT(3),
626     &li.game_of_life[2],                3
627   },
628   {
629     EL_GAME_OF_LIFE,                    -1,
630     TYPE_INTEGER,                       CONF_VALUE_8_BIT(4),
631     &li.game_of_life[3],                3
632   },
633
634   {
635     EL_BIOMAZE,                         -1,
636     TYPE_INTEGER,                       CONF_VALUE_8_BIT(1),
637     &li.biomaze[0],                     2
638   },
639   {
640     EL_BIOMAZE,                         -1,
641     TYPE_INTEGER,                       CONF_VALUE_8_BIT(2),
642     &li.biomaze[1],                     3
643   },
644   {
645     EL_BIOMAZE,                         -1,
646     TYPE_INTEGER,                       CONF_VALUE_8_BIT(3),
647     &li.biomaze[2],                     3
648   },
649   {
650     EL_BIOMAZE,                         -1,
651     TYPE_INTEGER,                       CONF_VALUE_8_BIT(4),
652     &li.biomaze[3],                     3
653   },
654
655   {
656     EL_TIMEGATE_SWITCH,                 -1,
657     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
658     &li.time_timegate,                  10
659   },
660
661   {
662     EL_LIGHT_SWITCH_ACTIVE,             -1,
663     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
664     &li.time_light,                     10
665   },
666
667   {
668     EL_SHIELD_NORMAL,                   -1,
669     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
670     &li.shield_normal_time,             10
671   },
672   {
673     EL_SHIELD_NORMAL,                   -1,
674     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
675     &li.score[SC_SHIELD],               10
676   },
677
678   {
679     EL_SHIELD_DEADLY,                   -1,
680     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
681     &li.shield_deadly_time,             10
682   },
683   {
684     EL_SHIELD_DEADLY,                   -1,
685     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
686     &li.score[SC_SHIELD],               10
687   },
688
689   {
690     EL_EXTRA_TIME,                      -1,
691     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
692     &li.extra_time,                     10
693   },
694   {
695     EL_EXTRA_TIME,                      -1,
696     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
697     &li.extra_time_score,               10
698   },
699
700   {
701     EL_TIME_ORB_FULL,                   -1,
702     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
703     &li.time_orb_time,                  10
704   },
705   {
706     EL_TIME_ORB_FULL,                   -1,
707     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
708     &li.use_time_orb_bug,               FALSE
709   },
710
711   {
712     EL_SPRING,                          -1,
713     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
714     &li.use_spring_bug,                 FALSE
715   },
716
717   {
718     EL_EMC_ANDROID,                     -1,
719     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
720     &li.android_move_time,              10
721   },
722   {
723     EL_EMC_ANDROID,                     -1,
724     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
725     &li.android_clone_time,             10
726   },
727   {
728     EL_EMC_ANDROID,                     -1,
729     TYPE_ELEMENT_LIST,                  CONF_VALUE_BYTES(1),
730     &li.android_clone_element[0],       EL_EMPTY, NULL,
731     &li.num_android_clone_elements,     1, MAX_ANDROID_ELEMENTS
732   },
733
734   {
735     EL_EMC_LENSES,                      -1,
736     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
737     &li.lenses_score,                   10
738   },
739   {
740     EL_EMC_LENSES,                      -1,
741     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
742     &li.lenses_time,                    10
743   },
744
745   {
746     EL_EMC_MAGNIFIER,                   -1,
747     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
748     &li.magnify_score,                  10
749   },
750   {
751     EL_EMC_MAGNIFIER,                   -1,
752     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
753     &li.magnify_time,                   10
754   },
755
756   {
757     EL_EMC_MAGIC_BALL,                  -1,
758     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
759     &li.ball_time,                      10
760   },
761   {
762     EL_EMC_MAGIC_BALL,                  -1,
763     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
764     &li.ball_random,                    FALSE
765   },
766   {
767     EL_EMC_MAGIC_BALL,                  -1,
768     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(2),
769     &li.ball_state_initial,             FALSE
770   },
771   {
772     EL_EMC_MAGIC_BALL,                  -1,
773     TYPE_CONTENT_LIST,                  CONF_VALUE_BYTES(1),
774     &li.ball_content,                   EL_EMPTY, NULL,
775     &li.num_ball_contents,              4, MAX_ELEMENT_CONTENTS
776   },
777
778   /* ---------- unused values ----------------------------------------------- */
779
780   {
781     EL_UNKNOWN,                         SAVE_CONF_NEVER,
782     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
783     &li.score[SC_UNKNOWN_14],           10
784   },
785   {
786     EL_UNKNOWN,                         SAVE_CONF_NEVER,
787     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
788     &li.score[SC_UNKNOWN_15],           10
789   },
790
791   {
792     -1,                                 -1,
793     -1,                                 -1,
794     NULL,                               -1
795   }
796 };
797
798 static struct LevelFileConfigInfo chunk_config_NOTE[] =
799 {
800   {
801     -1,                                 -1,
802     TYPE_INTEGER,                       CONF_VALUE_8_BIT(1),
803     &xx_envelope.xsize,                 MAX_ENVELOPE_XSIZE,
804   },
805   {
806     -1,                                 -1,
807     TYPE_INTEGER,                       CONF_VALUE_8_BIT(2),
808     &xx_envelope.ysize,                 MAX_ENVELOPE_YSIZE,
809   },
810
811   {
812     -1,                                 -1,
813     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(3),
814     &xx_envelope.autowrap,              FALSE
815   },
816   {
817     -1,                                 -1,
818     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(4),
819     &xx_envelope.centered,              FALSE
820   },
821
822   {
823     -1,                                 -1,
824     TYPE_STRING,                        CONF_VALUE_BYTES(1),
825     &xx_envelope.text,                  -1, NULL,
826     &xx_string_length_unused,           -1, MAX_ENVELOPE_TEXT_LEN,
827     &xx_default_string_empty[0]
828   },
829
830   {
831     -1,                                 -1,
832     -1,                                 -1,
833     NULL,                               -1
834   }
835 };
836
837 static struct LevelFileConfigInfo chunk_config_CUSX_base[] =
838 {
839   {
840     -1,                                 -1,
841     TYPE_STRING,                        CONF_VALUE_BYTES(1),
842     &xx_ei.description[0],              -1,
843     &yy_ei.description[0],
844     &xx_string_length_unused,           -1, MAX_ELEMENT_NAME_LEN,
845     &xx_default_description[0]
846   },
847
848   {
849     -1,                                 -1,
850     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(1),
851     &xx_ei.properties[EP_BITFIELD_BASE_NR], EP_BITMASK_BASE_DEFAULT,
852     &yy_ei.properties[EP_BITFIELD_BASE_NR]
853   },
854 #if 0
855   /* (reserved) */
856   {
857     -1,                                 -1,
858     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(2),
859     &xx_ei.properties[EP_BITFIELD_BASE_NR + 1], EP_BITMASK_DEFAULT,
860     &yy_ei.properties[EP_BITFIELD_BASE_NR + 1]
861   },
862 #endif
863
864   {
865     -1,                                 -1,
866     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
867     &xx_ei.use_gfx_element,             FALSE,
868     &yy_ei.use_gfx_element
869   },
870   {
871     -1,                                 -1,
872     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
873     &xx_ei.gfx_element_initial,         EL_EMPTY_SPACE,
874     &yy_ei.gfx_element_initial
875   },
876
877   {
878     -1,                                 -1,
879     TYPE_BITFIELD,                      CONF_VALUE_8_BIT(2),
880     &xx_ei.access_direction,            MV_ALL_DIRECTIONS,
881     &yy_ei.access_direction
882   },
883
884   {
885     -1,                                 -1,
886     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
887     &xx_ei.collect_score_initial,       10,
888     &yy_ei.collect_score_initial
889   },
890   {
891     -1,                                 -1,
892     TYPE_INTEGER,                       CONF_VALUE_16_BIT(3),
893     &xx_ei.collect_count_initial,       1,
894     &yy_ei.collect_count_initial
895   },
896
897   {
898     -1,                                 -1,
899     TYPE_INTEGER,                       CONF_VALUE_16_BIT(4),
900     &xx_ei.ce_value_fixed_initial,      0,
901     &yy_ei.ce_value_fixed_initial
902   },
903   {
904     -1,                                 -1,
905     TYPE_INTEGER,                       CONF_VALUE_16_BIT(5),
906     &xx_ei.ce_value_random_initial,     0,
907     &yy_ei.ce_value_random_initial
908   },
909   {
910     -1,                                 -1,
911     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(3),
912     &xx_ei.use_last_ce_value,           FALSE,
913     &yy_ei.use_last_ce_value
914   },
915
916   {
917     -1,                                 -1,
918     TYPE_INTEGER,                       CONF_VALUE_16_BIT(6),
919     &xx_ei.push_delay_fixed,            8,
920     &yy_ei.push_delay_fixed
921   },
922   {
923     -1,                                 -1,
924     TYPE_INTEGER,                       CONF_VALUE_16_BIT(7),
925     &xx_ei.push_delay_random,           8,
926     &yy_ei.push_delay_random
927   },
928   {
929     -1,                                 -1,
930     TYPE_INTEGER,                       CONF_VALUE_16_BIT(8),
931     &xx_ei.drop_delay_fixed,            0,
932     &yy_ei.drop_delay_fixed
933   },
934   {
935     -1,                                 -1,
936     TYPE_INTEGER,                       CONF_VALUE_16_BIT(9),
937     &xx_ei.drop_delay_random,           0,
938     &yy_ei.drop_delay_random
939   },
940   {
941     -1,                                 -1,
942     TYPE_INTEGER,                       CONF_VALUE_16_BIT(10),
943     &xx_ei.move_delay_fixed,            0,
944     &yy_ei.move_delay_fixed
945   },
946   {
947     -1,                                 -1,
948     TYPE_INTEGER,                       CONF_VALUE_16_BIT(11),
949     &xx_ei.move_delay_random,           0,
950     &yy_ei.move_delay_random
951   },
952
953   {
954     -1,                                 -1,
955     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(3),
956     &xx_ei.move_pattern,                MV_ALL_DIRECTIONS,
957     &yy_ei.move_pattern
958   },
959   {
960     -1,                                 -1,
961     TYPE_BITFIELD,                      CONF_VALUE_8_BIT(4),
962     &xx_ei.move_direction_initial,      MV_START_AUTOMATIC,
963     &yy_ei.move_direction_initial
964   },
965   {
966     -1,                                 -1,
967     TYPE_INTEGER,                       CONF_VALUE_8_BIT(5),
968     &xx_ei.move_stepsize,               TILEX / 8,
969     &yy_ei.move_stepsize
970   },
971
972   {
973     -1,                                 -1,
974     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(12),
975     &xx_ei.move_enter_element,          EL_EMPTY_SPACE,
976     &yy_ei.move_enter_element
977   },
978   {
979     -1,                                 -1,
980     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(13),
981     &xx_ei.move_leave_element,          EL_EMPTY_SPACE,
982     &yy_ei.move_leave_element
983   },
984   {
985     -1,                                 -1,
986     TYPE_INTEGER,                       CONF_VALUE_8_BIT(6),
987     &xx_ei.move_leave_type,             LEAVE_TYPE_UNLIMITED,
988     &yy_ei.move_leave_type
989   },
990
991   {
992     -1,                                 -1,
993     TYPE_INTEGER,                       CONF_VALUE_8_BIT(7),
994     &xx_ei.slippery_type,               SLIPPERY_ANY_RANDOM,
995     &yy_ei.slippery_type
996   },
997
998   {
999     -1,                                 -1,
1000     TYPE_INTEGER,                       CONF_VALUE_8_BIT(8),
1001     &xx_ei.explosion_type,              EXPLODES_3X3,
1002     &yy_ei.explosion_type
1003   },
1004   {
1005     -1,                                 -1,
1006     TYPE_INTEGER,                       CONF_VALUE_16_BIT(14),
1007     &xx_ei.explosion_delay,             16,
1008     &yy_ei.explosion_delay
1009   },
1010   {
1011     -1,                                 -1,
1012     TYPE_INTEGER,                       CONF_VALUE_16_BIT(15),
1013     &xx_ei.ignition_delay,              8,
1014     &yy_ei.ignition_delay
1015   },
1016
1017   {
1018     -1,                                 -1,
1019     TYPE_CONTENT_LIST,                  CONF_VALUE_BYTES(2),
1020     &xx_ei.content,                     EL_EMPTY_SPACE,
1021     &yy_ei.content,
1022     &xx_num_contents,                   1, 1
1023   },
1024
1025   /* ---------- "num_change_pages" must be the last entry ------------------- */
1026
1027   {
1028     -1,                                 SAVE_CONF_ALWAYS,
1029     TYPE_INTEGER,                       CONF_VALUE_8_BIT(9),
1030     &xx_ei.num_change_pages,            1,
1031     &yy_ei.num_change_pages
1032   },
1033
1034   {
1035     -1,                                 -1,
1036     -1,                                 -1,
1037     NULL,                               -1,
1038     NULL
1039   }
1040 };
1041
1042 static struct LevelFileConfigInfo chunk_config_CUSX_change[] =
1043 {
1044   /* ---------- "current_change_page" must be the first entry --------------- */
1045
1046   {
1047     -1,                                 SAVE_CONF_ALWAYS,
1048     TYPE_INTEGER,                       CONF_VALUE_8_BIT(1),
1049     &xx_current_change_page,            -1
1050   },
1051
1052   /* ---------- (the remaining entries can be in any order) ----------------- */
1053
1054   {
1055     -1,                                 -1,
1056     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(2),
1057     &xx_change.can_change,              FALSE
1058   },
1059
1060   {
1061     -1,                                 -1,
1062     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(1),
1063     &xx_event_bits[0],                  0
1064   },
1065   {
1066     -1,                                 -1,
1067     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(2),
1068     &xx_event_bits[1],                  0
1069   },
1070
1071   {
1072     -1,                                 -1,
1073     TYPE_BITFIELD,                      CONF_VALUE_8_BIT(3),
1074     &xx_change.trigger_player,          CH_PLAYER_ANY
1075   },
1076   {
1077     -1,                                 -1,
1078     TYPE_BITFIELD,                      CONF_VALUE_8_BIT(4),
1079     &xx_change.trigger_side,            CH_SIDE_ANY
1080   },
1081   {
1082     -1,                                 -1,
1083     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(3),
1084     &xx_change.trigger_page,            CH_PAGE_ANY
1085   },
1086
1087   {
1088     -1,                                 -1,
1089     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
1090     &xx_change.target_element,          EL_EMPTY_SPACE
1091   },
1092
1093   {
1094     -1,                                 -1,
1095     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
1096     &xx_change.delay_fixed,             0
1097   },
1098   {
1099     -1,                                 -1,
1100     TYPE_INTEGER,                       CONF_VALUE_16_BIT(3),
1101     &xx_change.delay_random,            0
1102   },
1103   {
1104     -1,                                 -1,
1105     TYPE_INTEGER,                       CONF_VALUE_16_BIT(4),
1106     &xx_change.delay_frames,            FRAMES_PER_SECOND
1107   },
1108
1109   {
1110     -1,                                 -1,
1111     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(5),
1112     &xx_change.initial_trigger_element, EL_EMPTY_SPACE
1113   },
1114
1115   {
1116     -1,                                 -1,
1117     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(6),
1118     &xx_change.explode,                 FALSE
1119   },
1120   {
1121     -1,                                 -1,
1122     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(7),
1123     &xx_change.use_target_content,      FALSE
1124   },
1125   {
1126     -1,                                 -1,
1127     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(8),
1128     &xx_change.only_if_complete,        FALSE
1129   },
1130   {
1131     -1,                                 -1,
1132     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(9),
1133     &xx_change.use_random_replace,      FALSE
1134   },
1135   {
1136     -1,                                 -1,
1137     TYPE_INTEGER,                       CONF_VALUE_8_BIT(10),
1138     &xx_change.random_percentage,       100
1139   },
1140   {
1141     -1,                                 -1,
1142     TYPE_INTEGER,                       CONF_VALUE_8_BIT(11),
1143     &xx_change.replace_when,            CP_WHEN_EMPTY
1144   },
1145
1146   {
1147     -1,                                 -1,
1148     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(12),
1149     &xx_change.has_action,              FALSE
1150   },
1151   {
1152     -1,                                 -1,
1153     TYPE_INTEGER,                       CONF_VALUE_8_BIT(13),
1154     &xx_change.action_type,             CA_NO_ACTION
1155   },
1156   {
1157     -1,                                 -1,
1158     TYPE_INTEGER,                       CONF_VALUE_8_BIT(14),
1159     &xx_change.action_mode,             CA_MODE_UNDEFINED
1160   },
1161   {
1162     -1,                                 -1,
1163     TYPE_INTEGER,                       CONF_VALUE_16_BIT(6),
1164     &xx_change.action_arg,              CA_ARG_UNDEFINED
1165   },
1166
1167   {
1168     -1,                                 -1,
1169     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(7),
1170     &xx_change.action_element,          EL_EMPTY_SPACE
1171   },
1172
1173   {
1174     -1,                                 -1,
1175     TYPE_CONTENT_LIST,                  CONF_VALUE_BYTES(1),
1176     &xx_change.target_content,          EL_EMPTY_SPACE, NULL,
1177     &xx_num_contents,                   1, 1
1178   },
1179
1180   {
1181     -1,                                 -1,
1182     -1,                                 -1,
1183     NULL,                               -1
1184   }
1185 };
1186
1187 static struct LevelFileConfigInfo chunk_config_GRPX[] =
1188 {
1189   {
1190     -1,                                 -1,
1191     TYPE_STRING,                        CONF_VALUE_BYTES(1),
1192     &xx_ei.description[0],              -1, NULL,
1193     &xx_string_length_unused,           -1, MAX_ELEMENT_NAME_LEN,
1194     &xx_default_description[0]
1195   },
1196
1197   {
1198     -1,                                 -1,
1199     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
1200     &xx_ei.use_gfx_element,             FALSE
1201   },
1202   {
1203     -1,                                 -1,
1204     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
1205     &xx_ei.gfx_element_initial,         EL_EMPTY_SPACE
1206   },
1207
1208   {
1209     -1,                                 -1,
1210     TYPE_INTEGER,                       CONF_VALUE_8_BIT(2),
1211     &xx_group.choice_mode,              ANIM_RANDOM
1212   },
1213
1214   {
1215     -1,                                 -1,
1216     TYPE_ELEMENT_LIST,                  CONF_VALUE_BYTES(2),
1217     &xx_group.element[0],               EL_EMPTY_SPACE, NULL,
1218     &xx_group.num_elements,             1, MAX_ELEMENTS_IN_GROUP
1219   },
1220
1221   {
1222     -1,                                 -1,
1223     -1,                                 -1,
1224     NULL,                               -1
1225   }
1226 };
1227
1228 static struct LevelFileConfigInfo chunk_config_CONF[] =         /* (OBSOLETE) */
1229 {
1230   {
1231     EL_PLAYER_1,                        -1,
1232     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(9),
1233     &li.block_snap_field,               TRUE
1234   },
1235   {
1236     EL_PLAYER_1,                        -1,
1237     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(13),
1238     &li.continuous_snapping,            TRUE
1239   },
1240   {
1241     EL_PLAYER_1,                        -1,
1242     TYPE_INTEGER,                       CONF_VALUE_8_BIT(1),
1243     &li.initial_player_stepsize[0],     STEPSIZE_NORMAL
1244   },
1245   {
1246     EL_PLAYER_1,                        -1,
1247     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(10),
1248     &li.use_start_element[0],           FALSE
1249   },
1250   {
1251     EL_PLAYER_1,                        -1,
1252     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
1253     &li.start_element[0],               EL_PLAYER_1
1254   },
1255   {
1256     EL_PLAYER_1,                        -1,
1257     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(11),
1258     &li.use_artwork_element[0],         FALSE
1259   },
1260   {
1261     EL_PLAYER_1,                        -1,
1262     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(2),
1263     &li.artwork_element[0],             EL_PLAYER_1
1264   },
1265   {
1266     EL_PLAYER_1,                        -1,
1267     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(12),
1268     &li.use_explosion_element[0],       FALSE
1269   },
1270   {
1271     EL_PLAYER_1,                        -1,
1272     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(3),
1273     &li.explosion_element[0],           EL_PLAYER_1
1274   },
1275
1276   {
1277     -1,                                 -1,
1278     -1,                                 -1,
1279     NULL,                               -1
1280   }
1281 };
1282
1283 static struct
1284 {
1285   int filetype;
1286   char *id;
1287 }
1288 filetype_id_list[] =
1289 {
1290   { LEVEL_FILE_TYPE_RND,        "RND"   },
1291   { LEVEL_FILE_TYPE_BD,         "BD"    },
1292   { LEVEL_FILE_TYPE_EM,         "EM"    },
1293   { LEVEL_FILE_TYPE_SP,         "SP"    },
1294   { LEVEL_FILE_TYPE_DX,         "DX"    },
1295   { LEVEL_FILE_TYPE_SB,         "SB"    },
1296   { LEVEL_FILE_TYPE_DC,         "DC"    },
1297   { -1,                         NULL    },
1298 };
1299
1300
1301 /* ========================================================================= */
1302 /* level file functions                                                      */
1303 /* ========================================================================= */
1304
1305 static struct DateInfo getCurrentDate()
1306 {
1307   time_t epoch_seconds = time(NULL);
1308   struct tm *now = localtime(&epoch_seconds);
1309   struct DateInfo date;
1310
1311   date.year  = now->tm_year + 1900;
1312   date.month = now->tm_mon  + 1;
1313   date.day   = now->tm_mday;
1314
1315   return date;
1316 }
1317
1318 static void resetEventFlags(struct ElementChangeInfo *change)
1319 {
1320   int i;
1321
1322   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
1323     change->has_event[i] = FALSE;
1324 }
1325
1326 static void resetEventBits()
1327 {
1328   int i;
1329
1330   for (i = 0; i < NUM_CE_BITFIELDS; i++)
1331     xx_event_bits[i] = 0;
1332 }
1333
1334 static void setEventFlagsFromEventBits(struct ElementChangeInfo *change)
1335 {
1336   int i;
1337
1338   /* important: only change event flag if corresponding event bit is set
1339      (this is because all xx_event_bits[] values are loaded separately,
1340      and all xx_event_bits[] values are set back to zero before loading
1341      another value xx_event_bits[x] (each value representing 32 flags)) */
1342
1343   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
1344     if (xx_event_bits[CH_EVENT_BITFIELD_NR(i)] & CH_EVENT_BIT(i))
1345       change->has_event[i] = TRUE;
1346 }
1347
1348 static void setEventBitsFromEventFlags(struct ElementChangeInfo *change)
1349 {
1350   int i;
1351
1352   /* in contrast to the above function setEventFlagsFromEventBits(), it
1353      would also be possible to set all bits in xx_event_bits[] to 0 or 1
1354      depending on the corresponding change->has_event[i] values here, as
1355      all xx_event_bits[] values are reset in resetEventBits() before */
1356
1357   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
1358     if (change->has_event[i])
1359       xx_event_bits[CH_EVENT_BITFIELD_NR(i)] |= CH_EVENT_BIT(i);
1360 }
1361
1362 static char *getDefaultElementDescription(struct ElementInfo *ei)
1363 {
1364   static char description[MAX_ELEMENT_NAME_LEN + 1];
1365   char *default_description = (ei->custom_description != NULL ?
1366                                ei->custom_description :
1367                                ei->editor_description);
1368   int i;
1369
1370   /* always start with reliable default values */
1371   for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++)
1372     description[i] = '\0';
1373
1374   /* truncate element description to MAX_ELEMENT_NAME_LEN bytes */
1375   strncpy(description, default_description, MAX_ELEMENT_NAME_LEN);
1376
1377   return &description[0];
1378 }
1379
1380 static void setElementDescriptionToDefault(struct ElementInfo *ei)
1381 {
1382   char *default_description = getDefaultElementDescription(ei);
1383   int i;
1384
1385   for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++)
1386     ei->description[i] = default_description[i];
1387 }
1388
1389 static void setConfigToDefaultsFromConfigList(struct LevelFileConfigInfo *conf)
1390 {
1391   int i;
1392
1393   for (i = 0; conf[i].data_type != -1; i++)
1394   {
1395     int default_value = conf[i].default_value;
1396     int data_type = conf[i].data_type;
1397     int conf_type = conf[i].conf_type;
1398     int byte_mask = conf_type & CONF_MASK_BYTES;
1399
1400     if (byte_mask == CONF_MASK_MULTI_BYTES)
1401     {
1402       int default_num_entities = conf[i].default_num_entities;
1403       int max_num_entities = conf[i].max_num_entities;
1404
1405       *(int *)(conf[i].num_entities) = default_num_entities;
1406
1407       if (data_type == TYPE_STRING)
1408       {
1409         char *default_string = conf[i].default_string;
1410         char *string = (char *)(conf[i].value);
1411
1412         strncpy(string, default_string, max_num_entities);
1413       }
1414       else if (data_type == TYPE_ELEMENT_LIST)
1415       {
1416         int *element_array = (int *)(conf[i].value);
1417         int j;
1418
1419         for (j = 0; j < max_num_entities; j++)
1420           element_array[j] = default_value;
1421       }
1422       else if (data_type == TYPE_CONTENT_LIST)
1423       {
1424         struct Content *content = (struct Content *)(conf[i].value);
1425         int c, x, y;
1426
1427         for (c = 0; c < max_num_entities; c++)
1428           for (y = 0; y < 3; y++)
1429             for (x = 0; x < 3; x++)
1430               content[c].e[x][y] = default_value;
1431       }
1432     }
1433     else        /* constant size configuration data (1, 2 or 4 bytes) */
1434     {
1435       if (data_type == TYPE_BOOLEAN)
1436         *(boolean *)(conf[i].value) = default_value;
1437       else
1438         *(int *)    (conf[i].value) = default_value;
1439     }
1440   }
1441 }
1442
1443 static void copyConfigFromConfigList(struct LevelFileConfigInfo *conf)
1444 {
1445   int i;
1446
1447   for (i = 0; conf[i].data_type != -1; i++)
1448   {
1449     int data_type = conf[i].data_type;
1450     int conf_type = conf[i].conf_type;
1451     int byte_mask = conf_type & CONF_MASK_BYTES;
1452
1453     if (byte_mask == CONF_MASK_MULTI_BYTES)
1454     {
1455       int max_num_entities = conf[i].max_num_entities;
1456
1457       if (data_type == TYPE_STRING)
1458       {
1459         char *string      = (char *)(conf[i].value);
1460         char *string_copy = (char *)(conf[i].value_copy);
1461
1462         strncpy(string_copy, string, max_num_entities);
1463       }
1464       else if (data_type == TYPE_ELEMENT_LIST)
1465       {
1466         int *element_array      = (int *)(conf[i].value);
1467         int *element_array_copy = (int *)(conf[i].value_copy);
1468         int j;
1469
1470         for (j = 0; j < max_num_entities; j++)
1471           element_array_copy[j] = element_array[j];
1472       }
1473       else if (data_type == TYPE_CONTENT_LIST)
1474       {
1475         struct Content *content      = (struct Content *)(conf[i].value);
1476         struct Content *content_copy = (struct Content *)(conf[i].value_copy);
1477         int c, x, y;
1478
1479         for (c = 0; c < max_num_entities; c++)
1480           for (y = 0; y < 3; y++)
1481             for (x = 0; x < 3; x++)
1482               content_copy[c].e[x][y] = content[c].e[x][y];
1483       }
1484     }
1485     else        /* constant size configuration data (1, 2 or 4 bytes) */
1486     {
1487       if (data_type == TYPE_BOOLEAN)
1488         *(boolean *)(conf[i].value_copy) = *(boolean *)(conf[i].value);
1489       else
1490         *(int *)    (conf[i].value_copy) = *(int *)    (conf[i].value);
1491     }
1492   }
1493 }
1494
1495 void copyElementInfo(struct ElementInfo *ei_from, struct ElementInfo *ei_to)
1496 {
1497   int i;
1498
1499   xx_ei = *ei_from;     /* copy element data into temporary buffer */
1500   yy_ei = *ei_to;       /* copy element data into temporary buffer */
1501
1502   copyConfigFromConfigList(chunk_config_CUSX_base);
1503
1504   *ei_from = xx_ei;
1505   *ei_to   = yy_ei;
1506
1507   /* ---------- reinitialize and copy change pages ---------- */
1508
1509   ei_to->num_change_pages = ei_from->num_change_pages;
1510   ei_to->current_change_page = ei_from->current_change_page;
1511
1512   setElementChangePages(ei_to, ei_to->num_change_pages);
1513
1514   for (i = 0; i < ei_to->num_change_pages; i++)
1515     ei_to->change_page[i] = ei_from->change_page[i];
1516
1517   /* ---------- copy group element info ---------- */
1518   if (ei_from->group != NULL && ei_to->group != NULL)   /* group or internal */
1519     *ei_to->group = *ei_from->group;
1520
1521   /* mark this custom element as modified */
1522   ei_to->modified_settings = TRUE;
1523 }
1524
1525 void setElementChangePages(struct ElementInfo *ei, int change_pages)
1526 {
1527   int change_page_size = sizeof(struct ElementChangeInfo);
1528
1529   ei->num_change_pages = MAX(1, change_pages);
1530
1531   ei->change_page =
1532     checked_realloc(ei->change_page, ei->num_change_pages * change_page_size);
1533
1534   if (ei->current_change_page >= ei->num_change_pages)
1535     ei->current_change_page = ei->num_change_pages - 1;
1536
1537   ei->change = &ei->change_page[ei->current_change_page];
1538 }
1539
1540 void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
1541 {
1542   xx_change = *change;          /* copy change data into temporary buffer */
1543
1544 #if 0
1545   /* (not needed; set by setConfigToDefaultsFromConfigList()) */
1546   xx_num_contents = 1;
1547 #endif
1548
1549   setConfigToDefaultsFromConfigList(chunk_config_CUSX_change);
1550
1551   *change = xx_change;
1552
1553   resetEventFlags(change);
1554
1555   change->direct_action = 0;
1556   change->other_action = 0;
1557
1558   change->pre_change_function = NULL;
1559   change->change_function = NULL;
1560   change->post_change_function = NULL;
1561 }
1562
1563 static void setLevelInfoToDefaults(struct LevelInfo *level)
1564 {
1565   static boolean clipboard_elements_initialized = FALSE;
1566   int i, x, y;
1567
1568   InitElementPropertiesStatic();
1569
1570   li = *level;          /* copy level data into temporary buffer */
1571
1572   setConfigToDefaultsFromConfigList(chunk_config_INFO);
1573   setConfigToDefaultsFromConfigList(chunk_config_ELEM);
1574
1575   *level = li;          /* copy temporary buffer back to level data */
1576
1577   setLevelInfoToDefaults_EM();
1578
1579   level->native_em_level = &native_em_level;
1580
1581   level->file_version = FILE_VERSION_ACTUAL;
1582   level->game_version = GAME_VERSION_ACTUAL;
1583
1584   level->creation_date = getCurrentDate();
1585
1586   level->encoding_16bit_field  = TRUE;
1587   level->encoding_16bit_yamyam = TRUE;
1588   level->encoding_16bit_amoeba = TRUE;
1589
1590   for (x = 0; x < MAX_LEV_FIELDX; x++)
1591     for (y = 0; y < MAX_LEV_FIELDY; y++)
1592       level->field[x][y] = EL_SAND;
1593
1594   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
1595     level->name[i] = '\0';
1596   for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
1597     level->author[i] = '\0';
1598
1599   strcpy(level->name, NAMELESS_LEVEL_NAME);
1600   strcpy(level->author, ANONYMOUS_NAME);
1601
1602   level->field[0][0] = EL_PLAYER_1;
1603   level->field[STD_LEV_FIELDX - 1][STD_LEV_FIELDY - 1] = EL_EXIT_CLOSED;
1604
1605   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1606   {
1607     int element = i;
1608     struct ElementInfo *ei = &element_info[element];
1609
1610     /* never initialize clipboard elements after the very first time */
1611     /* (to be able to use clipboard elements between several levels) */
1612     if (IS_CLIPBOARD_ELEMENT(element) && clipboard_elements_initialized)
1613       continue;
1614
1615     if (IS_ENVELOPE(element))
1616     {
1617       int envelope_nr = element - EL_ENVELOPE_1;
1618
1619       setConfigToDefaultsFromConfigList(chunk_config_NOTE);
1620
1621       level->envelope[envelope_nr] = xx_envelope;
1622     }
1623
1624     if (IS_CUSTOM_ELEMENT(element) ||
1625         IS_GROUP_ELEMENT(element) ||
1626         IS_INTERNAL_ELEMENT(element))
1627     {
1628       xx_ei = *ei;      /* copy element data into temporary buffer */
1629
1630       setConfigToDefaultsFromConfigList(chunk_config_CUSX_base);
1631
1632       *ei = xx_ei;
1633     }
1634
1635     setElementChangePages(ei, 1);
1636     setElementChangeInfoToDefaults(ei->change);
1637
1638     if (IS_CUSTOM_ELEMENT(element) ||
1639         IS_GROUP_ELEMENT(element) ||
1640         IS_INTERNAL_ELEMENT(element))
1641     {
1642       setElementDescriptionToDefault(ei);
1643
1644       ei->modified_settings = FALSE;
1645     }
1646
1647     if (IS_CUSTOM_ELEMENT(element) ||
1648         IS_INTERNAL_ELEMENT(element))
1649     {
1650       /* internal values used in level editor */
1651
1652       ei->access_type = 0;
1653       ei->access_layer = 0;
1654       ei->access_protected = 0;
1655       ei->walk_to_action = 0;
1656       ei->smash_targets = 0;
1657       ei->deadliness = 0;
1658
1659       ei->can_explode_by_fire = FALSE;
1660       ei->can_explode_smashed = FALSE;
1661       ei->can_explode_impact = FALSE;
1662
1663       ei->current_change_page = 0;
1664     }
1665
1666     if (IS_GROUP_ELEMENT(element) ||
1667         IS_INTERNAL_ELEMENT(element))
1668     {
1669       struct ElementGroupInfo *group;
1670
1671       /* initialize memory for list of elements in group */
1672       if (ei->group == NULL)
1673         ei->group = checked_malloc(sizeof(struct ElementGroupInfo));
1674
1675       group = ei->group;
1676
1677       xx_group = *group;        /* copy group data into temporary buffer */
1678
1679       setConfigToDefaultsFromConfigList(chunk_config_GRPX);
1680
1681       *group = xx_group;
1682     }
1683   }
1684
1685   clipboard_elements_initialized = TRUE;
1686
1687   BorderElement = EL_STEELWALL;
1688
1689   level->no_valid_file = FALSE;
1690
1691   level->changed = FALSE;
1692
1693   /* set all bug compatibility flags to "false" => do not emulate this bug */
1694   level->use_action_after_change_bug = FALSE;
1695
1696   if (leveldir_current == NULL)         /* only when dumping level */
1697     return;
1698
1699   /* try to determine better author name than 'anonymous' */
1700   if (!strEqual(leveldir_current->author, ANONYMOUS_NAME))
1701   {
1702     strncpy(level->author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN);
1703     level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
1704   }
1705   else
1706   {
1707     switch (LEVELCLASS(leveldir_current))
1708     {
1709       case LEVELCLASS_TUTORIAL:
1710         strcpy(level->author, PROGRAM_AUTHOR_STRING);
1711         break;
1712
1713       case LEVELCLASS_CONTRIB:
1714         strncpy(level->author, leveldir_current->name, MAX_LEVEL_AUTHOR_LEN);
1715         level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
1716         break;
1717
1718       case LEVELCLASS_PRIVATE:
1719         strncpy(level->author, getRealName(), MAX_LEVEL_AUTHOR_LEN);
1720         level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
1721         break;
1722
1723       default:
1724         /* keep default value */
1725         break;
1726     }
1727   }
1728 }
1729
1730 static void setFileInfoToDefaults(struct LevelFileInfo *level_file_info)
1731 {
1732   level_file_info->nr = 0;
1733   level_file_info->type = LEVEL_FILE_TYPE_UNKNOWN;
1734   level_file_info->packed = FALSE;
1735   level_file_info->basename = NULL;
1736   level_file_info->filename = NULL;
1737 }
1738
1739 static void ActivateLevelTemplate()
1740 {
1741   /* Currently there is no special action needed to activate the template
1742      data, because 'element_info' property settings overwrite the original
1743      level data, while all other variables do not change. */
1744 }
1745
1746 static char *getLevelFilenameFromBasename(char *basename)
1747 {
1748   static char *filename = NULL;
1749
1750   checked_free(filename);
1751
1752   filename = getPath2(getCurrentLevelDir(), basename);
1753
1754   return filename;
1755 }
1756
1757 static int getFileTypeFromBasename(char *basename)
1758 {
1759   static char *filename = NULL;
1760   struct stat file_status;
1761
1762   /* ---------- try to determine file type from filename ---------- */
1763
1764   /* check for typical filename of a Supaplex level package file */
1765   if (strlen(basename) == 10 && (strncmp(basename, "levels.d", 8) == 0 ||
1766                                  strncmp(basename, "LEVELS.D", 8) == 0))
1767     return LEVEL_FILE_TYPE_SP;
1768
1769   /* check for typical filename of a Diamond Caves II level package file */
1770   if (strSuffix(basename, ".dc") ||
1771       strSuffix(basename, ".dc2"))
1772     return LEVEL_FILE_TYPE_DC;
1773
1774   /* ---------- try to determine file type from filesize ---------- */
1775
1776   checked_free(filename);
1777   filename = getPath2(getCurrentLevelDir(), basename);
1778
1779   if (stat(filename, &file_status) == 0)
1780   {
1781     /* check for typical filesize of a Supaplex level package file */
1782     if (file_status.st_size == 170496)
1783       return LEVEL_FILE_TYPE_SP;
1784   }
1785
1786   return LEVEL_FILE_TYPE_UNKNOWN;
1787 }
1788
1789 static char *getSingleLevelBasename(int nr)
1790 {
1791   static char basename[MAX_FILENAME_LEN];
1792
1793   if (nr < 0)
1794     sprintf(basename, "template.%s", LEVELFILE_EXTENSION);
1795   else
1796     sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION);
1797
1798   return basename;
1799 }
1800
1801 static char *getPackedLevelBasename(int type)
1802 {
1803   static char basename[MAX_FILENAME_LEN];
1804   char *directory = getCurrentLevelDir();
1805   DIR *dir;
1806   struct dirent *dir_entry;
1807
1808   strcpy(basename, UNDEFINED_FILENAME);         /* default: undefined file */
1809
1810   if ((dir = opendir(directory)) == NULL)
1811   {
1812     Error(ERR_WARN, "cannot read current level directory '%s'", directory);
1813
1814     return basename;
1815   }
1816
1817   while ((dir_entry = readdir(dir)) != NULL)    /* loop until last dir entry */
1818   {
1819     char *entry_basename = dir_entry->d_name;
1820     int entry_type = getFileTypeFromBasename(entry_basename);
1821
1822     if (entry_type != LEVEL_FILE_TYPE_UNKNOWN)  /* found valid level package */
1823     {
1824       if (type == LEVEL_FILE_TYPE_UNKNOWN ||
1825           type == entry_type)
1826       {
1827         strcpy(basename, entry_basename);
1828
1829         break;
1830       }
1831     }
1832   }
1833
1834   closedir(dir);
1835
1836   return basename;
1837 }
1838
1839 static char *getSingleLevelFilename(int nr)
1840 {
1841   return getLevelFilenameFromBasename(getSingleLevelBasename(nr));
1842 }
1843
1844 #if 0
1845 static char *getPackedLevelFilename(int type)
1846 {
1847   return getLevelFilenameFromBasename(getPackedLevelBasename(type));
1848 }
1849 #endif
1850
1851 char *getDefaultLevelFilename(int nr)
1852 {
1853   return getSingleLevelFilename(nr);
1854 }
1855
1856 #if 0
1857 static void setLevelFileInfo_SingleLevelFilename(struct LevelFileInfo *lfi,
1858                                                  int type)
1859 {
1860   lfi->type = type;
1861   lfi->packed = FALSE;
1862   lfi->basename = getSingleLevelBasename(lfi->nr, lfi->type);
1863   lfi->filename = getLevelFilenameFromBasename(lfi->basename);
1864 }
1865 #endif
1866
1867 static void setLevelFileInfo_FormatLevelFilename(struct LevelFileInfo *lfi,
1868                                                  int type, char *format, ...)
1869 {
1870   static char basename[MAX_FILENAME_LEN];
1871   va_list ap;
1872
1873   va_start(ap, format);
1874   vsprintf(basename, format, ap);
1875   va_end(ap);
1876
1877   lfi->type = type;
1878   lfi->packed = FALSE;
1879   lfi->basename = basename;
1880   lfi->filename = getLevelFilenameFromBasename(lfi->basename);
1881 }
1882
1883 static void setLevelFileInfo_PackedLevelFilename(struct LevelFileInfo *lfi,
1884                                                  int type)
1885 {
1886   lfi->type = type;
1887   lfi->packed = TRUE;
1888   lfi->basename = getPackedLevelBasename(lfi->type);
1889   lfi->filename = getLevelFilenameFromBasename(lfi->basename);
1890 }
1891
1892 static int getFiletypeFromID(char *filetype_id)
1893 {
1894   char *filetype_id_lower;
1895   int filetype = LEVEL_FILE_TYPE_UNKNOWN;
1896   int i;
1897
1898   if (filetype_id == NULL)
1899     return LEVEL_FILE_TYPE_UNKNOWN;
1900
1901   filetype_id_lower = getStringToLower(filetype_id);
1902
1903   for (i = 0; filetype_id_list[i].id != NULL; i++)
1904   {
1905     char *id_lower = getStringToLower(filetype_id_list[i].id);
1906     
1907     if (strEqual(filetype_id_lower, id_lower))
1908       filetype = filetype_id_list[i].filetype;
1909
1910     free(id_lower);
1911
1912     if (filetype != LEVEL_FILE_TYPE_UNKNOWN)
1913       break;
1914   }
1915
1916   free(filetype_id_lower);
1917
1918   return filetype;
1919 }
1920
1921 static void determineLevelFileInfo_Filename(struct LevelFileInfo *lfi)
1922 {
1923   int nr = lfi->nr;
1924
1925   /* special case: level number is negative => check for level template file */
1926   if (nr < 0)
1927   {
1928     setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
1929                                          "template.%s", LEVELFILE_EXTENSION);
1930
1931     /* no fallback if template file not existing */
1932     return;
1933   }
1934
1935   /* special case: check for file name/pattern specified in "levelinfo.conf" */
1936   if (leveldir_current->level_filename != NULL)
1937   {
1938     int filetype = getFiletypeFromID(leveldir_current->level_filetype);
1939
1940     setLevelFileInfo_FormatLevelFilename(lfi, filetype,
1941                                          leveldir_current->level_filename, nr);
1942     if (fileExists(lfi->filename))
1943       return;
1944   }
1945
1946   /* check for native Rocks'n'Diamonds level file */
1947   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
1948                                        "%03d.%s", nr, LEVELFILE_EXTENSION);
1949   if (fileExists(lfi->filename))
1950     return;
1951
1952   /* check for Emerald Mine level file (V1) */
1953   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "a%c%c",
1954                                        'a' + (nr / 10) % 26, '0' + nr % 10);
1955   if (fileExists(lfi->filename))
1956     return;
1957   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "A%c%c",
1958                                        'A' + (nr / 10) % 26, '0' + nr % 10);
1959   if (fileExists(lfi->filename))
1960     return;
1961
1962   /* check for Emerald Mine level file (V2 to V5) */
1963   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%d", nr);
1964   if (fileExists(lfi->filename))
1965     return;
1966
1967   /* check for Emerald Mine level file (V6 / single mode) */
1968   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02ds", nr);
1969   if (fileExists(lfi->filename))
1970     return;
1971   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dS", nr);
1972   if (fileExists(lfi->filename))
1973     return;
1974
1975   /* check for Emerald Mine level file (V6 / teamwork mode) */
1976   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dt", nr);
1977   if (fileExists(lfi->filename))
1978     return;
1979   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dT", nr);
1980   if (fileExists(lfi->filename))
1981     return;
1982
1983   /* check for various packed level file formats */
1984   setLevelFileInfo_PackedLevelFilename(lfi, LEVEL_FILE_TYPE_UNKNOWN);
1985   if (fileExists(lfi->filename))
1986     return;
1987
1988   /* no known level file found -- use default values (and fail later) */
1989   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
1990                                        "%03d.%s", nr, LEVELFILE_EXTENSION);
1991 }
1992
1993 static void determineLevelFileInfo_Filetype(struct LevelFileInfo *lfi)
1994 {
1995   if (lfi->type == LEVEL_FILE_TYPE_UNKNOWN)
1996     lfi->type = getFileTypeFromBasename(lfi->basename);
1997 }
1998
1999 static void setLevelFileInfo(struct LevelFileInfo *level_file_info, int nr)
2000 {
2001   /* always start with reliable default values */
2002   setFileInfoToDefaults(level_file_info);
2003
2004   level_file_info->nr = nr;     /* set requested level number */
2005
2006   determineLevelFileInfo_Filename(level_file_info);
2007   determineLevelFileInfo_Filetype(level_file_info);
2008 }
2009
2010 /* ------------------------------------------------------------------------- */
2011 /* functions for loading R'n'D level                                         */
2012 /* ------------------------------------------------------------------------- */
2013
2014 int getMappedElement(int element)
2015 {
2016   /* remap some (historic, now obsolete) elements */
2017
2018   switch (element)
2019   {
2020     case EL_PLAYER_OBSOLETE:
2021       element = EL_PLAYER_1;
2022       break;
2023
2024     case EL_KEY_OBSOLETE:
2025       element = EL_KEY_1;
2026
2027     case EL_EM_KEY_1_FILE_OBSOLETE:
2028       element = EL_EM_KEY_1;
2029       break;
2030
2031     case EL_EM_KEY_2_FILE_OBSOLETE:
2032       element = EL_EM_KEY_2;
2033       break;
2034
2035     case EL_EM_KEY_3_FILE_OBSOLETE:
2036       element = EL_EM_KEY_3;
2037       break;
2038
2039     case EL_EM_KEY_4_FILE_OBSOLETE:
2040       element = EL_EM_KEY_4;
2041       break;
2042
2043     case EL_ENVELOPE_OBSOLETE:
2044       element = EL_ENVELOPE_1;
2045       break;
2046
2047     case EL_SP_EMPTY:
2048       element = EL_EMPTY;
2049       break;
2050
2051     default:
2052       if (element >= NUM_FILE_ELEMENTS)
2053       {
2054         Error(ERR_WARN, "invalid level element %d", element);
2055
2056         element = EL_UNKNOWN;
2057       }
2058       break;
2059   }
2060
2061   return element;
2062 }
2063
2064 int getMappedElementByVersion(int element, int game_version)
2065 {
2066   /* remap some elements due to certain game version */
2067
2068   if (game_version <= VERSION_IDENT(2,2,0,0))
2069   {
2070     /* map game font elements */
2071     element = (element == EL_CHAR('[')  ? EL_CHAR_AUMLAUT :
2072                element == EL_CHAR('\\') ? EL_CHAR_OUMLAUT :
2073                element == EL_CHAR(']')  ? EL_CHAR_UUMLAUT :
2074                element == EL_CHAR('^')  ? EL_CHAR_COPYRIGHT : element);
2075   }
2076
2077   if (game_version < VERSION_IDENT(3,0,0,0))
2078   {
2079     /* map Supaplex gravity tube elements */
2080     element = (element == EL_SP_GRAVITY_PORT_LEFT  ? EL_SP_PORT_LEFT  :
2081                element == EL_SP_GRAVITY_PORT_RIGHT ? EL_SP_PORT_RIGHT :
2082                element == EL_SP_GRAVITY_PORT_UP    ? EL_SP_PORT_UP    :
2083                element == EL_SP_GRAVITY_PORT_DOWN  ? EL_SP_PORT_DOWN  :
2084                element);
2085   }
2086
2087   return element;
2088 }
2089
2090 static int LoadLevel_VERS(FILE *file, int chunk_size, struct LevelInfo *level)
2091 {
2092   level->file_version = getFileVersion(file);
2093   level->game_version = getFileVersion(file);
2094
2095   return chunk_size;
2096 }
2097
2098 static int LoadLevel_DATE(FILE *file, int chunk_size, struct LevelInfo *level)
2099 {
2100   level->creation_date.year  = getFile16BitBE(file);
2101   level->creation_date.month = getFile8Bit(file);
2102   level->creation_date.day   = getFile8Bit(file);
2103
2104   return chunk_size;
2105 }
2106
2107 static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
2108 {
2109   int initial_player_stepsize;
2110   int initial_player_gravity;
2111   int i, x, y;
2112
2113   level->fieldx = getFile8Bit(file);
2114   level->fieldy = getFile8Bit(file);
2115
2116   level->time           = getFile16BitBE(file);
2117   level->gems_needed    = getFile16BitBE(file);
2118
2119   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
2120     level->name[i] = getFile8Bit(file);
2121   level->name[MAX_LEVEL_NAME_LEN] = 0;
2122
2123   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
2124     level->score[i] = getFile8Bit(file);
2125
2126   level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
2127   for (i = 0; i < STD_ELEMENT_CONTENTS; i++)
2128     for (y = 0; y < 3; y++)
2129       for (x = 0; x < 3; x++)
2130         level->yamyam_content[i].e[x][y] = getMappedElement(getFile8Bit(file));
2131
2132   level->amoeba_speed           = getFile8Bit(file);
2133   level->time_magic_wall        = getFile8Bit(file);
2134   level->time_wheel             = getFile8Bit(file);
2135   level->amoeba_content         = getMappedElement(getFile8Bit(file));
2136
2137   initial_player_stepsize       = (getFile8Bit(file) == 1 ? STEPSIZE_FAST :
2138                                    STEPSIZE_NORMAL);
2139
2140   for (i = 0; i < MAX_PLAYERS; i++)
2141     level->initial_player_stepsize[i] = initial_player_stepsize;
2142
2143   initial_player_gravity        = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2144
2145   for (i = 0; i < MAX_PLAYERS; i++)
2146     level->initial_player_gravity[i] = initial_player_gravity;
2147
2148   level->encoding_16bit_field   = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2149   level->em_slippery_gems       = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2150
2151   level->use_custom_template    = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2152
2153   level->block_last_field       = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2154   level->sp_block_last_field    = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2155   level->can_move_into_acid_bits = getFile32BitBE(file);
2156   level->dont_collide_with_bits = getFile8Bit(file);
2157
2158   level->use_spring_bug         = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2159   level->use_step_counter       = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2160
2161   level->instant_relocation     = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2162   level->can_pass_to_walkable   = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2163   level->grow_into_diggable     = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2164
2165   level->game_engine_type       = getFile8Bit(file);
2166
2167   ReadUnusedBytesFromFile(file, LEVEL_CHUNK_HEAD_UNUSED);
2168
2169   return chunk_size;
2170 }
2171
2172 static int LoadLevel_NAME(FILE *file, int chunk_size, struct LevelInfo *level)
2173 {
2174   int i;
2175
2176   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
2177     level->name[i] = getFile8Bit(file);
2178   level->name[MAX_LEVEL_NAME_LEN] = 0;
2179
2180   return chunk_size;
2181 }
2182
2183 static int LoadLevel_AUTH(FILE *file, int chunk_size, struct LevelInfo *level)
2184 {
2185   int i;
2186
2187   for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
2188     level->author[i] = getFile8Bit(file);
2189   level->author[MAX_LEVEL_AUTHOR_LEN] = 0;
2190
2191   return chunk_size;
2192 }
2193
2194 static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level)
2195 {
2196   int x, y;
2197   int chunk_size_expected = level->fieldx * level->fieldy;
2198
2199   /* Note: "chunk_size" was wrong before version 2.0 when elements are
2200      stored with 16-bit encoding (and should be twice as big then).
2201      Even worse, playfield data was stored 16-bit when only yamyam content
2202      contained 16-bit elements and vice versa. */
2203
2204   if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
2205     chunk_size_expected *= 2;
2206
2207   if (chunk_size_expected != chunk_size)
2208   {
2209     ReadUnusedBytesFromFile(file, chunk_size);
2210     return chunk_size_expected;
2211   }
2212
2213   for (y = 0; y < level->fieldy; y++)
2214     for (x = 0; x < level->fieldx; x++)
2215       level->field[x][y] =
2216         getMappedElement(level->encoding_16bit_field ? getFile16BitBE(file) :
2217                          getFile8Bit(file));
2218   return chunk_size;
2219 }
2220
2221 static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
2222 {
2223   int i, x, y;
2224   int header_size = 4;
2225   int content_size = MAX_ELEMENT_CONTENTS * 3 * 3;
2226   int chunk_size_expected = header_size + content_size;
2227
2228   /* Note: "chunk_size" was wrong before version 2.0 when elements are
2229      stored with 16-bit encoding (and should be twice as big then).
2230      Even worse, playfield data was stored 16-bit when only yamyam content
2231      contained 16-bit elements and vice versa. */
2232
2233   if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
2234     chunk_size_expected += content_size;
2235
2236   if (chunk_size_expected != chunk_size)
2237   {
2238     ReadUnusedBytesFromFile(file, chunk_size);
2239     return chunk_size_expected;
2240   }
2241
2242   getFile8Bit(file);
2243   level->num_yamyam_contents = getFile8Bit(file);
2244   getFile8Bit(file);
2245   getFile8Bit(file);
2246
2247   /* correct invalid number of content fields -- should never happen */
2248   if (level->num_yamyam_contents < 1 ||
2249       level->num_yamyam_contents > MAX_ELEMENT_CONTENTS)
2250     level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
2251
2252   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
2253     for (y = 0; y < 3; y++)
2254       for (x = 0; x < 3; x++)
2255         level->yamyam_content[i].e[x][y] =
2256           getMappedElement(level->encoding_16bit_field ?
2257                            getFile16BitBE(file) : getFile8Bit(file));
2258   return chunk_size;
2259 }
2260
2261 static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
2262 {
2263   int i, x, y;
2264   int element;
2265   int num_contents, content_xsize, content_ysize;
2266   int content_array[MAX_ELEMENT_CONTENTS][3][3];
2267
2268   element = getMappedElement(getFile16BitBE(file));
2269   num_contents = getFile8Bit(file);
2270   content_xsize = getFile8Bit(file);
2271   content_ysize = getFile8Bit(file);
2272
2273   ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED);
2274
2275   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
2276     for (y = 0; y < 3; y++)
2277       for (x = 0; x < 3; x++)
2278         content_array[i][x][y] = getMappedElement(getFile16BitBE(file));
2279
2280   /* correct invalid number of content fields -- should never happen */
2281   if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS)
2282     num_contents = STD_ELEMENT_CONTENTS;
2283
2284   if (element == EL_YAMYAM)
2285   {
2286     level->num_yamyam_contents = num_contents;
2287
2288     for (i = 0; i < num_contents; i++)
2289       for (y = 0; y < 3; y++)
2290         for (x = 0; x < 3; x++)
2291           level->yamyam_content[i].e[x][y] = content_array[i][x][y];
2292   }
2293   else if (element == EL_BD_AMOEBA)
2294   {
2295     level->amoeba_content = content_array[0][0][0];
2296   }
2297   else
2298   {
2299     Error(ERR_WARN, "cannot load content for element '%d'", element);
2300   }
2301
2302   return chunk_size;
2303 }
2304
2305 static int LoadLevel_CNT3(FILE *file, int chunk_size, struct LevelInfo *level)
2306 {
2307   int i;
2308   int element;
2309   int envelope_nr;
2310   int envelope_len;
2311   int chunk_size_expected;
2312
2313   element = getMappedElement(getFile16BitBE(file));
2314   if (!IS_ENVELOPE(element))
2315     element = EL_ENVELOPE_1;
2316
2317   envelope_nr = element - EL_ENVELOPE_1;
2318
2319   envelope_len = getFile16BitBE(file);
2320
2321   level->envelope[envelope_nr].xsize = getFile8Bit(file);
2322   level->envelope[envelope_nr].ysize = getFile8Bit(file);
2323
2324   ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT3_UNUSED);
2325
2326   chunk_size_expected = LEVEL_CHUNK_CNT3_SIZE(envelope_len);
2327   if (chunk_size_expected != chunk_size)
2328   {
2329     ReadUnusedBytesFromFile(file, chunk_size - LEVEL_CHUNK_CNT3_HEADER);
2330     return chunk_size_expected;
2331   }
2332
2333   for (i = 0; i < envelope_len; i++)
2334     level->envelope[envelope_nr].text[i] = getFile8Bit(file);
2335
2336   return chunk_size;
2337 }
2338
2339 static int LoadLevel_CUS1(FILE *file, int chunk_size, struct LevelInfo *level)
2340 {
2341   int num_changed_custom_elements = getFile16BitBE(file);
2342   int chunk_size_expected = 2 + num_changed_custom_elements * 6;
2343   int i;
2344
2345   if (chunk_size_expected != chunk_size)
2346   {
2347     ReadUnusedBytesFromFile(file, chunk_size - 2);
2348     return chunk_size_expected;
2349   }
2350
2351   for (i = 0; i < num_changed_custom_elements; i++)
2352   {
2353     int element = getMappedElement(getFile16BitBE(file));
2354     int properties = getFile32BitBE(file);
2355
2356     if (IS_CUSTOM_ELEMENT(element))
2357       element_info[element].properties[EP_BITFIELD_BASE_NR] = properties;
2358     else
2359       Error(ERR_WARN, "invalid custom element number %d", element);
2360
2361     /* older game versions that wrote level files with CUS1 chunks used
2362        different default push delay values (not yet stored in level file) */
2363     element_info[element].push_delay_fixed = 2;
2364     element_info[element].push_delay_random = 8;
2365   }
2366
2367   return chunk_size;
2368 }
2369
2370 static int LoadLevel_CUS2(FILE *file, int chunk_size, struct LevelInfo *level)
2371 {
2372   int num_changed_custom_elements = getFile16BitBE(file);
2373   int chunk_size_expected = 2 + num_changed_custom_elements * 4;
2374   int i;
2375
2376   if (chunk_size_expected != chunk_size)
2377   {
2378     ReadUnusedBytesFromFile(file, chunk_size - 2);
2379     return chunk_size_expected;
2380   }
2381
2382   for (i = 0; i < num_changed_custom_elements; i++)
2383   {
2384     int element = getMappedElement(getFile16BitBE(file));
2385     int custom_target_element = getMappedElement(getFile16BitBE(file));
2386
2387     if (IS_CUSTOM_ELEMENT(element))
2388       element_info[element].change->target_element = custom_target_element;
2389     else
2390       Error(ERR_WARN, "invalid custom element number %d", element);
2391   }
2392
2393   return chunk_size;
2394 }
2395
2396 static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level)
2397 {
2398   int num_changed_custom_elements = getFile16BitBE(file);
2399   int chunk_size_expected = LEVEL_CHUNK_CUS3_SIZE(num_changed_custom_elements);
2400   int i, j, x, y;
2401
2402   if (chunk_size_expected != chunk_size)
2403   {
2404     ReadUnusedBytesFromFile(file, chunk_size - 2);
2405     return chunk_size_expected;
2406   }
2407
2408   for (i = 0; i < num_changed_custom_elements; i++)
2409   {
2410     int element = getMappedElement(getFile16BitBE(file));
2411     struct ElementInfo *ei = &element_info[element];
2412     unsigned int event_bits;
2413
2414     if (!IS_CUSTOM_ELEMENT(element))
2415     {
2416       Error(ERR_WARN, "invalid custom element number %d", element);
2417
2418       element = EL_INTERNAL_DUMMY;
2419     }
2420
2421     for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++)
2422       ei->description[j] = getFile8Bit(file);
2423     ei->description[MAX_ELEMENT_NAME_LEN] = 0;
2424
2425     ei->properties[EP_BITFIELD_BASE_NR] = getFile32BitBE(file);
2426
2427     /* some free bytes for future properties and padding */
2428     ReadUnusedBytesFromFile(file, 7);
2429
2430     ei->use_gfx_element = getFile8Bit(file);
2431     ei->gfx_element_initial = getMappedElement(getFile16BitBE(file));
2432
2433     ei->collect_score_initial = getFile8Bit(file);
2434     ei->collect_count_initial = getFile8Bit(file);
2435
2436     ei->push_delay_fixed = getFile16BitBE(file);
2437     ei->push_delay_random = getFile16BitBE(file);
2438     ei->move_delay_fixed = getFile16BitBE(file);
2439     ei->move_delay_random = getFile16BitBE(file);
2440
2441     ei->move_pattern = getFile16BitBE(file);
2442     ei->move_direction_initial = getFile8Bit(file);
2443     ei->move_stepsize = getFile8Bit(file);
2444
2445     for (y = 0; y < 3; y++)
2446       for (x = 0; x < 3; x++)
2447         ei->content.e[x][y] = getMappedElement(getFile16BitBE(file));
2448
2449     event_bits = getFile32BitBE(file);
2450     for (j = 0; j < NUM_CHANGE_EVENTS; j++)
2451       if (event_bits & (1 << j))
2452         ei->change->has_event[j] = TRUE;
2453
2454     ei->change->target_element = getMappedElement(getFile16BitBE(file));
2455
2456     ei->change->delay_fixed = getFile16BitBE(file);
2457     ei->change->delay_random = getFile16BitBE(file);
2458     ei->change->delay_frames = getFile16BitBE(file);
2459
2460     ei->change->initial_trigger_element= getMappedElement(getFile16BitBE(file));
2461
2462     ei->change->explode = getFile8Bit(file);
2463     ei->change->use_target_content = getFile8Bit(file);
2464     ei->change->only_if_complete = getFile8Bit(file);
2465     ei->change->use_random_replace = getFile8Bit(file);
2466
2467     ei->change->random_percentage = getFile8Bit(file);
2468     ei->change->replace_when = getFile8Bit(file);
2469
2470     for (y = 0; y < 3; y++)
2471       for (x = 0; x < 3; x++)
2472         ei->change->target_content.e[x][y] =
2473           getMappedElement(getFile16BitBE(file));
2474
2475     ei->slippery_type = getFile8Bit(file);
2476
2477     /* some free bytes for future properties and padding */
2478     ReadUnusedBytesFromFile(file, LEVEL_CPART_CUS3_UNUSED);
2479
2480     /* mark that this custom element has been modified */
2481     ei->modified_settings = TRUE;
2482   }
2483
2484   return chunk_size;
2485 }
2486
2487 static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
2488 {
2489   struct ElementInfo *ei;
2490   int chunk_size_expected;
2491   int element;
2492   int i, j, x, y;
2493
2494   /* ---------- custom element base property values (96 bytes) ------------- */
2495
2496   element = getMappedElement(getFile16BitBE(file));
2497
2498   if (!IS_CUSTOM_ELEMENT(element))
2499   {
2500     Error(ERR_WARN, "invalid custom element number %d", element);
2501
2502     ReadUnusedBytesFromFile(file, chunk_size - 2);
2503     return chunk_size;
2504   }
2505
2506   ei = &element_info[element];
2507
2508   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
2509     ei->description[i] = getFile8Bit(file);
2510   ei->description[MAX_ELEMENT_NAME_LEN] = 0;
2511
2512   ei->properties[EP_BITFIELD_BASE_NR] = getFile32BitBE(file);
2513
2514   ReadUnusedBytesFromFile(file, 4);     /* reserved for more base properties */
2515
2516   ei->num_change_pages = getFile8Bit(file);
2517
2518   chunk_size_expected = LEVEL_CHUNK_CUS4_SIZE(ei->num_change_pages);
2519   if (chunk_size_expected != chunk_size)
2520   {
2521     ReadUnusedBytesFromFile(file, chunk_size - 43);
2522     return chunk_size_expected;
2523   }
2524
2525   ei->ce_value_fixed_initial = getFile16BitBE(file);
2526   ei->ce_value_random_initial = getFile16BitBE(file);
2527   ei->use_last_ce_value = getFile8Bit(file);
2528
2529   ei->use_gfx_element = getFile8Bit(file);
2530   ei->gfx_element_initial = getMappedElement(getFile16BitBE(file));
2531
2532   ei->collect_score_initial = getFile8Bit(file);
2533   ei->collect_count_initial = getFile8Bit(file);
2534
2535   ei->drop_delay_fixed = getFile8Bit(file);
2536   ei->push_delay_fixed = getFile8Bit(file);
2537   ei->drop_delay_random = getFile8Bit(file);
2538   ei->push_delay_random = getFile8Bit(file);
2539   ei->move_delay_fixed = getFile16BitBE(file);
2540   ei->move_delay_random = getFile16BitBE(file);
2541
2542   /* bits 0 - 15 of "move_pattern" ... */
2543   ei->move_pattern = getFile16BitBE(file);
2544   ei->move_direction_initial = getFile8Bit(file);
2545   ei->move_stepsize = getFile8Bit(file);
2546
2547   ei->slippery_type = getFile8Bit(file);
2548
2549   for (y = 0; y < 3; y++)
2550     for (x = 0; x < 3; x++)
2551       ei->content.e[x][y] = getMappedElement(getFile16BitBE(file));
2552
2553   ei->move_enter_element = getMappedElement(getFile16BitBE(file));
2554   ei->move_leave_element = getMappedElement(getFile16BitBE(file));
2555   ei->move_leave_type = getFile8Bit(file);
2556
2557   /* ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible) */
2558   ei->move_pattern |= (getFile16BitBE(file) << 16);
2559
2560   ei->access_direction = getFile8Bit(file);
2561
2562   ei->explosion_delay = getFile8Bit(file);
2563   ei->ignition_delay = getFile8Bit(file);
2564   ei->explosion_type = getFile8Bit(file);
2565
2566   /* some free bytes for future custom property values and padding */
2567   ReadUnusedBytesFromFile(file, 1);
2568
2569   /* ---------- change page property values (48 bytes) --------------------- */
2570
2571   setElementChangePages(ei, ei->num_change_pages);
2572
2573   for (i = 0; i < ei->num_change_pages; i++)
2574   {
2575     struct ElementChangeInfo *change = &ei->change_page[i];
2576     unsigned int event_bits;
2577
2578     /* always start with reliable default values */
2579     setElementChangeInfoToDefaults(change);
2580
2581     /* bits 0 - 31 of "has_event[]" ... */
2582     event_bits = getFile32BitBE(file);
2583     for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
2584       if (event_bits & (1 << j))
2585         change->has_event[j] = TRUE;
2586
2587     change->target_element = getMappedElement(getFile16BitBE(file));
2588
2589     change->delay_fixed = getFile16BitBE(file);
2590     change->delay_random = getFile16BitBE(file);
2591     change->delay_frames = getFile16BitBE(file);
2592
2593     change->initial_trigger_element = getMappedElement(getFile16BitBE(file));
2594
2595     change->explode = getFile8Bit(file);
2596     change->use_target_content = getFile8Bit(file);
2597     change->only_if_complete = getFile8Bit(file);
2598     change->use_random_replace = getFile8Bit(file);
2599
2600     change->random_percentage = getFile8Bit(file);
2601     change->replace_when = getFile8Bit(file);
2602
2603     for (y = 0; y < 3; y++)
2604       for (x = 0; x < 3; x++)
2605         change->target_content.e[x][y]= getMappedElement(getFile16BitBE(file));
2606
2607     change->can_change = getFile8Bit(file);
2608
2609     change->trigger_side = getFile8Bit(file);
2610
2611     change->trigger_player = getFile8Bit(file);
2612     change->trigger_page = getFile8Bit(file);
2613
2614     change->trigger_page = (change->trigger_page == CH_PAGE_ANY_FILE ?
2615                             CH_PAGE_ANY : (1 << change->trigger_page));
2616
2617     change->has_action = getFile8Bit(file);
2618     change->action_type = getFile8Bit(file);
2619     change->action_mode = getFile8Bit(file);
2620     change->action_arg = getFile16BitBE(file);
2621
2622     /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */
2623     event_bits = getFile8Bit(file);
2624     for (j = 32; j < NUM_CHANGE_EVENTS; j++)
2625       if (event_bits & (1 << (j - 32)))
2626         change->has_event[j] = TRUE;
2627   }
2628
2629   /* mark this custom element as modified */
2630   ei->modified_settings = TRUE;
2631
2632   return chunk_size;
2633 }
2634
2635 static int LoadLevel_GRP1(FILE *file, int chunk_size, struct LevelInfo *level)
2636 {
2637   struct ElementInfo *ei;
2638   struct ElementGroupInfo *group;
2639   int element;
2640   int i;
2641
2642   element = getMappedElement(getFile16BitBE(file));
2643
2644   if (!IS_GROUP_ELEMENT(element))
2645   {
2646     Error(ERR_WARN, "invalid group element number %d", element);
2647
2648     ReadUnusedBytesFromFile(file, chunk_size - 2);
2649     return chunk_size;
2650   }
2651
2652   ei = &element_info[element];
2653
2654   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
2655     ei->description[i] = getFile8Bit(file);
2656   ei->description[MAX_ELEMENT_NAME_LEN] = 0;
2657
2658   group = element_info[element].group;
2659
2660   group->num_elements = getFile8Bit(file);
2661
2662   ei->use_gfx_element = getFile8Bit(file);
2663   ei->gfx_element_initial = getMappedElement(getFile16BitBE(file));
2664
2665   group->choice_mode = getFile8Bit(file);
2666
2667   /* some free bytes for future values and padding */
2668   ReadUnusedBytesFromFile(file, 3);
2669
2670   for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
2671     group->element[i] = getMappedElement(getFile16BitBE(file));
2672
2673   /* mark this group element as modified */
2674   element_info[element].modified_settings = TRUE;
2675
2676   return chunk_size;
2677 }
2678
2679 static int LoadLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *conf,
2680                                 int element, int real_element)
2681 {
2682   int micro_chunk_size = 0;
2683   int conf_type = getFile8Bit(file);
2684   int byte_mask = conf_type & CONF_MASK_BYTES;
2685   boolean element_found = FALSE;
2686   int i;
2687
2688   micro_chunk_size += 1;
2689
2690   if (byte_mask == CONF_MASK_MULTI_BYTES)
2691   {
2692     int num_bytes = getFile16BitBE(file);
2693     byte *buffer = checked_malloc(num_bytes);
2694
2695     ReadBytesFromFile(file, buffer, num_bytes);
2696
2697     for (i = 0; conf[i].data_type != -1; i++)
2698     {
2699       if (conf[i].element == element &&
2700           conf[i].conf_type == conf_type)
2701       {
2702         int data_type = conf[i].data_type;
2703         int num_entities = num_bytes / CONF_ENTITY_NUM_BYTES(data_type);
2704         int max_num_entities = conf[i].max_num_entities;
2705
2706         if (num_entities > max_num_entities)
2707         {
2708           Error(ERR_WARN,
2709                 "truncating number of entities for element %d from %d to %d",
2710                 element, num_entities, max_num_entities);
2711
2712           num_entities = max_num_entities;
2713         }
2714
2715         if (num_entities == 0 && (data_type == TYPE_ELEMENT_LIST ||
2716                                   data_type == TYPE_CONTENT_LIST))
2717         {
2718           /* for element and content lists, zero entities are not allowed */
2719           Error(ERR_WARN, "found empty list of entities for element %d",
2720                 element);
2721
2722           /* do not set "num_entities" here to prevent reading behind buffer */
2723
2724           *(int *)(conf[i].num_entities) = 1;   /* at least one is required */
2725         }
2726         else
2727         {
2728           *(int *)(conf[i].num_entities) = num_entities;
2729         }
2730
2731         element_found = TRUE;
2732
2733         if (data_type == TYPE_STRING)
2734         {
2735           char *string = (char *)(conf[i].value);
2736           int j;
2737
2738           for (j = 0; j < max_num_entities; j++)
2739             string[j] = (j < num_entities ? buffer[j] : '\0');
2740         }
2741         else if (data_type == TYPE_ELEMENT_LIST)
2742         {
2743           int *element_array = (int *)(conf[i].value);
2744           int j;
2745
2746           for (j = 0; j < num_entities; j++)
2747             element_array[j] =
2748               getMappedElement(CONF_ELEMENTS_ELEMENT(buffer, j));
2749         }
2750         else if (data_type == TYPE_CONTENT_LIST)
2751         {
2752           struct Content *content= (struct Content *)(conf[i].value);
2753           int c, x, y;
2754
2755           for (c = 0; c < num_entities; c++)
2756             for (y = 0; y < 3; y++)
2757               for (x = 0; x < 3; x++)
2758                 content[c].e[x][y] =
2759                   getMappedElement(CONF_CONTENTS_ELEMENT(buffer, c, x, y));
2760         }
2761         else
2762           element_found = FALSE;
2763
2764         break;
2765       }
2766     }
2767
2768     checked_free(buffer);
2769
2770     micro_chunk_size += 2 + num_bytes;
2771   }
2772   else          /* constant size configuration data (1, 2 or 4 bytes) */
2773   {
2774     int value = (byte_mask == CONF_MASK_1_BYTE ? getFile8Bit   (file) :
2775                  byte_mask == CONF_MASK_2_BYTE ? getFile16BitBE(file) :
2776                  byte_mask == CONF_MASK_4_BYTE ? getFile32BitBE(file) : 0);
2777
2778     for (i = 0; conf[i].data_type != -1; i++)
2779     {
2780       if (conf[i].element == element &&
2781           conf[i].conf_type == conf_type)
2782       {
2783         int data_type = conf[i].data_type;
2784
2785         if (data_type == TYPE_ELEMENT)
2786           value = getMappedElement(value);
2787
2788         if (data_type == TYPE_BOOLEAN)
2789           *(boolean *)(conf[i].value) = value;
2790         else
2791           *(int *)    (conf[i].value) = value;
2792
2793         element_found = TRUE;
2794
2795         break;
2796       }
2797     }
2798
2799     micro_chunk_size += CONF_VALUE_NUM_BYTES(byte_mask);
2800   }
2801
2802   if (!element_found)
2803   {
2804     char *error_conf_chunk_bytes =
2805       (byte_mask == CONF_MASK_1_BYTE ? "CONF_VALUE_8_BIT" :
2806        byte_mask == CONF_MASK_2_BYTE ? "CONF_VALUE_16_BIT" :
2807        byte_mask == CONF_MASK_4_BYTE ? "CONF_VALUE_32_BIT" :"CONF_VALUE_BYTES");
2808     int error_conf_chunk_token = conf_type & CONF_MASK_TOKEN;
2809     int error_element = real_element;
2810
2811     Error(ERR_WARN, "cannot load micro chunk '%s(%d)' value for element %d ['%s']",
2812           error_conf_chunk_bytes, error_conf_chunk_token,
2813           error_element, EL_NAME(error_element));
2814   }
2815
2816   return micro_chunk_size;
2817 }
2818
2819 static int LoadLevel_INFO(FILE *file, int chunk_size, struct LevelInfo *level)
2820 {
2821   int real_chunk_size = 0;
2822
2823   li = *level;          /* copy level data into temporary buffer */
2824
2825   while (!feof(file))
2826   {
2827     real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_INFO, -1, -1);
2828
2829     if (real_chunk_size >= chunk_size)
2830       break;
2831   }
2832
2833   *level = li;          /* copy temporary buffer back to level data */
2834
2835   return real_chunk_size;
2836 }
2837
2838 static int LoadLevel_CONF(FILE *file, int chunk_size, struct LevelInfo *level)
2839 {
2840   int real_chunk_size = 0;
2841
2842   li = *level;          /* copy level data into temporary buffer */
2843
2844   while (!feof(file))
2845   {
2846     int element = getMappedElement(getFile16BitBE(file));
2847
2848     real_chunk_size += 2;
2849     real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CONF,
2850                                             element, element);
2851     if (real_chunk_size >= chunk_size)
2852       break;
2853   }
2854
2855   *level = li;          /* copy temporary buffer back to level data */
2856
2857   return real_chunk_size;
2858 }
2859
2860 static int LoadLevel_ELEM(FILE *file, int chunk_size, struct LevelInfo *level)
2861 {
2862   int real_chunk_size = 0;
2863
2864   li = *level;          /* copy level data into temporary buffer */
2865
2866   while (!feof(file))
2867   {
2868     int element = getMappedElement(getFile16BitBE(file));
2869
2870     real_chunk_size += 2;
2871     real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_ELEM,
2872                                             element, element);
2873     if (real_chunk_size >= chunk_size)
2874       break;
2875   }
2876
2877   *level = li;          /* copy temporary buffer back to level data */
2878
2879   return real_chunk_size;
2880 }
2881
2882 static int LoadLevel_NOTE(FILE *file, int chunk_size, struct LevelInfo *level)
2883 {
2884   int element = getMappedElement(getFile16BitBE(file));
2885   int envelope_nr = element - EL_ENVELOPE_1;
2886   int real_chunk_size = 2;
2887
2888   while (!feof(file))
2889   {
2890     real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_NOTE,
2891                                             -1, element);
2892
2893     if (real_chunk_size >= chunk_size)
2894       break;
2895   }
2896
2897   level->envelope[envelope_nr] = xx_envelope;
2898
2899   return real_chunk_size;
2900 }
2901
2902 static int LoadLevel_CUSX(FILE *file, int chunk_size, struct LevelInfo *level)
2903 {
2904   int element = getMappedElement(getFile16BitBE(file));
2905   int real_chunk_size = 2;
2906   struct ElementInfo *ei = &element_info[element];
2907   int i;
2908
2909   xx_ei = *ei;          /* copy element data into temporary buffer */
2910
2911   xx_ei.num_change_pages = -1;
2912
2913   while (!feof(file))
2914   {
2915     real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CUSX_base,
2916                                             -1, element);
2917     if (xx_ei.num_change_pages != -1)
2918       break;
2919
2920     if (real_chunk_size >= chunk_size)
2921       break;
2922   }
2923
2924   *ei = xx_ei;
2925
2926   if (ei->num_change_pages == -1)
2927   {
2928     Error(ERR_WARN, "LoadLevel_CUSX(): missing 'num_change_pages' for '%s'",
2929           EL_NAME(element));
2930
2931     ei->num_change_pages = 1;
2932
2933     setElementChangePages(ei, 1);
2934     setElementChangeInfoToDefaults(ei->change);
2935
2936     return real_chunk_size;
2937   }
2938
2939   /* initialize number of change pages stored for this custom element */
2940   setElementChangePages(ei, ei->num_change_pages);
2941   for (i = 0; i < ei->num_change_pages; i++)
2942     setElementChangeInfoToDefaults(&ei->change_page[i]);
2943
2944   /* start with reading properties for the first change page */
2945   xx_current_change_page = 0;
2946
2947   while (!feof(file))
2948   {
2949     struct ElementChangeInfo *change = &ei->change_page[xx_current_change_page];
2950
2951     xx_change = *change;        /* copy change data into temporary buffer */
2952
2953     resetEventBits();           /* reset bits; change page might have changed */
2954
2955     real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CUSX_change,
2956                                             -1, element);
2957
2958     *change = xx_change;
2959
2960     setEventFlagsFromEventBits(change);
2961
2962     if (real_chunk_size >= chunk_size)
2963       break;
2964   }
2965
2966   return real_chunk_size;
2967 }
2968
2969 static int LoadLevel_GRPX(FILE *file, int chunk_size, struct LevelInfo *level)
2970 {
2971   int element = getMappedElement(getFile16BitBE(file));
2972   int real_chunk_size = 2;
2973   struct ElementInfo *ei = &element_info[element];
2974   struct ElementGroupInfo *group = ei->group;
2975
2976   xx_ei = *ei;          /* copy element data into temporary buffer */
2977   xx_group = *group;    /* copy group data into temporary buffer */
2978
2979   while (!feof(file))
2980   {
2981     real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_GRPX,
2982                                             -1, element);
2983
2984     if (real_chunk_size >= chunk_size)
2985       break;
2986   }
2987
2988   *ei = xx_ei;
2989   *group = xx_group;
2990
2991   return real_chunk_size;
2992 }
2993
2994 static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
2995                                       struct LevelFileInfo *level_file_info)
2996 {
2997   char *filename = level_file_info->filename;
2998   char cookie[MAX_LINE_LEN];
2999   char chunk_name[CHUNK_ID_LEN + 1];
3000   int chunk_size;
3001   FILE *file;
3002
3003   if (!(file = fopen(filename, MODE_READ)))
3004   {
3005     level->no_valid_file = TRUE;
3006
3007     if (level != &level_template)
3008       Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
3009
3010     return;
3011   }
3012
3013   getFileChunkBE(file, chunk_name, NULL);
3014   if (strEqual(chunk_name, "RND1"))
3015   {
3016     getFile32BitBE(file);               /* not used */
3017
3018     getFileChunkBE(file, chunk_name, NULL);
3019     if (!strEqual(chunk_name, "CAVE"))
3020     {
3021       level->no_valid_file = TRUE;
3022
3023       Error(ERR_WARN, "unknown format of level file '%s'", filename);
3024       fclose(file);
3025       return;
3026     }
3027   }
3028   else  /* check for pre-2.0 file format with cookie string */
3029   {
3030     strcpy(cookie, chunk_name);
3031     fgets(&cookie[4], MAX_LINE_LEN - 4, file);
3032     if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
3033       cookie[strlen(cookie) - 1] = '\0';
3034
3035     if (!checkCookieString(cookie, LEVEL_COOKIE_TMPL))
3036     {
3037       level->no_valid_file = TRUE;
3038
3039       Error(ERR_WARN, "unknown format of level file '%s'", filename);
3040       fclose(file);
3041       return;
3042     }
3043
3044     if ((level->file_version = getFileVersionFromCookieString(cookie)) == -1)
3045     {
3046       level->no_valid_file = TRUE;
3047
3048       Error(ERR_WARN, "unsupported version of level file '%s'", filename);
3049       fclose(file);
3050       return;
3051     }
3052
3053     /* pre-2.0 level files have no game version, so use file version here */
3054     level->game_version = level->file_version;
3055   }
3056
3057   if (level->file_version < FILE_VERSION_1_2)
3058   {
3059     /* level files from versions before 1.2.0 without chunk structure */
3060     LoadLevel_HEAD(file, LEVEL_CHUNK_HEAD_SIZE,         level);
3061     LoadLevel_BODY(file, level->fieldx * level->fieldy, level);
3062   }
3063   else
3064   {
3065     static struct
3066     {
3067       char *name;
3068       int size;
3069       int (*loader)(FILE *, int, struct LevelInfo *);
3070     }
3071     chunk_info[] =
3072     {
3073       { "VERS", LEVEL_CHUNK_VERS_SIZE,  LoadLevel_VERS },
3074       { "DATE", LEVEL_CHUNK_DATE_SIZE,  LoadLevel_DATE },
3075       { "HEAD", LEVEL_CHUNK_HEAD_SIZE,  LoadLevel_HEAD },
3076       { "NAME", LEVEL_CHUNK_NAME_SIZE,  LoadLevel_NAME },
3077       { "AUTH", LEVEL_CHUNK_AUTH_SIZE,  LoadLevel_AUTH },
3078       { "INFO", -1,                     LoadLevel_INFO },
3079       { "BODY", -1,                     LoadLevel_BODY },
3080       { "CONT", -1,                     LoadLevel_CONT },
3081       { "CNT2", LEVEL_CHUNK_CNT2_SIZE,  LoadLevel_CNT2 },
3082       { "CNT3", -1,                     LoadLevel_CNT3 },
3083       { "CUS1", -1,                     LoadLevel_CUS1 },
3084       { "CUS2", -1,                     LoadLevel_CUS2 },
3085       { "CUS3", -1,                     LoadLevel_CUS3 },
3086       { "CUS4", -1,                     LoadLevel_CUS4 },
3087       { "GRP1", -1,                     LoadLevel_GRP1 },
3088       { "CONF", -1,                     LoadLevel_CONF },
3089       { "ELEM", -1,                     LoadLevel_ELEM },
3090       { "NOTE", -1,                     LoadLevel_NOTE },
3091       { "CUSX", -1,                     LoadLevel_CUSX },
3092       { "GRPX", -1,                     LoadLevel_GRPX },
3093
3094       {  NULL,  0,                      NULL }
3095     };
3096
3097     while (getFileChunkBE(file, chunk_name, &chunk_size))
3098     {
3099       int i = 0;
3100
3101       while (chunk_info[i].name != NULL &&
3102              !strEqual(chunk_name, chunk_info[i].name))
3103         i++;
3104
3105       if (chunk_info[i].name == NULL)
3106       {
3107         Error(ERR_WARN, "unknown chunk '%s' in level file '%s'",
3108               chunk_name, filename);
3109         ReadUnusedBytesFromFile(file, chunk_size);
3110       }
3111       else if (chunk_info[i].size != -1 &&
3112                chunk_info[i].size != chunk_size)
3113       {
3114         Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
3115               chunk_size, chunk_name, filename);
3116         ReadUnusedBytesFromFile(file, chunk_size);
3117       }
3118       else
3119       {
3120         /* call function to load this level chunk */
3121         int chunk_size_expected =
3122           (chunk_info[i].loader)(file, chunk_size, level);
3123
3124         /* the size of some chunks cannot be checked before reading other
3125            chunks first (like "HEAD" and "BODY") that contain some header
3126            information, so check them here */
3127         if (chunk_size_expected != chunk_size)
3128         {
3129           Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
3130                 chunk_size, chunk_name, filename);
3131         }
3132       }
3133     }
3134   }
3135
3136   fclose(file);
3137 }
3138
3139 /* ------------------------------------------------------------------------- */
3140 /* functions for loading EM level                                            */
3141 /* ------------------------------------------------------------------------- */
3142
3143 #if 0
3144
3145 static int map_em_element_yam(int element)
3146 {
3147   switch (element)
3148   {
3149     case 0x00:  return EL_EMPTY;
3150     case 0x01:  return EL_EMERALD;
3151     case 0x02:  return EL_DIAMOND;
3152     case 0x03:  return EL_ROCK;
3153     case 0x04:  return EL_ROBOT;
3154     case 0x05:  return EL_SPACESHIP_UP;
3155     case 0x06:  return EL_BOMB;
3156     case 0x07:  return EL_BUG_UP;
3157     case 0x08:  return EL_AMOEBA_DROP;
3158     case 0x09:  return EL_NUT;
3159     case 0x0a:  return EL_YAMYAM;
3160     case 0x0b:  return EL_QUICKSAND_FULL;
3161     case 0x0c:  return EL_SAND;
3162     case 0x0d:  return EL_WALL_SLIPPERY;
3163     case 0x0e:  return EL_STEELWALL;
3164     case 0x0f:  return EL_WALL;
3165     case 0x10:  return EL_EM_KEY_1;
3166     case 0x11:  return EL_EM_KEY_2;
3167     case 0x12:  return EL_EM_KEY_4;
3168     case 0x13:  return EL_EM_KEY_3;
3169     case 0x14:  return EL_MAGIC_WALL;
3170     case 0x15:  return EL_ROBOT_WHEEL;
3171     case 0x16:  return EL_DYNAMITE;
3172
3173     case 0x17:  return EL_EM_KEY_1;                     /* EMC */
3174     case 0x18:  return EL_BUG_UP;                       /* EMC */
3175     case 0x1a:  return EL_DIAMOND;                      /* EMC */
3176     case 0x1b:  return EL_EMERALD;                      /* EMC */
3177     case 0x25:  return EL_NUT;                          /* EMC */
3178     case 0x80:  return EL_EMPTY;                        /* EMC */
3179     case 0x85:  return EL_EM_KEY_1;                     /* EMC */
3180     case 0x86:  return EL_EM_KEY_2;                     /* EMC */
3181     case 0x87:  return EL_EM_KEY_4;                     /* EMC */
3182     case 0x88:  return EL_EM_KEY_3;                     /* EMC */
3183     case 0x94:  return EL_QUICKSAND_EMPTY;              /* EMC */
3184     case 0x9a:  return EL_AMOEBA_WET;                   /* EMC */
3185     case 0xaf:  return EL_DYNAMITE;                     /* EMC */
3186     case 0xbd:  return EL_SAND;                         /* EMC */
3187
3188     default:
3189       Error(ERR_WARN, "invalid level element %d", element);
3190       return EL_UNKNOWN;
3191   }
3192 }
3193
3194 static int map_em_element_field(int element)
3195 {
3196   if (element >= 0xc8 && element <= 0xe1)
3197     return EL_CHAR_A + (element - 0xc8);
3198   else if (element >= 0xe2 && element <= 0xeb)
3199     return EL_CHAR_0 + (element - 0xe2);
3200
3201   switch (element)
3202   {
3203     case 0x00:  return EL_ROCK;
3204     case 0x01:  return EL_ROCK;                         /* EMC */
3205     case 0x02:  return EL_DIAMOND;
3206     case 0x03:  return EL_DIAMOND;
3207     case 0x04:  return EL_ROBOT;
3208     case 0x05:  return EL_ROBOT;                        /* EMC */
3209     case 0x06:  return EL_EMPTY_SPACE;                  /* EMC */
3210     case 0x07:  return EL_EMPTY_SPACE;                  /* EMC */
3211     case 0x08:  return EL_SPACESHIP_UP;
3212     case 0x09:  return EL_SPACESHIP_RIGHT;
3213     case 0x0a:  return EL_SPACESHIP_DOWN;
3214     case 0x0b:  return EL_SPACESHIP_LEFT;
3215     case 0x0c:  return EL_SPACESHIP_UP;
3216     case 0x0d:  return EL_SPACESHIP_RIGHT;
3217     case 0x0e:  return EL_SPACESHIP_DOWN;
3218     case 0x0f:  return EL_SPACESHIP_LEFT;
3219
3220     case 0x10:  return EL_BOMB;
3221     case 0x11:  return EL_BOMB;                         /* EMC */
3222     case 0x12:  return EL_EMERALD;
3223     case 0x13:  return EL_EMERALD;
3224     case 0x14:  return EL_BUG_UP;
3225     case 0x15:  return EL_BUG_RIGHT;
3226     case 0x16:  return EL_BUG_DOWN;
3227     case 0x17:  return EL_BUG_LEFT;
3228     case 0x18:  return EL_BUG_UP;
3229     case 0x19:  return EL_BUG_RIGHT;
3230     case 0x1a:  return EL_BUG_DOWN;
3231     case 0x1b:  return EL_BUG_LEFT;
3232     case 0x1c:  return EL_AMOEBA_DROP;
3233     case 0x1d:  return EL_AMOEBA_DROP;                  /* EMC */
3234     case 0x1e:  return EL_AMOEBA_DROP;                  /* EMC */
3235     case 0x1f:  return EL_AMOEBA_DROP;                  /* EMC */
3236
3237     case 0x20:  return EL_ROCK;
3238     case 0x21:  return EL_BOMB;                         /* EMC */
3239     case 0x22:  return EL_DIAMOND;                      /* EMC */
3240     case 0x23:  return EL_EMERALD;                      /* EMC */
3241     case 0x24:  return EL_MAGIC_WALL;
3242     case 0x25:  return EL_NUT;
3243     case 0x26:  return EL_NUT;                          /* EMC */
3244     case 0x27:  return EL_NUT;                          /* EMC */
3245
3246       /* looks like magic wheel, but is _always_ activated */
3247     case 0x28:  return EL_ROBOT_WHEEL;                  /* EMC */
3248
3249     case 0x29:  return EL_YAMYAM;       /* up */
3250     case 0x2a:  return EL_YAMYAM;       /* down */
3251     case 0x2b:  return EL_YAMYAM;       /* left */      /* EMC */
3252     case 0x2c:  return EL_YAMYAM;       /* right */     /* EMC */
3253     case 0x2d:  return EL_QUICKSAND_FULL;
3254     case 0x2e:  return EL_EMPTY_SPACE;                  /* EMC */
3255     case 0x2f:  return EL_EMPTY_SPACE;                  /* EMC */
3256
3257     case 0x30:  return EL_EMPTY_SPACE;                  /* EMC */
3258     case 0x31:  return EL_SAND;                         /* EMC */
3259     case 0x32:  return EL_SAND;                         /* EMC */
3260     case 0x33:  return EL_SAND;                         /* EMC */
3261     case 0x34:  return EL_QUICKSAND_FULL;               /* EMC */
3262     case 0x35:  return EL_QUICKSAND_FULL;               /* EMC */
3263     case 0x36:  return EL_QUICKSAND_FULL;               /* EMC */
3264     case 0x37:  return EL_SAND;                         /* EMC */
3265     case 0x38:  return EL_ROCK;                         /* EMC */
3266     case 0x39:  return EL_EXPANDABLE_WALL_HORIZONTAL;   /* EMC */
3267     case 0x3a:  return EL_EXPANDABLE_WALL_VERTICAL;     /* EMC */
3268     case 0x3b:  return EL_DYNAMITE_ACTIVE;      /* 1 */
3269     case 0x3c:  return EL_DYNAMITE_ACTIVE;      /* 2 */
3270     case 0x3d:  return EL_DYNAMITE_ACTIVE;      /* 3 */
3271     case 0x3e:  return EL_DYNAMITE_ACTIVE;      /* 4 */
3272     case 0x3f:  return EL_ACID_POOL_BOTTOM;
3273
3274     case 0x40:  return EL_EXIT_OPEN;    /* 1 */
3275     case 0x41:  return EL_EXIT_OPEN;    /* 2 */
3276     case 0x42:  return EL_EXIT_OPEN;    /* 3 */
3277     case 0x43:  return EL_BALLOON;                      /* EMC */
3278     case 0x44:  return EL_UNKNOWN;                      /* EMC ("plant") */
3279     case 0x45:  return EL_SPRING;                       /* EMC */
3280     case 0x46:  return EL_SPRING;       /* falling */   /* EMC */
3281     case 0x47:  return EL_SPRING;       /* left */      /* EMC */
3282     case 0x48:  return EL_SPRING;       /* right */     /* EMC */
3283     case 0x49:  return EL_UNKNOWN;                      /* EMC ("ball 1") */
3284     case 0x4a:  return EL_UNKNOWN;                      /* EMC ("ball 2") */
3285     case 0x4b:  return EL_UNKNOWN;                      /* EMC ("android") */
3286     case 0x4c:  return EL_EMPTY_SPACE;                  /* EMC */
3287     case 0x4d:  return EL_UNKNOWN;                      /* EMC ("android") */
3288     case 0x4e:  return EL_INVISIBLE_WALL;               /* EMC (? "android") */
3289     case 0x4f:  return EL_UNKNOWN;                      /* EMC ("android") */
3290
3291     case 0x50:  return EL_UNKNOWN;                      /* EMC ("android") */
3292     case 0x51:  return EL_UNKNOWN;                      /* EMC ("android") */
3293     case 0x52:  return EL_UNKNOWN;                      /* EMC ("android") */
3294     case 0x53:  return EL_UNKNOWN;                      /* EMC ("android") */
3295     case 0x54:  return EL_UNKNOWN;                      /* EMC ("android") */
3296     case 0x55:  return EL_EMPTY_SPACE;                  /* EMC */
3297     case 0x56:  return EL_EMPTY_SPACE;                  /* EMC */
3298     case 0x57:  return EL_EMPTY_SPACE;                  /* EMC */
3299     case 0x58:  return EL_EMPTY_SPACE;                  /* EMC */
3300     case 0x59:  return EL_EMPTY_SPACE;                  /* EMC */
3301     case 0x5a:  return EL_EMPTY_SPACE;                  /* EMC */
3302     case 0x5b:  return EL_EMPTY_SPACE;                  /* EMC */
3303     case 0x5c:  return EL_EMPTY_SPACE;                  /* EMC */
3304     case 0x5d:  return EL_EMPTY_SPACE;                  /* EMC */
3305     case 0x5e:  return EL_EMPTY_SPACE;                  /* EMC */
3306     case 0x5f:  return EL_EMPTY_SPACE;                  /* EMC */
3307
3308     case 0x60:  return EL_EMPTY_SPACE;                  /* EMC */
3309     case 0x61:  return EL_EMPTY_SPACE;                  /* EMC */
3310     case 0x62:  return EL_EMPTY_SPACE;                  /* EMC */
3311     case 0x63:  return EL_SPRING;       /* left */      /* EMC */
3312     case 0x64:  return EL_SPRING;       /* right */     /* EMC */
3313     case 0x65:  return EL_ACID;         /* 1 */         /* EMC */
3314     case 0x66:  return EL_ACID;         /* 2 */         /* EMC */
3315     case 0x67:  return EL_ACID;         /* 3 */         /* EMC */
3316     case 0x68:  return EL_ACID;         /* 4 */         /* EMC */
3317     case 0x69:  return EL_ACID;         /* 5 */         /* EMC */
3318     case 0x6a:  return EL_ACID;         /* 6 */         /* EMC */
3319     case 0x6b:  return EL_ACID;         /* 7 */         /* EMC */
3320     case 0x6c:  return EL_ACID;         /* 8 */         /* EMC */
3321     case 0x6d:  return EL_EMPTY_SPACE;                  /* EMC */
3322     case 0x6e:  return EL_EMPTY_SPACE;                  /* EMC */
3323     case 0x6f:  return EL_EMPTY_SPACE;                  /* EMC */
3324
3325     case 0x70:  return EL_EMPTY_SPACE;                  /* EMC */
3326     case 0x71:  return EL_EMPTY_SPACE;                  /* EMC */
3327     case 0x72:  return EL_NUT;          /* left */      /* EMC */
3328     case 0x73:  return EL_SAND;                         /* EMC (? "nut") */
3329     case 0x74:  return EL_STEELWALL;
3330     case 0x75:  return EL_EMPTY_SPACE;                  /* EMC */
3331     case 0x76:  return EL_EMPTY_SPACE;                  /* EMC */
3332     case 0x77:  return EL_BOMB;         /* left */      /* EMC */
3333     case 0x78:  return EL_BOMB;         /* right */     /* EMC */
3334     case 0x79:  return EL_ROCK;         /* left */      /* EMC */
3335     case 0x7a:  return EL_ROCK;         /* right */     /* EMC */
3336     case 0x7b:  return EL_ACID;                         /* (? EMC "blank") */
3337     case 0x7c:  return EL_EMPTY_SPACE;                  /* EMC */
3338     case 0x7d:  return EL_EMPTY_SPACE;                  /* EMC */
3339     case 0x7e:  return EL_EMPTY_SPACE;                  /* EMC */
3340     case 0x7f:  return EL_EMPTY_SPACE;                  /* EMC */
3341
3342     case 0x80:  return EL_EMPTY;
3343     case 0x81:  return EL_WALL_SLIPPERY;
3344     case 0x82:  return EL_SAND;
3345     case 0x83:  return EL_STEELWALL;
3346     case 0x84:  return EL_WALL;
3347     case 0x85:  return EL_EM_KEY_1;
3348     case 0x86:  return EL_EM_KEY_2;
3349     case 0x87:  return EL_EM_KEY_4;
3350     case 0x88:  return EL_EM_KEY_3;
3351     case 0x89:  return EL_EM_GATE_1;
3352     case 0x8a:  return EL_EM_GATE_2;
3353     case 0x8b:  return EL_EM_GATE_4;
3354     case 0x8c:  return EL_EM_GATE_3;
3355     case 0x8d:  return EL_INVISIBLE_WALL;               /* EMC (? "dripper") */
3356     case 0x8e:  return EL_EM_GATE_1_GRAY;
3357     case 0x8f:  return EL_EM_GATE_2_GRAY;
3358
3359     case 0x90:  return EL_EM_GATE_4_GRAY;
3360     case 0x91:  return EL_EM_GATE_3_GRAY;
3361     case 0x92:  return EL_MAGIC_WALL;
3362     case 0x93:  return EL_ROBOT_WHEEL;
3363     case 0x94:  return EL_QUICKSAND_EMPTY;              /* (? EMC "sand") */
3364     case 0x95:  return EL_ACID_POOL_TOPLEFT;
3365     case 0x96:  return EL_ACID_POOL_TOPRIGHT;
3366     case 0x97:  return EL_ACID_POOL_BOTTOMLEFT;
3367     case 0x98:  return EL_ACID_POOL_BOTTOMRIGHT;
3368     case 0x99:  return EL_ACID;                 /* (? EMC "fake blank") */
3369     case 0x9a:  return EL_AMOEBA_DEAD;          /* 1 */
3370     case 0x9b:  return EL_AMOEBA_DEAD;          /* 2 */
3371     case 0x9c:  return EL_AMOEBA_DEAD;          /* 3 */
3372     case 0x9d:  return EL_AMOEBA_DEAD;          /* 4 */
3373     case 0x9e:  return EL_EXIT_CLOSED;
3374     case 0x9f:  return EL_CHAR_LESS;            /* arrow left */
3375
3376       /* looks like normal sand, but behaves like wall */
3377     case 0xa0:  return EL_UNKNOWN;              /* EMC ("fake grass") */
3378     case 0xa1:  return EL_UNKNOWN;              /* EMC ("lenses") */
3379     case 0xa2:  return EL_UNKNOWN;              /* EMC ("magnify") */
3380     case 0xa3:  return EL_UNKNOWN;              /* EMC ("fake blank") */
3381     case 0xa4:  return EL_UNKNOWN;              /* EMC ("fake grass") */
3382     case 0xa5:  return EL_UNKNOWN;              /* EMC ("switch") */
3383     case 0xa6:  return EL_UNKNOWN;              /* EMC ("switch") */
3384     case 0xa7:  return EL_EMPTY_SPACE;                  /* EMC */
3385     case 0xa8:  return EL_EMC_WALL_1;                   /* EMC ("decor 8") */
3386     case 0xa9:  return EL_EMC_WALL_2;                   /* EMC ("decor 9") */
3387     case 0xaa:  return EL_EMC_WALL_3;                   /* EMC ("decor 10") */
3388     case 0xab:  return EL_EMC_WALL_7;                   /* EMC ("decor 5") */
3389     case 0xac:  return EL_CHAR_COMMA;                   /* EMC */
3390     case 0xad:  return EL_CHAR_QUOTEDBL;                /* EMC */
3391     case 0xae:  return EL_CHAR_MINUS;                   /* EMC */
3392     case 0xaf:  return EL_DYNAMITE;
3393
3394     case 0xb0:  return EL_EMC_STEELWALL_1;              /* EMC ("steel 3") */
3395     case 0xb1:  return EL_EMC_WALL_8;                   /* EMC ("decor 6") */
3396     case 0xb2:  return EL_UNKNOWN;                      /* EMC ("decor 7") */
3397     case 0xb3:  return EL_STEELWALL;            /* 2 */ /* EMC */
3398     case 0xb4:  return EL_WALL_SLIPPERY;        /* 2 */ /* EMC */
3399     case 0xb5:  return EL_EMC_WALL_6;                   /* EMC ("decor 2") */
3400     case 0xb6:  return EL_EMC_WALL_5;                   /* EMC ("decor 4") */
3401     case 0xb7:  return EL_EMC_WALL_4;                   /* EMC ("decor 3") */
3402     case 0xb8:  return EL_BALLOON_SWITCH_ANY;           /* EMC */
3403     case 0xb9:  return EL_BALLOON_SWITCH_RIGHT;         /* EMC */
3404     case 0xba:  return EL_BALLOON_SWITCH_DOWN;          /* EMC */
3405     case 0xbb:  return EL_BALLOON_SWITCH_LEFT;          /* EMC */
3406     case 0xbc:  return EL_BALLOON_SWITCH_UP;            /* EMC */
3407     case 0xbd:  return EL_SAND;                         /* EMC ("dirt") */
3408     case 0xbe:  return EL_UNKNOWN;                      /* EMC ("plant") */
3409     case 0xbf:  return EL_UNKNOWN;                      /* EMC ("key 5") */
3410
3411     case 0xc0:  return EL_UNKNOWN;                      /* EMC ("key 6") */
3412     case 0xc1:  return EL_UNKNOWN;                      /* EMC ("key 7") */
3413     case 0xc2:  return EL_UNKNOWN;                      /* EMC ("key 8") */
3414     case 0xc3:  return EL_UNKNOWN;                      /* EMC ("door 5") */
3415     case 0xc4:  return EL_UNKNOWN;                      /* EMC ("door 6") */
3416     case 0xc5:  return EL_UNKNOWN;                      /* EMC ("door 7") */
3417     case 0xc6:  return EL_UNKNOWN;                      /* EMC ("door 8") */
3418     case 0xc7:  return EL_UNKNOWN;                      /* EMC ("bumper") */
3419
3420       /* characters: see above */
3421
3422     case 0xec:  return EL_CHAR_PERIOD;
3423     case 0xed:  return EL_CHAR_EXCLAM;
3424     case 0xee:  return EL_CHAR_COLON;
3425     case 0xef:  return EL_CHAR_QUESTION;
3426
3427     case 0xf0:  return EL_CHAR_GREATER;                 /* arrow right */
3428     case 0xf1:  return EL_CHAR_COPYRIGHT;               /* EMC: "decor 1" */
3429     case 0xf2:  return EL_UNKNOWN;              /* EMC ("fake door 5") */
3430     case 0xf3:  return EL_UNKNOWN;              /* EMC ("fake door 6") */
3431     case 0xf4:  return EL_UNKNOWN;              /* EMC ("fake door 7") */
3432     case 0xf5:  return EL_UNKNOWN;              /* EMC ("fake door 8") */
3433     case 0xf6:  return EL_EMPTY_SPACE;                  /* EMC */
3434     case 0xf7:  return EL_EMPTY_SPACE;                  /* EMC */
3435
3436     case 0xf8:  return EL_EMPTY_SPACE;                  /* EMC */
3437     case 0xf9:  return EL_EMPTY_SPACE;                  /* EMC */
3438     case 0xfa:  return EL_EMPTY_SPACE;                  /* EMC */
3439     case 0xfb:  return EL_EMPTY_SPACE;                  /* EMC */
3440     case 0xfc:  return EL_EMPTY_SPACE;                  /* EMC */
3441     case 0xfd:  return EL_EMPTY_SPACE;                  /* EMC */
3442
3443     case 0xfe:  return EL_PLAYER_1;                     /* EMC: "blank" */
3444     case 0xff:  return EL_PLAYER_2;                     /* EMC: "blank" */
3445
3446     default:
3447       /* should never happen (all 8-bit value cases should be handled) */
3448       Error(ERR_WARN, "invalid level element %d", element);
3449       return EL_UNKNOWN;
3450   }
3451 }
3452
3453 #define EM_LEVEL_SIZE                   2106
3454 #define EM_LEVEL_XSIZE                  64
3455 #define EM_LEVEL_YSIZE                  32
3456
3457 static void OLD_LoadLevelFromFileInfo_EM(struct LevelInfo *level,
3458                                          struct LevelFileInfo *level_file_info)
3459 {
3460   char *filename = level_file_info->filename;
3461   FILE *file;
3462   unsigned char leveldata[EM_LEVEL_SIZE];
3463   unsigned char *header = &leveldata[EM_LEVEL_XSIZE * EM_LEVEL_YSIZE];
3464   int nr = level_file_info->nr;
3465   int i, x, y;
3466
3467   if (!(file = fopen(filename, MODE_READ)))
3468   {
3469     level->no_valid_file = TRUE;
3470
3471     Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
3472
3473     return;
3474   }
3475
3476   for (i = 0; i < EM_LEVEL_SIZE; i++)
3477     leveldata[i] = fgetc(file);
3478
3479   fclose(file);
3480
3481   /* check if level data is crypted by testing against known starting bytes
3482      of the few existing crypted level files (from Emerald Mine 1 + 2) */
3483
3484   if ((leveldata[0] == 0xf1 ||
3485        leveldata[0] == 0xf5) && leveldata[2] == 0xe7 && leveldata[3] == 0xee)
3486   {
3487     unsigned char code0 = 0x65;
3488     unsigned char code1 = 0x11;
3489
3490     if (leveldata[0] == 0xf5)   /* error in crypted Emerald Mine 2 levels */
3491       leveldata[0] = 0xf1;
3492
3493     /* decode crypted level data */
3494
3495     for (i = 0; i < EM_LEVEL_SIZE; i++)
3496     {
3497       leveldata[i] ^= code0;
3498       leveldata[i] -= code1;
3499
3500       code0 = (code0 + 7) & 0xff;
3501     }
3502   }
3503
3504   level->fieldx = EM_LEVEL_XSIZE;
3505   level->fieldy = EM_LEVEL_YSIZE;
3506
3507   level->time           = header[46] * 10;
3508   level->gems_needed    = header[47];
3509
3510   /* The original Emerald Mine levels have their level number stored
3511      at the second byte of the level file...
3512      Do not trust this information at other level files, e.g. EMC,
3513      but correct it anyway (normally the first row is completely
3514      steel wall, so the correction does not hurt anyway). */
3515
3516   if (leveldata[1] == nr)
3517     leveldata[1] = leveldata[2];        /* correct level number field */
3518
3519   sprintf(level->name, "Level %d", nr);         /* set level name */
3520
3521   level->score[SC_EMERALD]      = header[36];
3522   level->score[SC_DIAMOND]      = header[37];
3523   level->score[SC_ROBOT]        = header[38];
3524   level->score[SC_SPACESHIP]    = header[39];
3525   level->score[SC_BUG]          = header[40];
3526   level->score[SC_YAMYAM]       = header[41];
3527   level->score[SC_NUT]          = header[42];
3528   level->score[SC_DYNAMITE]     = header[43];
3529   level->score[SC_TIME_BONUS]   = header[44];
3530
3531   level->num_yamyam_contents = 4;
3532
3533   for (i = 0; i < level->num_yamyam_contents; i++)
3534     for (y = 0; y < 3; y++)
3535       for (x = 0; x < 3; x++)
3536         level->yamyam_content[i].e[x][y] =
3537           map_em_element_yam(header[i * 9 + y * 3 + x]);
3538
3539   level->amoeba_speed           = (header[52] * 256 + header[53]) % 256;
3540   level->time_magic_wall        = (header[54] * 256 + header[55]) * 16 / 100;
3541   level->time_wheel             = (header[56] * 256 + header[57]) * 16 / 100;
3542   level->amoeba_content         = EL_DIAMOND;
3543
3544   for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
3545   {
3546     int new_element = map_em_element_field(leveldata[y * EM_LEVEL_XSIZE + x]);
3547
3548     if (new_element == EL_AMOEBA_DEAD && level->amoeba_speed)
3549       new_element = EL_AMOEBA_WET;
3550
3551     level->field[x][y] = new_element;
3552   }
3553
3554   x = (header[48] * 256 + header[49]) % EM_LEVEL_XSIZE;
3555   y = (header[48] * 256 + header[49]) / EM_LEVEL_XSIZE;
3556   level->field[x][y] = EL_PLAYER_1;
3557
3558   x = (header[50] * 256 + header[51]) % EM_LEVEL_XSIZE;
3559   y = (header[50] * 256 + header[51]) / EM_LEVEL_XSIZE;
3560   level->field[x][y] = EL_PLAYER_2;
3561 }
3562
3563 #endif
3564
3565 void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
3566 {
3567   static int ball_xy[8][2] =
3568   {
3569     { 0, 0 },
3570     { 1, 0 },
3571     { 2, 0 },
3572     { 0, 1 },
3573     { 2, 1 },
3574     { 0, 2 },
3575     { 1, 2 },
3576     { 2, 2 },
3577   };
3578   struct LevelInfo_EM *level_em = level->native_em_level;
3579   struct LEVEL *lev = level_em->lev;
3580   struct PLAYER **ply = level_em->ply;
3581   int i, j, x, y;
3582
3583   lev->width  = MIN(level->fieldx, EM_MAX_CAVE_WIDTH);
3584   lev->height = MIN(level->fieldy, EM_MAX_CAVE_HEIGHT);
3585
3586   lev->time_seconds     = level->time;
3587   lev->required_initial = level->gems_needed;
3588
3589   lev->emerald_score    = level->score[SC_EMERALD];
3590   lev->diamond_score    = level->score[SC_DIAMOND];
3591   lev->alien_score      = level->score[SC_ROBOT];
3592   lev->tank_score       = level->score[SC_SPACESHIP];
3593   lev->bug_score        = level->score[SC_BUG];
3594   lev->eater_score      = level->score[SC_YAMYAM];
3595   lev->nut_score        = level->score[SC_NUT];
3596   lev->dynamite_score   = level->score[SC_DYNAMITE];
3597   lev->key_score        = level->score[SC_KEY];
3598   lev->exit_score       = level->score[SC_TIME_BONUS];
3599
3600   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3601     for (y = 0; y < 3; y++)
3602       for (x = 0; x < 3; x++)
3603         lev->eater_array[i][y * 3 + x] =
3604           map_element_RND_to_EM(level->yamyam_content[i].e[x][y]);
3605
3606   lev->amoeba_time              = level->amoeba_speed;
3607   lev->wonderwall_time_initial  = level->time_magic_wall;
3608   lev->wheel_time               = level->time_wheel;
3609
3610   lev->android_move_time        = level->android_move_time;
3611   lev->android_clone_time       = level->android_clone_time;
3612   lev->ball_random              = level->ball_random;
3613   lev->ball_state_initial       = level->ball_state_initial;
3614   lev->ball_time                = level->ball_time;
3615   lev->num_ball_arrays          = level->num_ball_contents;
3616
3617   lev->lenses_score             = level->lenses_score;
3618   lev->magnify_score            = level->magnify_score;
3619   lev->slurp_score              = level->slurp_score;
3620
3621   lev->lenses_time              = level->lenses_time;
3622   lev->magnify_time             = level->magnify_time;
3623
3624   lev->wind_direction_initial =
3625     map_direction_RND_to_EM(level->wind_direction_initial);
3626   lev->wind_cnt_initial = (level->wind_direction_initial != MV_NONE ?
3627                            lev->wind_time : 0);
3628
3629   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3630     for (j = 0; j < 8; j++)
3631       lev->ball_array[i][j] =
3632         map_element_RND_to_EM(level->
3633                               ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
3634
3635   map_android_clone_elements_RND_to_EM(level);
3636
3637   /* first fill the complete playfield with the default border element */
3638   for (y = 0; y < EM_MAX_CAVE_HEIGHT; y++)
3639     for (x = 0; x < EM_MAX_CAVE_WIDTH; x++)
3640       level_em->cave[x][y] = ZBORDER;
3641
3642   if (BorderElement == EL_STEELWALL)
3643   {
3644     for (y = 0; y < lev->height + 2; y++)
3645       for (x = 0; x < lev->width + 2; x++)
3646         level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_STEELWALL);
3647   }
3648
3649   /* then copy the real level contents from level file into the playfield */
3650   for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
3651   {
3652     int new_element = map_element_RND_to_EM(level->field[x][y]);
3653     int offset = (BorderElement == EL_STEELWALL ? 1 : 0);
3654     int xx = x + 1 + offset;
3655     int yy = y + 1 + offset;
3656
3657     if (level->field[x][y] == EL_AMOEBA_DEAD)
3658       new_element = map_element_RND_to_EM(EL_AMOEBA_WET);
3659
3660     level_em->cave[xx][yy] = new_element;
3661   }
3662
3663   for (i = 0; i < MAX_PLAYERS; i++)
3664   {
3665     ply[i]->x_initial = 0;
3666     ply[i]->y_initial = 0;
3667   }
3668
3669   /* initialize player positions and delete players from the playfield */
3670   for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
3671   {
3672     if (ELEM_IS_PLAYER(level->field[x][y]))
3673     {
3674       int player_nr = GET_PLAYER_NR(level->field[x][y]);
3675       int offset = (BorderElement == EL_STEELWALL ? 1 : 0);
3676       int xx = x + 1 + offset;
3677       int yy = y + 1 + offset;
3678
3679       ply[player_nr]->x_initial = xx;
3680       ply[player_nr]->y_initial = yy;
3681
3682       level_em->cave[xx][yy] = map_element_RND_to_EM(EL_EMPTY);
3683     }
3684   }
3685
3686   if (BorderElement == EL_STEELWALL)
3687   {
3688     lev->width  += 2;
3689     lev->height += 2;
3690   }
3691 }
3692
3693 void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
3694 {
3695   static int ball_xy[8][2] =
3696   {
3697     { 0, 0 },
3698     { 1, 0 },
3699     { 2, 0 },
3700     { 0, 1 },
3701     { 2, 1 },
3702     { 0, 2 },
3703     { 1, 2 },
3704     { 2, 2 },
3705   };
3706   struct LevelInfo_EM *level_em = level->native_em_level;
3707   struct LEVEL *lev = level_em->lev;
3708   struct PLAYER **ply = level_em->ply;
3709   int i, j, x, y;
3710
3711   level->fieldx = MIN(lev->width,  MAX_LEV_FIELDX);
3712   level->fieldy = MIN(lev->height, MAX_LEV_FIELDY);
3713
3714   level->time        = lev->time_seconds;
3715   level->gems_needed = lev->required_initial;
3716
3717   sprintf(level->name, "Level %d", level->file_info.nr);
3718
3719   level->score[SC_EMERALD]      = lev->emerald_score;
3720   level->score[SC_DIAMOND]      = lev->diamond_score;
3721   level->score[SC_ROBOT]        = lev->alien_score;
3722   level->score[SC_SPACESHIP]    = lev->tank_score;
3723   level->score[SC_BUG]          = lev->bug_score;
3724   level->score[SC_YAMYAM]       = lev->eater_score;
3725   level->score[SC_NUT]          = lev->nut_score;
3726   level->score[SC_DYNAMITE]     = lev->dynamite_score;
3727   level->score[SC_KEY]          = lev->key_score;
3728   level->score[SC_TIME_BONUS]   = lev->exit_score;
3729
3730   level->num_yamyam_contents = MAX_ELEMENT_CONTENTS;
3731
3732   for (i = 0; i < level->num_yamyam_contents; i++)
3733     for (y = 0; y < 3; y++)
3734       for (x = 0; x < 3; x++)
3735         level->yamyam_content[i].e[x][y] =
3736           map_element_EM_to_RND(lev->eater_array[i][y * 3 + x]);
3737
3738   level->amoeba_speed           = lev->amoeba_time;
3739   level->time_magic_wall        = lev->wonderwall_time_initial;
3740   level->time_wheel             = lev->wheel_time;
3741
3742   level->android_move_time      = lev->android_move_time;
3743   level->android_clone_time     = lev->android_clone_time;
3744   level->ball_random            = lev->ball_random;
3745   level->ball_state_initial     = lev->ball_state_initial;
3746   level->ball_time              = lev->ball_time;
3747   level->num_ball_contents      = lev->num_ball_arrays;
3748
3749   level->lenses_score           = lev->lenses_score;
3750   level->magnify_score          = lev->magnify_score;
3751   level->slurp_score            = lev->slurp_score;
3752
3753   level->lenses_time            = lev->lenses_time;
3754   level->magnify_time           = lev->magnify_time;
3755
3756   level->wind_direction_initial =
3757     map_direction_EM_to_RND(lev->wind_direction_initial);
3758
3759   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3760     for (j = 0; j < 8; j++)
3761       level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]] =
3762         map_element_EM_to_RND(lev->ball_array[i][j]);
3763
3764   map_android_clone_elements_EM_to_RND(level);
3765
3766   /* convert the playfield (some elements need special treatment) */
3767   for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
3768   {
3769     int new_element = map_element_EM_to_RND(level_em->cave[x + 1][y + 1]);
3770
3771     if (new_element == EL_AMOEBA_WET && level->amoeba_speed == 0)
3772       new_element = EL_AMOEBA_DEAD;
3773
3774     level->field[x][y] = new_element;
3775   }
3776
3777   for (i = 0; i < MAX_PLAYERS; i++)
3778   {
3779     /* in case of all players set to the same field, use the first player */
3780     int nr = MAX_PLAYERS - i - 1;
3781     int jx = ply[nr]->x_initial - 1;
3782     int jy = ply[nr]->y_initial - 1;
3783
3784     if (jx != -1 && jy != -1)
3785       level->field[jx][jy] = EL_PLAYER_1 + nr;
3786   }
3787 }
3788
3789 static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,
3790                                      struct LevelFileInfo *level_file_info)
3791 {
3792   if (!LoadNativeLevel_EM(level_file_info->filename))
3793     level->no_valid_file = TRUE;
3794 }
3795
3796 void CopyNativeLevel_RND_to_Native(struct LevelInfo *level)
3797 {
3798   if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
3799     CopyNativeLevel_RND_to_EM(level);
3800 }
3801
3802 void CopyNativeLevel_Native_to_RND(struct LevelInfo *level)
3803 {
3804   if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
3805     CopyNativeLevel_EM_to_RND(level);
3806 }
3807
3808
3809 /* ------------------------------------------------------------------------- */
3810 /* functions for loading SP level                                            */
3811 /* ------------------------------------------------------------------------- */
3812
3813 #define NUM_SUPAPLEX_LEVELS_PER_PACKAGE 111
3814 #define SP_LEVEL_SIZE                   1536
3815 #define SP_LEVEL_XSIZE                  60
3816 #define SP_LEVEL_YSIZE                  24
3817 #define SP_LEVEL_NAME_LEN               23
3818
3819 static void LoadLevelFromFileStream_SP(FILE *file, struct LevelInfo *level,
3820                                        int nr)
3821 {
3822   int initial_player_gravity;
3823   int num_special_ports;
3824   int i, x, y;
3825
3826   /* for details of the Supaplex level format, see Herman Perk's Supaplex
3827      documentation file "SPFIX63.DOC" from his Supaplex "SpeedFix" package */
3828
3829   /* read level body (width * height == 60 * 24 tiles == 1440 bytes) */
3830   for (y = 0; y < SP_LEVEL_YSIZE; y++)
3831   {
3832     for (x = 0; x < SP_LEVEL_XSIZE; x++)
3833     {
3834       int element_old = fgetc(file);
3835       int element_new;
3836
3837       if (element_old <= 0x27)
3838         element_new = getMappedElement(EL_SP_START + element_old);
3839       else if (element_old == 0x28)
3840         element_new = EL_INVISIBLE_WALL;
3841       else
3842       {
3843         Error(ERR_WARN, "in level %d, at position %d, %d:", nr, x, y);
3844         Error(ERR_WARN, "invalid level element %d", element_old);
3845
3846         element_new = EL_UNKNOWN;
3847       }
3848
3849       level->field[x][y] = element_new;
3850     }
3851   }
3852
3853   ReadUnusedBytesFromFile(file, 4);     /* (not used by Supaplex engine) */
3854
3855   /* initial gravity: 1 == "on", anything else (0) == "off" */
3856   initial_player_gravity = (fgetc(file) == 1 ? TRUE : FALSE);
3857
3858   for (i = 0; i < MAX_PLAYERS; i++)
3859     level->initial_player_gravity[i] = initial_player_gravity;
3860
3861   ReadUnusedBytesFromFile(file, 1);     /* (not used by Supaplex engine) */
3862
3863   /* level title in uppercase letters, padded with dashes ("-") (23 bytes) */
3864   for (i = 0; i < SP_LEVEL_NAME_LEN; i++)
3865     level->name[i] = fgetc(file);
3866   level->name[SP_LEVEL_NAME_LEN] = '\0';
3867
3868   /* initial "freeze zonks": 2 == "on", anything else (0, 1) == "off" */
3869   ReadUnusedBytesFromFile(file, 1);     /* (not used by R'n'D engine) */
3870
3871   /* number of infotrons needed; 0 means that Supaplex will count the total
3872      amount of infotrons in the level and use the low byte of that number
3873      (a multiple of 256 infotrons will result in "0 infotrons needed"!) */
3874   level->gems_needed = fgetc(file);
3875
3876   /* number of special ("gravity") port entries below (maximum 10 allowed) */
3877   num_special_ports = fgetc(file);
3878
3879   /* database of properties of up to 10 special ports (6 bytes per port) */
3880   for (i = 0; i < 10; i++)
3881   {
3882     int port_location, port_x, port_y, port_element;
3883     int gravity;
3884
3885     /* high and low byte of the location of a special port; if (x, y) are the
3886        coordinates of a port in the field and (0, 0) is the top-left corner,
3887        the 16 bit value here calculates as 2 * (x + (y * 60)) (this is twice
3888        of what may be expected: Supaplex works with a game field in memory
3889        which is 2 bytes per tile) */
3890     port_location = getFile16BitBE(file);
3891
3892     /* change gravity: 1 == "turn on", anything else (0) == "turn off" */
3893     gravity = fgetc(file);
3894
3895     /* "freeze zonks": 2 == "turn on", anything else (0, 1) == "turn off" */
3896     ReadUnusedBytesFromFile(file, 1);   /* (not used by R'n'D engine) */
3897
3898     /* "freeze enemies": 1 == "turn on", anything else (0) == "turn off" */
3899     ReadUnusedBytesFromFile(file, 1);   /* (not used by R'n'D engine) */
3900
3901     ReadUnusedBytesFromFile(file, 1);   /* (not used by Supaplex engine) */
3902
3903     if (i >= num_special_ports)
3904       continue;
3905
3906     port_x = (port_location / 2) % SP_LEVEL_XSIZE;
3907     port_y = (port_location / 2) / SP_LEVEL_XSIZE;
3908
3909     if (port_x < 0 || port_x >= SP_LEVEL_XSIZE ||
3910         port_y < 0 || port_y >= SP_LEVEL_YSIZE)
3911     {
3912       Error(ERR_WARN, "special port position (%d, %d) out of bounds",
3913             port_x, port_y);
3914
3915       continue;
3916     }
3917
3918     port_element = level->field[port_x][port_y];
3919
3920     if (port_element < EL_SP_GRAVITY_PORT_RIGHT ||
3921         port_element > EL_SP_GRAVITY_PORT_UP)
3922     {
3923       Error(ERR_WARN, "no special port at position (%d, %d)", port_x, port_y);
3924
3925       continue;
3926     }
3927
3928     /* change previous (wrong) gravity inverting special port to either
3929        gravity enabling special port or gravity disabling special port */
3930     level->field[port_x][port_y] +=
3931       (gravity == 1 ? EL_SP_GRAVITY_ON_PORT_RIGHT :
3932        EL_SP_GRAVITY_OFF_PORT_RIGHT) - EL_SP_GRAVITY_PORT_RIGHT;
3933   }
3934
3935   ReadUnusedBytesFromFile(file, 4);     /* (not used by Supaplex engine) */
3936
3937   /* change special gravity ports without database entries to normal ports */
3938   for (y = 0; y < SP_LEVEL_YSIZE; y++)
3939     for (x = 0; x < SP_LEVEL_XSIZE; x++)
3940       if (level->field[x][y] >= EL_SP_GRAVITY_PORT_RIGHT &&
3941           level->field[x][y] <= EL_SP_GRAVITY_PORT_UP)
3942         level->field[x][y] += EL_SP_PORT_RIGHT - EL_SP_GRAVITY_PORT_RIGHT;
3943
3944   /* auto-determine number of infotrons if it was stored as "0" -- see above */
3945   if (level->gems_needed == 0)
3946   {
3947     for (y = 0; y < SP_LEVEL_YSIZE; y++)
3948       for (x = 0; x < SP_LEVEL_XSIZE; x++)
3949         if (level->field[x][y] == EL_SP_INFOTRON)
3950           level->gems_needed++;
3951
3952     level->gems_needed &= 0xff;         /* only use low byte -- see above */
3953   }
3954
3955   level->fieldx = SP_LEVEL_XSIZE;
3956   level->fieldy = SP_LEVEL_YSIZE;
3957
3958   level->time = 0;                      /* no time limit */
3959   level->amoeba_speed = 0;
3960   level->time_magic_wall = 0;
3961   level->time_wheel = 0;
3962   level->amoeba_content = EL_EMPTY;
3963
3964 #if 1
3965   /* original Supaplex does not use score values -- use default values */
3966 #else
3967   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
3968     level->score[i] = 0;
3969 #endif
3970
3971   /* there are no yamyams in supaplex levels */
3972   for (i = 0; i < level->num_yamyam_contents; i++)
3973     for (y = 0; y < 3; y++)
3974       for (x = 0; x < 3; x++)
3975         level->yamyam_content[i].e[x][y] = EL_EMPTY;
3976 }
3977
3978 static void LoadLevelFromFileInfo_SP(struct LevelInfo *level,
3979                                      struct LevelFileInfo *level_file_info)
3980 {
3981   char *filename = level_file_info->filename;
3982   FILE *file;
3983   int nr = level_file_info->nr - leveldir_current->first_level;
3984   int i, l, x, y;
3985   char name_first, name_last;
3986   struct LevelInfo multipart_level;
3987   int multipart_xpos, multipart_ypos;
3988   boolean is_multipart_level;
3989   boolean is_first_part;
3990   boolean reading_multipart_level = FALSE;
3991   boolean use_empty_level = FALSE;
3992
3993   if (!(file = fopen(filename, MODE_READ)))
3994   {
3995     level->no_valid_file = TRUE;
3996
3997     Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
3998
3999     return;
4000   }
4001
4002   /* position file stream to the requested level inside the level package */
4003   if (fseek(file, nr * SP_LEVEL_SIZE, SEEK_SET) != 0)
4004   {
4005     level->no_valid_file = TRUE;
4006
4007     Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level", filename);
4008
4009     return;
4010   }
4011
4012   /* there exist Supaplex level package files with multi-part levels which
4013      can be detected as follows: instead of leading and trailing dashes ('-')
4014      to pad the level name, they have leading and trailing numbers which are
4015      the x and y coordinations of the current part of the multi-part level;
4016      if there are '?' characters instead of numbers on the left or right side
4017      of the level name, the multi-part level consists of only horizontal or
4018      vertical parts */
4019
4020   for (l = nr; l < NUM_SUPAPLEX_LEVELS_PER_PACKAGE; l++)
4021   {
4022     LoadLevelFromFileStream_SP(file, level, l);
4023
4024     /* check if this level is a part of a bigger multi-part level */
4025
4026     name_first = level->name[0];
4027     name_last  = level->name[SP_LEVEL_NAME_LEN - 1];
4028
4029     is_multipart_level =
4030       ((name_first == '?' || (name_first >= '0' && name_first <= '9')) &&
4031        (name_last  == '?' || (name_last  >= '0' && name_last  <= '9')));
4032
4033     is_first_part =
4034       ((name_first == '?' || name_first == '1') &&
4035        (name_last  == '?' || name_last  == '1'));
4036
4037     /* correct leading multipart level meta information in level name */
4038     for (i = 0; i < SP_LEVEL_NAME_LEN && level->name[i] == name_first; i++)
4039       level->name[i] = '-';
4040
4041     /* correct trailing multipart level meta information in level name */
4042     for (i = SP_LEVEL_NAME_LEN - 1; i >= 0 && level->name[i] == name_last; i--)
4043       level->name[i] = '-';
4044
4045     /* ---------- check for normal single level ---------- */
4046
4047     if (!reading_multipart_level && !is_multipart_level)
4048     {
4049       /* the current level is simply a normal single-part level, and we are
4050          not reading a multi-part level yet, so return the level as it is */
4051
4052       break;
4053     }
4054
4055     /* ---------- check for empty level (unused multi-part) ---------- */
4056
4057     if (!reading_multipart_level && is_multipart_level && !is_first_part)
4058     {
4059       /* this is a part of a multi-part level, but not the first part
4060          (and we are not already reading parts of a multi-part level);
4061          in this case, use an empty level instead of the single part */
4062
4063       use_empty_level = TRUE;
4064
4065       break;
4066     }
4067
4068     /* ---------- check for finished multi-part level ---------- */
4069
4070     if (reading_multipart_level &&
4071         (!is_multipart_level ||
4072          !strEqual(level->name, multipart_level.name)))
4073     {
4074       /* we are already reading parts of a multi-part level, but this level is
4075          either not a multi-part level, or a part of a different multi-part
4076          level; in both cases, the multi-part level seems to be complete */
4077
4078       break;
4079     }
4080
4081     /* ---------- here we have one part of a multi-part level ---------- */
4082
4083     reading_multipart_level = TRUE;
4084
4085     if (is_first_part)  /* start with first part of new multi-part level */
4086     {
4087       /* copy level info structure from first part */
4088       multipart_level = *level;
4089
4090       /* clear playfield of new multi-part level */
4091       for (y = 0; y < MAX_LEV_FIELDY; y++)
4092         for (x = 0; x < MAX_LEV_FIELDX; x++)
4093           multipart_level.field[x][y] = EL_EMPTY;
4094     }
4095
4096     if (name_first == '?')
4097       name_first = '1';
4098     if (name_last == '?')
4099       name_last = '1';
4100
4101     multipart_xpos = (int)(name_first - '0');
4102     multipart_ypos = (int)(name_last  - '0');
4103
4104 #if 0
4105     printf("----------> part (%d/%d) of multi-part level '%s'\n",
4106            multipart_xpos, multipart_ypos, multipart_level.name);
4107 #endif
4108
4109     if (multipart_xpos * SP_LEVEL_XSIZE > MAX_LEV_FIELDX ||
4110         multipart_ypos * SP_LEVEL_YSIZE > MAX_LEV_FIELDY)
4111     {
4112       Error(ERR_WARN, "multi-part level is too big -- ignoring part of it");
4113
4114       break;
4115     }
4116
4117     multipart_level.fieldx = MAX(multipart_level.fieldx,
4118                                  multipart_xpos * SP_LEVEL_XSIZE);
4119     multipart_level.fieldy = MAX(multipart_level.fieldy,
4120                                  multipart_ypos * SP_LEVEL_YSIZE);
4121
4122     /* copy level part at the right position of multi-part level */
4123     for (y = 0; y < SP_LEVEL_YSIZE; y++)
4124     {
4125       for (x = 0; x < SP_LEVEL_XSIZE; x++)
4126       {
4127         int start_x = (multipart_xpos - 1) * SP_LEVEL_XSIZE;
4128         int start_y = (multipart_ypos - 1) * SP_LEVEL_YSIZE;
4129
4130         multipart_level.field[start_x + x][start_y + y] = level->field[x][y];
4131       }
4132     }
4133   }
4134
4135   fclose(file);
4136
4137   if (use_empty_level)
4138   {
4139     setLevelInfoToDefaults(level);
4140
4141     level->fieldx = SP_LEVEL_XSIZE;
4142     level->fieldy = SP_LEVEL_YSIZE;
4143
4144     for (y = 0; y < SP_LEVEL_YSIZE; y++)
4145       for (x = 0; x < SP_LEVEL_XSIZE; x++)
4146         level->field[x][y] = EL_EMPTY;
4147
4148     strcpy(level->name, "-------- EMPTY --------");
4149
4150     Error(ERR_WARN, "single part of multi-part level -- using empty level");
4151   }
4152
4153   if (reading_multipart_level)
4154     *level = multipart_level;
4155 }
4156
4157
4158 #define DC_LEVEL_HEADER_SIZE            344
4159
4160 unsigned short getDecodedWord_DC(unsigned short data_encoded, boolean init)
4161 {
4162   static int last_data_encoded;
4163   static int offset1;
4164   static int offset2;
4165   int diff;
4166   int diff_hi, diff_lo;
4167   int data_hi, data_lo;
4168   unsigned short data_decoded;
4169
4170   if (init)
4171   {
4172     last_data_encoded = 0;
4173     offset1 = -1;
4174     offset2 = 0;
4175
4176     return 0;
4177   }
4178
4179   diff = data_encoded - last_data_encoded;
4180   diff_hi = diff & ~0xff;
4181   diff_lo = diff &  0xff;
4182
4183   offset2 += diff_lo;
4184
4185   data_hi = diff_hi - (offset1 << 8) + (offset2 & 0xff00);
4186   data_lo = (diff_lo + (data_hi >> 16)) & 0x00ff;
4187   data_hi = data_hi & 0xff00;
4188
4189   data_decoded = data_hi | data_lo;
4190
4191   last_data_encoded = data_encoded;
4192
4193   offset1 = (offset1 + 1) % 31;
4194   offset2 = offset2 & 0xff;
4195
4196   return data_decoded;
4197 }
4198
4199 int getMappedElement_DC(int element)
4200 {
4201   switch (element)
4202   {
4203     case 0x0000:
4204       element = EL_ROCK;
4205       break;
4206
4207       /* 0x0117 - 0x036e: (?) */
4208       /* EL_DIAMOND */
4209
4210       /* 0x042d - 0x0684: (?) */
4211       /* EL_EMERALD */
4212
4213     case 0x06f1:
4214       element = EL_NUT;
4215       break;
4216
4217     case 0x074c:
4218       element = EL_BOMB;
4219       break;
4220
4221     case 0x07a4:
4222       element = EL_PEARL;
4223       break;
4224
4225     case 0x0823:
4226       element = EL_CRYSTAL;
4227       break;
4228
4229     case 0x0e77:        /* quicksand (boulder) */
4230       element = EL_QUICKSAND_FAST_FULL;
4231       break;
4232
4233     case 0x0e99:        /* slow quicksand (boulder) */
4234       element = EL_QUICKSAND_FULL;
4235       break;
4236
4237     case 0x0ed2:
4238       element = EL_EM_EXIT_OPEN;
4239       break;
4240
4241     case 0x0ee3:
4242       element = EL_EM_EXIT_CLOSED;
4243       break;
4244
4245     case 0x0eeb:
4246       element = EL_EM_STEEL_EXIT_OPEN;
4247       break;
4248
4249     case 0x0efc:
4250       element = EL_EM_STEEL_EXIT_CLOSED;
4251       break;
4252
4253     case 0x0f4f:        /* dynamite (lit 1) */
4254       element = EL_EM_DYNAMITE_ACTIVE;
4255       break;
4256
4257     case 0x0f57:        /* dynamite (lit 2) */
4258       element = EL_EM_DYNAMITE_ACTIVE;
4259       break;
4260
4261     case 0x0f5f:        /* dynamite (lit 3) */
4262       element = EL_EM_DYNAMITE_ACTIVE;
4263       break;
4264
4265     case 0x0f67:        /* dynamite (lit 4) */
4266       element = EL_EM_DYNAMITE_ACTIVE;
4267       break;
4268
4269     case 0x0f81:
4270     case 0x0f82:
4271     case 0x0f83:
4272     case 0x0f84:
4273       element = EL_AMOEBA_WET;
4274       break;
4275
4276     case 0x0f85:
4277       element = EL_AMOEBA_DROP;
4278       break;
4279
4280     case 0x0fb9:
4281       element = EL_DC_MAGIC_WALL;
4282       break;
4283
4284     case 0x0fd0:
4285       element = EL_SPACESHIP_UP;
4286       break;
4287
4288     case 0x0fd9:
4289       element = EL_SPACESHIP_DOWN;
4290       break;
4291
4292     case 0x0ff1:
4293       element = EL_SPACESHIP_LEFT;
4294       break;
4295
4296     case 0x0ff9:
4297       element = EL_SPACESHIP_RIGHT;
4298       break;
4299
4300     case 0x1057:
4301       element = EL_BUG_UP;
4302       break;
4303
4304     case 0x1060:
4305       element = EL_BUG_DOWN;
4306       break;
4307
4308     case 0x1078:
4309       element = EL_BUG_LEFT;
4310       break;
4311
4312     case 0x1080:
4313       element = EL_BUG_RIGHT;
4314       break;
4315
4316     case 0x10de:
4317       element = EL_MOLE_UP;
4318       break;
4319
4320     case 0x10e7:
4321       element = EL_MOLE_DOWN;
4322       break;
4323
4324     case 0x10ff:
4325       element = EL_MOLE_LEFT;
4326       break;
4327
4328     case 0x1107:
4329       element = EL_MOLE_RIGHT;
4330       break;
4331
4332     case 0x11c0:
4333       element = EL_ROBOT;
4334       break;
4335
4336     case 0x13f5:
4337       element = EL_YAMYAM;
4338       break;
4339
4340     case 0x1425:
4341       element = EL_SWITCHGATE_OPEN;
4342       break;
4343
4344     case 0x1426:
4345       element = EL_SWITCHGATE_CLOSED;
4346       break;
4347
4348     case 0x1437:
4349       element = EL_DC_SWITCHGATE_SWITCH_UP;
4350       break;
4351
4352     case 0x143a:
4353       element = EL_TIMEGATE_CLOSED;
4354       break;
4355
4356     case 0x144c:        /* conveyor belt switch (green) */
4357       element = EL_CONVEYOR_BELT_3_SWITCH_MIDDLE;
4358       break;
4359
4360     case 0x144f:        /* conveyor belt switch (red) */
4361       element = EL_CONVEYOR_BELT_1_SWITCH_MIDDLE;
4362       break;
4363
4364     case 0x1452:        /* conveyor belt switch (blue) */
4365       element = EL_CONVEYOR_BELT_4_SWITCH_MIDDLE;
4366       break;
4367
4368     case 0x145b:
4369       element = EL_CONVEYOR_BELT_3_MIDDLE;
4370       break;
4371
4372     case 0x1463:
4373       element = EL_CONVEYOR_BELT_3_LEFT;
4374       break;
4375
4376     case 0x146b:
4377       element = EL_CONVEYOR_BELT_3_RIGHT;
4378       break;
4379
4380     case 0x1473:
4381       element = EL_CONVEYOR_BELT_1_MIDDLE;
4382       break;
4383
4384     case 0x147b:
4385       element = EL_CONVEYOR_BELT_1_LEFT;
4386       break;
4387
4388     case 0x1483:
4389       element = EL_CONVEYOR_BELT_1_RIGHT;
4390       break;
4391
4392     case 0x148b:
4393       element = EL_CONVEYOR_BELT_4_MIDDLE;
4394       break;
4395
4396     case 0x1493:
4397       element = EL_CONVEYOR_BELT_4_LEFT;
4398       break;
4399
4400     case 0x149b:
4401       element = EL_CONVEYOR_BELT_4_RIGHT;
4402       break;
4403
4404     case 0x14ac:
4405       element = EL_EXPANDABLE_WALL_HORIZONTAL;
4406       break;
4407
4408     case 0x14bd:
4409       element = EL_EXPANDABLE_WALL_VERTICAL;
4410       break;
4411
4412     case 0x14c6:
4413       element = EL_EXPANDABLE_WALL_ANY;
4414       break;
4415
4416     case 0x14ce:        /* growing steel wall (left/right) */
4417       element = EL_EXPANDABLE_STEELWALL_HORIZONTAL;
4418       break;
4419
4420     case 0x14df:        /* growing steel wall (up/down) */
4421       element = EL_EXPANDABLE_STEELWALL_VERTICAL;
4422       break;
4423
4424     case 0x14e8:        /* growing steel wall (up/down/left/right) */
4425       element = EL_EXPANDABLE_STEELWALL_ANY;
4426       break;
4427
4428     case 0x14e9:
4429       element = EL_SHIELD_DEADLY;
4430       break;
4431
4432     case 0x1501:
4433       element = EL_EXTRA_TIME;
4434       break;
4435
4436     case 0x154f:
4437       element = EL_ACID;
4438       break;
4439
4440     case 0x1577:
4441       element = EL_EMPTY_SPACE;
4442       break;
4443
4444     case 0x1578:        /* quicksand (empty) */
4445       element = EL_QUICKSAND_FAST_EMPTY;
4446       break;
4447
4448     case 0x1579:        /* slow quicksand (empty) */
4449       element = EL_QUICKSAND_EMPTY;
4450       break;
4451
4452       /* 0x157c - 0x158b: */
4453       /* EL_SAND */
4454
4455       /* 0x1590 - 0x159f: */
4456       /* EL_DC_LANDMINE */
4457
4458     case 0x15a0:
4459       element = EL_EM_DYNAMITE;
4460       break;
4461
4462     case 0x15a1:        /* key (red) */
4463       element = EL_EM_KEY_1;
4464       break;
4465
4466     case 0x15a2:        /* key (yellow) */
4467       element = EL_EM_KEY_2;
4468       break;
4469
4470     case 0x15a3:        /* key (blue) */
4471       element = EL_EM_KEY_4;
4472       break;
4473
4474     case 0x15a4:        /* key (green) */
4475       element = EL_EM_KEY_3;
4476       break;
4477
4478     case 0x15a5:        /* key (white) */
4479       element = EL_DC_KEY_WHITE;
4480       break;
4481
4482     case 0x15a6:
4483       element = EL_WALL_SLIPPERY;
4484       break;
4485
4486     case 0x15a7:
4487       element = EL_WALL;
4488       break;
4489
4490     case 0x15a8:        /* wall (not round) */
4491       element = EL_WALL;
4492       break;
4493
4494     case 0x15a9:        /* (blue) */
4495       element = EL_CHAR_A;
4496       break;
4497
4498     case 0x15aa:        /* (blue) */
4499       element = EL_CHAR_B;
4500       break;
4501
4502     case 0x15ab:        /* (blue) */
4503       element = EL_CHAR_C;
4504       break;
4505
4506     case 0x15ac:        /* (blue) */
4507       element = EL_CHAR_D;
4508       break;
4509
4510     case 0x15ad:        /* (blue) */
4511       element = EL_CHAR_E;
4512       break;
4513
4514     case 0x15ae:        /* (blue) */
4515       element = EL_CHAR_F;
4516       break;
4517
4518     case 0x15af:        /* (blue) */
4519       element = EL_CHAR_G;
4520       break;
4521
4522     case 0x15b0:        /* (blue) */
4523       element = EL_CHAR_H;
4524       break;
4525
4526     case 0x15b1:        /* (blue) */
4527       element = EL_CHAR_I;
4528       break;
4529
4530     case 0x15b2:        /* (blue) */
4531       element = EL_CHAR_J;
4532       break;
4533
4534     case 0x15b3:        /* (blue) */
4535       element = EL_CHAR_K;
4536       break;
4537
4538     case 0x15b4:        /* (blue) */
4539       element = EL_CHAR_L;
4540       break;
4541
4542     case 0x15b5:        /* (blue) */
4543       element = EL_CHAR_M;
4544       break;
4545
4546     case 0x15b6:        /* (blue) */
4547       element = EL_CHAR_N;
4548       break;
4549
4550     case 0x15b7:        /* (blue) */
4551       element = EL_CHAR_O;
4552       break;
4553
4554     case 0x15b8:        /* (blue) */
4555       element = EL_CHAR_P;
4556       break;
4557
4558     case 0x15b9:        /* (blue) */
4559       element = EL_CHAR_Q;
4560       break;
4561
4562     case 0x15ba:        /* (blue) */
4563       element = EL_CHAR_R;
4564       break;
4565
4566     case 0x15bb:        /* (blue) */
4567       element = EL_CHAR_S;
4568       break;
4569
4570     case 0x15bc:        /* (blue) */
4571       element = EL_CHAR_T;
4572       break;
4573
4574     case 0x15bd:        /* (blue) */
4575       element = EL_CHAR_U;
4576       break;
4577
4578     case 0x15be:        /* (blue) */
4579       element = EL_CHAR_V;
4580       break;
4581
4582     case 0x15bf:        /* (blue) */
4583       element = EL_CHAR_W;
4584       break;
4585
4586     case 0x15c0:        /* (blue) */
4587       element = EL_CHAR_X;
4588       break;
4589
4590     case 0x15c1:        /* (blue) */
4591       element = EL_CHAR_Y;
4592       break;
4593
4594     case 0x15c2:        /* (blue) */
4595       element = EL_CHAR_Z;
4596       break;
4597
4598     case 0x15c3:        /* (blue) */
4599       element = EL_CHAR_AUMLAUT;
4600       break;
4601
4602     case 0x15c4:        /* (blue) */
4603       element = EL_CHAR_OUMLAUT;
4604       break;
4605
4606     case 0x15c5:        /* (blue) */
4607       element = EL_CHAR_UUMLAUT;
4608       break;
4609
4610     case 0x15c6:        /* (blue) */
4611       element = EL_CHAR_0;
4612       break;
4613
4614     case 0x15c7:        /* (blue) */
4615       element = EL_CHAR_1;
4616       break;
4617
4618     case 0x15c8:        /* (blue) */
4619       element = EL_CHAR_2;
4620       break;
4621
4622     case 0x15c9:        /* (blue) */
4623       element = EL_CHAR_3;
4624       break;
4625
4626     case 0x15ca:        /* (blue) */
4627       element = EL_CHAR_4;
4628       break;
4629
4630     case 0x15cb:        /* (blue) */
4631       element = EL_CHAR_5;
4632       break;
4633
4634     case 0x15cc:        /* (blue) */
4635       element = EL_CHAR_6;
4636       break;
4637
4638     case 0x15cd:        /* (blue) */
4639       element = EL_CHAR_7;
4640       break;
4641
4642     case 0x15ce:        /* (blue) */
4643       element = EL_CHAR_8;
4644       break;
4645
4646     case 0x15cf:        /* (blue) */
4647       element = EL_CHAR_9;
4648       break;
4649
4650     case 0x15d0:        /* (blue) */
4651       element = EL_CHAR_PERIOD;
4652       break;
4653
4654     case 0x15d1:        /* (blue) */
4655       element = EL_CHAR_EXCLAM;
4656       break;
4657
4658     case 0x15d2:        /* (blue) */
4659       element = EL_CHAR_COLON;
4660       break;
4661
4662     case 0x15d3:        /* (blue) */
4663       element = EL_CHAR_LESS;
4664       break;
4665
4666     case 0x15d4:        /* (blue) */
4667       element = EL_CHAR_GREATER;
4668       break;
4669
4670     case 0x15d5:        /* (blue) */
4671       element = EL_CHAR_QUESTION;
4672       break;
4673
4674     case 0x15d6:        /* (blue) */
4675       element = EL_CHAR_COPYRIGHT;
4676       break;
4677
4678     case 0x15d7:        /* (blue) */
4679       element = EL_CHAR_UP;
4680       break;
4681
4682     case 0x15d8:        /* (blue) */
4683       element = EL_CHAR_DOWN;
4684       break;
4685
4686     case 0x15d9:        /* (blue) */
4687       element = EL_CHAR_BUTTON;
4688       break;
4689
4690     case 0x15da:        /* (blue) */
4691       element = EL_CHAR_PLUS;
4692       break;
4693
4694     case 0x15db:        /* (blue) */
4695       element = EL_CHAR_MINUS;
4696       break;
4697
4698     case 0x15dc:        /* (blue) */
4699       element = EL_CHAR_APOSTROPHE;
4700       break;
4701
4702     case 0x15dd:        /* (blue) */
4703       element = EL_CHAR_PARENLEFT;
4704       break;
4705
4706     case 0x15de:        /* (blue) */
4707       element = EL_CHAR_PARENRIGHT;
4708       break;
4709
4710     case 0x15df:        /* (green) */
4711       element = EL_CHAR_A;
4712       break;
4713
4714     case 0x15e0:        /* (green) */
4715       element = EL_CHAR_B;
4716       break;
4717
4718     case 0x15e1:        /* (green) */
4719       element = EL_CHAR_C;
4720       break;
4721
4722     case 0x15e2:        /* (green) */
4723       element = EL_CHAR_D;
4724       break;
4725
4726     case 0x15e3:        /* (green) */
4727       element = EL_CHAR_E;
4728       break;
4729
4730     case 0x15e4:        /* (green) */
4731       element = EL_CHAR_F;
4732       break;
4733
4734     case 0x15e5:        /* (green) */
4735       element = EL_CHAR_G;
4736       break;
4737
4738     case 0x15e6:        /* (green) */
4739       element = EL_CHAR_H;
4740       break;
4741
4742     case 0x15e7:        /* (green) */
4743       element = EL_CHAR_I;
4744       break;
4745
4746     case 0x15e8:        /* (green) */
4747       element = EL_CHAR_J;
4748       break;
4749
4750     case 0x15e9:        /* (green) */
4751       element = EL_CHAR_K;
4752       break;
4753
4754     case 0x15ea:        /* (green) */
4755       element = EL_CHAR_L;
4756       break;
4757
4758     case 0x15eb:        /* (green) */
4759       element = EL_CHAR_M;
4760       break;
4761
4762     case 0x15ec:        /* (green) */
4763       element = EL_CHAR_N;
4764       break;
4765
4766     case 0x15ed:        /* (green) */
4767       element = EL_CHAR_O;
4768       break;
4769
4770     case 0x15ee:        /* (green) */
4771       element = EL_CHAR_P;
4772       break;
4773
4774     case 0x15ef:        /* (green) */
4775       element = EL_CHAR_Q;
4776       break;
4777
4778     case 0x15f0:        /* (green) */
4779       element = EL_CHAR_R;
4780       break;
4781
4782     case 0x15f1:        /* (green) */
4783       element = EL_CHAR_S;
4784       break;
4785
4786     case 0x15f2:        /* (green) */
4787       element = EL_CHAR_T;
4788       break;
4789
4790     case 0x15f3:        /* (green) */
4791       element = EL_CHAR_U;
4792       break;
4793
4794     case 0x15f4:        /* (green) */
4795       element = EL_CHAR_V;
4796       break;
4797
4798     case 0x15f5:        /* (green) */
4799       element = EL_CHAR_W;
4800       break;
4801
4802     case 0x15f6:        /* (green) */
4803       element = EL_CHAR_X;
4804       break;
4805
4806     case 0x15f7:        /* (green) */
4807       element = EL_CHAR_Y;
4808       break;
4809
4810     case 0x15f8:        /* (green) */
4811       element = EL_CHAR_Z;
4812       break;
4813
4814     case 0x15f9:        /* (green) */
4815       element = EL_CHAR_AUMLAUT;
4816       break;
4817
4818     case 0x15fa:        /* (green) */
4819       element = EL_CHAR_OUMLAUT;
4820       break;
4821
4822     case 0x15fb:        /* (green) */
4823       element = EL_CHAR_UUMLAUT;
4824       break;
4825
4826     case 0x15fc:        /* (green) */
4827       element = EL_CHAR_0;
4828       break;
4829
4830     case 0x15fd:        /* (green) */
4831       element = EL_CHAR_1;
4832       break;
4833
4834     case 0x15fe:        /* (green) */
4835       element = EL_CHAR_2;
4836       break;
4837
4838     case 0x15ff:        /* (green) */
4839       element = EL_CHAR_3;
4840       break;
4841
4842     case 0x1600:        /* (green) */
4843       element = EL_CHAR_4;
4844       break;
4845
4846     case 0x1601:        /* (green) */
4847       element = EL_CHAR_5;
4848       break;
4849
4850     case 0x1602:        /* (green) */
4851       element = EL_CHAR_6;
4852       break;
4853
4854     case 0x1603:        /* (green) */
4855       element = EL_CHAR_7;
4856       break;
4857
4858     case 0x1604:        /* (green) */
4859       element = EL_CHAR_8;
4860       break;
4861
4862     case 0x1605:        /* (green) */
4863       element = EL_CHAR_9;
4864       break;
4865
4866     case 0x1606:        /* (green) */
4867       element = EL_CHAR_PERIOD;
4868       break;
4869
4870     case 0x1607:        /* (green) */
4871       element = EL_CHAR_EXCLAM;
4872       break;
4873
4874     case 0x1608:        /* (green) */
4875       element = EL_CHAR_COLON;
4876       break;
4877
4878     case 0x1609:        /* (green) */
4879       element = EL_CHAR_LESS;
4880       break;
4881
4882     case 0x160a:        /* (green) */
4883       element = EL_CHAR_GREATER;
4884       break;
4885
4886     case 0x160b:        /* (green) */
4887       element = EL_CHAR_QUESTION;
4888       break;
4889
4890     case 0x160c:        /* (green) */
4891       element = EL_CHAR_COPYRIGHT;
4892       break;
4893
4894     case 0x160d:        /* (green) */
4895       element = EL_CHAR_UP;
4896       break;
4897
4898     case 0x160e:        /* (green) */
4899       element = EL_CHAR_DOWN;
4900       break;
4901
4902     case 0x160f:        /* (green) */
4903       element = EL_CHAR_BUTTON;
4904       break;
4905
4906     case 0x1610:        /* (green) */
4907       element = EL_CHAR_PLUS;
4908       break;
4909
4910     case 0x1611:        /* (green) */
4911       element = EL_CHAR_MINUS;
4912       break;
4913
4914     case 0x1612:        /* (green) */
4915       element = EL_CHAR_APOSTROPHE;
4916       break;
4917
4918     case 0x1613:        /* (green) */
4919       element = EL_CHAR_PARENLEFT;
4920       break;
4921
4922     case 0x1614:        /* (green) */
4923       element = EL_CHAR_PARENRIGHT;
4924       break;
4925
4926     case 0x1615:        /* (blue steel) */
4927       element = EL_STEEL_CHAR_A;
4928       break;
4929
4930     case 0x1616:        /* (blue steel) */
4931       element = EL_STEEL_CHAR_B;
4932       break;
4933
4934     case 0x1617:        /* (blue steel) */
4935       element = EL_STEEL_CHAR_C;
4936       break;
4937
4938     case 0x1618:        /* (blue steel) */
4939       element = EL_STEEL_CHAR_D;
4940       break;
4941
4942     case 0x1619:        /* (blue steel) */
4943       element = EL_STEEL_CHAR_E;
4944       break;
4945
4946     case 0x161a:        /* (blue steel) */
4947       element = EL_STEEL_CHAR_F;
4948       break;
4949
4950     case 0x161b:        /* (blue steel) */
4951       element = EL_STEEL_CHAR_G;
4952       break;
4953
4954     case 0x161c:        /* (blue steel) */
4955       element = EL_STEEL_CHAR_H;
4956       break;
4957
4958     case 0x161d:        /* (blue steel) */
4959       element = EL_STEEL_CHAR_I;
4960       break;
4961
4962     case 0x161e:        /* (blue steel) */
4963       element = EL_STEEL_CHAR_J;
4964       break;
4965
4966     case 0x161f:        /* (blue steel) */
4967       element = EL_STEEL_CHAR_K;
4968       break;
4969
4970     case 0x1620:        /* (blue steel) */
4971       element = EL_STEEL_CHAR_L;
4972       break;
4973
4974     case 0x1621:        /* (blue steel) */
4975       element = EL_STEEL_CHAR_M;
4976       break;
4977
4978     case 0x1622:        /* (blue steel) */
4979       element = EL_STEEL_CHAR_N;
4980       break;
4981
4982     case 0x1623:        /* (blue steel) */
4983       element = EL_STEEL_CHAR_O;
4984       break;
4985
4986     case 0x1624:        /* (blue steel) */
4987       element = EL_STEEL_CHAR_P;
4988       break;
4989
4990     case 0x1625:        /* (blue steel) */
4991       element = EL_STEEL_CHAR_Q;
4992       break;
4993
4994     case 0x1626:        /* (blue steel) */
4995       element = EL_STEEL_CHAR_R;
4996       break;
4997
4998     case 0x1627:        /* (blue steel) */
4999       element = EL_STEEL_CHAR_S;
5000       break;
5001
5002     case 0x1628:        /* (blue steel) */
5003       element = EL_STEEL_CHAR_T;
5004       break;
5005
5006     case 0x1629:        /* (blue steel) */
5007       element = EL_STEEL_CHAR_U;
5008       break;
5009
5010     case 0x162a:        /* (blue steel) */
5011       element = EL_STEEL_CHAR_V;
5012       break;
5013
5014     case 0x162b:        /* (blue steel) */
5015       element = EL_STEEL_CHAR_W;
5016       break;
5017
5018     case 0x162c:        /* (blue steel) */
5019       element = EL_STEEL_CHAR_X;
5020       break;
5021
5022     case 0x162d:        /* (blue steel) */
5023       element = EL_STEEL_CHAR_Y;
5024       break;
5025
5026     case 0x162e:        /* (blue steel) */
5027       element = EL_STEEL_CHAR_Z;
5028       break;
5029
5030     case 0x162f:        /* (blue steel) */
5031       element = EL_STEEL_CHAR_AUMLAUT;
5032       break;
5033
5034     case 0x1630:        /* (blue steel) */
5035       element = EL_STEEL_CHAR_OUMLAUT;
5036       break;
5037
5038     case 0x1631:        /* (blue steel) */
5039       element = EL_STEEL_CHAR_UUMLAUT;
5040       break;
5041
5042     case 0x1632:        /* (blue steel) */
5043       element = EL_STEEL_CHAR_0;
5044       break;
5045
5046     case 0x1633:        /* (blue steel) */
5047       element = EL_STEEL_CHAR_1;
5048       break;
5049
5050     case 0x1634:        /* (blue steel) */
5051       element = EL_STEEL_CHAR_2;
5052       break;
5053
5054     case 0x1635:        /* (blue steel) */
5055       element = EL_STEEL_CHAR_3;
5056       break;
5057
5058     case 0x1636:        /* (blue steel) */
5059       element = EL_STEEL_CHAR_4;
5060       break;
5061
5062     case 0x1637:        /* (blue steel) */
5063       element = EL_STEEL_CHAR_5;
5064       break;
5065
5066     case 0x1638:        /* (blue steel) */
5067       element = EL_STEEL_CHAR_6;
5068       break;
5069
5070     case 0x1639:        /* (blue steel) */
5071       element = EL_STEEL_CHAR_7;
5072       break;
5073
5074     case 0x163a:        /* (blue steel) */
5075       element = EL_STEEL_CHAR_8;
5076       break;
5077
5078     case 0x163b:        /* (blue steel) */
5079       element = EL_STEEL_CHAR_9;
5080       break;
5081
5082     case 0x163c:        /* (blue steel) */
5083       element = EL_STEEL_CHAR_PERIOD;
5084       break;
5085
5086     case 0x163d:        /* (blue steel) */
5087       element = EL_STEEL_CHAR_EXCLAM;
5088       break;
5089
5090     case 0x163e:        /* (blue steel) */
5091       element = EL_STEEL_CHAR_COLON;
5092       break;
5093
5094     case 0x163f:        /* (blue steel) */
5095       element = EL_STEEL_CHAR_LESS;
5096       break;
5097
5098     case 0x1640:        /* (blue steel) */
5099       element = EL_STEEL_CHAR_GREATER;
5100       break;
5101
5102     case 0x1641:        /* (blue steel) */
5103       element = EL_STEEL_CHAR_QUESTION;
5104       break;
5105
5106     case 0x1642:        /* (blue steel) */
5107       element = EL_STEEL_CHAR_COPYRIGHT;
5108       break;
5109
5110     case 0x1643:        /* (blue steel) */
5111       element = EL_STEEL_CHAR_UP;
5112       break;
5113
5114     case 0x1644:        /* (blue steel) */
5115       element = EL_STEEL_CHAR_DOWN;
5116       break;
5117
5118     case 0x1645:        /* (blue steel) */
5119       element = EL_STEEL_CHAR_BUTTON;
5120       break;
5121
5122     case 0x1646:        /* (blue steel) */
5123       element = EL_STEEL_CHAR_PLUS;
5124       break;
5125
5126     case 0x1647:        /* (blue steel) */
5127       element = EL_STEEL_CHAR_MINUS;
5128       break;
5129
5130     case 0x1648:        /* (blue steel) */
5131       element = EL_STEEL_CHAR_APOSTROPHE;
5132       break;
5133
5134     case 0x1649:        /* (blue steel) */
5135       element = EL_STEEL_CHAR_PARENLEFT;
5136       break;
5137
5138     case 0x164a:        /* (blue steel) */
5139       element = EL_STEEL_CHAR_PARENRIGHT;
5140       break;
5141
5142     case 0x164b:        /* (green steel) */
5143       element = EL_STEEL_CHAR_A;
5144       break;
5145
5146     case 0x164c:        /* (green steel) */
5147       element = EL_STEEL_CHAR_B;
5148       break;
5149
5150     case 0x164d:        /* (green steel) */
5151       element = EL_STEEL_CHAR_C;
5152       break;
5153
5154     case 0x164e:        /* (green steel) */
5155       element = EL_STEEL_CHAR_D;
5156       break;
5157
5158     case 0x164f:        /* (green steel) */
5159       element = EL_STEEL_CHAR_E;
5160       break;
5161
5162     case 0x1650:        /* (green steel) */
5163       element = EL_STEEL_CHAR_F;
5164       break;
5165
5166     case 0x1651:        /* (green steel) */
5167       element = EL_STEEL_CHAR_G;
5168       break;
5169
5170     case 0x1652:        /* (green steel) */
5171       element = EL_STEEL_CHAR_H;
5172       break;
5173
5174     case 0x1653:        /* (green steel) */
5175       element = EL_STEEL_CHAR_I;
5176       break;
5177
5178     case 0x1654:        /* (green steel) */
5179       element = EL_STEEL_CHAR_J;
5180       break;
5181
5182     case 0x1655:        /* (green steel) */
5183       element = EL_STEEL_CHAR_K;
5184       break;
5185
5186     case 0x1656:        /* (green steel) */
5187       element = EL_STEEL_CHAR_L;
5188       break;
5189
5190     case 0x1657:        /* (green steel) */
5191       element = EL_STEEL_CHAR_M;
5192       break;
5193
5194     case 0x1658:        /* (green steel) */
5195       element = EL_STEEL_CHAR_N;
5196       break;
5197
5198     case 0x1659:        /* (green steel) */
5199       element = EL_STEEL_CHAR_O;
5200       break;
5201
5202     case 0x165a:        /* (green steel) */
5203       element = EL_STEEL_CHAR_P;
5204       break;
5205
5206     case 0x165b:        /* (green steel) */
5207       element = EL_STEEL_CHAR_Q;
5208       break;
5209
5210     case 0x165c:        /* (green steel) */
5211       element = EL_STEEL_CHAR_R;
5212       break;
5213
5214     case 0x165d:        /* (green steel) */
5215       element = EL_STEEL_CHAR_S;
5216       break;
5217
5218     case 0x165e:        /* (green steel) */
5219       element = EL_STEEL_CHAR_T;
5220       break;
5221
5222     case 0x165f:        /* (green steel) */
5223       element = EL_STEEL_CHAR_U;
5224       break;
5225
5226     case 0x1660:        /* (green steel) */
5227       element = EL_STEEL_CHAR_V;
5228       break;
5229
5230     case 0x1661:        /* (green steel) */
5231       element = EL_STEEL_CHAR_W;
5232       break;
5233
5234     case 0x1662:        /* (green steel) */
5235       element = EL_STEEL_CHAR_X;
5236       break;
5237
5238     case 0x1663:        /* (green steel) */
5239       element = EL_STEEL_CHAR_Y;
5240       break;
5241
5242     case 0x1664:        /* (green steel) */
5243       element = EL_STEEL_CHAR_Z;
5244       break;
5245
5246     case 0x1665:        /* (green steel) */
5247       element = EL_STEEL_CHAR_AUMLAUT;
5248       break;
5249
5250     case 0x1666:        /* (green steel) */
5251       element = EL_STEEL_CHAR_OUMLAUT;
5252       break;
5253
5254     case 0x1667:        /* (green steel) */
5255       element = EL_STEEL_CHAR_UUMLAUT;
5256       break;
5257
5258     case 0x1668:        /* (green steel) */
5259       element = EL_STEEL_CHAR_0;
5260       break;
5261
5262     case 0x1669:        /* (green steel) */
5263       element = EL_STEEL_CHAR_1;
5264       break;
5265
5266     case 0x166a:        /* (green steel) */
5267       element = EL_STEEL_CHAR_2;
5268       break;
5269
5270     case 0x166b:        /* (green steel) */
5271       element = EL_STEEL_CHAR_3;
5272       break;
5273
5274     case 0x166c:        /* (green steel) */
5275       element = EL_STEEL_CHAR_4;
5276       break;
5277
5278     case 0x166d:        /* (green steel) */
5279       element = EL_STEEL_CHAR_5;
5280       break;
5281
5282     case 0x166e:        /* (green steel) */
5283       element = EL_STEEL_CHAR_6;
5284       break;
5285
5286     case 0x166f:        /* (green steel) */
5287       element = EL_STEEL_CHAR_7;
5288       break;
5289
5290     case 0x1670:        /* (green steel) */
5291       element = EL_STEEL_CHAR_8;
5292       break;
5293
5294     case 0x1671:        /* (green steel) */
5295       element = EL_STEEL_CHAR_9;
5296       break;
5297
5298     case 0x1672:        /* (green steel) */
5299       element = EL_STEEL_CHAR_PERIOD;
5300       break;
5301
5302     case 0x1673:        /* (green steel) */
5303       element = EL_STEEL_CHAR_EXCLAM;
5304       break;
5305
5306     case 0x1674:        /* (green steel) */
5307       element = EL_STEEL_CHAR_COLON;
5308       break;
5309
5310     case 0x1675:        /* (green steel) */
5311       element = EL_STEEL_CHAR_LESS;
5312       break;
5313
5314     case 0x1676:        /* (green steel) */
5315       element = EL_STEEL_CHAR_GREATER;
5316       break;
5317
5318     case 0x1677:        /* (green steel) */
5319       element = EL_STEEL_CHAR_QUESTION;
5320       break;
5321
5322     case 0x1678:        /* (green steel) */
5323       element = EL_STEEL_CHAR_COPYRIGHT;
5324       break;
5325
5326     case 0x1679:        /* (green steel) */
5327       element = EL_STEEL_CHAR_UP;
5328       break;
5329
5330     case 0x167a:        /* (green steel) */
5331       element = EL_STEEL_CHAR_DOWN;
5332       break;
5333
5334     case 0x167b:        /* (green steel) */
5335       element = EL_STEEL_CHAR_BUTTON;
5336       break;
5337
5338     case 0x167c:        /* (green steel) */
5339       element = EL_STEEL_CHAR_PLUS;
5340       break;
5341
5342     case 0x167d:        /* (green steel) */
5343       element = EL_STEEL_CHAR_MINUS;
5344       break;
5345
5346     case 0x167e:        /* (green steel) */
5347       element = EL_STEEL_CHAR_APOSTROPHE;
5348       break;
5349
5350     case 0x167f:        /* (green steel) */
5351       element = EL_STEEL_CHAR_PARENLEFT;
5352       break;
5353
5354     case 0x1680:        /* (green steel) */
5355       element = EL_STEEL_CHAR_PARENRIGHT;
5356       break;
5357
5358     case 0x1681:        /* gate (red) */
5359       element = EL_EM_GATE_1;
5360       break;
5361
5362     case 0x1682:        /* secret gate (red) */
5363       element = EL_GATE_1_GRAY;
5364       break;
5365
5366     case 0x1683:        /* gate (yellow) */
5367       element = EL_EM_GATE_2;
5368       break;
5369
5370     case 0x1684:        /* secret gate (yellow) */
5371       element = EL_GATE_2_GRAY;
5372       break;
5373
5374     case 0x1685:        /* gate (blue) */
5375       element = EL_EM_GATE_4;
5376       break;
5377
5378     case 0x1686:        /* secret gate (blue) */
5379       element = EL_GATE_4_GRAY;
5380       break;
5381
5382     case 0x1687:        /* gate (green) */
5383       element = EL_EM_GATE_3;
5384       break;
5385
5386     case 0x1688:        /* secret gate (green) */
5387       element = EL_GATE_3_GRAY;
5388       break;
5389
5390     case 0x1689:        /* gate (white) */
5391       element = EL_DC_GATE_WHITE;
5392       break;
5393
5394     case 0x168a:        /* secret gate (white) */
5395       element = EL_DC_GATE_WHITE_GRAY;
5396       break;
5397
5398     case 0x168b:        /* secret gate (no key) */
5399       element = EL_DC_GATE_FAKE_GRAY;
5400       break;
5401
5402     case 0x168c:
5403       element = EL_ROBOT_WHEEL;
5404       break;
5405
5406     case 0x168d:
5407       element = EL_DC_TIMEGATE_SWITCH;
5408       break;
5409
5410     case 0x168e:
5411       element = EL_ACID_POOL_BOTTOM;
5412       break;
5413
5414     case 0x168f:
5415       element = EL_ACID_POOL_TOPLEFT;
5416       break;
5417
5418     case 0x1690:
5419       element = EL_ACID_POOL_TOPRIGHT;
5420       break;
5421
5422     case 0x1691:
5423       element = EL_ACID_POOL_BOTTOMLEFT;
5424       break;
5425
5426     case 0x1692:
5427       element = EL_ACID_POOL_BOTTOMRIGHT;
5428       break;
5429
5430     case 0x1693:
5431       element = EL_STEELWALL;
5432       break;
5433
5434     case 0x1694:
5435       element = EL_STEELWALL_SLIPPERY;
5436       break;
5437
5438     case 0x1695:        /* steel wall (not round) */
5439       element = EL_STEELWALL;
5440       break;
5441
5442     case 0x1696:        /* steel wall (left) */
5443       element = EL_DC_STEELWALL_1_LEFT;
5444       break;
5445
5446     case 0x1697:        /* steel wall (bottom) */
5447       element = EL_DC_STEELWALL_1_BOTTOM;
5448       break;
5449
5450     case 0x1698:        /* steel wall (right) */
5451       element = EL_DC_STEELWALL_1_RIGHT;
5452       break;
5453
5454     case 0x1699:        /* steel wall (top) */
5455       element = EL_DC_STEELWALL_1_TOP;
5456       break;
5457
5458     case 0x169a:        /* steel wall (left/bottom) */
5459       element = EL_DC_STEELWALL_1_BOTTOMLEFT;
5460       break;
5461
5462     case 0x169b:        /* steel wall (right/bottom) */
5463       element = EL_DC_STEELWALL_1_BOTTOMRIGHT;
5464       break;
5465
5466     case 0x169c:        /* steel wall (right/top) */
5467       element = EL_DC_STEELWALL_1_TOPRIGHT;
5468       break;
5469
5470     case 0x169d:        /* steel wall (left/top) */
5471       element = EL_DC_STEELWALL_1_TOPLEFT;
5472       break;
5473
5474     case 0x169e:        /* steel wall (right/bottom small) */
5475       element = EL_DC_STEELWALL_1_BOTTOMRIGHT_2;
5476       break;
5477
5478     case 0x169f:        /* steel wall (left/bottom small) */
5479       element = EL_DC_STEELWALL_1_BOTTOMLEFT_2;
5480       break;
5481
5482     case 0x16a0:        /* steel wall (right/top small) */
5483       element = EL_DC_STEELWALL_1_TOPRIGHT_2;
5484       break;
5485
5486     case 0x16a1:        /* steel wall (left/top small) */
5487       element = EL_DC_STEELWALL_1_TOPLEFT_2;
5488       break;
5489
5490     case 0x16a2:        /* steel wall (left/right) */
5491       element = EL_DC_STEELWALL_1_VERTICAL;
5492       break;
5493
5494     case 0x16a3:        /* steel wall (top/bottom) */
5495       element = EL_DC_STEELWALL_1_HORIZONTAL;
5496       break;
5497
5498     case 0x16a4:        /* steel wall 2 (left end) */
5499       element = EL_DC_STEELWALL_2_LEFT;
5500       break;
5501
5502     case 0x16a5:        /* steel wall 2 (right end) */
5503       element = EL_DC_STEELWALL_2_RIGHT;
5504       break;
5505
5506     case 0x16a6:        /* steel wall 2 (top end) */
5507       element = EL_DC_STEELWALL_2_TOP;
5508       break;
5509
5510     case 0x16a7:        /* steel wall 2 (bottom end) */
5511       element = EL_DC_STEELWALL_2_BOTTOM;
5512       break;
5513
5514     case 0x16a8:        /* steel wall 2 (left/right) */
5515       element = EL_DC_STEELWALL_2_HORIZONTAL;
5516       break;
5517
5518     case 0x16a9:        /* steel wall 2 (up/down) */
5519       element = EL_DC_STEELWALL_2_VERTICAL;
5520       break;
5521
5522     case 0x16aa:        /* steel wall 2 (mid) */
5523       element = EL_DC_STEELWALL_2_MIDDLE;
5524       break;
5525
5526     case 0x16ab:
5527       element = EL_SIGN_EXCLAMATION;
5528       break;
5529
5530     case 0x16ac:
5531       element = EL_SIGN_RADIOACTIVITY;
5532       break;
5533
5534     case 0x16ad:
5535       element = EL_SIGN_STOP;
5536       break;
5537
5538     case 0x16ae:
5539       element = EL_SIGN_WHEELCHAIR;
5540       break;
5541
5542     case 0x16af:
5543       element = EL_SIGN_PARKING;
5544       break;
5545
5546     case 0x16b0:
5547       element = EL_SIGN_NO_ENTRY;
5548       break;
5549
5550     case 0x16b1:
5551       element = EL_SIGN_HEART;
5552       break;
5553
5554     case 0x16b2:
5555       element = EL_SIGN_GIVE_WAY;
5556       break;
5557
5558     case 0x16b3:
5559       element = EL_SIGN_ENTRY_FORBIDDEN;
5560       break;
5561
5562     case 0x16b4:
5563       element = EL_SIGN_EMERGENCY_EXIT;
5564       break;
5565
5566     case 0x16b5:
5567       element = EL_SIGN_YIN_YANG;
5568       break;
5569
5570     case 0x16b6:
5571       element = EL_WALL_EMERALD;
5572       break;
5573
5574     case 0x16b7:
5575       element = EL_WALL_DIAMOND;
5576       break;
5577
5578     case 0x16b8:
5579       element = EL_WALL_PEARL;
5580       break;
5581
5582     case 0x16b9:
5583       element = EL_WALL_CRYSTAL;
5584       break;
5585
5586     case 0x16ba:
5587       element = EL_INVISIBLE_WALL;
5588       break;
5589
5590     case 0x16bb:
5591       element = EL_INVISIBLE_STEELWALL;
5592       break;
5593
5594       /* 0x16bc - 0x16cb: */
5595       /* EL_INVISIBLE_SAND */
5596
5597     case 0x16cc:
5598       element = EL_LIGHT_SWITCH;
5599       break;
5600
5601     case 0x16cd:
5602       element = EL_ENVELOPE_1;
5603       break;
5604
5605     default:
5606       if (element >= 0x0117 && element <= 0x036e)       /* (?) */
5607         element = EL_DIAMOND;
5608       else if (element >= 0x042d && element <= 0x0684)  /* (?) */
5609         element = EL_EMERALD;
5610       else if (element >= 0x157c && element <= 0x158b)
5611         element = EL_SAND;
5612       else if (element >= 0x1590 && element <= 0x159f)
5613         element = EL_DC_LANDMINE;
5614       else if (element >= 0x16bc && element <= 0x16cb)
5615         element = EL_INVISIBLE_SAND;
5616       else
5617       {
5618         Error(ERR_WARN, "unknown Diamond Caves element 0x%04x", element);
5619         element = EL_UNKNOWN;
5620       }
5621       break;
5622   }
5623
5624   return getMappedElement(element);
5625 }
5626
5627 #if 1
5628
5629 static void LoadLevelFromFileStream_DC(FILE *file, struct LevelInfo *level,
5630                                        int nr)
5631 {
5632   byte header[DC_LEVEL_HEADER_SIZE];
5633   int envelope_size;
5634   int envelope_header_pos = 62;
5635   int envelope_content_pos = 94;
5636   int level_name_pos = 251;
5637   int level_author_pos = 292;
5638   int envelope_header_len;
5639   int envelope_content_len;
5640   int level_name_len;
5641   int level_author_len;
5642   int fieldx, fieldy;
5643   int num_yamyam_contents;
5644   int i, x, y;
5645
5646   getDecodedWord_DC(0, TRUE);           /* initialize DC2 decoding engine */
5647
5648   for (i = 0; i < DC_LEVEL_HEADER_SIZE / 2; i++)
5649   {
5650     unsigned short header_word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
5651
5652     header[i * 2 + 0] = header_word >> 8;
5653     header[i * 2 + 1] = header_word & 0xff;
5654   }
5655
5656   /* read some values from level header to check level decoding integrity */
5657   fieldx = header[6] | (header[7] << 8);
5658   fieldy = header[8] | (header[9] << 8);
5659   num_yamyam_contents = header[60] | (header[61] << 8);
5660
5661   /* do some simple sanity checks to ensure that level was correctly decoded */
5662   if (fieldx < 1 || fieldx > 256 ||
5663       fieldy < 1 || fieldy > 256 ||
5664       num_yamyam_contents < 1 || num_yamyam_contents > 8)
5665   {
5666     level->no_valid_file = TRUE;
5667
5668     Error(ERR_WARN, "cannot decode level from stream -- using empty level");
5669
5670     return;
5671   }
5672
5673   /* maximum envelope header size is 31 bytes */
5674   envelope_header_len   = header[envelope_header_pos];
5675   /* maximum envelope content size is 110 (156?) bytes */
5676   envelope_content_len  = header[envelope_content_pos];
5677
5678   /* maximum level title size is 40 bytes */
5679   level_name_len        = MIN(header[level_name_pos],   MAX_LEVEL_NAME_LEN);
5680   /* maximum level author size is 30 (51?) bytes */
5681   level_author_len      = MIN(header[level_author_pos], MAX_LEVEL_AUTHOR_LEN);
5682
5683   envelope_size = 0;
5684
5685   for (i = 0; i < envelope_header_len; i++)
5686     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
5687       level->envelope[0].text[envelope_size++] =
5688         header[envelope_header_pos + 1 + i];
5689
5690   if (envelope_header_len > 0 && envelope_content_len > 0)
5691   {
5692     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
5693       level->envelope[0].text[envelope_size++] = '\n';
5694     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
5695       level->envelope[0].text[envelope_size++] = '\n';
5696   }
5697
5698   for (i = 0; i < envelope_content_len; i++)
5699     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
5700       level->envelope[0].text[envelope_size++] =
5701         header[envelope_content_pos + 1 + i];
5702
5703   level->envelope[0].text[envelope_size] = '\0';
5704
5705   level->envelope[0].xsize = MAX_ENVELOPE_XSIZE;
5706   level->envelope[0].ysize = 10;
5707   level->envelope[0].autowrap = TRUE;
5708   level->envelope[0].centered = TRUE;
5709
5710   for (i = 0; i < level_name_len; i++)
5711     level->name[i] = header[level_name_pos + 1 + i];
5712   level->name[level_name_len] = '\0';
5713
5714   for (i = 0; i < level_author_len; i++)
5715     level->author[i] = header[level_author_pos + 1 + i];
5716   level->author[level_author_len] = '\0';
5717
5718   num_yamyam_contents = header[60] | (header[61] << 8);
5719   level->num_yamyam_contents =
5720     MIN(MAX(MIN_ELEMENT_CONTENTS, num_yamyam_contents), MAX_ELEMENT_CONTENTS);
5721
5722   for (i = 0; i < num_yamyam_contents; i++)
5723   {
5724     for (y = 0; y < 3; y++) for (x = 0; x < 3; x++)
5725     {
5726       unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
5727 #if 1
5728       int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff);
5729 #else
5730       int element_dc = word;
5731 #endif
5732
5733       if (i < MAX_ELEMENT_CONTENTS)
5734         level->yamyam_content[i].e[x][y] = getMappedElement_DC(element_dc);
5735     }
5736   }
5737
5738   fieldx = header[6] | (header[7] << 8);
5739   fieldy = header[8] | (header[9] << 8);
5740   level->fieldx = MIN(MAX(MIN_LEV_FIELDX, fieldx), MAX_LEV_FIELDX);
5741   level->fieldy = MIN(MAX(MIN_LEV_FIELDY, fieldy), MAX_LEV_FIELDY);
5742
5743   for (y = 0; y < fieldy; y++) for (x = 0; x < fieldx; x++)
5744   {
5745     unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
5746 #if 1
5747     int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff);
5748 #else
5749     int element_dc = word;
5750 #endif
5751
5752     if (x < MAX_LEV_FIELDX && y < MAX_LEV_FIELDY)
5753       level->field[x][y] = getMappedElement_DC(element_dc);
5754   }
5755
5756   x = MIN(MAX(0, (header[10] | (header[11] << 8)) - 1), MAX_LEV_FIELDX - 1);
5757   y = MIN(MAX(0, (header[12] | (header[13] << 8)) - 1), MAX_LEV_FIELDY - 1);
5758   level->field[x][y] = EL_PLAYER_1;
5759
5760   x = MIN(MAX(0, (header[14] | (header[15] << 8)) - 1), MAX_LEV_FIELDX - 1);
5761   y = MIN(MAX(0, (header[16] | (header[17] << 8)) - 1), MAX_LEV_FIELDY - 1);
5762   level->field[x][y] = EL_PLAYER_2;
5763
5764   level->gems_needed            = header[18] | (header[19] << 8);
5765
5766   level->score[SC_EMERALD]      = header[20] | (header[21] << 8);
5767   level->score[SC_DIAMOND]      = header[22] | (header[23] << 8);
5768   level->score[SC_PEARL]        = header[24] | (header[25] << 8);
5769   level->score[SC_CRYSTAL]      = header[26] | (header[27] << 8);
5770   level->score[SC_NUT]          = header[28] | (header[29] << 8);
5771   level->score[SC_ROBOT]        = header[30] | (header[31] << 8);
5772   level->score[SC_SPACESHIP]    = header[32] | (header[33] << 8);
5773   level->score[SC_BUG]          = header[34] | (header[35] << 8);
5774   level->score[SC_YAMYAM]       = header[36] | (header[37] << 8);
5775   level->score[SC_DYNAMITE]     = header[38] | (header[39] << 8);
5776   level->score[SC_KEY]          = header[40] | (header[41] << 8);
5777   level->score[SC_TIME_BONUS]   = header[42] | (header[43] << 8);
5778
5779   level->time                   = header[44] | (header[45] << 8);
5780
5781   level->amoeba_speed           = header[46] | (header[47] << 8);
5782   level->time_light             = header[48] | (header[49] << 8);
5783   level->time_timegate          = header[50] | (header[51] << 8);
5784   level->time_wheel             = header[52] | (header[53] << 8);
5785   level->time_magic_wall        = header[54] | (header[55] << 8);
5786   level->extra_time             = header[56] | (header[57] << 8);
5787   level->shield_normal_time     = header[58] | (header[59] << 8);
5788
5789   /* Diamond Caves has the same (strange) behaviour as Emerald Mine that gems
5790      can slip down from flat walls, like normal walls and steel walls */
5791   level->em_slippery_gems = TRUE;
5792
5793 #if 0
5794   /* Diamond Caves II levels are always surrounded by indestructible wall, but
5795      not necessarily in a rectangular way -- fill with invisible steel wall */
5796
5797   /* !!! not always true !!! keep level and set BorderElement instead !!! */
5798
5799   for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
5800   {
5801 #if 1
5802     if ((x == 0 || x == level->fieldx - 1 ||
5803          y == 0 || y == level->fieldy - 1) &&
5804         level->field[x][y] == EL_EMPTY)
5805       level->field[x][y] = EL_INVISIBLE_STEELWALL;
5806 #else
5807     if ((x == 0 || x == level->fieldx - 1 ||
5808          y == 0 || y == level->fieldy - 1) &&
5809         level->field[x][y] == EL_EMPTY)
5810       FloodFillLevel(x, y, EL_INVISIBLE_STEELWALL,
5811                      level->field, level->fieldx, level->fieldy);
5812 #endif
5813   }
5814 #endif
5815 }
5816
5817 static void LoadLevelFromFileInfo_DC(struct LevelInfo *level,
5818                                      struct LevelFileInfo *level_file_info)
5819 {
5820   char *filename = level_file_info->filename;
5821   FILE *file;
5822   int num_magic_bytes = 8;
5823   char magic_bytes[num_magic_bytes + 1];
5824   int num_levels_to_skip = level_file_info->nr - leveldir_current->first_level;
5825
5826   if (!(file = fopen(filename, MODE_READ)))
5827   {
5828     level->no_valid_file = TRUE;
5829
5830     Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
5831
5832     return;
5833   }
5834
5835   // fseek(file, 0x0000, SEEK_SET);
5836
5837   if (level_file_info->packed)
5838   {
5839     /* read "magic bytes" from start of file */
5840     fgets(magic_bytes, num_magic_bytes + 1, file);
5841
5842     /* check "magic bytes" for correct file format */
5843     if (!strPrefix(magic_bytes, "DC2"))
5844     {
5845       level->no_valid_file = TRUE;
5846
5847       Error(ERR_WARN, "unknown DC level file '%s' -- using empty level",
5848             filename);
5849
5850       return;
5851     }
5852
5853     if (strPrefix(magic_bytes, "DC2Win95") ||
5854         strPrefix(magic_bytes, "DC2Win98"))
5855     {
5856       int position_first_level = 0x00fa;
5857       int extra_bytes = 4;
5858       int skip_bytes;
5859
5860       /* advance file stream to first level inside the level package */
5861       skip_bytes = position_first_level - num_magic_bytes - extra_bytes;
5862
5863       /* each block of level data is followed by block of non-level data */
5864       num_levels_to_skip *= 2;
5865
5866       /* at least skip header bytes, therefore use ">= 0" instead of "> 0" */
5867       while (num_levels_to_skip >= 0)
5868       {
5869         /* advance file stream to next level inside the level package */
5870         if (fseek(file, skip_bytes, SEEK_CUR) != 0)
5871         {
5872           level->no_valid_file = TRUE;
5873
5874           Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level",
5875                 filename);
5876
5877           return;
5878         }
5879
5880         /* skip apparently unused extra bytes following each level */
5881         ReadUnusedBytesFromFile(file, extra_bytes);
5882
5883         /* read size of next level in level package */
5884         skip_bytes = getFile32BitLE(file);
5885
5886         num_levels_to_skip--;
5887       }
5888     }
5889     else
5890     {
5891       level->no_valid_file = TRUE;
5892
5893       Error(ERR_WARN, "unknown DC2 level file '%s' -- using empty level",
5894             filename);
5895
5896       return;
5897     }
5898   }
5899
5900   LoadLevelFromFileStream_DC(file, level, level_file_info->nr);
5901
5902   fclose(file);
5903 }
5904
5905 #else
5906
5907 static void LoadLevelFromFileInfo_DC(struct LevelInfo *level,
5908                                      struct LevelFileInfo *level_file_info)
5909 {
5910   char *filename = level_file_info->filename;
5911   FILE *file;
5912 #if 0
5913   int nr = level_file_info->nr - leveldir_current->first_level;
5914 #endif
5915   byte header[DC_LEVEL_HEADER_SIZE];
5916   int envelope_size;
5917   int envelope_header_pos = 62;
5918   int envelope_content_pos = 94;
5919   int level_name_pos = 251;
5920   int level_author_pos = 292;
5921   int envelope_header_len;
5922   int envelope_content_len;
5923   int level_name_len;
5924   int level_author_len;
5925   int fieldx, fieldy;
5926   int num_yamyam_contents;
5927   int i, x, y;
5928
5929   if (!(file = fopen(filename, MODE_READ)))
5930   {
5931     level->no_valid_file = TRUE;
5932
5933     Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
5934
5935     return;
5936   }
5937
5938 #if 0
5939   /* position file stream to the requested level inside the level package */
5940   if (fseek(file, nr * SP_LEVEL_SIZE, SEEK_SET) != 0)
5941   {
5942     level->no_valid_file = TRUE;
5943
5944     Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level", filename);
5945
5946     return;
5947   }
5948 #endif
5949
5950   getDecodedWord_DC(0, TRUE);           /* initialize DC2 decoding engine */
5951
5952   for (i = 0; i < DC_LEVEL_HEADER_SIZE / 2; i++)
5953   {
5954     unsigned short header_word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
5955
5956     header[i * 2 + 0] = header_word >> 8;
5957     header[i * 2 + 1] = header_word & 0xff;
5958   }
5959
5960   /* read some values from level header to check level decoding integrity */
5961   fieldx = header[6] | (header[7] << 8);
5962   fieldy = header[8] | (header[9] << 8);
5963   num_yamyam_contents = header[60] | (header[61] << 8);
5964
5965   /* do some simple sanity checks to ensure that level was correctly decoded */
5966   if (fieldx < 1 || fieldx > 256 ||
5967       fieldy < 1 || fieldy > 256 ||
5968       num_yamyam_contents < 1 || num_yamyam_contents > 8)
5969   {
5970     level->no_valid_file = TRUE;
5971
5972     Error(ERR_WARN, "cannot read level from file '%s' -- using empty level",
5973           filename);
5974
5975     return;
5976   }
5977
5978   /* maximum envelope header size is 31 bytes */
5979   envelope_header_len   = header[envelope_header_pos];
5980   /* maximum envelope content size is 110 (156?) bytes */
5981   envelope_content_len  = header[envelope_content_pos];
5982
5983   /* maximum level title size is 40 bytes */
5984   level_name_len        = MIN(header[level_name_pos],   MAX_LEVEL_NAME_LEN);
5985   /* maximum level author size is 30 (51?) bytes */
5986   level_author_len      = MIN(header[level_author_pos], MAX_LEVEL_AUTHOR_LEN);
5987
5988   envelope_size = 0;
5989
5990   for (i = 0; i < envelope_header_len; i++)
5991     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
5992       level->envelope[0].text[envelope_size++] =
5993         header[envelope_header_pos + 1 + i];
5994
5995   if (envelope_header_len > 0 && envelope_content_len > 0)
5996   {
5997     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
5998       level->envelope[0].text[envelope_size++] = '\n';
5999     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
6000       level->envelope[0].text[envelope_size++] = '\n';
6001   }
6002
6003   for (i = 0; i < envelope_content_len; i++)
6004     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
6005       level->envelope[0].text[envelope_size++] =
6006         header[envelope_content_pos + 1 + i];
6007
6008   level->envelope[0].text[envelope_size] = '\0';
6009
6010   level->envelope[0].xsize = MAX_ENVELOPE_XSIZE;
6011   level->envelope[0].ysize = 10;
6012   level->envelope[0].autowrap = TRUE;
6013   level->envelope[0].centered = TRUE;
6014
6015   for (i = 0; i < level_name_len; i++)
6016     level->name[i] = header[level_name_pos + 1 + i];
6017   level->name[level_name_len] = '\0';
6018
6019   for (i = 0; i < level_author_len; i++)
6020     level->author[i] = header[level_author_pos + 1 + i];
6021   level->author[level_author_len] = '\0';
6022
6023   num_yamyam_contents = header[60] | (header[61] << 8);
6024   level->num_yamyam_contents =
6025     MIN(MAX(MIN_ELEMENT_CONTENTS, num_yamyam_contents), MAX_ELEMENT_CONTENTS);
6026
6027   for (i = 0; i < num_yamyam_contents; i++)
6028   {
6029     for (y = 0; y < 3; y++) for (x = 0; x < 3; x++)
6030     {
6031       unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
6032 #if 1
6033       int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff);
6034 #else
6035       int element_dc = word;
6036 #endif
6037
6038       if (i < MAX_ELEMENT_CONTENTS)
6039         level->yamyam_content[i].e[x][y] = getMappedElement_DC(element_dc);
6040     }
6041   }
6042
6043   fieldx = header[6] | (header[7] << 8);
6044   fieldy = header[8] | (header[9] << 8);
6045   level->fieldx = MIN(MAX(MIN_LEV_FIELDX, fieldx), MAX_LEV_FIELDX);
6046   level->fieldy = MIN(MAX(MIN_LEV_FIELDY, fieldy), MAX_LEV_FIELDY);
6047
6048   for (y = 0; y < fieldy; y++) for (x = 0; x < fieldx; x++)
6049   {
6050     unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
6051 #if 1
6052     int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff);
6053 #else
6054     int element_dc = word;
6055 #endif
6056
6057     if (x < MAX_LEV_FIELDX && y < MAX_LEV_FIELDY)
6058       level->field[x][y] = getMappedElement_DC(element_dc);
6059   }
6060
6061   x = MIN(MAX(0, (header[10] | (header[11] << 8)) - 1), MAX_LEV_FIELDX - 1);
6062   y = MIN(MAX(0, (header[12] | (header[13] << 8)) - 1), MAX_LEV_FIELDY - 1);
6063   level->field[x][y] = EL_PLAYER_1;
6064
6065   x = MIN(MAX(0, (header[14] | (header[15] << 8)) - 1), MAX_LEV_FIELDX - 1);
6066   y = MIN(MAX(0, (header[16] | (header[17] << 8)) - 1), MAX_LEV_FIELDY - 1);
6067   level->field[x][y] = EL_PLAYER_2;
6068
6069   level->gems_needed            = header[18] | (header[19] << 8);
6070
6071   level->score[SC_EMERALD]      = header[20] | (header[21] << 8);
6072   level->score[SC_DIAMOND]      = header[22] | (header[23] << 8);
6073   level->score[SC_PEARL]        = header[24] | (header[25] << 8);
6074   level->score[SC_CRYSTAL]      = header[26] | (header[27] << 8);
6075   level->score[SC_NUT]          = header[28] | (header[29] << 8);
6076   level->score[SC_ROBOT]        = header[30] | (header[31] << 8);
6077   level->score[SC_SPACESHIP]    = header[32] | (header[33] << 8);
6078   level->score[SC_BUG]          = header[34] | (header[35] << 8);
6079   level->score[SC_YAMYAM]       = header[36] | (header[37] << 8);
6080   level->score[SC_DYNAMITE]     = header[38] | (header[39] << 8);
6081   level->score[SC_KEY]          = header[40] | (header[41] << 8);
6082   level->score[SC_TIME_BONUS]   = header[42] | (header[43] << 8);
6083
6084   level->time                   = header[44] | (header[45] << 8);
6085
6086   level->amoeba_speed           = header[46] | (header[47] << 8);
6087   level->time_light             = header[48] | (header[49] << 8);
6088   level->time_timegate          = header[50] | (header[51] << 8);
6089   level->time_wheel             = header[52] | (header[53] << 8);
6090   level->time_magic_wall        = header[54] | (header[55] << 8);
6091   level->extra_time             = header[56] | (header[57] << 8);
6092   level->shield_normal_time     = header[58] | (header[59] << 8);
6093
6094   fclose(file);
6095
6096   /* Diamond Caves has the same (strange) behaviour as Emerald Mine that gems
6097      can slip down from flat walls, like normal walls and steel walls */
6098   level->em_slippery_gems = TRUE;
6099
6100 #if 0
6101   /* Diamond Caves II levels are always surrounded by indestructible wall, but
6102      not necessarily in a rectangular way -- fill with invisible steel wall */
6103
6104   /* !!! not always true !!! keep level and set BorderElement instead !!! */
6105
6106   for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
6107   {
6108 #if 1
6109     if ((x == 0 || x == level->fieldx - 1 ||
6110          y == 0 || y == level->fieldy - 1) &&
6111         level->field[x][y] == EL_EMPTY)
6112       level->field[x][y] = EL_INVISIBLE_STEELWALL;
6113 #else
6114     if ((x == 0 || x == level->fieldx - 1 ||
6115          y == 0 || y == level->fieldy - 1) &&
6116         level->field[x][y] == EL_EMPTY)
6117       FloodFillLevel(x, y, EL_INVISIBLE_STEELWALL,
6118                      level->field, level->fieldx, level->fieldy);
6119 #endif
6120   }
6121 #endif
6122 }
6123
6124 #endif
6125
6126
6127 /* ------------------------------------------------------------------------- */
6128 /* functions for loading generic level                                       */
6129 /* ------------------------------------------------------------------------- */
6130
6131 void LoadLevelFromFileInfo(struct LevelInfo *level,
6132                            struct LevelFileInfo *level_file_info)
6133 {
6134   /* always start with reliable default values */
6135   setLevelInfoToDefaults(level);
6136
6137   switch (level_file_info->type)
6138   {
6139     case LEVEL_FILE_TYPE_RND:
6140       LoadLevelFromFileInfo_RND(level, level_file_info);
6141       break;
6142
6143     case LEVEL_FILE_TYPE_EM:
6144       LoadLevelFromFileInfo_EM(level, level_file_info);
6145       level->game_engine_type = GAME_ENGINE_TYPE_EM;
6146       break;
6147
6148     case LEVEL_FILE_TYPE_SP:
6149       LoadLevelFromFileInfo_SP(level, level_file_info);
6150       break;
6151
6152     case LEVEL_FILE_TYPE_DC:
6153       LoadLevelFromFileInfo_DC(level, level_file_info);
6154       break;
6155
6156     default:
6157       LoadLevelFromFileInfo_RND(level, level_file_info);
6158       break;
6159   }
6160
6161   /* if level file is invalid, restore level structure to default values */
6162   if (level->no_valid_file)
6163     setLevelInfoToDefaults(level);
6164
6165   if (level->game_engine_type == GAME_ENGINE_TYPE_UNKNOWN)
6166     level->game_engine_type = GAME_ENGINE_TYPE_RND;
6167
6168   if (level_file_info->type != LEVEL_FILE_TYPE_RND)
6169     CopyNativeLevel_Native_to_RND(level);
6170 }
6171
6172 void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
6173 {
6174   static struct LevelFileInfo level_file_info;
6175
6176   /* always start with reliable default values */
6177   setFileInfoToDefaults(&level_file_info);
6178
6179   level_file_info.nr = 0;                       /* unknown level number */
6180   level_file_info.type = LEVEL_FILE_TYPE_RND;   /* no others supported yet */
6181   level_file_info.filename = filename;
6182
6183   LoadLevelFromFileInfo(level, &level_file_info);
6184 }
6185
6186 static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
6187 {
6188   int i, j;
6189
6190   if (leveldir_current == NULL)         /* only when dumping level */
6191     return;
6192
6193   /* all engine modifications also valid for levels which use latest engine */
6194   if (level->game_version < VERSION_IDENT(3,2,0,5))
6195   {
6196     /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */
6197     level->score[SC_TIME_BONUS] /= 10;
6198   }
6199
6200 #if 0
6201   leveldir_current->latest_engine = TRUE;       /* !!! TEST ONLY !!! */
6202 #endif
6203
6204   if (leveldir_current->latest_engine)
6205   {
6206     /* ---------- use latest game engine ----------------------------------- */
6207
6208     /* For all levels which are forced to use the latest game engine version
6209        (normally all but user contributed, private and undefined levels), set
6210        the game engine version to the actual version; this allows for actual
6211        corrections in the game engine to take effect for existing, converted
6212        levels (from "classic" or other existing games) to make the emulation
6213        of the corresponding game more accurate, while (hopefully) not breaking
6214        existing levels created from other players. */
6215
6216     level->game_version = GAME_VERSION_ACTUAL;
6217
6218     /* Set special EM style gems behaviour: EM style gems slip down from
6219        normal, steel and growing wall. As this is a more fundamental change,
6220        it seems better to set the default behaviour to "off" (as it is more
6221        natural) and make it configurable in the level editor (as a property
6222        of gem style elements). Already existing converted levels (neither
6223        private nor contributed levels) are changed to the new behaviour. */
6224
6225     if (level->file_version < FILE_VERSION_2_0)
6226       level->em_slippery_gems = TRUE;
6227
6228     return;
6229   }
6230
6231   /* ---------- use game engine the level was created with ----------------- */
6232
6233   /* For all levels which are not forced to use the latest game engine
6234      version (normally user contributed, private and undefined levels),
6235      use the version of the game engine the levels were created for.
6236
6237      Since 2.0.1, the game engine version is now directly stored
6238      in the level file (chunk "VERS"), so there is no need anymore
6239      to set the game version from the file version (except for old,
6240      pre-2.0 levels, where the game version is still taken from the
6241      file format version used to store the level -- see above). */
6242
6243   /* player was faster than enemies in 1.0.0 and before */
6244   if (level->file_version == FILE_VERSION_1_0)
6245     for (i = 0; i < MAX_PLAYERS; i++)
6246       level->initial_player_stepsize[i] = STEPSIZE_FAST;
6247
6248   /* default behaviour for EM style gems was "slippery" only in 2.0.1 */
6249   if (level->game_version == VERSION_IDENT(2,0,1,0))
6250     level->em_slippery_gems = TRUE;
6251
6252   /* springs could be pushed over pits before (pre-release version) 2.2.0 */
6253   if (level->game_version < VERSION_IDENT(2,2,0,0))
6254     level->use_spring_bug = TRUE;
6255
6256   if (level->game_version < VERSION_IDENT(3,2,0,5))
6257   {
6258     /* time orb caused limited time in endless time levels before 3.2.0-5 */
6259     level->use_time_orb_bug = TRUE;
6260
6261     /* default behaviour for snapping was "no snap delay" before 3.2.0-5 */
6262     level->block_snap_field = FALSE;
6263
6264     /* extra time score was same value as time left score before 3.2.0-5 */
6265     level->extra_time_score = level->score[SC_TIME_BONUS];
6266
6267 #if 0
6268     /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */
6269     level->score[SC_TIME_BONUS] /= 10;
6270 #endif
6271   }
6272
6273   if (level->game_version < VERSION_IDENT(3,2,0,7))
6274   {
6275     /* default behaviour for snapping was "not continuous" before 3.2.0-7 */
6276     level->continuous_snapping = FALSE;
6277   }
6278
6279   /* only few elements were able to actively move into acid before 3.1.0 */
6280   /* trigger settings did not exist before 3.1.0; set to default "any" */
6281   if (level->game_version < VERSION_IDENT(3,1,0,0))
6282   {
6283     /* correct "can move into acid" settings (all zero in old levels) */
6284
6285     level->can_move_into_acid_bits = 0; /* nothing can move into acid */
6286     level->dont_collide_with_bits = 0; /* nothing is deadly when colliding */
6287
6288     setMoveIntoAcidProperty(level, EL_ROBOT,     TRUE);
6289     setMoveIntoAcidProperty(level, EL_SATELLITE, TRUE);
6290     setMoveIntoAcidProperty(level, EL_PENGUIN,   TRUE);
6291     setMoveIntoAcidProperty(level, EL_BALLOON,   TRUE);
6292
6293     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6294       SET_PROPERTY(EL_CUSTOM_START + i, EP_CAN_MOVE_INTO_ACID, TRUE);
6295
6296     /* correct trigger settings (stored as zero == "none" in old levels) */
6297
6298     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6299     {
6300       int element = EL_CUSTOM_START + i;
6301       struct ElementInfo *ei = &element_info[element];
6302
6303       for (j = 0; j < ei->num_change_pages; j++)
6304       {
6305         struct ElementChangeInfo *change = &ei->change_page[j];
6306
6307         change->trigger_player = CH_PLAYER_ANY;
6308         change->trigger_page = CH_PAGE_ANY;
6309       }
6310     }
6311   }
6312
6313   /* try to detect and fix "Snake Bite" levels, which are broken with 3.2.0 */
6314   {
6315     int element = EL_CUSTOM_256;
6316     struct ElementInfo *ei = &element_info[element];
6317     struct ElementChangeInfo *change = &ei->change_page[0];
6318
6319     /* This is needed to fix a problem that was caused by a bugfix in function
6320        game.c/CreateFieldExt() introduced with 3.2.0 that corrects the behaviour
6321        when a custom element changes to EL_SOKOBAN_FIELD_PLAYER (before, it did
6322        not replace walkable elements, but instead just placed the player on it,
6323        without placing the Sokoban field under the player). Unfortunately, this
6324        breaks "Snake Bite" style levels when the snake is halfway through a door
6325        that just closes (the snake head is still alive and can be moved in this
6326        case). This can be fixed by replacing the EL_SOKOBAN_FIELD_PLAYER by the
6327        player (without Sokoban element) which then gets killed as designed). */
6328
6329     if ((strncmp(leveldir_current->identifier, "snake_bite", 10) == 0 ||
6330          strncmp(ei->description, "pause b4 death", 14) == 0) &&
6331         change->target_element == EL_SOKOBAN_FIELD_PLAYER)
6332       change->target_element = EL_PLAYER_1;
6333   }
6334
6335   /* try to detect and fix "Zelda II" levels, which are broken with 3.2.5 */
6336   {
6337     int element = EL_CUSTOM_16;
6338     struct ElementInfo *ei = &element_info[element];
6339
6340     /* This is needed to fix a problem that was caused by a bugfix in function
6341        game.c/CheckTriggeredElementChangeExt() introduced with 3.2.5 that
6342        corrects the behaviour when a custom element changes to another custom
6343        element with a higher element number that has change actions defined.
6344        Normally, only one change per frame is allowed for custom elements.
6345        Therefore, it is checked if a custom element already changed in the
6346        current frame; if it did, subsequent changes are suppressed.
6347        Unfortunately, this is only checked for element changes, but not for
6348        change actions, which are still executed. As the function above loops
6349        through all custom elements from lower to higher, an element change
6350        resulting in a lower CE number won't be checked again, while a target
6351        element with a higher number will also be checked, and potential change
6352        actions will get executed for this CE, too (which is wrong), while
6353        further changes are ignored (which is correct). As this bugfix breaks
6354        Zelda II (but no other levels), allow the previous, incorrect behaviour
6355        for this outstanding level set to not break the game or existing tapes */
6356
6357     if (strncmp(leveldir_current->identifier, "zelda2", 6) == 0 ||
6358         strncmp(ei->description, "scanline - row 1", 16) == 0)
6359       level->use_action_after_change_bug = TRUE;
6360   }
6361
6362   /* not centering level after relocating player was default only in 3.2.3 */
6363   if (level->game_version == VERSION_IDENT(3,2,3,0))    /* (no pre-releases) */
6364     level->shifted_relocation = TRUE;
6365 }
6366
6367 static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
6368 {
6369   int i, j, x, y;
6370
6371   /* map custom element change events that have changed in newer versions
6372      (these following values were accidentally changed in version 3.0.1)
6373      (this seems to be needed only for 'ab_levelset3' and 'ab_levelset4') */
6374   if (level->game_version <= VERSION_IDENT(3,0,0,0))
6375   {
6376     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6377     {
6378       int element = EL_CUSTOM_START + i;
6379
6380       /* order of checking and copying events to be mapped is important */
6381       /* (do not change the start and end value -- they are constant) */
6382       for (j = CE_BY_OTHER_ACTION; j >= CE_VALUE_GETS_ZERO; j--)
6383       {
6384         if (HAS_CHANGE_EVENT(element, j - 2))
6385         {
6386           SET_CHANGE_EVENT(element, j - 2, FALSE);
6387           SET_CHANGE_EVENT(element, j, TRUE);
6388         }
6389       }
6390
6391       /* order of checking and copying events to be mapped is important */
6392       /* (do not change the start and end value -- they are constant) */
6393       for (j = CE_PLAYER_COLLECTS_X; j >= CE_HITTING_SOMETHING; j--)
6394       {
6395         if (HAS_CHANGE_EVENT(element, j - 1))
6396         {
6397           SET_CHANGE_EVENT(element, j - 1, FALSE);
6398           SET_CHANGE_EVENT(element, j, TRUE);
6399         }
6400       }
6401     }
6402   }
6403
6404   /* initialize "can_change" field for old levels with only one change page */
6405   if (level->game_version <= VERSION_IDENT(3,0,2,0))
6406   {
6407     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6408     {
6409       int element = EL_CUSTOM_START + i;
6410
6411       if (CAN_CHANGE(element))
6412         element_info[element].change->can_change = TRUE;
6413     }
6414   }
6415
6416   /* correct custom element values (for old levels without these options) */
6417   if (level->game_version < VERSION_IDENT(3,1,1,0))
6418   {
6419     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6420     {
6421       int element = EL_CUSTOM_START + i;
6422       struct ElementInfo *ei = &element_info[element];
6423
6424       if (ei->access_direction == MV_NO_DIRECTION)
6425         ei->access_direction = MV_ALL_DIRECTIONS;
6426     }
6427   }
6428
6429   /* correct custom element values (fix invalid values for all versions) */
6430   if (1)
6431   {
6432     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6433     {
6434       int element = EL_CUSTOM_START + i;
6435       struct ElementInfo *ei = &element_info[element];
6436
6437       for (j = 0; j < ei->num_change_pages; j++)
6438       {
6439         struct ElementChangeInfo *change = &ei->change_page[j];
6440
6441         if (change->trigger_player == CH_PLAYER_NONE)
6442           change->trigger_player = CH_PLAYER_ANY;
6443
6444         if (change->trigger_side == CH_SIDE_NONE)
6445           change->trigger_side = CH_SIDE_ANY;
6446       }
6447     }
6448   }
6449
6450   /* initialize "can_explode" field for old levels which did not store this */
6451   /* !!! CHECK THIS -- "<= 3,1,0,0" IS PROBABLY WRONG !!! */
6452   if (level->game_version <= VERSION_IDENT(3,1,0,0))
6453   {
6454     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6455     {
6456       int element = EL_CUSTOM_START + i;
6457
6458       if (EXPLODES_1X1_OLD(element))
6459         element_info[element].explosion_type = EXPLODES_1X1;
6460
6461       SET_PROPERTY(element, EP_CAN_EXPLODE, (EXPLODES_BY_FIRE(element) ||
6462                                              EXPLODES_SMASHED(element) ||
6463                                              EXPLODES_IMPACT(element)));
6464     }
6465   }
6466
6467   /* correct previously hard-coded move delay values for maze runner style */
6468   if (level->game_version < VERSION_IDENT(3,1,1,0))
6469   {
6470     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6471     {
6472       int element = EL_CUSTOM_START + i;
6473
6474       if (element_info[element].move_pattern & MV_MAZE_RUNNER_STYLE)
6475       {
6476         /* previously hard-coded and therefore ignored */
6477         element_info[element].move_delay_fixed = 9;
6478         element_info[element].move_delay_random = 0;
6479       }
6480     }
6481   }
6482
6483   /* map elements that have changed in newer versions */
6484   level->amoeba_content = getMappedElementByVersion(level->amoeba_content,
6485                                                     level->game_version);
6486   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
6487     for (x = 0; x < 3; x++)
6488       for (y = 0; y < 3; y++)
6489         level->yamyam_content[i].e[x][y] =
6490           getMappedElementByVersion(level->yamyam_content[i].e[x][y],
6491                                     level->game_version);
6492
6493   /* initialize element properties for level editor etc. */
6494   InitElementPropertiesEngine(level->game_version);
6495   InitElementPropertiesAfterLoading(level->game_version);
6496   InitElementPropertiesGfxElement();
6497 }
6498
6499 static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
6500 {
6501   int x, y;
6502
6503   /* map elements that have changed in newer versions */
6504   for (y = 0; y < level->fieldy; y++)
6505     for (x = 0; x < level->fieldx; x++)
6506       level->field[x][y] = getMappedElementByVersion(level->field[x][y],
6507                                                      level->game_version);
6508
6509   /* copy elements to runtime playfield array */
6510   for (x = 0; x < MAX_LEV_FIELDX; x++)
6511     for (y = 0; y < MAX_LEV_FIELDY; y++)
6512       Feld[x][y] = level->field[x][y];
6513
6514   /* initialize level size variables for faster access */
6515   lev_fieldx = level->fieldx;
6516   lev_fieldy = level->fieldy;
6517
6518   /* determine border element for this level */
6519   if (level->file_info.type == LEVEL_FILE_TYPE_DC)
6520     BorderElement = EL_EMPTY;   /* (in editor, SetBorderElement() is used) */
6521   else
6522     SetBorderElement();
6523 }
6524
6525 static void LoadLevel_InitNativeEngines(struct LevelInfo *level,char *filename)
6526 {
6527   struct LevelFileInfo *level_file_info = &level->file_info;
6528
6529   if (level_file_info->type == LEVEL_FILE_TYPE_RND)
6530     CopyNativeLevel_RND_to_Native(level);
6531 }
6532
6533 void LoadLevelTemplate(int nr)
6534 {
6535   char *filename;
6536
6537   setLevelFileInfo(&level_template.file_info, nr);
6538   filename = level_template.file_info.filename;
6539
6540   LoadLevelFromFileInfo(&level_template, &level_template.file_info);
6541
6542   LoadLevel_InitVersion(&level_template, filename);
6543   LoadLevel_InitElements(&level_template, filename);
6544
6545   ActivateLevelTemplate();
6546 }
6547
6548 void LoadLevel(int nr)
6549 {
6550   char *filename;
6551
6552   setLevelFileInfo(&level.file_info, nr);
6553   filename = level.file_info.filename;
6554
6555   LoadLevelFromFileInfo(&level, &level.file_info);
6556
6557   if (level.use_custom_template)
6558     LoadLevelTemplate(-1);
6559
6560   LoadLevel_InitVersion(&level, filename);
6561   LoadLevel_InitElements(&level, filename);
6562   LoadLevel_InitPlayfield(&level, filename);
6563
6564   LoadLevel_InitNativeEngines(&level, filename);
6565 }
6566
6567 static int SaveLevel_VERS(FILE *file, struct LevelInfo *level)
6568 {
6569   int chunk_size = 0;
6570
6571   chunk_size += putFileVersion(file, level->file_version);
6572   chunk_size += putFileVersion(file, level->game_version);
6573
6574   return chunk_size;
6575 }
6576
6577 static int SaveLevel_DATE(FILE *file, struct LevelInfo *level)
6578 {
6579   int chunk_size = 0;
6580
6581   chunk_size += putFile16BitBE(file, level->creation_date.year);
6582   chunk_size += putFile8Bit(file,    level->creation_date.month);
6583   chunk_size += putFile8Bit(file,    level->creation_date.day);
6584
6585   return chunk_size;
6586 }
6587
6588 #if 0
6589 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
6590 {
6591   int i, x, y;
6592
6593   putFile8Bit(file, level->fieldx);
6594   putFile8Bit(file, level->fieldy);
6595
6596   putFile16BitBE(file, level->time);
6597   putFile16BitBE(file, level->gems_needed);
6598
6599   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
6600     putFile8Bit(file, level->name[i]);
6601
6602   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
6603     putFile8Bit(file, level->score[i]);
6604
6605   for (i = 0; i < STD_ELEMENT_CONTENTS; i++)
6606     for (y = 0; y < 3; y++)
6607       for (x = 0; x < 3; x++)
6608         putFile8Bit(file, (level->encoding_16bit_yamyam ? EL_EMPTY :
6609                            level->yamyam_content[i].e[x][y]));
6610   putFile8Bit(file, level->amoeba_speed);
6611   putFile8Bit(file, level->time_magic_wall);
6612   putFile8Bit(file, level->time_wheel);
6613   putFile8Bit(file, (level->encoding_16bit_amoeba ? EL_EMPTY :
6614                      level->amoeba_content));
6615   putFile8Bit(file, (level->initial_player_stepsize == STEPSIZE_FAST ? 1 : 0));
6616   putFile8Bit(file, (level->initial_gravity ? 1 : 0));
6617   putFile8Bit(file, (level->encoding_16bit_field ? 1 : 0));
6618   putFile8Bit(file, (level->em_slippery_gems ? 1 : 0));
6619
6620   putFile8Bit(file, (level->use_custom_template ? 1 : 0));
6621
6622   putFile8Bit(file, (level->block_last_field ? 1 : 0));
6623   putFile8Bit(file, (level->sp_block_last_field ? 1 : 0));
6624   putFile32BitBE(file, level->can_move_into_acid_bits);
6625   putFile8Bit(file, level->dont_collide_with_bits);
6626
6627   putFile8Bit(file, (level->use_spring_bug ? 1 : 0));
6628   putFile8Bit(file, (level->use_step_counter ? 1 : 0));
6629
6630   putFile8Bit(file, (level->instant_relocation ? 1 : 0));
6631   putFile8Bit(file, (level->can_pass_to_walkable ? 1 : 0));
6632   putFile8Bit(file, (level->grow_into_diggable ? 1 : 0));
6633
6634   putFile8Bit(file, level->game_engine_type);
6635
6636   WriteUnusedBytesToFile(file, LEVEL_CHUNK_HEAD_UNUSED);
6637 }
6638 #endif
6639
6640 static int SaveLevel_NAME(FILE *file, struct LevelInfo *level)
6641 {
6642   int chunk_size = 0;
6643   int i;
6644
6645   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
6646     chunk_size += putFile8Bit(file, level->name[i]);
6647
6648   return chunk_size;
6649 }
6650
6651 static int SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
6652 {
6653   int chunk_size = 0;
6654   int i;
6655
6656   for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
6657     chunk_size += putFile8Bit(file, level->author[i]);
6658
6659   return chunk_size;
6660 }
6661
6662 #if 0
6663 static int SaveLevel_BODY(FILE *file, struct LevelInfo *level)
6664 {
6665   int chunk_size = 0;
6666   int x, y;
6667
6668   for (y = 0; y < level->fieldy; y++) 
6669     for (x = 0; x < level->fieldx; x++) 
6670       if (level->encoding_16bit_field)
6671         chunk_size += putFile16BitBE(file, level->field[x][y]);
6672       else
6673         chunk_size += putFile8Bit(file, level->field[x][y]);
6674
6675   return chunk_size;
6676 }
6677 #endif
6678
6679 static int SaveLevel_BODY(FILE *file, struct LevelInfo *level)
6680 {
6681   int chunk_size = 0;
6682   int x, y;
6683
6684   for (y = 0; y < level->fieldy; y++) 
6685     for (x = 0; x < level->fieldx; x++) 
6686       chunk_size += putFile16BitBE(file, level->field[x][y]);
6687
6688   return chunk_size;
6689 }
6690
6691 #if 0
6692 static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
6693 {
6694   int i, x, y;
6695
6696   putFile8Bit(file, EL_YAMYAM);
6697   putFile8Bit(file, level->num_yamyam_contents);
6698   putFile8Bit(file, 0);
6699   putFile8Bit(file, 0);
6700
6701   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
6702     for (y = 0; y < 3; y++)
6703       for (x = 0; x < 3; x++)
6704         if (level->encoding_16bit_field)
6705           putFile16BitBE(file, level->yamyam_content[i].e[x][y]);
6706         else
6707           putFile8Bit(file, level->yamyam_content[i].e[x][y]);
6708 }
6709 #endif
6710
6711 #if 0
6712 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
6713 {
6714   int i, x, y;
6715   int num_contents, content_xsize, content_ysize;
6716   int content_array[MAX_ELEMENT_CONTENTS][3][3];
6717
6718   if (element == EL_YAMYAM)
6719   {
6720     num_contents = level->num_yamyam_contents;
6721     content_xsize = 3;
6722     content_ysize = 3;
6723
6724     for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
6725       for (y = 0; y < 3; y++)
6726         for (x = 0; x < 3; x++)
6727           content_array[i][x][y] = level->yamyam_content[i].e[x][y];
6728   }
6729   else if (element == EL_BD_AMOEBA)
6730   {
6731     num_contents = 1;
6732     content_xsize = 1;
6733     content_ysize = 1;
6734
6735     for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
6736       for (y = 0; y < 3; y++)
6737         for (x = 0; x < 3; x++)
6738           content_array[i][x][y] = EL_EMPTY;
6739     content_array[0][0][0] = level->amoeba_content;
6740   }
6741   else
6742   {
6743     /* chunk header already written -- write empty chunk data */
6744     WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_SIZE);
6745
6746     Error(ERR_WARN, "cannot save content for element '%d'", element);
6747     return;
6748   }
6749
6750   putFile16BitBE(file, element);
6751   putFile8Bit(file, num_contents);
6752   putFile8Bit(file, content_xsize);
6753   putFile8Bit(file, content_ysize);
6754
6755   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED);
6756
6757   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
6758     for (y = 0; y < 3; y++)
6759       for (x = 0; x < 3; x++)
6760         putFile16BitBE(file, content_array[i][x][y]);
6761 }
6762 #endif
6763
6764 #if 0
6765 static int SaveLevel_CNT3(FILE *file, struct LevelInfo *level, int element)
6766 {
6767   int envelope_nr = element - EL_ENVELOPE_1;
6768   int envelope_len = strlen(level->envelope_text[envelope_nr]) + 1;
6769   int chunk_size = 0;
6770   int i;
6771
6772   chunk_size += putFile16BitBE(file, element);
6773   chunk_size += putFile16BitBE(file, envelope_len);
6774   chunk_size += putFile8Bit(file, level->envelope_xsize[envelope_nr]);
6775   chunk_size += putFile8Bit(file, level->envelope_ysize[envelope_nr]);
6776
6777   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT3_UNUSED);
6778   chunk_size += LEVEL_CHUNK_CNT3_UNUSED;
6779
6780   for (i = 0; i < envelope_len; i++)
6781     chunk_size += putFile8Bit(file, level->envelope_text[envelope_nr][i]);
6782
6783   return chunk_size;
6784 }
6785 #endif
6786
6787 #if 0
6788 static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level,
6789                            int num_changed_custom_elements)
6790 {
6791   int i, check = 0;
6792
6793   putFile16BitBE(file, num_changed_custom_elements);
6794
6795   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6796   {
6797     int element = EL_CUSTOM_START + i;
6798
6799     struct ElementInfo *ei = &element_info[element];
6800
6801     if (ei->properties[EP_BITFIELD_BASE_NR] != EP_BITMASK_DEFAULT)
6802     {
6803       if (check < num_changed_custom_elements)
6804       {
6805         putFile16BitBE(file, element);
6806         putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
6807       }
6808
6809       check++;
6810     }
6811   }
6812
6813   if (check != num_changed_custom_elements)     /* should not happen */
6814     Error(ERR_WARN, "inconsistent number of custom element properties");
6815 }
6816 #endif
6817
6818 #if 0
6819 static void SaveLevel_CUS2(FILE *file, struct LevelInfo *level,
6820                            int num_changed_custom_elements)
6821 {
6822   int i, check = 0;
6823
6824   putFile16BitBE(file, num_changed_custom_elements);
6825
6826   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6827   {
6828     int element = EL_CUSTOM_START + i;
6829
6830     if (element_info[element].change->target_element != EL_EMPTY_SPACE)
6831     {
6832       if (check < num_changed_custom_elements)
6833       {
6834         putFile16BitBE(file, element);
6835         putFile16BitBE(file, element_info[element].change->target_element);
6836       }
6837
6838       check++;
6839     }
6840   }
6841
6842   if (check != num_changed_custom_elements)     /* should not happen */
6843     Error(ERR_WARN, "inconsistent number of custom target elements");
6844 }
6845 #endif
6846
6847 #if 0
6848 static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
6849                            int num_changed_custom_elements)
6850 {
6851   int i, j, x, y, check = 0;
6852
6853   putFile16BitBE(file, num_changed_custom_elements);
6854
6855   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6856   {
6857     int element = EL_CUSTOM_START + i;
6858     struct ElementInfo *ei = &element_info[element];
6859
6860     if (ei->modified_settings)
6861     {
6862       if (check < num_changed_custom_elements)
6863       {
6864         putFile16BitBE(file, element);
6865
6866         for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++)
6867           putFile8Bit(file, ei->description[j]);
6868
6869         putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
6870
6871         /* some free bytes for future properties and padding */
6872         WriteUnusedBytesToFile(file, 7);
6873
6874         putFile8Bit(file, ei->use_gfx_element);
6875         putFile16BitBE(file, ei->gfx_element_initial);
6876
6877         putFile8Bit(file, ei->collect_score_initial);
6878         putFile8Bit(file, ei->collect_count_initial);
6879
6880         putFile16BitBE(file, ei->push_delay_fixed);
6881         putFile16BitBE(file, ei->push_delay_random);
6882         putFile16BitBE(file, ei->move_delay_fixed);
6883         putFile16BitBE(file, ei->move_delay_random);
6884
6885         putFile16BitBE(file, ei->move_pattern);
6886         putFile8Bit(file, ei->move_direction_initial);
6887         putFile8Bit(file, ei->move_stepsize);
6888
6889         for (y = 0; y < 3; y++)
6890           for (x = 0; x < 3; x++)
6891             putFile16BitBE(file, ei->content.e[x][y]);
6892
6893         putFile32BitBE(file, ei->change->events);
6894
6895         putFile16BitBE(file, ei->change->target_element);
6896
6897         putFile16BitBE(file, ei->change->delay_fixed);
6898         putFile16BitBE(file, ei->change->delay_random);
6899         putFile16BitBE(file, ei->change->delay_frames);
6900
6901         putFile16BitBE(file, ei->change->initial_trigger_element);
6902
6903         putFile8Bit(file, ei->change->explode);
6904         putFile8Bit(file, ei->change->use_target_content);
6905         putFile8Bit(file, ei->change->only_if_complete);
6906         putFile8Bit(file, ei->change->use_random_replace);
6907
6908         putFile8Bit(file, ei->change->random_percentage);
6909         putFile8Bit(file, ei->change->replace_when);
6910
6911         for (y = 0; y < 3; y++)
6912           for (x = 0; x < 3; x++)
6913             putFile16BitBE(file, ei->change->content.e[x][y]);
6914
6915         putFile8Bit(file, ei->slippery_type);
6916
6917         /* some free bytes for future properties and padding */
6918         WriteUnusedBytesToFile(file, LEVEL_CPART_CUS3_UNUSED);
6919       }
6920
6921       check++;
6922     }
6923   }
6924
6925   if (check != num_changed_custom_elements)     /* should not happen */
6926     Error(ERR_WARN, "inconsistent number of custom element properties");
6927 }
6928 #endif
6929
6930 #if 0
6931 static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
6932 {
6933   struct ElementInfo *ei = &element_info[element];
6934   int i, j, x, y;
6935
6936   /* ---------- custom element base property values (96 bytes) ------------- */
6937
6938   putFile16BitBE(file, element);
6939
6940   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
6941     putFile8Bit(file, ei->description[i]);
6942
6943   putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
6944
6945   WriteUnusedBytesToFile(file, 4);      /* reserved for more base properties */
6946
6947   putFile8Bit(file, ei->num_change_pages);
6948
6949   putFile16BitBE(file, ei->ce_value_fixed_initial);
6950   putFile16BitBE(file, ei->ce_value_random_initial);
6951   putFile8Bit(file, ei->use_last_ce_value);
6952
6953   putFile8Bit(file, ei->use_gfx_element);
6954   putFile16BitBE(file, ei->gfx_element_initial);
6955
6956   putFile8Bit(file, ei->collect_score_initial);
6957   putFile8Bit(file, ei->collect_count_initial);
6958
6959   putFile8Bit(file, ei->drop_delay_fixed);
6960   putFile8Bit(file, ei->push_delay_fixed);
6961   putFile8Bit(file, ei->drop_delay_random);
6962   putFile8Bit(file, ei->push_delay_random);
6963   putFile16BitBE(file, ei->move_delay_fixed);
6964   putFile16BitBE(file, ei->move_delay_random);
6965
6966   /* bits 0 - 15 of "move_pattern" ... */
6967   putFile16BitBE(file, ei->move_pattern & 0xffff);
6968   putFile8Bit(file, ei->move_direction_initial);
6969   putFile8Bit(file, ei->move_stepsize);
6970
6971   putFile8Bit(file, ei->slippery_type);
6972
6973   for (y = 0; y < 3; y++)
6974     for (x = 0; x < 3; x++)
6975       putFile16BitBE(file, ei->content.e[x][y]);
6976
6977   putFile16BitBE(file, ei->move_enter_element);
6978   putFile16BitBE(file, ei->move_leave_element);
6979   putFile8Bit(file, ei->move_leave_type);
6980
6981   /* ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible) */
6982   putFile16BitBE(file, (ei->move_pattern >> 16) & 0xffff);
6983
6984   putFile8Bit(file, ei->access_direction);
6985
6986   putFile8Bit(file, ei->explosion_delay);
6987   putFile8Bit(file, ei->ignition_delay);
6988   putFile8Bit(file, ei->explosion_type);
6989
6990   /* some free bytes for future custom property values and padding */
6991   WriteUnusedBytesToFile(file, 1);
6992
6993   /* ---------- change page property values (48 bytes) --------------------- */
6994
6995   for (i = 0; i < ei->num_change_pages; i++)
6996   {
6997     struct ElementChangeInfo *change = &ei->change_page[i];
6998     unsigned int event_bits;
6999
7000     /* bits 0 - 31 of "has_event[]" ... */
7001     event_bits = 0;
7002     for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
7003       if (change->has_event[j])
7004         event_bits |= (1 << j);
7005     putFile32BitBE(file, event_bits);
7006
7007     putFile16BitBE(file, change->target_element);
7008
7009     putFile16BitBE(file, change->delay_fixed);
7010     putFile16BitBE(file, change->delay_random);
7011     putFile16BitBE(file, change->delay_frames);
7012
7013     putFile16BitBE(file, change->initial_trigger_element);
7014
7015     putFile8Bit(file, change->explode);
7016     putFile8Bit(file, change->use_target_content);
7017     putFile8Bit(file, change->only_if_complete);
7018     putFile8Bit(file, change->use_random_replace);
7019
7020     putFile8Bit(file, change->random_percentage);
7021     putFile8Bit(file, change->replace_when);
7022
7023     for (y = 0; y < 3; y++)
7024       for (x = 0; x < 3; x++)
7025         putFile16BitBE(file, change->target_content.e[x][y]);
7026
7027     putFile8Bit(file, change->can_change);
7028
7029     putFile8Bit(file, change->trigger_side);
7030
7031     putFile8Bit(file, change->trigger_player);
7032     putFile8Bit(file, (change->trigger_page == CH_PAGE_ANY ? CH_PAGE_ANY_FILE :
7033                        log_2(change->trigger_page)));
7034
7035     putFile8Bit(file, change->has_action);
7036     putFile8Bit(file, change->action_type);
7037     putFile8Bit(file, change->action_mode);
7038     putFile16BitBE(file, change->action_arg);
7039
7040     /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */
7041     event_bits = 0;
7042     for (j = 32; j < NUM_CHANGE_EVENTS; j++)
7043       if (change->has_event[j])
7044         event_bits |= (1 << (j - 32));
7045     putFile8Bit(file, event_bits);
7046   }
7047 }
7048 #endif
7049
7050 #if 0
7051 static void SaveLevel_GRP1(FILE *file, struct LevelInfo *level, int element)
7052 {
7053   struct ElementInfo *ei = &element_info[element];
7054   struct ElementGroupInfo *group = ei->group;
7055   int i;
7056
7057   putFile16BitBE(file, element);
7058
7059   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
7060     putFile8Bit(file, ei->description[i]);
7061
7062   putFile8Bit(file, group->num_elements);
7063
7064   putFile8Bit(file, ei->use_gfx_element);
7065   putFile16BitBE(file, ei->gfx_element_initial);
7066
7067   putFile8Bit(file, group->choice_mode);
7068
7069   /* some free bytes for future values and padding */
7070   WriteUnusedBytesToFile(file, 3);
7071
7072   for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
7073     putFile16BitBE(file, group->element[i]);
7074 }
7075 #endif
7076
7077 static int SaveLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *entry,
7078                                 boolean write_element)
7079 {
7080   int save_type = entry->save_type;
7081   int data_type = entry->data_type;
7082   int conf_type = entry->conf_type;
7083   int byte_mask = conf_type & CONF_MASK_BYTES;
7084   int element = entry->element;
7085   int default_value = entry->default_value;
7086   int num_bytes = 0;
7087   boolean modified = FALSE;
7088
7089   if (byte_mask != CONF_MASK_MULTI_BYTES)
7090   {
7091     void *value_ptr = entry->value;
7092     int value = (data_type == TYPE_BOOLEAN ? *(boolean *)value_ptr :
7093                  *(int *)value_ptr);
7094
7095     /* check if any settings have been modified before saving them */
7096     if (value != default_value)
7097       modified = TRUE;
7098
7099     /* do not save if explicitly told or if unmodified default settings */
7100     if ((save_type == SAVE_CONF_NEVER) ||
7101         (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
7102       return 0;
7103
7104     if (write_element)
7105       num_bytes += putFile16BitBE(file, element);
7106
7107     num_bytes += putFile8Bit(file, conf_type);
7108     num_bytes += (byte_mask == CONF_MASK_1_BYTE ? putFile8Bit   (file, value) :
7109                   byte_mask == CONF_MASK_2_BYTE ? putFile16BitBE(file, value) :
7110                   byte_mask == CONF_MASK_4_BYTE ? putFile32BitBE(file, value) :
7111                   0);
7112   }
7113   else if (data_type == TYPE_STRING)
7114   {
7115     char *default_string = entry->default_string;
7116     char *string = (char *)(entry->value);
7117     int string_length = strlen(string);
7118     int i;
7119
7120     /* check if any settings have been modified before saving them */
7121     if (!strEqual(string, default_string))
7122       modified = TRUE;
7123
7124     /* do not save if explicitly told or if unmodified default settings */
7125     if ((save_type == SAVE_CONF_NEVER) ||
7126         (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
7127       return 0;
7128
7129     if (write_element)
7130       num_bytes += putFile16BitBE(file, element);
7131
7132     num_bytes += putFile8Bit(file, conf_type);
7133     num_bytes += putFile16BitBE(file, string_length);
7134
7135     for (i = 0; i < string_length; i++)
7136       num_bytes += putFile8Bit(file, string[i]);
7137   }
7138   else if (data_type == TYPE_ELEMENT_LIST)
7139   {
7140     int *element_array = (int *)(entry->value);
7141     int num_elements = *(int *)(entry->num_entities);
7142     int i;
7143
7144     /* check if any settings have been modified before saving them */
7145     for (i = 0; i < num_elements; i++)
7146       if (element_array[i] != default_value)
7147         modified = TRUE;
7148
7149     /* do not save if explicitly told or if unmodified default settings */
7150     if ((save_type == SAVE_CONF_NEVER) ||
7151         (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
7152       return 0;
7153
7154     if (write_element)
7155       num_bytes += putFile16BitBE(file, element);
7156
7157     num_bytes += putFile8Bit(file, conf_type);
7158     num_bytes += putFile16BitBE(file, num_elements * CONF_ELEMENT_NUM_BYTES);
7159
7160     for (i = 0; i < num_elements; i++)
7161       num_bytes += putFile16BitBE(file, element_array[i]);
7162   }
7163   else if (data_type == TYPE_CONTENT_LIST)
7164   {
7165     struct Content *content = (struct Content *)(entry->value);
7166     int num_contents = *(int *)(entry->num_entities);
7167     int i, x, y;
7168
7169     /* check if any settings have been modified before saving them */
7170     for (i = 0; i < num_contents; i++)
7171       for (y = 0; y < 3; y++)
7172         for (x = 0; x < 3; x++)
7173           if (content[i].e[x][y] != default_value)
7174             modified = TRUE;
7175
7176     /* do not save if explicitly told or if unmodified default settings */
7177     if ((save_type == SAVE_CONF_NEVER) ||
7178         (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
7179       return 0;
7180
7181     if (write_element)
7182       num_bytes += putFile16BitBE(file, element);
7183
7184     num_bytes += putFile8Bit(file, conf_type);
7185     num_bytes += putFile16BitBE(file, num_contents * CONF_CONTENT_NUM_BYTES);
7186
7187     for (i = 0; i < num_contents; i++)
7188       for (y = 0; y < 3; y++)
7189         for (x = 0; x < 3; x++)
7190           num_bytes += putFile16BitBE(file, content[i].e[x][y]);
7191   }
7192
7193   return num_bytes;
7194 }
7195
7196 static int SaveLevel_INFO(FILE *file, struct LevelInfo *level)
7197 {
7198   int chunk_size = 0;
7199   int i;
7200
7201   li = *level;          /* copy level data into temporary buffer */
7202
7203   for (i = 0; chunk_config_INFO[i].data_type != -1; i++)
7204     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_INFO[i], FALSE);
7205
7206   return chunk_size;
7207 }
7208
7209 static int SaveLevel_ELEM(FILE *file, struct LevelInfo *level)
7210 {
7211   int chunk_size = 0;
7212   int i;
7213
7214   li = *level;          /* copy level data into temporary buffer */
7215
7216   for (i = 0; chunk_config_ELEM[i].data_type != -1; i++)
7217     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_ELEM[i], TRUE);
7218
7219   return chunk_size;
7220 }
7221
7222 static int SaveLevel_NOTE(FILE *file, struct LevelInfo *level, int element)
7223 {
7224   int envelope_nr = element - EL_ENVELOPE_1;
7225   int chunk_size = 0;
7226   int i;
7227
7228   chunk_size += putFile16BitBE(file, element);
7229
7230   /* copy envelope data into temporary buffer */
7231   xx_envelope = level->envelope[envelope_nr];
7232
7233   for (i = 0; chunk_config_NOTE[i].data_type != -1; i++)
7234     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_NOTE[i], FALSE);
7235
7236   return chunk_size;
7237 }
7238
7239 static int SaveLevel_CUSX(FILE *file, struct LevelInfo *level, int element)
7240 {
7241   struct ElementInfo *ei = &element_info[element];
7242   int chunk_size = 0;
7243   int i, j;
7244
7245   chunk_size += putFile16BitBE(file, element);
7246
7247   xx_ei = *ei;          /* copy element data into temporary buffer */
7248
7249   /* set default description string for this specific element */
7250   strcpy(xx_default_description, getDefaultElementDescription(ei));
7251
7252 #if 0
7253   /* set (fixed) number of content areas (may be wrong by broken level file) */
7254   /* (this is now directly corrected for broken level files after loading) */
7255   xx_num_contents = 1;
7256 #endif
7257
7258   for (i = 0; chunk_config_CUSX_base[i].data_type != -1; i++)
7259     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_CUSX_base[i], FALSE);
7260
7261   for (i = 0; i < ei->num_change_pages; i++)
7262   {
7263     struct ElementChangeInfo *change = &ei->change_page[i];
7264
7265     xx_current_change_page = i;
7266
7267     xx_change = *change;        /* copy change data into temporary buffer */
7268
7269     resetEventBits();
7270     setEventBitsFromEventFlags(change);
7271
7272     for (j = 0; chunk_config_CUSX_change[j].data_type != -1; j++)
7273       chunk_size += SaveLevel_MicroChunk(file, &chunk_config_CUSX_change[j],
7274                                          FALSE);
7275   }
7276
7277   return chunk_size;
7278 }
7279
7280 static int SaveLevel_GRPX(FILE *file, struct LevelInfo *level, int element)
7281 {
7282   struct ElementInfo *ei = &element_info[element];
7283   struct ElementGroupInfo *group = ei->group;
7284   int chunk_size = 0;
7285   int i;
7286
7287   chunk_size += putFile16BitBE(file, element);
7288
7289   xx_ei = *ei;          /* copy element data into temporary buffer */
7290   xx_group = *group;    /* copy group data into temporary buffer */
7291
7292   /* set default description string for this specific element */
7293   strcpy(xx_default_description, getDefaultElementDescription(ei));
7294
7295   for (i = 0; chunk_config_GRPX[i].data_type != -1; i++)
7296     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_GRPX[i], FALSE);
7297
7298   return chunk_size;
7299 }
7300
7301 static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
7302 {
7303   int chunk_size;
7304   int i;
7305   FILE *file;
7306
7307   if (!(file = fopen(filename, MODE_WRITE)))
7308   {
7309     Error(ERR_WARN, "cannot save level file '%s'", filename);
7310     return;
7311   }
7312
7313   level->file_version = FILE_VERSION_ACTUAL;
7314   level->game_version = GAME_VERSION_ACTUAL;
7315
7316   level->creation_date = getCurrentDate();
7317
7318   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
7319   putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
7320
7321   chunk_size = SaveLevel_VERS(NULL, level);
7322   putFileChunkBE(file, "VERS", chunk_size);
7323   SaveLevel_VERS(file, level);
7324
7325   chunk_size = SaveLevel_DATE(NULL, level);
7326   putFileChunkBE(file, "DATE", chunk_size);
7327   SaveLevel_DATE(file, level);
7328
7329   chunk_size = SaveLevel_NAME(NULL, level);
7330   putFileChunkBE(file, "NAME", chunk_size);
7331   SaveLevel_NAME(file, level);
7332
7333   chunk_size = SaveLevel_AUTH(NULL, level);
7334   putFileChunkBE(file, "AUTH", chunk_size);
7335   SaveLevel_AUTH(file, level);
7336
7337   chunk_size = SaveLevel_INFO(NULL, level);
7338   putFileChunkBE(file, "INFO", chunk_size);
7339   SaveLevel_INFO(file, level);
7340
7341   chunk_size = SaveLevel_BODY(NULL, level);
7342   putFileChunkBE(file, "BODY", chunk_size);
7343   SaveLevel_BODY(file, level);
7344
7345   chunk_size = SaveLevel_ELEM(NULL, level);
7346   if (chunk_size > LEVEL_CHUNK_ELEM_UNCHANGED)          /* save if changed */
7347   {
7348     putFileChunkBE(file, "ELEM", chunk_size);
7349     SaveLevel_ELEM(file, level);
7350   }
7351
7352   for (i = 0; i < NUM_ENVELOPES; i++)
7353   {
7354     int element = EL_ENVELOPE_1 + i;
7355
7356     chunk_size = SaveLevel_NOTE(NULL, level, element);
7357     if (chunk_size > LEVEL_CHUNK_NOTE_UNCHANGED)        /* save if changed */
7358     {
7359       putFileChunkBE(file, "NOTE", chunk_size);
7360       SaveLevel_NOTE(file, level, element);
7361     }
7362   }
7363
7364   /* if not using template level, check for non-default custom/group elements */
7365   if (!level->use_custom_template)
7366   {
7367     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
7368     {
7369       int element = EL_CUSTOM_START + i;
7370
7371       chunk_size = SaveLevel_CUSX(NULL, level, element);
7372       if (chunk_size > LEVEL_CHUNK_CUSX_UNCHANGED)      /* save if changed */
7373       {
7374         putFileChunkBE(file, "CUSX", chunk_size);
7375         SaveLevel_CUSX(file, level, element);
7376       }
7377     }
7378
7379     for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
7380     {
7381       int element = EL_GROUP_START + i;
7382
7383       chunk_size = SaveLevel_GRPX(NULL, level, element);
7384       if (chunk_size > LEVEL_CHUNK_GRPX_UNCHANGED)      /* save if changed */
7385       {
7386         putFileChunkBE(file, "GRPX", chunk_size);
7387         SaveLevel_GRPX(file, level, element);
7388       }
7389     }
7390   }
7391
7392   fclose(file);
7393
7394   SetFilePermissions(filename, PERMS_PRIVATE);
7395 }
7396
7397 void SaveLevel(int nr)
7398 {
7399   char *filename = getDefaultLevelFilename(nr);
7400
7401   SaveLevelFromFilename(&level, filename);
7402 }
7403
7404 void SaveLevelTemplate()
7405 {
7406   char *filename = getDefaultLevelFilename(-1);
7407
7408   SaveLevelFromFilename(&level, filename);
7409 }
7410
7411 boolean SaveLevelChecked(int nr)
7412 {
7413   char *filename = getDefaultLevelFilename(nr);
7414   boolean new_level = !fileExists(filename);
7415   boolean level_saved = FALSE;
7416
7417   if (new_level || Request("Save this level and kill the old ?", REQ_ASK))
7418   {
7419     SaveLevel(nr);
7420
7421     if (new_level)
7422       Request("Level saved !", REQ_CONFIRM);
7423
7424     level_saved = TRUE;
7425   }
7426
7427   return level_saved;
7428 }
7429
7430 void DumpLevel(struct LevelInfo *level)
7431 {
7432   if (level->no_valid_file)
7433   {
7434     Error(ERR_WARN, "cannot dump -- no valid level file found");
7435
7436     return;
7437   }
7438
7439   printf_line("-", 79);
7440   printf("Level xxx (file version %08d, game version %08d)\n",
7441          level->file_version, level->game_version);
7442   printf_line("-", 79);
7443
7444   printf("Level author: '%s'\n", level->author);
7445   printf("Level title:  '%s'\n", level->name);
7446   printf("\n");
7447   printf("Playfield size: %d x %d\n", level->fieldx, level->fieldy);
7448   printf("\n");
7449   printf("Level time:  %d seconds\n", level->time);
7450   printf("Gems needed: %d\n", level->gems_needed);
7451   printf("\n");
7452   printf("Time for magic wall: %d seconds\n", level->time_magic_wall);
7453   printf("Time for wheel:      %d seconds\n", level->time_wheel);
7454   printf("Time for light:      %d seconds\n", level->time_light);
7455   printf("Time for timegate:   %d seconds\n", level->time_timegate);
7456   printf("\n");
7457   printf("Amoeba speed: %d\n", level->amoeba_speed);
7458   printf("\n");
7459
7460   printf("EM style slippery gems:      %s\n", (level->em_slippery_gems ? "yes" : "no"));
7461   printf("Player blocks last field:    %s\n", (level->block_last_field ? "yes" : "no"));
7462   printf("SP player blocks last field: %s\n", (level->sp_block_last_field ? "yes" : "no"));
7463   printf("use spring bug: %s\n", (level->use_spring_bug ? "yes" : "no"));
7464   printf("use step counter: %s\n", (level->use_step_counter ? "yes" : "no"));
7465
7466   printf_line("-", 79);
7467 }
7468
7469
7470 /* ========================================================================= */
7471 /* tape file functions                                                       */
7472 /* ========================================================================= */
7473
7474 static void setTapeInfoToDefaults()
7475 {
7476   int i;
7477
7478   /* always start with reliable default values (empty tape) */
7479   TapeErase();
7480
7481   /* default values (also for pre-1.2 tapes) with only the first player */
7482   tape.player_participates[0] = TRUE;
7483   for (i = 1; i < MAX_PLAYERS; i++)
7484     tape.player_participates[i] = FALSE;
7485
7486   /* at least one (default: the first) player participates in every tape */
7487   tape.num_participating_players = 1;
7488
7489   tape.level_nr = level_nr;
7490   tape.counter = 0;
7491   tape.changed = FALSE;
7492
7493   tape.recording = FALSE;
7494   tape.playing = FALSE;
7495   tape.pausing = FALSE;
7496
7497   tape.no_valid_file = FALSE;
7498 }
7499
7500 static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
7501 {
7502   tape->file_version = getFileVersion(file);
7503   tape->game_version = getFileVersion(file);
7504
7505   return chunk_size;
7506 }
7507
7508 static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
7509 {
7510   int i;
7511
7512   tape->random_seed = getFile32BitBE(file);
7513   tape->date        = getFile32BitBE(file);
7514   tape->length      = getFile32BitBE(file);
7515
7516   /* read header fields that are new since version 1.2 */
7517   if (tape->file_version >= FILE_VERSION_1_2)
7518   {
7519     byte store_participating_players = getFile8Bit(file);
7520     int engine_version;
7521
7522     /* since version 1.2, tapes store which players participate in the tape */
7523     tape->num_participating_players = 0;
7524     for (i = 0; i < MAX_PLAYERS; i++)
7525     {
7526       tape->player_participates[i] = FALSE;
7527
7528       if (store_participating_players & (1 << i))
7529       {
7530         tape->player_participates[i] = TRUE;
7531         tape->num_participating_players++;
7532       }
7533     }
7534
7535     ReadUnusedBytesFromFile(file, TAPE_CHUNK_HEAD_UNUSED);
7536
7537     engine_version = getFileVersion(file);
7538     if (engine_version > 0)
7539       tape->engine_version = engine_version;
7540     else
7541       tape->engine_version = tape->game_version;
7542   }
7543
7544   return chunk_size;
7545 }
7546
7547 static int LoadTape_INFO(FILE *file, int chunk_size, struct TapeInfo *tape)
7548 {
7549   int level_identifier_size;
7550   int i;
7551
7552   level_identifier_size = getFile16BitBE(file);
7553
7554   tape->level_identifier =
7555     checked_realloc(tape->level_identifier, level_identifier_size);
7556
7557   for (i = 0; i < level_identifier_size; i++)
7558     tape->level_identifier[i] = getFile8Bit(file);
7559
7560   tape->level_nr = getFile16BitBE(file);
7561
7562   chunk_size = 2 + level_identifier_size + 2;
7563
7564   return chunk_size;
7565 }
7566
7567 static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
7568 {
7569   int i, j;
7570   int chunk_size_expected =
7571     (tape->num_participating_players + 1) * tape->length;
7572
7573   if (chunk_size_expected != chunk_size)
7574   {
7575     ReadUnusedBytesFromFile(file, chunk_size);
7576     return chunk_size_expected;
7577   }
7578
7579   for (i = 0; i < tape->length; i++)
7580   {
7581     if (i >= MAX_TAPE_LEN)
7582       break;
7583
7584     for (j = 0; j < MAX_PLAYERS; j++)
7585     {
7586       tape->pos[i].action[j] = MV_NONE;
7587
7588       if (tape->player_participates[j])
7589         tape->pos[i].action[j] = getFile8Bit(file);
7590     }
7591
7592     tape->pos[i].delay = getFile8Bit(file);
7593
7594     if (tape->file_version == FILE_VERSION_1_0)
7595     {
7596       /* eliminate possible diagonal moves in old tapes */
7597       /* this is only for backward compatibility */
7598
7599       byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
7600       byte action = tape->pos[i].action[0];
7601       int k, num_moves = 0;
7602
7603       for (k = 0; k<4; k++)
7604       {
7605         if (action & joy_dir[k])
7606         {
7607           tape->pos[i + num_moves].action[0] = joy_dir[k];
7608           if (num_moves > 0)
7609             tape->pos[i + num_moves].delay = 0;
7610           num_moves++;
7611         }
7612       }
7613
7614       if (num_moves > 1)
7615       {
7616         num_moves--;
7617         i += num_moves;
7618         tape->length += num_moves;
7619       }
7620     }
7621     else if (tape->file_version < FILE_VERSION_2_0)
7622     {
7623       /* convert pre-2.0 tapes to new tape format */
7624
7625       if (tape->pos[i].delay > 1)
7626       {
7627         /* action part */
7628         tape->pos[i + 1] = tape->pos[i];
7629         tape->pos[i + 1].delay = 1;
7630
7631         /* delay part */
7632         for (j = 0; j < MAX_PLAYERS; j++)
7633           tape->pos[i].action[j] = MV_NONE;
7634         tape->pos[i].delay--;
7635
7636         i++;
7637         tape->length++;
7638       }
7639     }
7640
7641     if (feof(file))
7642       break;
7643   }
7644
7645   if (i != tape->length)
7646     chunk_size = (tape->num_participating_players + 1) * i;
7647
7648   return chunk_size;
7649 }
7650
7651 void LoadTapeFromFilename(char *filename)
7652 {
7653   char cookie[MAX_LINE_LEN];
7654   char chunk_name[CHUNK_ID_LEN + 1];
7655   FILE *file;
7656   int chunk_size;
7657
7658   /* always start with reliable default values */
7659   setTapeInfoToDefaults();
7660
7661   if (!(file = fopen(filename, MODE_READ)))
7662   {
7663     tape.no_valid_file = TRUE;
7664
7665     return;
7666   }
7667
7668   getFileChunkBE(file, chunk_name, NULL);
7669   if (strEqual(chunk_name, "RND1"))
7670   {
7671     getFile32BitBE(file);               /* not used */
7672
7673     getFileChunkBE(file, chunk_name, NULL);
7674     if (!strEqual(chunk_name, "TAPE"))
7675     {
7676       tape.no_valid_file = TRUE;
7677
7678       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
7679       fclose(file);
7680       return;
7681     }
7682   }
7683   else  /* check for pre-2.0 file format with cookie string */
7684   {
7685     strcpy(cookie, chunk_name);
7686     fgets(&cookie[4], MAX_LINE_LEN - 4, file);
7687     if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
7688       cookie[strlen(cookie) - 1] = '\0';
7689
7690     if (!checkCookieString(cookie, TAPE_COOKIE_TMPL))
7691     {
7692       tape.no_valid_file = TRUE;
7693
7694       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
7695       fclose(file);
7696       return;
7697     }
7698
7699     if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1)
7700     {
7701       tape.no_valid_file = TRUE;
7702
7703       Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
7704       fclose(file);
7705       return;
7706     }
7707
7708     /* pre-2.0 tape files have no game version, so use file version here */
7709     tape.game_version = tape.file_version;
7710   }
7711
7712   if (tape.file_version < FILE_VERSION_1_2)
7713   {
7714     /* tape files from versions before 1.2.0 without chunk structure */
7715     LoadTape_HEAD(file, TAPE_CHUNK_HEAD_SIZE, &tape);
7716     LoadTape_BODY(file, 2 * tape.length,      &tape);
7717   }
7718   else
7719   {
7720     static struct
7721     {
7722       char *name;
7723       int size;
7724       int (*loader)(FILE *, int, struct TapeInfo *);
7725     }
7726     chunk_info[] =
7727     {
7728       { "VERS", TAPE_CHUNK_VERS_SIZE,   LoadTape_VERS },
7729       { "HEAD", TAPE_CHUNK_HEAD_SIZE,   LoadTape_HEAD },
7730       { "INFO", -1,                     LoadTape_INFO },
7731       { "BODY", -1,                     LoadTape_BODY },
7732       {  NULL,  0,                      NULL }
7733     };
7734
7735     while (getFileChunkBE(file, chunk_name, &chunk_size))
7736     {
7737       int i = 0;
7738
7739       while (chunk_info[i].name != NULL &&
7740              !strEqual(chunk_name, chunk_info[i].name))
7741         i++;
7742
7743       if (chunk_info[i].name == NULL)
7744       {
7745         Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'",
7746               chunk_name, filename);
7747         ReadUnusedBytesFromFile(file, chunk_size);
7748       }
7749       else if (chunk_info[i].size != -1 &&
7750                chunk_info[i].size != chunk_size)
7751       {
7752         Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
7753               chunk_size, chunk_name, filename);
7754         ReadUnusedBytesFromFile(file, chunk_size);
7755       }
7756       else
7757       {
7758         /* call function to load this tape chunk */
7759         int chunk_size_expected =
7760           (chunk_info[i].loader)(file, chunk_size, &tape);
7761
7762         /* the size of some chunks cannot be checked before reading other
7763            chunks first (like "HEAD" and "BODY") that contain some header
7764            information, so check them here */
7765         if (chunk_size_expected != chunk_size)
7766         {
7767           Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
7768                 chunk_size, chunk_name, filename);
7769         }
7770       }
7771     }
7772   }
7773
7774   fclose(file);
7775
7776   tape.length_seconds = GetTapeLength();
7777
7778 #if 0
7779   printf("::: tape file version: %d\n", tape.file_version);
7780   printf("::: tape game version: %d\n", tape.game_version);
7781   printf("::: tape engine version: %d\n", tape.engine_version);
7782 #endif
7783 }
7784
7785 void LoadTape(int nr)
7786 {
7787   char *filename = getTapeFilename(nr);
7788
7789   LoadTapeFromFilename(filename);
7790 }
7791
7792 void LoadSolutionTape(int nr)
7793 {
7794   char *filename = getSolutionTapeFilename(nr);
7795
7796   LoadTapeFromFilename(filename);
7797 }
7798
7799 static void SaveTape_VERS(FILE *file, struct TapeInfo *tape)
7800 {
7801   putFileVersion(file, tape->file_version);
7802   putFileVersion(file, tape->game_version);
7803 }
7804
7805 static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
7806 {
7807   int i;
7808   byte store_participating_players = 0;
7809
7810   /* set bits for participating players for compact storage */
7811   for (i = 0; i < MAX_PLAYERS; i++)
7812     if (tape->player_participates[i])
7813       store_participating_players |= (1 << i);
7814
7815   putFile32BitBE(file, tape->random_seed);
7816   putFile32BitBE(file, tape->date);
7817   putFile32BitBE(file, tape->length);
7818
7819   putFile8Bit(file, store_participating_players);
7820
7821   /* unused bytes not at the end here for 4-byte alignment of engine_version */
7822   WriteUnusedBytesToFile(file, TAPE_CHUNK_HEAD_UNUSED);
7823
7824   putFileVersion(file, tape->engine_version);
7825 }
7826
7827 static void SaveTape_INFO(FILE *file, struct TapeInfo *tape)
7828 {
7829   int level_identifier_size = strlen(tape->level_identifier) + 1;
7830   int i;
7831
7832   putFile16BitBE(file, level_identifier_size);
7833
7834   for (i = 0; i < level_identifier_size; i++)
7835     putFile8Bit(file, tape->level_identifier[i]);
7836
7837   putFile16BitBE(file, tape->level_nr);
7838 }
7839
7840 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
7841 {
7842   int i, j;
7843
7844   for (i = 0; i < tape->length; i++)
7845   {
7846     for (j = 0; j < MAX_PLAYERS; j++)
7847       if (tape->player_participates[j])
7848         putFile8Bit(file, tape->pos[i].action[j]);
7849
7850     putFile8Bit(file, tape->pos[i].delay);
7851   }
7852 }
7853
7854 void SaveTape(int nr)
7855 {
7856   char *filename = getTapeFilename(nr);
7857   FILE *file;
7858 #if 0
7859   boolean new_tape = TRUE;
7860 #endif
7861   int num_participating_players = 0;
7862   int info_chunk_size;
7863   int body_chunk_size;
7864   int i;
7865
7866   InitTapeDirectory(leveldir_current->subdir);
7867
7868 #if 0
7869   /* if a tape still exists, ask to overwrite it */
7870   if (fileExists(filename))
7871   {
7872     new_tape = FALSE;
7873     if (!Request("Replace old tape ?", REQ_ASK))
7874       return;
7875   }
7876 #endif
7877
7878   if (!(file = fopen(filename, MODE_WRITE)))
7879   {
7880     Error(ERR_WARN, "cannot save level recording file '%s'", filename);
7881     return;
7882   }
7883
7884   tape.file_version = FILE_VERSION_ACTUAL;
7885   tape.game_version = GAME_VERSION_ACTUAL;
7886
7887   /* count number of participating players  */
7888   for (i = 0; i < MAX_PLAYERS; i++)
7889     if (tape.player_participates[i])
7890       num_participating_players++;
7891
7892   info_chunk_size = 2 + (strlen(tape.level_identifier) + 1) + 2;
7893   body_chunk_size = (num_participating_players + 1) * tape.length;
7894
7895   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
7896   putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
7897
7898   putFileChunkBE(file, "VERS", TAPE_CHUNK_VERS_SIZE);
7899   SaveTape_VERS(file, &tape);
7900
7901   putFileChunkBE(file, "HEAD", TAPE_CHUNK_HEAD_SIZE);
7902   SaveTape_HEAD(file, &tape);
7903
7904   putFileChunkBE(file, "INFO", info_chunk_size);
7905   SaveTape_INFO(file, &tape);
7906
7907   putFileChunkBE(file, "BODY", body_chunk_size);
7908   SaveTape_BODY(file, &tape);
7909
7910   fclose(file);
7911
7912   SetFilePermissions(filename, PERMS_PRIVATE);
7913
7914   tape.changed = FALSE;
7915
7916 #if 0
7917   if (new_tape)
7918     Request("Tape saved !", REQ_CONFIRM);
7919 #endif
7920 }
7921
7922 boolean SaveTapeChecked(int nr)
7923 {
7924   char *filename = getTapeFilename(nr);
7925   boolean new_tape = !fileExists(filename);
7926   boolean tape_saved = FALSE;
7927
7928   if (new_tape || Request("Replace old tape ?", REQ_ASK))
7929   {
7930     SaveTape(nr);
7931
7932     if (new_tape)
7933       Request("Tape saved !", REQ_CONFIRM);
7934
7935     tape_saved = TRUE;
7936   }
7937
7938   return tape_saved;
7939 }
7940
7941 void DumpTape(struct TapeInfo *tape)
7942 {
7943   int tape_frame_counter;
7944   int i, j;
7945
7946   if (tape->no_valid_file)
7947   {
7948     Error(ERR_WARN, "cannot dump -- no valid tape file found");
7949
7950     return;
7951   }
7952
7953   printf_line("-", 79);
7954   printf("Tape of Level %03d (file version %08d, game version %08d)\n",
7955          tape->level_nr, tape->file_version, tape->game_version);
7956   printf("                  (effective engine version %08d)\n",
7957          tape->engine_version);
7958   printf("Level series identifier: '%s'\n", tape->level_identifier);
7959   printf_line("-", 79);
7960
7961   tape_frame_counter = 0;
7962
7963   for (i = 0; i < tape->length; i++)
7964   {
7965     if (i >= MAX_TAPE_LEN)
7966       break;
7967
7968     printf("%04d: ", i);
7969
7970     for (j = 0; j < MAX_PLAYERS; j++)
7971     {
7972       if (tape->player_participates[j])
7973       {
7974         int action = tape->pos[i].action[j];
7975
7976         printf("%d:%02x ", j, action);
7977         printf("[%c%c%c%c|%c%c] - ",
7978                (action & JOY_LEFT ? '<' : ' '),
7979                (action & JOY_RIGHT ? '>' : ' '),
7980                (action & JOY_UP ? '^' : ' '),
7981                (action & JOY_DOWN ? 'v' : ' '),
7982                (action & JOY_BUTTON_1 ? '1' : ' '),
7983                (action & JOY_BUTTON_2 ? '2' : ' '));
7984       }
7985     }
7986
7987     printf("(%03d) ", tape->pos[i].delay);
7988     printf("[%05d]\n", tape_frame_counter);
7989
7990     tape_frame_counter += tape->pos[i].delay;
7991   }
7992
7993   printf_line("-", 79);
7994 }
7995
7996
7997 /* ========================================================================= */
7998 /* score file functions                                                      */
7999 /* ========================================================================= */
8000
8001 void LoadScore(int nr)
8002 {
8003   int i;
8004   char *filename = getScoreFilename(nr);
8005   char cookie[MAX_LINE_LEN];
8006   char line[MAX_LINE_LEN];
8007   char *line_ptr;
8008   FILE *file;
8009
8010   /* always start with reliable default values */
8011   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
8012   {
8013     strcpy(highscore[i].Name, EMPTY_PLAYER_NAME);
8014     highscore[i].Score = 0;
8015   }
8016
8017   if (!(file = fopen(filename, MODE_READ)))
8018     return;
8019
8020   /* check file identifier */
8021   fgets(cookie, MAX_LINE_LEN, file);
8022   if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
8023     cookie[strlen(cookie) - 1] = '\0';
8024
8025   if (!checkCookieString(cookie, SCORE_COOKIE))
8026   {
8027     Error(ERR_WARN, "unknown format of score file '%s'", filename);
8028     fclose(file);
8029     return;
8030   }
8031
8032   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
8033   {
8034     fscanf(file, "%d", &highscore[i].Score);
8035     fgets(line, MAX_LINE_LEN, file);
8036
8037     if (line[strlen(line) - 1] == '\n')
8038       line[strlen(line) - 1] = '\0';
8039
8040     for (line_ptr = line; *line_ptr; line_ptr++)
8041     {
8042       if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
8043       {
8044         strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN);
8045         highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0';
8046         break;
8047       }
8048     }
8049   }
8050
8051   fclose(file);
8052 }
8053
8054 void SaveScore(int nr)
8055 {
8056   int i;
8057   char *filename = getScoreFilename(nr);
8058   FILE *file;
8059
8060   InitScoreDirectory(leveldir_current->subdir);
8061
8062   if (!(file = fopen(filename, MODE_WRITE)))
8063   {
8064     Error(ERR_WARN, "cannot save score for level %d", nr);
8065     return;
8066   }
8067
8068   fprintf(file, "%s\n\n", SCORE_COOKIE);
8069
8070   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
8071     fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name);
8072
8073   fclose(file);
8074
8075   SetFilePermissions(filename, PERMS_PUBLIC);
8076 }
8077
8078
8079 /* ========================================================================= */
8080 /* setup file functions                                                      */
8081 /* ========================================================================= */
8082
8083 #define TOKEN_STR_PLAYER_PREFIX                 "player_"
8084
8085 /* global setup */
8086 #define SETUP_TOKEN_PLAYER_NAME                 0
8087 #define SETUP_TOKEN_SOUND                       1
8088 #define SETUP_TOKEN_SOUND_LOOPS                 2
8089 #define SETUP_TOKEN_SOUND_MUSIC                 3
8090 #define SETUP_TOKEN_SOUND_SIMPLE                4
8091 #define SETUP_TOKEN_TOONS                       5
8092 #define SETUP_TOKEN_SCROLL_DELAY                6
8093 #define SETUP_TOKEN_SCROLL_DELAY_VALUE          7
8094 #define SETUP_TOKEN_SOFT_SCROLLING              8
8095 #define SETUP_TOKEN_FADE_SCREENS                9
8096 #define SETUP_TOKEN_AUTORECORD                  10
8097 #define SETUP_TOKEN_SHOW_TITLESCREEN            11
8098 #define SETUP_TOKEN_QUICK_DOORS                 12
8099 #define SETUP_TOKEN_TEAM_MODE                   13
8100 #define SETUP_TOKEN_HANDICAP                    14
8101 #define SETUP_TOKEN_SKIP_LEVELS                 15
8102 #define SETUP_TOKEN_TIME_LIMIT                  16
8103 #define SETUP_TOKEN_FULLSCREEN                  17
8104 #define SETUP_TOKEN_FULLSCREEN_MODE             18
8105 #define SETUP_TOKEN_ASK_ON_ESCAPE               19
8106 #define SETUP_TOKEN_ASK_ON_ESCAPE_EDITOR        20
8107 #define SETUP_TOKEN_QUICK_SWITCH                21
8108 #define SETUP_TOKEN_INPUT_ON_FOCUS              22
8109 #define SETUP_TOKEN_PREFER_AGA_GRAPHICS         23
8110 #define SETUP_TOKEN_GAME_FRAME_DELAY            24
8111 #define SETUP_TOKEN_GRAPHICS_SET                25
8112 #define SETUP_TOKEN_SOUNDS_SET                  26
8113 #define SETUP_TOKEN_MUSIC_SET                   27
8114 #define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS     28
8115 #define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS       29
8116 #define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC        30
8117
8118 #define NUM_GLOBAL_SETUP_TOKENS                 31
8119
8120 /* editor setup */
8121 #define SETUP_TOKEN_EDITOR_EL_BOULDERDASH       0
8122 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE      1
8123 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE_CLUB 2
8124 #define SETUP_TOKEN_EDITOR_EL_MORE              3
8125 #define SETUP_TOKEN_EDITOR_EL_SOKOBAN           4
8126 #define SETUP_TOKEN_EDITOR_EL_SUPAPLEX          5
8127 #define SETUP_TOKEN_EDITOR_EL_DIAMOND_CAVES     6
8128 #define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH    7
8129 #define SETUP_TOKEN_EDITOR_EL_CHARS             8
8130 #define SETUP_TOKEN_EDITOR_EL_STEEL_CHARS       9
8131 #define SETUP_TOKEN_EDITOR_EL_CUSTOM            10
8132 #define SETUP_TOKEN_EDITOR_EL_HEADLINES         11
8133 #define SETUP_TOKEN_EDITOR_EL_USER_DEFINED      12
8134 #define SETUP_TOKEN_EDITOR_EL_DYNAMIC           13
8135 #define SETUP_TOKEN_EDITOR_EL_BY_GAME           14
8136 #define SETUP_TOKEN_EDITOR_EL_BY_TYPE           15
8137 #define SETUP_TOKEN_EDITOR_SHOW_ELEMENT_TOKEN   16
8138
8139 #define NUM_EDITOR_SETUP_TOKENS                 17
8140
8141 /* editor cascade setup */
8142 #define SETUP_TOKEN_EDITOR_CASCADE_BD           0
8143 #define SETUP_TOKEN_EDITOR_CASCADE_EM           1
8144 #define SETUP_TOKEN_EDITOR_CASCADE_EMC          2
8145 #define SETUP_TOKEN_EDITOR_CASCADE_RND          3
8146 #define SETUP_TOKEN_EDITOR_CASCADE_SB           4
8147 #define SETUP_TOKEN_EDITOR_CASCADE_SP           5
8148 #define SETUP_TOKEN_EDITOR_CASCADE_DC           6
8149 #define SETUP_TOKEN_EDITOR_CASCADE_DX           7
8150 #define SETUP_TOKEN_EDITOR_CASCADE_TEXT         8
8151 #define SETUP_TOKEN_EDITOR_CASCADE_STEELTEXT    9
8152 #define SETUP_TOKEN_EDITOR_CASCADE_CE           10
8153 #define SETUP_TOKEN_EDITOR_CASCADE_GE           11
8154 #define SETUP_TOKEN_EDITOR_CASCADE_REF          12
8155 #define SETUP_TOKEN_EDITOR_CASCADE_USER         13
8156 #define SETUP_TOKEN_EDITOR_CASCADE_DYNAMIC      14
8157
8158 #define NUM_EDITOR_CASCADE_SETUP_TOKENS         15
8159
8160 /* shortcut setup */
8161 #define SETUP_TOKEN_SHORTCUT_SAVE_GAME          0
8162 #define SETUP_TOKEN_SHORTCUT_LOAD_GAME          1
8163 #define SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE       2
8164 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_1     3
8165 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_2     4
8166 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_3     5
8167 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_4     6
8168 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_ALL   7
8169
8170 #define NUM_SHORTCUT_SETUP_TOKENS               8
8171
8172 /* player setup */
8173 #define SETUP_TOKEN_PLAYER_USE_JOYSTICK         0
8174 #define SETUP_TOKEN_PLAYER_JOY_DEVICE_NAME      1
8175 #define SETUP_TOKEN_PLAYER_JOY_XLEFT            2
8176 #define SETUP_TOKEN_PLAYER_JOY_XMIDDLE          3
8177 #define SETUP_TOKEN_PLAYER_JOY_XRIGHT           4
8178 #define SETUP_TOKEN_PLAYER_JOY_YUPPER           5
8179 #define SETUP_TOKEN_PLAYER_JOY_YMIDDLE          6
8180 #define SETUP_TOKEN_PLAYER_JOY_YLOWER           7
8181 #define SETUP_TOKEN_PLAYER_JOY_SNAP             8
8182 #define SETUP_TOKEN_PLAYER_JOY_DROP             9
8183 #define SETUP_TOKEN_PLAYER_KEY_LEFT             10
8184 #define SETUP_TOKEN_PLAYER_KEY_RIGHT            11
8185 #define SETUP_TOKEN_PLAYER_KEY_UP               12
8186 #define SETUP_TOKEN_PLAYER_KEY_DOWN             13
8187 #define SETUP_TOKEN_PLAYER_KEY_SNAP             14
8188 #define SETUP_TOKEN_PLAYER_KEY_DROP             15
8189
8190 #define NUM_PLAYER_SETUP_TOKENS                 16
8191
8192 /* system setup */
8193 #define SETUP_TOKEN_SYSTEM_SDL_VIDEODRIVER      0
8194 #define SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER      1
8195 #define SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE  2
8196
8197 #define NUM_SYSTEM_SETUP_TOKENS                 3
8198
8199 /* options setup */
8200 #define SETUP_TOKEN_OPTIONS_VERBOSE             0
8201
8202 #define NUM_OPTIONS_SETUP_TOKENS                1
8203
8204
8205 static struct SetupInfo si;
8206 static struct SetupEditorInfo sei;
8207 static struct SetupEditorCascadeInfo seci;
8208 static struct SetupShortcutInfo ssi;
8209 static struct SetupInputInfo sii;
8210 static struct SetupSystemInfo syi;
8211 static struct OptionInfo soi;
8212
8213 static struct TokenInfo global_setup_tokens[] =
8214 {
8215   { TYPE_STRING, &si.player_name,       "player_name"                   },
8216   { TYPE_SWITCH, &si.sound,             "sound"                         },
8217   { TYPE_SWITCH, &si.sound_loops,       "repeating_sound_loops"         },
8218   { TYPE_SWITCH, &si.sound_music,       "background_music"              },
8219   { TYPE_SWITCH, &si.sound_simple,      "simple_sound_effects"          },
8220   { TYPE_SWITCH, &si.toons,             "toons"                         },
8221   { TYPE_SWITCH, &si.scroll_delay,      "scroll_delay"                  },
8222   { TYPE_INTEGER,&si.scroll_delay_value,"scroll_delay_value"            },
8223   { TYPE_SWITCH, &si.soft_scrolling,    "soft_scrolling"                },
8224   { TYPE_SWITCH, &si.fade_screens,      "fade_screens"                  },
8225   { TYPE_SWITCH, &si.autorecord,        "automatic_tape_recording"      },
8226   { TYPE_SWITCH, &si.show_titlescreen,  "show_titlescreen"              },
8227   { TYPE_SWITCH, &si.quick_doors,       "quick_doors"                   },
8228   { TYPE_SWITCH, &si.team_mode,         "team_mode"                     },
8229   { TYPE_SWITCH, &si.handicap,          "handicap"                      },
8230   { TYPE_SWITCH, &si.skip_levels,       "skip_levels"                   },
8231   { TYPE_SWITCH, &si.time_limit,        "time_limit"                    },
8232   { TYPE_SWITCH, &si.fullscreen,        "fullscreen"                    },
8233   { TYPE_STRING, &si.fullscreen_mode,   "fullscreen_mode"               },
8234   { TYPE_SWITCH, &si.ask_on_escape,     "ask_on_escape"                 },
8235   { TYPE_SWITCH, &si.ask_on_escape_editor, "ask_on_escape_editor"       },
8236   { TYPE_SWITCH, &si.quick_switch,      "quick_player_switch"           },
8237   { TYPE_SWITCH, &si.input_on_focus,    "input_on_focus"                },
8238   { TYPE_SWITCH, &si.prefer_aga_graphics, "prefer_aga_graphics"         },
8239   { TYPE_INTEGER,&si.game_frame_delay,  "game_frame_delay"              },
8240   { TYPE_STRING, &si.graphics_set,      "graphics_set"                  },
8241   { TYPE_STRING, &si.sounds_set,        "sounds_set"                    },
8242   { TYPE_STRING, &si.music_set,         "music_set"                     },
8243   { TYPE_SWITCH3,&si.override_level_graphics, "override_level_graphics" },
8244   { TYPE_SWITCH3,&si.override_level_sounds,   "override_level_sounds"   },
8245   { TYPE_SWITCH3,&si.override_level_music,    "override_level_music"    },
8246 };
8247
8248 static boolean not_used = FALSE;
8249 static struct TokenInfo editor_setup_tokens[] =
8250 {
8251 #if 1
8252   { TYPE_SWITCH, &not_used,             "editor.el_boulderdash"         },
8253   { TYPE_SWITCH, &not_used,             "editor.el_emerald_mine"        },
8254   { TYPE_SWITCH, &not_used,             "editor.el_emerald_mine_club"   },
8255   { TYPE_SWITCH, &not_used,             "editor.el_more"                },
8256   { TYPE_SWITCH, &not_used,             "editor.el_sokoban"             },
8257   { TYPE_SWITCH, &not_used,             "editor.el_supaplex"            },
8258   { TYPE_SWITCH, &not_used,             "editor.el_diamond_caves"       },
8259   { TYPE_SWITCH, &not_used,             "editor.el_dx_boulderdash"      },
8260 #else
8261   { TYPE_SWITCH, &sei.el_boulderdash,   "editor.el_boulderdash"         },
8262   { TYPE_SWITCH, &sei.el_emerald_mine,  "editor.el_emerald_mine"        },
8263   { TYPE_SWITCH, &sei.el_emerald_mine_club,"editor.el_emerald_mine_club"},
8264   { TYPE_SWITCH, &sei.el_more,          "editor.el_more"                },
8265   { TYPE_SWITCH, &sei.el_sokoban,       "editor.el_sokoban"             },
8266   { TYPE_SWITCH, &sei.el_supaplex,      "editor.el_supaplex"            },
8267   { TYPE_SWITCH, &sei.el_diamond_caves, "editor.el_diamond_caves"       },
8268   { TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash"      },
8269 #endif
8270   { TYPE_SWITCH, &sei.el_chars,         "editor.el_chars"               },
8271   { TYPE_SWITCH, &sei.el_steel_chars,   "editor.el_steel_chars"         },
8272   { TYPE_SWITCH, &sei.el_custom,        "editor.el_custom"              },
8273 #if 1
8274   { TYPE_SWITCH, &not_used,             "editor.el_headlines"           },
8275 #else
8276   { TYPE_SWITCH, &sei.el_headlines,     "editor.el_headlines"           },
8277 #endif
8278   { TYPE_SWITCH, &sei.el_user_defined,  "editor.el_user_defined"        },
8279   { TYPE_SWITCH, &sei.el_dynamic,       "editor.el_dynamic"             },
8280   { TYPE_SWITCH, &sei.el_by_game,       "editor.el_by_game"             },
8281   { TYPE_SWITCH, &sei.el_by_type,       "editor.el_by_type"             },
8282   { TYPE_SWITCH, &sei.show_element_token,"editor.show_element_token"    },
8283 };
8284
8285 static struct TokenInfo editor_cascade_setup_tokens[] =
8286 {
8287   { TYPE_SWITCH, &seci.el_bd,           "editor.cascade.el_bd"          },
8288   { TYPE_SWITCH, &seci.el_em,           "editor.cascade.el_em"          },
8289   { TYPE_SWITCH, &seci.el_emc,          "editor.cascade.el_emc"         },
8290   { TYPE_SWITCH, &seci.el_rnd,          "editor.cascade.el_rnd"         },
8291   { TYPE_SWITCH, &seci.el_sb,           "editor.cascade.el_sb"          },
8292   { TYPE_SWITCH, &seci.el_sp,           "editor.cascade.el_sp"          },
8293   { TYPE_SWITCH, &seci.el_dc,           "editor.cascade.el_dc"          },
8294   { TYPE_SWITCH, &seci.el_dx,           "editor.cascade.el_dx"          },
8295   { TYPE_SWITCH, &seci.el_chars,        "editor.cascade.el_chars"       },
8296   { TYPE_SWITCH, &seci.el_steel_chars,  "editor.cascade.el_steel_chars" },
8297   { TYPE_SWITCH, &seci.el_ce,           "editor.cascade.el_ce"          },
8298   { TYPE_SWITCH, &seci.el_ge,           "editor.cascade.el_ge"          },
8299   { TYPE_SWITCH, &seci.el_ref,          "editor.cascade.el_ref"         },
8300   { TYPE_SWITCH, &seci.el_user,         "editor.cascade.el_user"        },
8301   { TYPE_SWITCH, &seci.el_dynamic,      "editor.cascade.el_dynamic"     },
8302 };
8303
8304 static struct TokenInfo shortcut_setup_tokens[] =
8305 {
8306   { TYPE_KEY_X11, &ssi.save_game,       "shortcut.save_game"            },
8307   { TYPE_KEY_X11, &ssi.load_game,       "shortcut.load_game"            },
8308   { TYPE_KEY_X11, &ssi.toggle_pause,    "shortcut.toggle_pause"         },
8309   { TYPE_KEY_X11, &ssi.focus_player[0], "shortcut.focus_player_1"       },
8310   { TYPE_KEY_X11, &ssi.focus_player[1], "shortcut.focus_player_2"       },
8311   { TYPE_KEY_X11, &ssi.focus_player[2], "shortcut.focus_player_3"       },
8312   { TYPE_KEY_X11, &ssi.focus_player[3], "shortcut.focus_player_4"       },
8313   { TYPE_KEY_X11, &ssi.focus_player_all,"shortcut.focus_player_all"     },
8314 };
8315
8316 static struct TokenInfo player_setup_tokens[] =
8317 {
8318   { TYPE_BOOLEAN, &sii.use_joystick,    ".use_joystick"                 },
8319   { TYPE_STRING,  &sii.joy.device_name, ".joy.device_name"              },
8320   { TYPE_INTEGER, &sii.joy.xleft,       ".joy.xleft"                    },
8321   { TYPE_INTEGER, &sii.joy.xmiddle,     ".joy.xmiddle"                  },
8322   { TYPE_INTEGER, &sii.joy.xright,      ".joy.xright"                   },
8323   { TYPE_INTEGER, &sii.joy.yupper,      ".joy.yupper"                   },
8324   { TYPE_INTEGER, &sii.joy.ymiddle,     ".joy.ymiddle"                  },
8325   { TYPE_INTEGER, &sii.joy.ylower,      ".joy.ylower"                   },
8326   { TYPE_INTEGER, &sii.joy.snap,        ".joy.snap_field"               },
8327   { TYPE_INTEGER, &sii.joy.drop,        ".joy.place_bomb"               },
8328   { TYPE_KEY_X11, &sii.key.left,        ".key.move_left"                },
8329   { TYPE_KEY_X11, &sii.key.right,       ".key.move_right"               },
8330   { TYPE_KEY_X11, &sii.key.up,          ".key.move_up"                  },
8331   { TYPE_KEY_X11, &sii.key.down,        ".key.move_down"                },
8332   { TYPE_KEY_X11, &sii.key.snap,        ".key.snap_field"               },
8333   { TYPE_KEY_X11, &sii.key.drop,        ".key.place_bomb"               },
8334 };
8335
8336 static struct TokenInfo system_setup_tokens[] =
8337 {
8338   { TYPE_STRING,  &syi.sdl_videodriver, "system.sdl_videodriver"        },
8339   { TYPE_STRING,  &syi.sdl_audiodriver, "system.sdl_audiodriver"        },
8340   { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size" },
8341 };
8342
8343 static struct TokenInfo options_setup_tokens[] =
8344 {
8345   { TYPE_BOOLEAN, &soi.verbose,         "options.verbose"               },
8346 };
8347
8348 static char *get_corrected_login_name(char *login_name)
8349 {
8350   /* needed because player name must be a fixed length string */
8351   char *login_name_new = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
8352
8353   strncpy(login_name_new, login_name, MAX_PLAYER_NAME_LEN);
8354   login_name_new[MAX_PLAYER_NAME_LEN] = '\0';
8355
8356   if (strlen(login_name) > MAX_PLAYER_NAME_LEN)         /* name has been cut */
8357     if (strchr(login_name_new, ' '))
8358       *strchr(login_name_new, ' ') = '\0';
8359
8360   return login_name_new;
8361 }
8362
8363 static void setSetupInfoToDefaults(struct SetupInfo *si)
8364 {
8365   int i;
8366
8367   si->player_name = get_corrected_login_name(getLoginName());
8368
8369   si->sound = TRUE;
8370   si->sound_loops = TRUE;
8371   si->sound_music = TRUE;
8372   si->sound_simple = TRUE;
8373   si->toons = TRUE;
8374   si->scroll_delay = TRUE;
8375   si->scroll_delay_value = STD_SCROLL_DELAY;
8376   si->soft_scrolling = TRUE;
8377   si->fade_screens = TRUE;
8378   si->autorecord = TRUE;
8379   si->show_titlescreen = TRUE;
8380   si->quick_doors = FALSE;
8381   si->team_mode = FALSE;
8382   si->handicap = TRUE;
8383   si->skip_levels = TRUE;
8384   si->time_limit = TRUE;
8385   si->fullscreen = FALSE;
8386   si->fullscreen_mode = getStringCopy(DEFAULT_FULLSCREEN_MODE);
8387   si->ask_on_escape = TRUE;
8388   si->ask_on_escape_editor = TRUE;
8389   si->quick_switch = FALSE;
8390   si->input_on_focus = FALSE;
8391   si->prefer_aga_graphics = TRUE;
8392   si->game_frame_delay = GAME_FRAME_DELAY;
8393
8394   si->graphics_set = getStringCopy(GFX_DEFAULT_SUBDIR);
8395   si->sounds_set = getStringCopy(SND_DEFAULT_SUBDIR);
8396   si->music_set = getStringCopy(MUS_DEFAULT_SUBDIR);
8397   si->override_level_graphics = FALSE;
8398   si->override_level_sounds = FALSE;
8399   si->override_level_music = FALSE;
8400
8401   si->editor.el_boulderdash             = TRUE;
8402   si->editor.el_emerald_mine            = TRUE;
8403   si->editor.el_emerald_mine_club       = TRUE;
8404   si->editor.el_more                    = TRUE;
8405   si->editor.el_sokoban                 = TRUE;
8406   si->editor.el_supaplex                = TRUE;
8407   si->editor.el_diamond_caves           = TRUE;
8408   si->editor.el_dx_boulderdash          = TRUE;
8409   si->editor.el_chars                   = TRUE;
8410   si->editor.el_steel_chars             = TRUE;
8411   si->editor.el_custom                  = TRUE;
8412
8413   si->editor.el_headlines = TRUE;
8414   si->editor.el_user_defined = FALSE;
8415   si->editor.el_dynamic = TRUE;
8416
8417   si->editor.show_element_token = FALSE;
8418
8419   si->shortcut.save_game        = DEFAULT_KEY_SAVE_GAME;
8420   si->shortcut.load_game        = DEFAULT_KEY_LOAD_GAME;
8421   si->shortcut.toggle_pause     = DEFAULT_KEY_TOGGLE_PAUSE;
8422
8423   si->shortcut.focus_player[0]  = DEFAULT_KEY_FOCUS_PLAYER_1;
8424   si->shortcut.focus_player[1]  = DEFAULT_KEY_FOCUS_PLAYER_2;
8425   si->shortcut.focus_player[2]  = DEFAULT_KEY_FOCUS_PLAYER_3;
8426   si->shortcut.focus_player[3]  = DEFAULT_KEY_FOCUS_PLAYER_4;
8427   si->shortcut.focus_player_all = DEFAULT_KEY_FOCUS_PLAYER_ALL;
8428
8429   for (i = 0; i < MAX_PLAYERS; i++)
8430   {
8431     si->input[i].use_joystick = FALSE;
8432     si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
8433     si->input[i].joy.xleft   = JOYSTICK_XLEFT;
8434     si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
8435     si->input[i].joy.xright  = JOYSTICK_XRIGHT;
8436     si->input[i].joy.yupper  = JOYSTICK_YUPPER;
8437     si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
8438     si->input[i].joy.ylower  = JOYSTICK_YLOWER;
8439     si->input[i].joy.snap  = (i == 0 ? JOY_BUTTON_1 : 0);
8440     si->input[i].joy.drop  = (i == 0 ? JOY_BUTTON_2 : 0);
8441     si->input[i].key.left  = (i == 0 ? DEFAULT_KEY_LEFT  : KSYM_UNDEFINED);
8442     si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
8443     si->input[i].key.up    = (i == 0 ? DEFAULT_KEY_UP    : KSYM_UNDEFINED);
8444     si->input[i].key.down  = (i == 0 ? DEFAULT_KEY_DOWN  : KSYM_UNDEFINED);
8445     si->input[i].key.snap  = (i == 0 ? DEFAULT_KEY_SNAP  : KSYM_UNDEFINED);
8446     si->input[i].key.drop  = (i == 0 ? DEFAULT_KEY_DROP  : KSYM_UNDEFINED);
8447   }
8448
8449   si->system.sdl_videodriver = getStringCopy(ARG_DEFAULT);
8450   si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT);
8451   si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
8452
8453   si->options.verbose = FALSE;
8454
8455 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
8456   si->handicap = FALSE;
8457   si->fullscreen = TRUE;
8458   si->override_level_graphics = AUTO;
8459   si->override_level_sounds = AUTO;
8460   si->override_level_music = AUTO;
8461 #endif
8462 }
8463
8464 static void setSetupInfoToDefaults_EditorCascade(struct SetupInfo *si)
8465 {
8466   si->editor_cascade.el_bd              = TRUE;
8467   si->editor_cascade.el_em              = TRUE;
8468   si->editor_cascade.el_emc             = TRUE;
8469   si->editor_cascade.el_rnd             = TRUE;
8470   si->editor_cascade.el_sb              = TRUE;
8471   si->editor_cascade.el_sp              = TRUE;
8472   si->editor_cascade.el_dc              = TRUE;
8473   si->editor_cascade.el_dx              = TRUE;
8474
8475   si->editor_cascade.el_chars           = FALSE;
8476   si->editor_cascade.el_steel_chars     = FALSE;
8477   si->editor_cascade.el_ce              = FALSE;
8478   si->editor_cascade.el_ge              = FALSE;
8479   si->editor_cascade.el_ref             = FALSE;
8480   si->editor_cascade.el_user            = FALSE;
8481   si->editor_cascade.el_dynamic         = FALSE;
8482 }
8483
8484 static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
8485 {
8486   int i, pnr;
8487
8488   if (!setup_file_hash)
8489     return;
8490
8491   /* global setup */
8492   si = setup;
8493   for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
8494     setSetupInfo(global_setup_tokens, i,
8495                  getHashEntry(setup_file_hash, global_setup_tokens[i].text));
8496   setup = si;
8497
8498   /* editor setup */
8499   sei = setup.editor;
8500   for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
8501     setSetupInfo(editor_setup_tokens, i,
8502                  getHashEntry(setup_file_hash,editor_setup_tokens[i].text));
8503   setup.editor = sei;
8504
8505   /* shortcut setup */
8506   ssi = setup.shortcut;
8507   for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
8508     setSetupInfo(shortcut_setup_tokens, i,
8509                  getHashEntry(setup_file_hash,shortcut_setup_tokens[i].text));
8510   setup.shortcut = ssi;
8511
8512   /* player setup */
8513   for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
8514   {
8515     char prefix[30];
8516
8517     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
8518
8519     sii = setup.input[pnr];
8520     for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
8521     {
8522       char full_token[100];
8523
8524       sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
8525       setSetupInfo(player_setup_tokens, i,
8526                    getHashEntry(setup_file_hash, full_token));
8527     }
8528     setup.input[pnr] = sii;
8529   }
8530
8531   /* system setup */
8532   syi = setup.system;
8533   for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
8534     setSetupInfo(system_setup_tokens, i,
8535                  getHashEntry(setup_file_hash, system_setup_tokens[i].text));
8536   setup.system = syi;
8537
8538   /* options setup */
8539   soi = setup.options;
8540   for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
8541     setSetupInfo(options_setup_tokens, i,
8542                  getHashEntry(setup_file_hash, options_setup_tokens[i].text));
8543   setup.options = soi;
8544 }
8545
8546 static void decodeSetupFileHash_EditorCascade(SetupFileHash *setup_file_hash)
8547 {
8548   int i;
8549
8550   if (!setup_file_hash)
8551     return;
8552
8553   /* editor cascade setup */
8554   seci = setup.editor_cascade;
8555   for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
8556     setSetupInfo(editor_cascade_setup_tokens, i,
8557                  getHashEntry(setup_file_hash,
8558                               editor_cascade_setup_tokens[i].text));
8559   setup.editor_cascade = seci;
8560 }
8561
8562 void LoadSetup()
8563 {
8564   char *filename = getSetupFilename();
8565   SetupFileHash *setup_file_hash = NULL;
8566
8567   /* always start with reliable default values */
8568   setSetupInfoToDefaults(&setup);
8569
8570   setup_file_hash = loadSetupFileHash(filename);
8571
8572   if (setup_file_hash)
8573   {
8574     char *player_name_new;
8575
8576     checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP"));
8577     decodeSetupFileHash(setup_file_hash);
8578
8579     freeSetupFileHash(setup_file_hash);
8580
8581     /* needed to work around problems with fixed length strings */
8582     player_name_new = get_corrected_login_name(setup.player_name);
8583     free(setup.player_name);
8584     setup.player_name = player_name_new;
8585
8586     /* "scroll_delay: on(3) / off(0)" was replaced by scroll delay value */
8587     if (setup.scroll_delay == FALSE)
8588     {
8589       setup.scroll_delay_value = MIN_SCROLL_DELAY;
8590       setup.scroll_delay = TRUE;                        /* now always "on" */
8591     }
8592
8593     /* make sure that scroll delay value stays inside valid range */
8594     setup.scroll_delay_value =
8595       MIN(MAX(MIN_SCROLL_DELAY, setup.scroll_delay_value), MAX_SCROLL_DELAY);
8596   }
8597   else
8598     Error(ERR_WARN, "using default setup values");
8599 }
8600
8601 void LoadSetup_EditorCascade()
8602 {
8603   char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
8604   SetupFileHash *setup_file_hash = NULL;
8605
8606   /* always start with reliable default values */
8607   setSetupInfoToDefaults_EditorCascade(&setup);
8608
8609   setup_file_hash = loadSetupFileHash(filename);
8610
8611   if (setup_file_hash)
8612   {
8613     checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP"));
8614     decodeSetupFileHash_EditorCascade(setup_file_hash);
8615
8616     freeSetupFileHash(setup_file_hash);
8617   }
8618
8619   free(filename);
8620 }
8621
8622 void SaveSetup()
8623 {
8624   char *filename = getSetupFilename();
8625   FILE *file;
8626   int i, pnr;
8627
8628   InitUserDataDirectory();
8629
8630   if (!(file = fopen(filename, MODE_WRITE)))
8631   {
8632     Error(ERR_WARN, "cannot write setup file '%s'", filename);
8633     return;
8634   }
8635
8636   fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
8637                                                getCookie("SETUP")));
8638   fprintf(file, "\n");
8639
8640   /* global setup */
8641   si = setup;
8642   for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
8643   {
8644     /* just to make things nicer :) */
8645     if (i == SETUP_TOKEN_PLAYER_NAME + 1 ||
8646         i == SETUP_TOKEN_GRAPHICS_SET)
8647       fprintf(file, "\n");
8648
8649     fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
8650   }
8651
8652   /* editor setup */
8653   sei = setup.editor;
8654   fprintf(file, "\n");
8655   for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
8656     fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i));
8657
8658   /* shortcut setup */
8659   ssi = setup.shortcut;
8660   fprintf(file, "\n");
8661   for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
8662     fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
8663
8664   /* player setup */
8665   for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
8666   {
8667     char prefix[30];
8668
8669     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
8670     fprintf(file, "\n");
8671
8672     sii = setup.input[pnr];
8673     for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
8674       fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
8675   }
8676
8677   /* system setup */
8678   syi = setup.system;
8679   fprintf(file, "\n");
8680   for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
8681     fprintf(file, "%s\n", getSetupLine(system_setup_tokens, "", i));
8682
8683   /* options setup */
8684   soi = setup.options;
8685   fprintf(file, "\n");
8686   for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
8687     fprintf(file, "%s\n", getSetupLine(options_setup_tokens, "", i));
8688
8689   fclose(file);
8690
8691   SetFilePermissions(filename, PERMS_PRIVATE);
8692 }
8693
8694 void SaveSetup_EditorCascade()
8695 {
8696   char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
8697   FILE *file;
8698   int i;
8699
8700   InitUserDataDirectory();
8701
8702   if (!(file = fopen(filename, MODE_WRITE)))
8703   {
8704     Error(ERR_WARN, "cannot write editor cascade state file '%s'", filename);
8705     free(filename);
8706     return;
8707   }
8708
8709   fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
8710                                                getCookie("SETUP")));
8711   fprintf(file, "\n");
8712
8713   seci = setup.editor_cascade;
8714   fprintf(file, "\n");
8715   for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
8716     fprintf(file, "%s\n", getSetupLine(editor_cascade_setup_tokens, "", i));
8717
8718   fclose(file);
8719
8720   SetFilePermissions(filename, PERMS_PRIVATE);
8721
8722   free(filename);
8723 }
8724
8725 void LoadCustomElementDescriptions()
8726 {
8727   char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
8728   SetupFileHash *setup_file_hash;
8729   int i;
8730
8731   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
8732   {
8733     if (element_info[i].custom_description != NULL)
8734     {
8735       free(element_info[i].custom_description);
8736       element_info[i].custom_description = NULL;
8737     }
8738   }
8739
8740   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
8741     return;
8742
8743   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
8744   {
8745     char *token = getStringCat2(element_info[i].token_name, ".name");
8746     char *value = getHashEntry(setup_file_hash, token);
8747
8748     if (value != NULL)
8749       element_info[i].custom_description = getStringCopy(value);
8750
8751     free(token);
8752   }
8753
8754   freeSetupFileHash(setup_file_hash);
8755 }
8756
8757 static int getElementFromToken(char *token)
8758 {
8759 #if 1
8760   char *value = getHashEntry(element_token_hash, token);
8761
8762   if (value != NULL)
8763     return atoi(value);
8764 #else
8765   int i;
8766
8767   /* !!! OPTIMIZE THIS BY USING HASH !!! */
8768   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
8769     if (strEqual(token, element_info[i].token_name))
8770       return i;
8771 #endif
8772
8773   Error(ERR_WARN, "unknown element token '%s'", token);
8774
8775   return EL_UNDEFINED;
8776 }
8777
8778 static int get_token_parameter_value(char *token, char *value_raw)
8779 {
8780   char *suffix;
8781
8782   if (token == NULL || value_raw == NULL)
8783     return ARG_UNDEFINED_VALUE;
8784
8785   suffix = strrchr(token, '.');
8786   if (suffix == NULL)
8787     suffix = token;
8788
8789 #if 1
8790   if (strEqual(suffix, ".element"))
8791     return getElementFromToken(value_raw);
8792 #endif
8793
8794 #if 0
8795   if (strncmp(suffix, ".font", 5) == 0)
8796   {
8797     int i;
8798
8799     /* !!! OPTIMIZE THIS BY USING HASH !!! */
8800     for (i = 0; i < NUM_FONTS; i++)
8801       if (strEqual(value_raw, font_info[i].token_name))
8802         return i;
8803
8804     /* if font not found, use reliable default value */
8805     return FONT_INITIAL_1;
8806   }
8807 #endif
8808
8809   /* !!! USE CORRECT VALUE TYPE (currently works also for TYPE_BOOLEAN) !!! */
8810   return get_parameter_value(value_raw, suffix, TYPE_INTEGER);
8811 }
8812
8813 void InitMenuDesignSettings_Static()
8814 {
8815 #if 0
8816   static SetupFileHash *image_config_hash = NULL;
8817 #endif
8818   int i;
8819
8820 #if 0
8821   if (image_config_hash == NULL)
8822   {
8823     image_config_hash = newSetupFileHash();
8824
8825     for (i = 0; image_config[i].token != NULL; i++)
8826       setHashEntry(image_config_hash,
8827                    image_config[i].token,
8828                    image_config[i].value);
8829   }
8830 #endif
8831
8832 #if 1
8833   /* always start with reliable default values from static default config */
8834   for (i = 0; image_config_vars[i].token != NULL; i++)
8835   {
8836     char *value = getHashEntry(image_config_hash, image_config_vars[i].token);
8837
8838     if (value != NULL)
8839       *image_config_vars[i].value =
8840         get_token_parameter_value(image_config_vars[i].token, value);
8841   }
8842
8843 #else
8844
8845   int j;
8846
8847   /* always start with reliable default values from static default config */
8848   for (i = 0; image_config_vars[i].token != NULL; i++)
8849     for (j = 0; image_config[j].token != NULL; j++)
8850       if (strEqual(image_config_vars[i].token, image_config[j].token))
8851         *image_config_vars[i].value =
8852           get_token_parameter_value(image_config_vars[i].token,
8853                                     image_config[j].value);
8854 #endif
8855 }
8856
8857 static void InitMenuDesignSettings_SpecialPreProcessing()
8858 {
8859   int i;
8860
8861   /* the following initializes hierarchical values from static configuration */
8862
8863   /* special case: initialize "ARG_DEFAULT" values in static default config */
8864   /* (e.g., initialize "[titlemessage].fade_mode" from "[title].fade_mode") */
8865   titlemessage_initial_default.fade_mode  = title_initial_default.fade_mode;
8866   titlemessage_initial_default.fade_delay = title_initial_default.fade_delay;
8867   titlemessage_initial_default.post_delay = title_initial_default.post_delay;
8868   titlemessage_initial_default.auto_delay = title_initial_default.auto_delay;
8869   titlemessage_default.fade_mode  = title_default.fade_mode;
8870   titlemessage_default.fade_delay = title_default.fade_delay;
8871   titlemessage_default.post_delay = title_default.post_delay;
8872   titlemessage_default.auto_delay = title_default.auto_delay;
8873
8874   /* special case: initialize "ARG_DEFAULT" values in static default config */
8875   /* (e.g., init "titlemessage_1.fade_mode" from "[titlemessage].fade_mode") */
8876   for (i = 0; i < MAX_NUM_TITLE_MESSAGES; i++)
8877   {
8878     titlemessage_initial[i] = titlemessage_initial_default;
8879     titlemessage[i] = titlemessage_default;
8880   }
8881
8882   /* special case: initialize "ARG_DEFAULT" values in static default config */
8883   /* (eg, init "menu.enter_screen.SCORES.xyz" from "menu.enter_screen.xyz") */
8884   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
8885   {
8886     menu.enter_screen[i] = menu.enter_screen[GFX_SPECIAL_ARG_DEFAULT];
8887     menu.leave_screen[i] = menu.leave_screen[GFX_SPECIAL_ARG_DEFAULT];
8888   }
8889 }
8890
8891 static void InitMenuDesignSettings_SpecialPostProcessing()
8892 {
8893   /* special case: initialize later added SETUP list size from LEVELS value */
8894   if (menu.list_size[GAME_MODE_SETUP] == -1)
8895     menu.list_size[GAME_MODE_SETUP] = menu.list_size[GAME_MODE_LEVELS];
8896 }
8897
8898 static void LoadMenuDesignSettingsFromFilename(char *filename)
8899 {
8900   static struct TitleMessageInfo tmi;
8901   static struct TokenInfo titlemessage_tokens[] =
8902   {
8903     { TYPE_INTEGER,     &tmi.x,                 ".x"                    },
8904     { TYPE_INTEGER,     &tmi.y,                 ".y"                    },
8905     { TYPE_INTEGER,     &tmi.width,             ".width"                },
8906     { TYPE_INTEGER,     &tmi.height,            ".height"               },
8907     { TYPE_INTEGER,     &tmi.chars,             ".chars"                },
8908     { TYPE_INTEGER,     &tmi.lines,             ".lines"                },
8909     { TYPE_INTEGER,     &tmi.align,             ".align"                },
8910     { TYPE_INTEGER,     &tmi.valign,            ".valign"               },
8911     { TYPE_INTEGER,     &tmi.font,              ".font"                 },
8912     { TYPE_BOOLEAN,     &tmi.autowrap,          ".autowrap"             },
8913     { TYPE_BOOLEAN,     &tmi.centered,          ".centered"             },
8914     { TYPE_BOOLEAN,     &tmi.parse_comments,    ".parse_comments"       },
8915     { TYPE_INTEGER,     &tmi.sort_priority,     ".sort_priority"        },
8916     { TYPE_INTEGER,     &tmi.fade_mode,         ".fade_mode"            },
8917     { TYPE_INTEGER,     &tmi.fade_delay,        ".fade_delay"           },
8918     { TYPE_INTEGER,     &tmi.post_delay,        ".post_delay"           },
8919     { TYPE_INTEGER,     &tmi.auto_delay,        ".auto_delay"           },
8920
8921     { -1,               NULL,                   NULL                    }
8922   };
8923   static struct
8924   {
8925     struct TitleMessageInfo *array;
8926     char *text;
8927   }
8928   titlemessage_arrays[] =
8929   {
8930     { titlemessage_initial,             "[titlemessage_initial]"        },
8931     { titlemessage,                     "[titlemessage]"                },
8932
8933     { NULL,                             NULL                            }
8934   };
8935   SetupFileHash *setup_file_hash;
8936   int i, j, k;
8937
8938 #if 0
8939   printf("LoadMenuDesignSettings from file '%s' ...\n", filename);
8940 #endif
8941
8942   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
8943     return;
8944
8945   /* the following initializes hierarchical values from dynamic configuration */
8946
8947   /* special case: initialize with default values that may be overwritten */
8948   /* (e.g., init "menu.draw_xoffset.INFO" from "menu.draw_xoffset") */
8949   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
8950   {
8951     char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset");
8952     char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset");
8953     char *value_3 = getHashEntry(setup_file_hash, "menu.list_size");
8954
8955     if (value_1 != NULL)
8956       menu.draw_xoffset[i] = get_integer_from_string(value_1);
8957     if (value_2 != NULL)
8958       menu.draw_yoffset[i] = get_integer_from_string(value_2);
8959     if (value_3 != NULL)
8960       menu.list_size[i] = get_integer_from_string(value_3);
8961   }
8962
8963   /* special case: initialize with default values that may be overwritten */
8964   /* (eg, init "menu.draw_xoffset.INFO[XXX]" from "menu.draw_xoffset.INFO") */
8965   for (i = 0; i < NUM_SPECIAL_GFX_INFO_ARGS; i++)
8966   {
8967     char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset.INFO");
8968     char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset.INFO");
8969
8970     if (value_1 != NULL)
8971       menu.draw_xoffset_info[i] = get_integer_from_string(value_1);
8972     if (value_2 != NULL)
8973       menu.draw_yoffset_info[i] = get_integer_from_string(value_2);
8974   }
8975
8976   /* special case: initialize with default values that may be overwritten */
8977   /* (eg, init "menu.draw_xoffset.SETUP[XXX]" from "menu.draw_xoffset.SETUP") */
8978   for (i = 0; i < NUM_SPECIAL_GFX_SETUP_ARGS; i++)
8979   {
8980     char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset.SETUP");
8981     char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset.SETUP");
8982
8983     if (value_1 != NULL)
8984       menu.draw_xoffset_setup[i] = get_integer_from_string(value_1);
8985     if (value_2 != NULL)
8986       menu.draw_yoffset_setup[i] = get_integer_from_string(value_2);
8987   }
8988
8989   /* special case: initialize with default values that may be overwritten */
8990   /* (eg, init "menu.enter_screen.SCORES.xyz" from "menu.enter_screen.xyz") */
8991   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
8992   {
8993     char *token_1 = "menu.enter_screen.fade_mode";
8994     char *token_2 = "menu.enter_screen.fade_delay";
8995     char *token_3 = "menu.enter_screen.post_delay";
8996     char *token_4 = "menu.leave_screen.fade_mode";
8997     char *token_5 = "menu.leave_screen.fade_delay";
8998     char *token_6 = "menu.leave_screen.post_delay";
8999     char *value_1 = getHashEntry(setup_file_hash, token_1);
9000     char *value_2 = getHashEntry(setup_file_hash, token_2);
9001     char *value_3 = getHashEntry(setup_file_hash, token_3);
9002     char *value_4 = getHashEntry(setup_file_hash, token_4);
9003     char *value_5 = getHashEntry(setup_file_hash, token_5);
9004     char *value_6 = getHashEntry(setup_file_hash, token_6);
9005
9006     if (value_1 != NULL)
9007       menu.enter_screen[i].fade_mode = get_token_parameter_value(token_1,
9008                                                                  value_1);
9009     if (value_2 != NULL)
9010       menu.enter_screen[i].fade_delay = get_token_parameter_value(token_2,
9011                                                                   value_2);
9012     if (value_3 != NULL)
9013       menu.enter_screen[i].post_delay = get_token_parameter_value(token_3,
9014                                                                   value_3);
9015     if (value_4 != NULL)
9016       menu.leave_screen[i].fade_mode = get_token_parameter_value(token_4,
9017                                                                  value_4);
9018     if (value_5 != NULL)
9019       menu.leave_screen[i].fade_delay = get_token_parameter_value(token_5,
9020                                                                   value_5);
9021     if (value_6 != NULL)
9022       menu.leave_screen[i].post_delay = get_token_parameter_value(token_6,
9023                                                                   value_6);
9024   }
9025
9026   /* special case: initialize with default values that may be overwritten */
9027   /* (e.g., init "titlemessage_1.fade_mode" from "[titlemessage].fade_mode") */
9028   for (i = 0; titlemessage_arrays[i].array != NULL; i++)
9029   {
9030     struct TitleMessageInfo *array = titlemessage_arrays[i].array;
9031     char *base_token = titlemessage_arrays[i].text;
9032
9033     for (j = 0; titlemessage_tokens[j].type != -1; j++)
9034     {
9035       char *token = getStringCat2(base_token, titlemessage_tokens[j].text);
9036       char *value = getHashEntry(setup_file_hash, token);
9037
9038       if (value != NULL)
9039       {
9040         int parameter_value = get_token_parameter_value(token, value);
9041
9042         for (k = 0; k < MAX_NUM_TITLE_MESSAGES; k++)
9043         {
9044           tmi = array[k];
9045
9046           if (titlemessage_tokens[j].type == TYPE_INTEGER)
9047             *(boolean *)titlemessage_tokens[j].value = (boolean)parameter_value;
9048           else
9049             *(int     *)titlemessage_tokens[j].value = (int)parameter_value;
9050
9051           array[k] = tmi;
9052         }
9053       }
9054
9055       free(token);
9056     }
9057   }
9058
9059   /* read (and overwrite with) values that may be specified in config file */
9060   for (i = 0; image_config_vars[i].token != NULL; i++)
9061   {
9062     char *value = getHashEntry(setup_file_hash, image_config_vars[i].token);
9063
9064     /* (ignore definitions set to "[DEFAULT]" which are already initialized) */
9065     if (value != NULL && !strEqual(value, ARG_DEFAULT))
9066       *image_config_vars[i].value =
9067         get_token_parameter_value(image_config_vars[i].token, value);
9068   }
9069
9070   freeSetupFileHash(setup_file_hash);
9071 }
9072
9073 void LoadMenuDesignSettings()
9074 {
9075   char *filename_base = UNDEFINED_FILENAME, *filename_local;
9076
9077   InitMenuDesignSettings_Static();
9078   InitMenuDesignSettings_SpecialPreProcessing();
9079
9080 #if 1
9081   if (!GFX_OVERRIDE_ARTWORK(ARTWORK_TYPE_GRAPHICS))
9082 #else
9083   if (!SETUP_OVERRIDE_ARTWORK(setup, ARTWORK_TYPE_GRAPHICS))
9084 #endif
9085   {
9086     /* first look for special settings configured in level series config */
9087     filename_base = getCustomArtworkLevelConfigFilename(ARTWORK_TYPE_GRAPHICS);
9088
9089     if (fileExists(filename_base))
9090       LoadMenuDesignSettingsFromFilename(filename_base);
9091   }
9092
9093   filename_local = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
9094
9095   if (filename_local != NULL && !strEqual(filename_base, filename_local))
9096     LoadMenuDesignSettingsFromFilename(filename_local);
9097
9098   InitMenuDesignSettings_SpecialPostProcessing();
9099 }
9100
9101 void LoadUserDefinedEditorElementList(int **elements, int *num_elements)
9102 {
9103   char *filename = getEditorSetupFilename();
9104   SetupFileList *setup_file_list, *list;
9105   SetupFileHash *element_hash;
9106   int num_unknown_tokens = 0;
9107   int i;
9108
9109   if ((setup_file_list = loadSetupFileList(filename)) == NULL)
9110     return;
9111
9112   element_hash = newSetupFileHash();
9113
9114   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9115     setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
9116
9117   /* determined size may be larger than needed (due to unknown elements) */
9118   *num_elements = 0;
9119   for (list = setup_file_list; list != NULL; list = list->next)
9120     (*num_elements)++;
9121
9122   /* add space for up to 3 more elements for padding that may be needed */
9123   *num_elements += 3;
9124
9125   /* free memory for old list of elements, if needed */
9126   checked_free(*elements);
9127
9128   /* allocate memory for new list of elements */
9129   *elements = checked_malloc(*num_elements * sizeof(int));
9130
9131   *num_elements = 0;
9132   for (list = setup_file_list; list != NULL; list = list->next)
9133   {
9134     char *value = getHashEntry(element_hash, list->token);
9135
9136     if (value == NULL)          /* try to find obsolete token mapping */
9137     {
9138       char *mapped_token = get_mapped_token(list->token);
9139
9140       if (mapped_token != NULL)
9141       {
9142         value = getHashEntry(element_hash, mapped_token);
9143
9144         free(mapped_token);
9145       }
9146     }
9147
9148     if (value != NULL)
9149     {
9150       (*elements)[(*num_elements)++] = atoi(value);
9151     }
9152     else
9153     {
9154       if (num_unknown_tokens == 0)
9155       {
9156         Error(ERR_INFO_LINE, "-");
9157         Error(ERR_INFO, "warning: unknown token(s) found in config file:");
9158         Error(ERR_INFO, "- config file: '%s'", filename);
9159
9160         num_unknown_tokens++;
9161       }
9162
9163       Error(ERR_INFO, "- token: '%s'", list->token);
9164     }
9165   }
9166
9167   if (num_unknown_tokens > 0)
9168     Error(ERR_INFO_LINE, "-");
9169
9170   while (*num_elements % 4)     /* pad with empty elements, if needed */
9171     (*elements)[(*num_elements)++] = EL_EMPTY;
9172
9173   freeSetupFileList(setup_file_list);
9174   freeSetupFileHash(element_hash);
9175
9176 #if 0
9177   for (i = 0; i < *num_elements; i++)
9178     printf("editor: element '%s' [%d]\n",
9179            element_info[(*elements)[i]].token_name, (*elements)[i]);
9180 #endif
9181 }
9182
9183 static struct MusicFileInfo *get_music_file_info_ext(char *basename, int music,
9184                                                      boolean is_sound)
9185 {
9186   SetupFileHash *setup_file_hash = NULL;
9187   struct MusicFileInfo tmp_music_file_info, *new_music_file_info;
9188   char *filename_music, *filename_prefix, *filename_info;
9189   struct
9190   {
9191     char *token;
9192     char **value_ptr;
9193   }
9194   token_to_value_ptr[] =
9195   {
9196     { "title_header",   &tmp_music_file_info.title_header       },
9197     { "artist_header",  &tmp_music_file_info.artist_header      },
9198     { "album_header",   &tmp_music_file_info.album_header       },
9199     { "year_header",    &tmp_music_file_info.year_header        },
9200
9201     { "title",          &tmp_music_file_info.title              },
9202     { "artist",         &tmp_music_file_info.artist             },
9203     { "album",          &tmp_music_file_info.album              },
9204     { "year",           &tmp_music_file_info.year               },
9205
9206     { NULL,             NULL                                    },
9207   };
9208   int i;
9209
9210   filename_music = (is_sound ? getCustomSoundFilename(basename) :
9211                     getCustomMusicFilename(basename));
9212
9213   if (filename_music == NULL)
9214     return NULL;
9215
9216   /* ---------- try to replace file extension ---------- */
9217
9218   filename_prefix = getStringCopy(filename_music);
9219   if (strrchr(filename_prefix, '.') != NULL)
9220     *strrchr(filename_prefix, '.') = '\0';
9221   filename_info = getStringCat2(filename_prefix, ".txt");
9222
9223 #if 0
9224   printf("trying to load file '%s'...\n", filename_info);
9225 #endif
9226
9227   if (fileExists(filename_info))
9228     setup_file_hash = loadSetupFileHash(filename_info);
9229
9230   free(filename_prefix);
9231   free(filename_info);
9232
9233   if (setup_file_hash == NULL)
9234   {
9235     /* ---------- try to add file extension ---------- */
9236
9237     filename_prefix = getStringCopy(filename_music);
9238     filename_info = getStringCat2(filename_prefix, ".txt");
9239
9240 #if 0
9241     printf("trying to load file '%s'...\n", filename_info);
9242 #endif
9243
9244     if (fileExists(filename_info))
9245       setup_file_hash = loadSetupFileHash(filename_info);
9246
9247     free(filename_prefix);
9248     free(filename_info);
9249   }
9250
9251   if (setup_file_hash == NULL)
9252     return NULL;
9253
9254   /* ---------- music file info found ---------- */
9255
9256   clear_mem(&tmp_music_file_info, sizeof(struct MusicFileInfo));
9257
9258   for (i = 0; token_to_value_ptr[i].token != NULL; i++)
9259   {
9260     char *value = getHashEntry(setup_file_hash, token_to_value_ptr[i].token);
9261
9262     *token_to_value_ptr[i].value_ptr =
9263       getStringCopy(value != NULL && *value != '\0' ? value : UNKNOWN_NAME);
9264   }
9265
9266   tmp_music_file_info.basename = getStringCopy(basename);
9267   tmp_music_file_info.music = music;
9268   tmp_music_file_info.is_sound = is_sound;
9269
9270   new_music_file_info = checked_malloc(sizeof(struct MusicFileInfo));
9271   *new_music_file_info = tmp_music_file_info;
9272
9273   return new_music_file_info;
9274 }
9275
9276 static struct MusicFileInfo *get_music_file_info(char *basename, int music)
9277 {
9278   return get_music_file_info_ext(basename, music, FALSE);
9279 }
9280
9281 static struct MusicFileInfo *get_sound_file_info(char *basename, int sound)
9282 {
9283   return get_music_file_info_ext(basename, sound, TRUE);
9284 }
9285
9286 static boolean music_info_listed_ext(struct MusicFileInfo *list,
9287                                      char *basename, boolean is_sound)
9288 {
9289   for (; list != NULL; list = list->next)
9290     if (list->is_sound == is_sound && strEqual(list->basename, basename))
9291       return TRUE;
9292
9293   return FALSE;
9294 }
9295
9296 static boolean music_info_listed(struct MusicFileInfo *list, char *basename)
9297 {
9298   return music_info_listed_ext(list, basename, FALSE);
9299 }
9300
9301 static boolean sound_info_listed(struct MusicFileInfo *list, char *basename)
9302 {
9303   return music_info_listed_ext(list, basename, TRUE);
9304 }
9305
9306 void LoadMusicInfo()
9307 {
9308   char *music_directory = getCustomMusicDirectory();
9309   int num_music = getMusicListSize();
9310   int num_music_noconf = 0;
9311   int num_sounds = getSoundListSize();
9312   DIR *dir;
9313   struct dirent *dir_entry;
9314   struct FileInfo *music, *sound;
9315   struct MusicFileInfo *next, **new;
9316   int i;
9317
9318   while (music_file_info != NULL)
9319   {
9320     next = music_file_info->next;
9321
9322     checked_free(music_file_info->basename);
9323
9324     checked_free(music_file_info->title_header);
9325     checked_free(music_file_info->artist_header);
9326     checked_free(music_file_info->album_header);
9327     checked_free(music_file_info->year_header);
9328
9329     checked_free(music_file_info->title);
9330     checked_free(music_file_info->artist);
9331     checked_free(music_file_info->album);
9332     checked_free(music_file_info->year);
9333
9334     free(music_file_info);
9335
9336     music_file_info = next;
9337   }
9338
9339   new = &music_file_info;
9340
9341   for (i = 0; i < num_music; i++)
9342   {
9343     music = getMusicListEntry(i);
9344
9345     if (music->filename == NULL)
9346       continue;
9347
9348     if (strEqual(music->filename, UNDEFINED_FILENAME))
9349       continue;
9350
9351     /* a configured file may be not recognized as music */
9352     if (!FileIsMusic(music->filename))
9353       continue;
9354
9355 #if 0
9356     printf("::: -> '%s' (configured)\n", music->filename);
9357 #endif
9358
9359     if (!music_info_listed(music_file_info, music->filename))
9360     {
9361       *new = get_music_file_info(music->filename, i);
9362       if (*new != NULL)
9363         new = &(*new)->next;
9364     }
9365   }
9366
9367   if ((dir = opendir(music_directory)) == NULL)
9368   {
9369     Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
9370     return;
9371   }
9372
9373   while ((dir_entry = readdir(dir)) != NULL)    /* loop until last dir entry */
9374   {
9375     char *basename = dir_entry->d_name;
9376     boolean music_already_used = FALSE;
9377     int i;
9378
9379     /* skip all music files that are configured in music config file */
9380     for (i = 0; i < num_music; i++)
9381     {
9382       music = getMusicListEntry(i);
9383
9384       if (music->filename == NULL)
9385         continue;
9386
9387       if (strEqual(basename, music->filename))
9388       {
9389         music_already_used = TRUE;
9390         break;
9391       }
9392     }
9393
9394     if (music_already_used)
9395       continue;
9396
9397     if (!FileIsMusic(basename))
9398       continue;
9399
9400 #if 0
9401     printf("::: -> '%s' (found in directory)\n", basename);
9402 #endif
9403
9404     if (!music_info_listed(music_file_info, basename))
9405     {
9406       *new = get_music_file_info(basename, MAP_NOCONF_MUSIC(num_music_noconf));
9407       if (*new != NULL)
9408         new = &(*new)->next;
9409     }
9410
9411     num_music_noconf++;
9412   }
9413
9414   closedir(dir);
9415
9416   for (i = 0; i < num_sounds; i++)
9417   {
9418     sound = getSoundListEntry(i);
9419
9420     if (sound->filename == NULL)
9421       continue;
9422
9423     if (strEqual(sound->filename, UNDEFINED_FILENAME))
9424       continue;
9425
9426     /* a configured file may be not recognized as sound */
9427     if (!FileIsSound(sound->filename))
9428       continue;
9429
9430 #if 0
9431     printf("::: -> '%s' (configured)\n", sound->filename);
9432 #endif
9433
9434     if (!sound_info_listed(music_file_info, sound->filename))
9435     {
9436       *new = get_sound_file_info(sound->filename, i);
9437       if (*new != NULL)
9438         new = &(*new)->next;
9439     }
9440   }
9441
9442 #if 0
9443   for (next = music_file_info; next != NULL; next = next->next)
9444     printf("::: title == '%s'\n", next->title);
9445 #endif
9446 }
9447
9448 void add_helpanim_entry(int element, int action, int direction, int delay,
9449                         int *num_list_entries)
9450 {
9451   struct HelpAnimInfo *new_list_entry;
9452   (*num_list_entries)++;
9453
9454   helpanim_info =
9455     checked_realloc(helpanim_info,
9456                     *num_list_entries * sizeof(struct HelpAnimInfo));
9457   new_list_entry = &helpanim_info[*num_list_entries - 1];
9458
9459   new_list_entry->element = element;
9460   new_list_entry->action = action;
9461   new_list_entry->direction = direction;
9462   new_list_entry->delay = delay;
9463 }
9464
9465 void print_unknown_token(char *filename, char *token, int token_nr)
9466 {
9467   if (token_nr == 0)
9468   {
9469     Error(ERR_INFO_LINE, "-");
9470     Error(ERR_INFO, "warning: unknown token(s) found in config file:");
9471     Error(ERR_INFO, "- config file: '%s'", filename);
9472   }
9473
9474   Error(ERR_INFO, "- token: '%s'", token);
9475 }
9476
9477 void print_unknown_token_end(int token_nr)
9478 {
9479   if (token_nr > 0)
9480     Error(ERR_INFO_LINE, "-");
9481 }
9482
9483 void LoadHelpAnimInfo()
9484 {
9485   char *filename = getHelpAnimFilename();
9486   SetupFileList *setup_file_list = NULL, *list;
9487   SetupFileHash *element_hash, *action_hash, *direction_hash;
9488   int num_list_entries = 0;
9489   int num_unknown_tokens = 0;
9490   int i;
9491
9492   if (fileExists(filename))
9493     setup_file_list = loadSetupFileList(filename);
9494
9495   if (setup_file_list == NULL)
9496   {
9497     /* use reliable default values from static configuration */
9498     SetupFileList *insert_ptr;
9499
9500     insert_ptr = setup_file_list =
9501       newSetupFileList(helpanim_config[0].token,
9502                        helpanim_config[0].value);
9503
9504     for (i = 1; helpanim_config[i].token; i++)
9505       insert_ptr = addListEntry(insert_ptr,
9506                                 helpanim_config[i].token,
9507                                 helpanim_config[i].value);
9508   }
9509
9510   element_hash   = newSetupFileHash();
9511   action_hash    = newSetupFileHash();
9512   direction_hash = newSetupFileHash();
9513
9514   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
9515     setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
9516
9517   for (i = 0; i < NUM_ACTIONS; i++)
9518     setHashEntry(action_hash, element_action_info[i].suffix,
9519                  i_to_a(element_action_info[i].value));
9520
9521   /* do not store direction index (bit) here, but direction value! */
9522   for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
9523     setHashEntry(direction_hash, element_direction_info[i].suffix,
9524                  i_to_a(1 << element_direction_info[i].value));
9525
9526   for (list = setup_file_list; list != NULL; list = list->next)
9527   {
9528     char *element_token, *action_token, *direction_token;
9529     char *element_value, *action_value, *direction_value;
9530     int delay = atoi(list->value);
9531
9532     if (strEqual(list->token, "end"))
9533     {
9534       add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
9535
9536       continue;
9537     }
9538
9539     /* first try to break element into element/action/direction parts;
9540        if this does not work, also accept combined "element[.act][.dir]"
9541        elements (like "dynamite.active"), which are unique elements */
9542
9543     if (strchr(list->token, '.') == NULL)       /* token contains no '.' */
9544     {
9545       element_value = getHashEntry(element_hash, list->token);
9546       if (element_value != NULL)        /* element found */
9547         add_helpanim_entry(atoi(element_value), -1, -1, delay,
9548                            &num_list_entries);
9549       else
9550       {
9551         /* no further suffixes found -- this is not an element */
9552         print_unknown_token(filename, list->token, num_unknown_tokens++);
9553       }
9554
9555       continue;
9556     }
9557
9558     /* token has format "<prefix>.<something>" */
9559
9560     action_token = strchr(list->token, '.');    /* suffix may be action ... */
9561     direction_token = action_token;             /* ... or direction */
9562
9563     element_token = getStringCopy(list->token);
9564     *strchr(element_token, '.') = '\0';
9565
9566     element_value = getHashEntry(element_hash, element_token);
9567
9568     if (element_value == NULL)          /* this is no element */
9569     {
9570       element_value = getHashEntry(element_hash, list->token);
9571       if (element_value != NULL)        /* combined element found */
9572         add_helpanim_entry(atoi(element_value), -1, -1, delay,
9573                            &num_list_entries);
9574       else
9575         print_unknown_token(filename, list->token, num_unknown_tokens++);
9576
9577       free(element_token);
9578
9579       continue;
9580     }
9581
9582     action_value = getHashEntry(action_hash, action_token);
9583
9584     if (action_value != NULL)           /* action found */
9585     {
9586       add_helpanim_entry(atoi(element_value), atoi(action_value), -1, delay,
9587                     &num_list_entries);
9588
9589       free(element_token);
9590
9591       continue;
9592     }
9593
9594     direction_value = getHashEntry(direction_hash, direction_token);
9595
9596     if (direction_value != NULL)        /* direction found */
9597     {
9598       add_helpanim_entry(atoi(element_value), -1, atoi(direction_value), delay,
9599                          &num_list_entries);
9600
9601       free(element_token);
9602
9603       continue;
9604     }
9605
9606     if (strchr(action_token + 1, '.') == NULL)
9607     {
9608       /* no further suffixes found -- this is not an action nor direction */
9609
9610       element_value = getHashEntry(element_hash, list->token);
9611       if (element_value != NULL)        /* combined element found */
9612         add_helpanim_entry(atoi(element_value), -1, -1, delay,
9613                            &num_list_entries);
9614       else
9615         print_unknown_token(filename, list->token, num_unknown_tokens++);
9616
9617       free(element_token);
9618
9619       continue;
9620     }
9621
9622     /* token has format "<prefix>.<suffix>.<something>" */
9623
9624     direction_token = strchr(action_token + 1, '.');
9625
9626     action_token = getStringCopy(action_token);
9627     *strchr(action_token + 1, '.') = '\0';
9628
9629     action_value = getHashEntry(action_hash, action_token);
9630
9631     if (action_value == NULL)           /* this is no action */
9632     {
9633       element_value = getHashEntry(element_hash, list->token);
9634       if (element_value != NULL)        /* combined element found */
9635         add_helpanim_entry(atoi(element_value), -1, -1, delay,
9636                            &num_list_entries);
9637       else
9638         print_unknown_token(filename, list->token, num_unknown_tokens++);
9639
9640       free(element_token);
9641       free(action_token);
9642
9643       continue;
9644     }
9645
9646     direction_value = getHashEntry(direction_hash, direction_token);
9647
9648     if (direction_value != NULL)        /* direction found */
9649     {
9650       add_helpanim_entry(atoi(element_value), atoi(action_value),
9651                          atoi(direction_value), delay, &num_list_entries);
9652
9653       free(element_token);
9654       free(action_token);
9655
9656       continue;
9657     }
9658
9659     /* this is no direction */
9660
9661     element_value = getHashEntry(element_hash, list->token);
9662     if (element_value != NULL)          /* combined element found */
9663       add_helpanim_entry(atoi(element_value), -1, -1, delay,
9664                          &num_list_entries);
9665     else
9666       print_unknown_token(filename, list->token, num_unknown_tokens++);
9667
9668     free(element_token);
9669     free(action_token);
9670   }
9671
9672   print_unknown_token_end(num_unknown_tokens);
9673
9674   add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
9675   add_helpanim_entry(HELPANIM_LIST_END,  -1, -1, -1, &num_list_entries);
9676
9677   freeSetupFileList(setup_file_list);
9678   freeSetupFileHash(element_hash);
9679   freeSetupFileHash(action_hash);
9680   freeSetupFileHash(direction_hash);
9681
9682 #if 0
9683   for (i = 0; i < num_list_entries; i++)
9684     printf("::: '%s': %d, %d, %d => %d\n",
9685            EL_NAME(helpanim_info[i].element),
9686            helpanim_info[i].element,
9687            helpanim_info[i].action,
9688            helpanim_info[i].direction,
9689            helpanim_info[i].delay);
9690 #endif
9691 }
9692
9693 void LoadHelpTextInfo()
9694 {
9695   char *filename = getHelpTextFilename();
9696   int i;
9697
9698   if (helptext_info != NULL)
9699   {
9700     freeSetupFileHash(helptext_info);
9701     helptext_info = NULL;
9702   }
9703
9704   if (fileExists(filename))
9705     helptext_info = loadSetupFileHash(filename);
9706
9707   if (helptext_info == NULL)
9708   {
9709     /* use reliable default values from static configuration */
9710     helptext_info = newSetupFileHash();
9711
9712     for (i = 0; helptext_config[i].token; i++)
9713       setHashEntry(helptext_info,
9714                    helptext_config[i].token,
9715                    helptext_config[i].value);
9716   }
9717
9718 #if 0
9719   BEGIN_HASH_ITERATION(helptext_info, itr)
9720   {
9721     printf("::: '%s' => '%s'\n",
9722            HASH_ITERATION_TOKEN(itr), HASH_ITERATION_VALUE(itr));
9723   }
9724   END_HASH_ITERATION(hash, itr)
9725 #endif
9726 }
9727
9728
9729 /* ------------------------------------------------------------------------- */
9730 /* convert levels                                                            */
9731 /* ------------------------------------------------------------------------- */
9732
9733 #define MAX_NUM_CONVERT_LEVELS          1000
9734
9735 void ConvertLevels()
9736 {
9737   static LevelDirTree *convert_leveldir = NULL;
9738   static int convert_level_nr = -1;
9739   static int num_levels_handled = 0;
9740   static int num_levels_converted = 0;
9741   static boolean levels_failed[MAX_NUM_CONVERT_LEVELS];
9742   int i;
9743
9744   convert_leveldir = getTreeInfoFromIdentifier(leveldir_first,
9745                                                global.convert_leveldir);
9746
9747   if (convert_leveldir == NULL)
9748     Error(ERR_EXIT, "no such level identifier: '%s'",
9749           global.convert_leveldir);
9750
9751   leveldir_current = convert_leveldir;
9752
9753   if (global.convert_level_nr != -1)
9754   {
9755     convert_leveldir->first_level = global.convert_level_nr;
9756     convert_leveldir->last_level  = global.convert_level_nr;
9757   }
9758
9759   convert_level_nr = convert_leveldir->first_level;
9760
9761   printf_line("=", 79);
9762   printf("Converting levels\n");
9763   printf_line("-", 79);
9764   printf("Level series identifier: '%s'\n", convert_leveldir->identifier);
9765   printf("Level series name:       '%s'\n", convert_leveldir->name);
9766   printf("Level series author:     '%s'\n", convert_leveldir->author);
9767   printf("Number of levels:        %d\n",   convert_leveldir->levels);
9768   printf_line("=", 79);
9769   printf("\n");
9770
9771   for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++)
9772     levels_failed[i] = FALSE;
9773
9774   while (convert_level_nr <= convert_leveldir->last_level)
9775   {
9776     char *level_filename;
9777     boolean new_level;
9778
9779     level_nr = convert_level_nr++;
9780
9781     printf("Level %03d: ", level_nr);
9782
9783     LoadLevel(level_nr);
9784     if (level.no_valid_file)
9785     {
9786       printf("(no level)\n");
9787       continue;
9788     }
9789
9790     printf("converting level ... ");
9791
9792     level_filename = getDefaultLevelFilename(level_nr);
9793     new_level = !fileExists(level_filename);
9794
9795     if (new_level)
9796     {
9797       SaveLevel(level_nr);
9798
9799       num_levels_converted++;
9800
9801       printf("converted.\n");
9802     }
9803     else
9804     {
9805       if (level_nr >= 0 && level_nr < MAX_NUM_CONVERT_LEVELS)
9806         levels_failed[level_nr] = TRUE;
9807
9808       printf("NOT CONVERTED -- LEVEL ALREADY EXISTS.\n");
9809     }
9810
9811     num_levels_handled++;
9812   }
9813
9814   printf("\n");
9815   printf_line("=", 79);
9816   printf("Number of levels handled: %d\n", num_levels_handled);
9817   printf("Number of levels converted: %d (%d%%)\n", num_levels_converted,
9818          (num_levels_handled ?
9819           num_levels_converted * 100 / num_levels_handled : 0));
9820   printf_line("-", 79);
9821   printf("Summary (for automatic parsing by scripts):\n");
9822   printf("LEVELDIR '%s', CONVERTED %d/%d (%d%%)",
9823          convert_leveldir->identifier, num_levels_converted,
9824          num_levels_handled,
9825          (num_levels_handled ?
9826           num_levels_converted * 100 / num_levels_handled : 0));
9827
9828   if (num_levels_handled != num_levels_converted)
9829   {
9830     printf(", FAILED:");
9831     for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++)
9832       if (levels_failed[i])
9833         printf(" %03d", i);
9834   }
9835
9836   printf("\n");
9837   printf_line("=", 79);
9838
9839   CloseAllAndExit(0);
9840 }
9841
9842
9843 /* ------------------------------------------------------------------------- */
9844 /* create and save images for use in level sketches (raw BMP format)         */
9845 /* ------------------------------------------------------------------------- */
9846
9847 void CreateLevelSketchImages()
9848 {
9849 #if defined(TARGET_SDL)
9850   Bitmap *bitmap1;
9851   Bitmap *bitmap2;
9852   int i;
9853
9854   bitmap1 = CreateBitmap(TILEX, TILEY, DEFAULT_DEPTH);
9855   bitmap2 = CreateBitmap(MINI_TILEX, MINI_TILEY, DEFAULT_DEPTH);
9856
9857   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9858   {
9859     Bitmap *src_bitmap;
9860     int src_x, src_y;
9861     int graphic = el2edimg(i);
9862     char basename1[16];
9863     char basename2[16];
9864     char *filename1;
9865     char *filename2;
9866
9867     sprintf(basename1, "%03d.bmp", i);
9868     sprintf(basename2, "%03ds.bmp", i);
9869
9870     filename1 = getPath2(global.create_images_dir, basename1);
9871     filename2 = getPath2(global.create_images_dir, basename2);
9872
9873     getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
9874     BlitBitmap(src_bitmap, bitmap1, src_x, src_y, TILEX, TILEY, 0, 0);
9875
9876     if (SDL_SaveBMP(bitmap1->surface, filename1) != 0)
9877       Error(ERR_EXIT, "cannot save level sketch image file '%s'", filename1);
9878
9879     getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
9880     BlitBitmap(src_bitmap, bitmap2, src_x, src_y, MINI_TILEX, MINI_TILEY, 0, 0);
9881
9882     if (SDL_SaveBMP(bitmap2->surface, filename2) != 0)
9883       Error(ERR_EXIT, "cannot save level sketch image file '%s'", filename2);
9884
9885     free(filename1);
9886     free(filename2);
9887
9888     if (options.debug)
9889       printf("%03d `%03d%c", i, i, (i % 10 < 9 ? ' ' : '\n'));
9890   }
9891
9892   FreeBitmap(bitmap1);
9893   FreeBitmap(bitmap2);
9894
9895   if (options.debug)
9896     printf("\n");
9897
9898   Error(ERR_INFO, "%d normal and small images created", NUM_FILE_ELEMENTS);
9899
9900   CloseAllAndExit(0);
9901 #endif
9902 }
9903
9904
9905 /* ------------------------------------------------------------------------- */
9906 /* create and save images for custom and group elements (raw BMP format)     */
9907 /* ------------------------------------------------------------------------- */
9908
9909 void CreateCustomElementImages()
9910 {
9911 #if defined(TARGET_SDL)
9912   char *filename = "graphics.classic/RocksCE.bmp";
9913   Bitmap *bitmap;
9914   Bitmap *src_bitmap;
9915   int dummy_graphic = IMG_CUSTOM_99;
9916   int yoffset_ce = 0;
9917   int yoffset_ge = (TILEY * NUM_CUSTOM_ELEMENTS / 16);
9918   int src_x, src_y;
9919   int i;
9920
9921   bitmap = CreateBitmap(TILEX * 16 * 2,
9922                         TILEY * (NUM_CUSTOM_ELEMENTS + NUM_GROUP_ELEMENTS) / 16,
9923                         DEFAULT_DEPTH);
9924
9925   getGraphicSource(dummy_graphic, 0, &src_bitmap, &src_x, &src_y);
9926
9927   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
9928   {
9929     int x = i % 16;
9930     int y = i / 16;
9931     int ii = i + 1;
9932     int j;
9933
9934     BlitBitmap(src_bitmap, bitmap, 0, 0, TILEX, TILEY,
9935                TILEX * x, TILEY * y + yoffset_ce);
9936
9937     BlitBitmap(src_bitmap, bitmap, 0, TILEY, TILEX, TILEY,
9938                TILEX * x + TILEX * 16, TILEY * y + yoffset_ce);
9939
9940     for (j = 2; j >= 0; j--)
9941     {
9942       int c = ii % 10;
9943
9944       BlitBitmap(src_bitmap, bitmap, TILEX + c * 7, 0, 6, 10,
9945                  TILEX * x + 6 + j * 7,
9946                  TILEY * y + 11 + yoffset_ce);
9947
9948       BlitBitmap(src_bitmap, bitmap, TILEX + c * 8, TILEY, 6, 10,
9949                  TILEX * 16 + TILEX * x + 6 + j * 8,
9950                  TILEY * y + 10 + yoffset_ce);
9951
9952       ii /= 10;
9953     }
9954   }
9955
9956   for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
9957   {
9958     int x = i % 16;
9959     int y = i / 16;
9960     int ii = i + 1;
9961     int j;
9962
9963     BlitBitmap(src_bitmap, bitmap, 0, 0, TILEX, TILEY,
9964                TILEX * x, TILEY * y + yoffset_ge);
9965
9966     BlitBitmap(src_bitmap, bitmap, 0, TILEY, TILEX, TILEY,
9967                TILEX * x + TILEX * 16, TILEY * y + yoffset_ge);
9968
9969     for (j = 1; j >= 0; j--)
9970     {
9971       int c = ii % 10;
9972
9973       BlitBitmap(src_bitmap, bitmap, TILEX + c * 10, 11, 10, 10,
9974                  TILEX * x + 6 + j * 10,
9975                  TILEY * y + 11 + yoffset_ge);
9976
9977       BlitBitmap(src_bitmap, bitmap, TILEX + c * 8, TILEY + 12, 6, 10,
9978                  TILEX * 16 + TILEX * x + 10 + j * 8,
9979                  TILEY * y + 10 + yoffset_ge);
9980
9981       ii /= 10;
9982     }
9983   }
9984
9985   if (SDL_SaveBMP(bitmap->surface, filename) != 0)
9986     Error(ERR_EXIT, "cannot save CE graphics file '%s'", filename);
9987
9988   FreeBitmap(bitmap);
9989
9990   CloseAllAndExit(0);
9991 #endif
9992 }
9993
9994 #if 0
9995 void CreateLevelSketchImages_TEST()
9996 {
9997   void CreateCustomElementImages()
9998 }
9999 #endif