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