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