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