rnd-20071029-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.initial_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 (strSuffix(basename, ".dc") ||
1698       strSuffix(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->initial_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->initial_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 (!strPrefix(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 (strPrefix(magic_bytes, "DC2Win95") ||
5781         strPrefix(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->initial_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->initial_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_SWITCH3,&si.override_level_graphics, "override_level_graphics" },
8143   { TYPE_SWITCH3,&si.override_level_sounds,   "override_level_sounds"   },
8144   { TYPE_SWITCH3,&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->scroll_delay = TRUE;
8274   si->scroll_delay_value = STD_SCROLL_DELAY;
8275   si->soft_scrolling = TRUE;
8276   si->fade_screens = TRUE;
8277   si->autorecord = TRUE;
8278   si->show_titlescreen = TRUE;
8279   si->quick_doors = FALSE;
8280   si->team_mode = FALSE;
8281   si->handicap = TRUE;
8282   si->skip_levels = TRUE;
8283   si->time_limit = TRUE;
8284   si->fullscreen = FALSE;
8285   si->fullscreen_mode = getStringCopy(DEFAULT_FULLSCREEN_MODE);
8286   si->ask_on_escape = TRUE;
8287   si->ask_on_escape_editor = TRUE;
8288   si->quick_switch = FALSE;
8289   si->input_on_focus = FALSE;
8290   si->prefer_aga_graphics = TRUE;
8291   si->game_frame_delay = GAME_FRAME_DELAY;
8292
8293   si->graphics_set = getStringCopy(GFX_DEFAULT_SUBDIR);
8294   si->sounds_set = getStringCopy(SND_DEFAULT_SUBDIR);
8295   si->music_set = getStringCopy(MUS_DEFAULT_SUBDIR);
8296   si->override_level_graphics = FALSE;
8297   si->override_level_sounds = FALSE;
8298   si->override_level_music = FALSE;
8299
8300   si->editor.el_boulderdash             = TRUE;
8301   si->editor.el_emerald_mine            = TRUE;
8302   si->editor.el_emerald_mine_club       = TRUE;
8303   si->editor.el_more                    = TRUE;
8304   si->editor.el_sokoban                 = TRUE;
8305   si->editor.el_supaplex                = TRUE;
8306   si->editor.el_diamond_caves           = TRUE;
8307   si->editor.el_dx_boulderdash          = TRUE;
8308   si->editor.el_chars                   = TRUE;
8309   si->editor.el_steel_chars             = TRUE;
8310   si->editor.el_custom                  = TRUE;
8311
8312   si->editor.el_headlines = TRUE;
8313   si->editor.el_user_defined = FALSE;
8314   si->editor.el_dynamic = TRUE;
8315
8316   si->editor.show_element_token = FALSE;
8317
8318   si->shortcut.save_game        = DEFAULT_KEY_SAVE_GAME;
8319   si->shortcut.load_game        = DEFAULT_KEY_LOAD_GAME;
8320   si->shortcut.toggle_pause     = DEFAULT_KEY_TOGGLE_PAUSE;
8321
8322   si->shortcut.focus_player[0]  = DEFAULT_KEY_FOCUS_PLAYER_1;
8323   si->shortcut.focus_player[1]  = DEFAULT_KEY_FOCUS_PLAYER_2;
8324   si->shortcut.focus_player[2]  = DEFAULT_KEY_FOCUS_PLAYER_3;
8325   si->shortcut.focus_player[3]  = DEFAULT_KEY_FOCUS_PLAYER_4;
8326   si->shortcut.focus_player_all = DEFAULT_KEY_FOCUS_PLAYER_ALL;
8327
8328   for (i = 0; i < MAX_PLAYERS; i++)
8329   {
8330     si->input[i].use_joystick = FALSE;
8331     si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
8332     si->input[i].joy.xleft   = JOYSTICK_XLEFT;
8333     si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
8334     si->input[i].joy.xright  = JOYSTICK_XRIGHT;
8335     si->input[i].joy.yupper  = JOYSTICK_YUPPER;
8336     si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
8337     si->input[i].joy.ylower  = JOYSTICK_YLOWER;
8338     si->input[i].joy.snap  = (i == 0 ? JOY_BUTTON_1 : 0);
8339     si->input[i].joy.drop  = (i == 0 ? JOY_BUTTON_2 : 0);
8340     si->input[i].key.left  = (i == 0 ? DEFAULT_KEY_LEFT  : KSYM_UNDEFINED);
8341     si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
8342     si->input[i].key.up    = (i == 0 ? DEFAULT_KEY_UP    : KSYM_UNDEFINED);
8343     si->input[i].key.down  = (i == 0 ? DEFAULT_KEY_DOWN  : KSYM_UNDEFINED);
8344     si->input[i].key.snap  = (i == 0 ? DEFAULT_KEY_SNAP  : KSYM_UNDEFINED);
8345     si->input[i].key.drop  = (i == 0 ? DEFAULT_KEY_DROP  : KSYM_UNDEFINED);
8346   }
8347
8348   si->system.sdl_videodriver = getStringCopy(ARG_DEFAULT);
8349   si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT);
8350   si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
8351
8352   si->options.verbose = FALSE;
8353
8354 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
8355   si->handicap = FALSE;
8356   si->fullscreen = TRUE;
8357   si->override_level_graphics = AUTO;
8358   si->override_level_sounds = AUTO;
8359   si->override_level_music = AUTO;
8360 #endif
8361 }
8362
8363 static void setSetupInfoToDefaults_EditorCascade(struct SetupInfo *si)
8364 {
8365   si->editor_cascade.el_bd              = TRUE;
8366   si->editor_cascade.el_em              = TRUE;
8367   si->editor_cascade.el_emc             = TRUE;
8368   si->editor_cascade.el_rnd             = TRUE;
8369   si->editor_cascade.el_sb              = TRUE;
8370   si->editor_cascade.el_sp              = TRUE;
8371   si->editor_cascade.el_dc              = TRUE;
8372   si->editor_cascade.el_dx              = TRUE;
8373
8374   si->editor_cascade.el_chars           = FALSE;
8375   si->editor_cascade.el_steel_chars     = FALSE;
8376   si->editor_cascade.el_ce              = FALSE;
8377   si->editor_cascade.el_ge              = FALSE;
8378   si->editor_cascade.el_ref             = FALSE;
8379   si->editor_cascade.el_user            = FALSE;
8380   si->editor_cascade.el_dynamic         = FALSE;
8381 }
8382
8383 static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
8384 {
8385   int i, pnr;
8386
8387   if (!setup_file_hash)
8388     return;
8389
8390   /* global setup */
8391   si = setup;
8392   for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
8393     setSetupInfo(global_setup_tokens, i,
8394                  getHashEntry(setup_file_hash, global_setup_tokens[i].text));
8395   setup = si;
8396
8397   /* editor setup */
8398   sei = setup.editor;
8399   for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
8400     setSetupInfo(editor_setup_tokens, i,
8401                  getHashEntry(setup_file_hash,editor_setup_tokens[i].text));
8402   setup.editor = sei;
8403
8404   /* shortcut setup */
8405   ssi = setup.shortcut;
8406   for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
8407     setSetupInfo(shortcut_setup_tokens, i,
8408                  getHashEntry(setup_file_hash,shortcut_setup_tokens[i].text));
8409   setup.shortcut = ssi;
8410
8411   /* player setup */
8412   for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
8413   {
8414     char prefix[30];
8415
8416     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
8417
8418     sii = setup.input[pnr];
8419     for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
8420     {
8421       char full_token[100];
8422
8423       sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
8424       setSetupInfo(player_setup_tokens, i,
8425                    getHashEntry(setup_file_hash, full_token));
8426     }
8427     setup.input[pnr] = sii;
8428   }
8429
8430   /* system setup */
8431   syi = setup.system;
8432   for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
8433     setSetupInfo(system_setup_tokens, i,
8434                  getHashEntry(setup_file_hash, system_setup_tokens[i].text));
8435   setup.system = syi;
8436
8437   /* options setup */
8438   soi = setup.options;
8439   for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
8440     setSetupInfo(options_setup_tokens, i,
8441                  getHashEntry(setup_file_hash, options_setup_tokens[i].text));
8442   setup.options = soi;
8443 }
8444
8445 static void decodeSetupFileHash_EditorCascade(SetupFileHash *setup_file_hash)
8446 {
8447   int i;
8448
8449   if (!setup_file_hash)
8450     return;
8451
8452   /* editor cascade setup */
8453   seci = setup.editor_cascade;
8454   for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
8455     setSetupInfo(editor_cascade_setup_tokens, i,
8456                  getHashEntry(setup_file_hash,
8457                               editor_cascade_setup_tokens[i].text));
8458   setup.editor_cascade = seci;
8459 }
8460
8461 void LoadSetup()
8462 {
8463   char *filename = getSetupFilename();
8464   SetupFileHash *setup_file_hash = NULL;
8465
8466   /* always start with reliable default values */
8467   setSetupInfoToDefaults(&setup);
8468
8469   setup_file_hash = loadSetupFileHash(filename);
8470
8471   if (setup_file_hash)
8472   {
8473     char *player_name_new;
8474
8475     checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP"));
8476     decodeSetupFileHash(setup_file_hash);
8477
8478     freeSetupFileHash(setup_file_hash);
8479
8480     /* needed to work around problems with fixed length strings */
8481     player_name_new = get_corrected_login_name(setup.player_name);
8482     free(setup.player_name);
8483     setup.player_name = player_name_new;
8484
8485     /* "scroll_delay: on(3) / off(0)" was replaced by scroll delay value */
8486     if (setup.scroll_delay == FALSE)
8487     {
8488       setup.scroll_delay_value = MIN_SCROLL_DELAY;
8489       setup.scroll_delay = TRUE;                        /* now always "on" */
8490     }
8491
8492     /* make sure that scroll delay value stays inside valid range */
8493     setup.scroll_delay_value =
8494       MIN(MAX(MIN_SCROLL_DELAY, setup.scroll_delay_value), MAX_SCROLL_DELAY);
8495   }
8496   else
8497     Error(ERR_WARN, "using default setup values");
8498 }
8499
8500 void LoadSetup_EditorCascade()
8501 {
8502   char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
8503   SetupFileHash *setup_file_hash = NULL;
8504
8505   /* always start with reliable default values */
8506   setSetupInfoToDefaults_EditorCascade(&setup);
8507
8508   setup_file_hash = loadSetupFileHash(filename);
8509
8510   if (setup_file_hash)
8511   {
8512     checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP"));
8513     decodeSetupFileHash_EditorCascade(setup_file_hash);
8514
8515     freeSetupFileHash(setup_file_hash);
8516   }
8517
8518   free(filename);
8519 }
8520
8521 void SaveSetup()
8522 {
8523   char *filename = getSetupFilename();
8524   FILE *file;
8525   int i, pnr;
8526
8527   InitUserDataDirectory();
8528
8529   if (!(file = fopen(filename, MODE_WRITE)))
8530   {
8531     Error(ERR_WARN, "cannot write setup file '%s'", filename);
8532     return;
8533   }
8534
8535   fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
8536                                                getCookie("SETUP")));
8537   fprintf(file, "\n");
8538
8539   /* global setup */
8540   si = setup;
8541   for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
8542   {
8543     /* just to make things nicer :) */
8544     if (i == SETUP_TOKEN_PLAYER_NAME + 1 ||
8545         i == SETUP_TOKEN_GRAPHICS_SET)
8546       fprintf(file, "\n");
8547
8548     fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
8549   }
8550
8551   /* editor setup */
8552   sei = setup.editor;
8553   fprintf(file, "\n");
8554   for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
8555     fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i));
8556
8557   /* shortcut setup */
8558   ssi = setup.shortcut;
8559   fprintf(file, "\n");
8560   for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
8561     fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
8562
8563   /* player setup */
8564   for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
8565   {
8566     char prefix[30];
8567
8568     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
8569     fprintf(file, "\n");
8570
8571     sii = setup.input[pnr];
8572     for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
8573       fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
8574   }
8575
8576   /* system setup */
8577   syi = setup.system;
8578   fprintf(file, "\n");
8579   for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
8580     fprintf(file, "%s\n", getSetupLine(system_setup_tokens, "", i));
8581
8582   /* options setup */
8583   soi = setup.options;
8584   fprintf(file, "\n");
8585   for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
8586     fprintf(file, "%s\n", getSetupLine(options_setup_tokens, "", i));
8587
8588   fclose(file);
8589
8590   SetFilePermissions(filename, PERMS_PRIVATE);
8591 }
8592
8593 void SaveSetup_EditorCascade()
8594 {
8595   char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
8596   FILE *file;
8597   int i;
8598
8599   InitUserDataDirectory();
8600
8601   if (!(file = fopen(filename, MODE_WRITE)))
8602   {
8603     Error(ERR_WARN, "cannot write editor cascade state file '%s'", filename);
8604     free(filename);
8605     return;
8606   }
8607
8608   fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
8609                                                getCookie("SETUP")));
8610   fprintf(file, "\n");
8611
8612   seci = setup.editor_cascade;
8613   fprintf(file, "\n");
8614   for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
8615     fprintf(file, "%s\n", getSetupLine(editor_cascade_setup_tokens, "", i));
8616
8617   fclose(file);
8618
8619   SetFilePermissions(filename, PERMS_PRIVATE);
8620
8621   free(filename);
8622 }
8623
8624 void LoadCustomElementDescriptions()
8625 {
8626   char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
8627   SetupFileHash *setup_file_hash;
8628   int i;
8629
8630   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
8631   {
8632     if (element_info[i].custom_description != NULL)
8633     {
8634       free(element_info[i].custom_description);
8635       element_info[i].custom_description = NULL;
8636     }
8637   }
8638
8639   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
8640     return;
8641
8642   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
8643   {
8644     char *token = getStringCat2(element_info[i].token_name, ".name");
8645     char *value = getHashEntry(setup_file_hash, token);
8646
8647     if (value != NULL)
8648       element_info[i].custom_description = getStringCopy(value);
8649
8650     free(token);
8651   }
8652
8653   freeSetupFileHash(setup_file_hash);
8654 }
8655
8656 static int getElementFromToken(char *token)
8657 {
8658 #if 1
8659   char *value = getHashEntry(element_token_hash, token);
8660
8661   if (value != NULL)
8662     return atoi(value);
8663 #else
8664   int i;
8665
8666   /* !!! OPTIMIZE THIS BY USING HASH !!! */
8667   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
8668     if (strEqual(token, element_info[i].token_name))
8669       return i;
8670 #endif
8671
8672   Error(ERR_WARN, "unknown element token '%s'", token);
8673
8674   return EL_UNDEFINED;
8675 }
8676
8677 static int get_token_parameter_value(char *token, char *value_raw)
8678 {
8679   char *suffix;
8680
8681   if (token == NULL || value_raw == NULL)
8682     return ARG_UNDEFINED_VALUE;
8683
8684   suffix = strrchr(token, '.');
8685   if (suffix == NULL)
8686     suffix = token;
8687
8688 #if 1
8689   if (strEqual(suffix, ".element"))
8690     return getElementFromToken(value_raw);
8691 #endif
8692
8693 #if 0
8694   if (strncmp(suffix, ".font", 5) == 0)
8695   {
8696     int i;
8697
8698     /* !!! OPTIMIZE THIS BY USING HASH !!! */
8699     for (i = 0; i < NUM_FONTS; i++)
8700       if (strEqual(value_raw, font_info[i].token_name))
8701         return i;
8702
8703     /* if font not found, use reliable default value */
8704     return FONT_INITIAL_1;
8705   }
8706 #endif
8707
8708   /* !!! USE CORRECT VALUE TYPE (currently works also for TYPE_BOOLEAN) !!! */
8709   return get_parameter_value(value_raw, suffix, TYPE_INTEGER);
8710 }
8711
8712 void InitMenuDesignSettings_Static()
8713 {
8714 #if 0
8715   static SetupFileHash *image_config_hash = NULL;
8716 #endif
8717   int i;
8718
8719 #if 0
8720   if (image_config_hash == NULL)
8721   {
8722     image_config_hash = newSetupFileHash();
8723
8724     for (i = 0; image_config[i].token != NULL; i++)
8725       setHashEntry(image_config_hash,
8726                    image_config[i].token,
8727                    image_config[i].value);
8728   }
8729 #endif
8730
8731 #if 1
8732   /* always start with reliable default values from static default config */
8733   for (i = 0; image_config_vars[i].token != NULL; i++)
8734   {
8735     char *value = getHashEntry(image_config_hash, image_config_vars[i].token);
8736
8737     if (value != NULL)
8738       *image_config_vars[i].value =
8739         get_token_parameter_value(image_config_vars[i].token, value);
8740   }
8741
8742 #else
8743
8744   int j;
8745
8746   /* always start with reliable default values from static default config */
8747   for (i = 0; image_config_vars[i].token != NULL; i++)
8748     for (j = 0; image_config[j].token != NULL; j++)
8749       if (strEqual(image_config_vars[i].token, image_config[j].token))
8750         *image_config_vars[i].value =
8751           get_token_parameter_value(image_config_vars[i].token,
8752                                     image_config[j].value);
8753 #endif
8754 }
8755
8756 static void InitMenuDesignSettings_SpecialPreProcessing()
8757 {
8758   int i;
8759
8760   /* the following initializes hierarchical values from static configuration */
8761
8762   /* special case: initialize "ARG_DEFAULT" values in static default config */
8763   /* (e.g., initialize "[titlemessage].fade_mode" from "[title].fade_mode") */
8764   titlemessage_initial_default.fade_mode  = title_initial_default.fade_mode;
8765   titlemessage_initial_default.fade_delay = title_initial_default.fade_delay;
8766   titlemessage_initial_default.post_delay = title_initial_default.post_delay;
8767   titlemessage_initial_default.auto_delay = title_initial_default.auto_delay;
8768   titlemessage_default.fade_mode  = title_default.fade_mode;
8769   titlemessage_default.fade_delay = title_default.fade_delay;
8770   titlemessage_default.post_delay = title_default.post_delay;
8771   titlemessage_default.auto_delay = title_default.auto_delay;
8772
8773   /* special case: initialize "ARG_DEFAULT" values in static default config */
8774   /* (e.g., init "titlemessage_1.fade_mode" from "[titlemessage].fade_mode") */
8775   for (i = 0; i < MAX_NUM_TITLE_MESSAGES; i++)
8776   {
8777     titlemessage_initial[i] = titlemessage_initial_default;
8778     titlemessage[i] = titlemessage_default;
8779   }
8780
8781   /* special case: initialize "ARG_DEFAULT" values in static default config */
8782   /* (eg, init "menu.enter_screen.SCORES.xyz" from "menu.enter_screen.xyz") */
8783   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
8784   {
8785     menu.enter_screen[i] = menu.enter_screen[GFX_SPECIAL_ARG_DEFAULT];
8786     menu.leave_screen[i] = menu.leave_screen[GFX_SPECIAL_ARG_DEFAULT];
8787   }
8788 }
8789
8790 static void InitMenuDesignSettings_SpecialPostProcessing()
8791 {
8792   /* special case: initialize later added SETUP list size from LEVELS value */
8793   if (menu.list_size[GAME_MODE_SETUP] == -1)
8794     menu.list_size[GAME_MODE_SETUP] = menu.list_size[GAME_MODE_LEVELS];
8795 }
8796
8797 static void LoadMenuDesignSettingsFromFilename(char *filename)
8798 {
8799   static struct TitleMessageInfo tmi;
8800   static struct TokenInfo titlemessage_tokens[] =
8801   {
8802     { TYPE_INTEGER,     &tmi.x,                 ".x"                    },
8803     { TYPE_INTEGER,     &tmi.y,                 ".y"                    },
8804     { TYPE_INTEGER,     &tmi.width,             ".width"                },
8805     { TYPE_INTEGER,     &tmi.height,            ".height"               },
8806     { TYPE_INTEGER,     &tmi.chars,             ".chars"                },
8807     { TYPE_INTEGER,     &tmi.lines,             ".lines"                },
8808     { TYPE_INTEGER,     &tmi.align,             ".align"                },
8809     { TYPE_INTEGER,     &tmi.valign,            ".valign"               },
8810     { TYPE_INTEGER,     &tmi.font,              ".font"                 },
8811     { TYPE_BOOLEAN,     &tmi.autowrap,          ".autowrap"             },
8812     { TYPE_BOOLEAN,     &tmi.centered,          ".centered"             },
8813     { TYPE_BOOLEAN,     &tmi.parse_comments,    ".parse_comments"       },
8814     { TYPE_INTEGER,     &tmi.sort_priority,     ".sort_priority"        },
8815     { TYPE_INTEGER,     &tmi.fade_mode,         ".fade_mode"            },
8816     { TYPE_INTEGER,     &tmi.fade_delay,        ".fade_delay"           },
8817     { TYPE_INTEGER,     &tmi.post_delay,        ".post_delay"           },
8818     { TYPE_INTEGER,     &tmi.auto_delay,        ".auto_delay"           },
8819
8820     { -1,               NULL,                   NULL                    }
8821   };
8822   static struct
8823   {
8824     struct TitleMessageInfo *array;
8825     char *text;
8826   }
8827   titlemessage_arrays[] =
8828   {
8829     { titlemessage_initial,             "[titlemessage_initial]"        },
8830     { titlemessage,                     "[titlemessage]"                },
8831
8832     { NULL,                             NULL                            }
8833   };
8834   SetupFileHash *setup_file_hash;
8835   int i, j, k;
8836
8837 #if 0
8838   printf("LoadMenuDesignSettings from file '%s' ...\n", filename);
8839 #endif
8840
8841   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
8842     return;
8843
8844   /* the following initializes hierarchical values from dynamic configuration */
8845
8846   /* special case: initialize with default values that may be overwritten */
8847   /* (e.g., init "menu.draw_xoffset.INFO" from "menu.draw_xoffset") */
8848   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
8849   {
8850     char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset");
8851     char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset");
8852     char *value_3 = getHashEntry(setup_file_hash, "menu.list_size");
8853
8854     if (value_1 != NULL)
8855       menu.draw_xoffset[i] = get_integer_from_string(value_1);
8856     if (value_2 != NULL)
8857       menu.draw_yoffset[i] = get_integer_from_string(value_2);
8858     if (value_3 != NULL)
8859       menu.list_size[i] = get_integer_from_string(value_3);
8860   }
8861
8862   /* special case: initialize with default values that may be overwritten */
8863   /* (eg, init "menu.draw_xoffset.INFO[XXX]" from "menu.draw_xoffset.INFO") */
8864   for (i = 0; i < NUM_SPECIAL_GFX_INFO_ARGS; i++)
8865   {
8866     char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset.INFO");
8867     char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset.INFO");
8868
8869     if (value_1 != NULL)
8870       menu.draw_xoffset_info[i] = get_integer_from_string(value_1);
8871     if (value_2 != NULL)
8872       menu.draw_yoffset_info[i] = get_integer_from_string(value_2);
8873   }
8874
8875   /* special case: initialize with default values that may be overwritten */
8876   /* (eg, init "menu.draw_xoffset.SETUP[XXX]" from "menu.draw_xoffset.SETUP") */
8877   for (i = 0; i < NUM_SPECIAL_GFX_SETUP_ARGS; i++)
8878   {
8879     char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset.SETUP");
8880     char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset.SETUP");
8881
8882     if (value_1 != NULL)
8883       menu.draw_xoffset_setup[i] = get_integer_from_string(value_1);
8884     if (value_2 != NULL)
8885       menu.draw_yoffset_setup[i] = get_integer_from_string(value_2);
8886   }
8887
8888   /* special case: initialize with default values that may be overwritten */
8889   /* (eg, init "menu.enter_screen.SCORES.xyz" from "menu.enter_screen.xyz") */
8890   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
8891   {
8892     char *token_1 = "menu.enter_screen.fade_mode";
8893     char *token_2 = "menu.enter_screen.fade_delay";
8894     char *token_3 = "menu.enter_screen.post_delay";
8895     char *token_4 = "menu.leave_screen.fade_mode";
8896     char *token_5 = "menu.leave_screen.fade_delay";
8897     char *token_6 = "menu.leave_screen.post_delay";
8898     char *value_1 = getHashEntry(setup_file_hash, token_1);
8899     char *value_2 = getHashEntry(setup_file_hash, token_2);
8900     char *value_3 = getHashEntry(setup_file_hash, token_3);
8901     char *value_4 = getHashEntry(setup_file_hash, token_4);
8902     char *value_5 = getHashEntry(setup_file_hash, token_5);
8903     char *value_6 = getHashEntry(setup_file_hash, token_6);
8904
8905     if (value_1 != NULL)
8906       menu.enter_screen[i].fade_mode = get_token_parameter_value(token_1,
8907                                                                  value_1);
8908     if (value_2 != NULL)
8909       menu.enter_screen[i].fade_delay = get_token_parameter_value(token_2,
8910                                                                   value_2);
8911     if (value_3 != NULL)
8912       menu.enter_screen[i].post_delay = get_token_parameter_value(token_3,
8913                                                                   value_3);
8914     if (value_4 != NULL)
8915       menu.leave_screen[i].fade_mode = get_token_parameter_value(token_4,
8916                                                                  value_4);
8917     if (value_5 != NULL)
8918       menu.leave_screen[i].fade_delay = get_token_parameter_value(token_5,
8919                                                                   value_5);
8920     if (value_6 != NULL)
8921       menu.leave_screen[i].post_delay = get_token_parameter_value(token_6,
8922                                                                   value_6);
8923   }
8924
8925   /* special case: initialize with default values that may be overwritten */
8926   /* (e.g., init "titlemessage_1.fade_mode" from "[titlemessage].fade_mode") */
8927   for (i = 0; titlemessage_arrays[i].array != NULL; i++)
8928   {
8929     struct TitleMessageInfo *array = titlemessage_arrays[i].array;
8930     char *base_token = titlemessage_arrays[i].text;
8931
8932     for (j = 0; titlemessage_tokens[j].type != -1; j++)
8933     {
8934       char *token = getStringCat2(base_token, titlemessage_tokens[j].text);
8935       char *value = getHashEntry(setup_file_hash, token);
8936
8937       if (value != NULL)
8938       {
8939         int parameter_value = get_token_parameter_value(token, value);
8940
8941         for (k = 0; k < MAX_NUM_TITLE_MESSAGES; k++)
8942         {
8943           tmi = array[k];
8944
8945           if (titlemessage_tokens[j].type == TYPE_INTEGER)
8946             *(boolean *)titlemessage_tokens[j].value = (boolean)parameter_value;
8947           else
8948             *(int     *)titlemessage_tokens[j].value = (int)parameter_value;
8949
8950           array[k] = tmi;
8951         }
8952       }
8953
8954       free(token);
8955     }
8956   }
8957
8958   /* read (and overwrite with) values that may be specified in config file */
8959   for (i = 0; image_config_vars[i].token != NULL; i++)
8960   {
8961     char *value = getHashEntry(setup_file_hash, image_config_vars[i].token);
8962
8963     /* (ignore definitions set to "[DEFAULT]" which are already initialized) */
8964     if (value != NULL && !strEqual(value, ARG_DEFAULT))
8965       *image_config_vars[i].value =
8966         get_token_parameter_value(image_config_vars[i].token, value);
8967   }
8968
8969   freeSetupFileHash(setup_file_hash);
8970 }
8971
8972 void LoadMenuDesignSettings()
8973 {
8974   char *filename_base = UNDEFINED_FILENAME, *filename_local;
8975
8976   InitMenuDesignSettings_Static();
8977   InitMenuDesignSettings_SpecialPreProcessing();
8978
8979 #if 1
8980   if (!GFX_OVERRIDE_ARTWORK(ARTWORK_TYPE_GRAPHICS))
8981 #else
8982   if (!SETUP_OVERRIDE_ARTWORK(setup, ARTWORK_TYPE_GRAPHICS))
8983 #endif
8984   {
8985     /* first look for special settings configured in level series config */
8986     filename_base = getCustomArtworkLevelConfigFilename(ARTWORK_TYPE_GRAPHICS);
8987
8988     if (fileExists(filename_base))
8989       LoadMenuDesignSettingsFromFilename(filename_base);
8990   }
8991
8992   filename_local = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
8993
8994   if (filename_local != NULL && !strEqual(filename_base, filename_local))
8995     LoadMenuDesignSettingsFromFilename(filename_local);
8996
8997   InitMenuDesignSettings_SpecialPostProcessing();
8998 }
8999
9000 void LoadUserDefinedEditorElementList(int **elements, int *num_elements)
9001 {
9002   char *filename = getEditorSetupFilename();
9003   SetupFileList *setup_file_list, *list;
9004   SetupFileHash *element_hash;
9005   int num_unknown_tokens = 0;
9006   int i;
9007
9008   if ((setup_file_list = loadSetupFileList(filename)) == NULL)
9009     return;
9010
9011   element_hash = newSetupFileHash();
9012
9013   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9014     setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
9015
9016   /* determined size may be larger than needed (due to unknown elements) */
9017   *num_elements = 0;
9018   for (list = setup_file_list; list != NULL; list = list->next)
9019     (*num_elements)++;
9020
9021   /* add space for up to 3 more elements for padding that may be needed */
9022   *num_elements += 3;
9023
9024   /* free memory for old list of elements, if needed */
9025   checked_free(*elements);
9026
9027   /* allocate memory for new list of elements */
9028   *elements = checked_malloc(*num_elements * sizeof(int));
9029
9030   *num_elements = 0;
9031   for (list = setup_file_list; list != NULL; list = list->next)
9032   {
9033     char *value = getHashEntry(element_hash, list->token);
9034
9035     if (value == NULL)          /* try to find obsolete token mapping */
9036     {
9037       char *mapped_token = get_mapped_token(list->token);
9038
9039       if (mapped_token != NULL)
9040       {
9041         value = getHashEntry(element_hash, mapped_token);
9042
9043         free(mapped_token);
9044       }
9045     }
9046
9047     if (value != NULL)
9048     {
9049       (*elements)[(*num_elements)++] = atoi(value);
9050     }
9051     else
9052     {
9053       if (num_unknown_tokens == 0)
9054       {
9055         Error(ERR_INFO_LINE, "-");
9056         Error(ERR_INFO, "warning: unknown token(s) found in config file:");
9057         Error(ERR_INFO, "- config file: '%s'", filename);
9058
9059         num_unknown_tokens++;
9060       }
9061
9062       Error(ERR_INFO, "- token: '%s'", list->token);
9063     }
9064   }
9065
9066   if (num_unknown_tokens > 0)
9067     Error(ERR_INFO_LINE, "-");
9068
9069   while (*num_elements % 4)     /* pad with empty elements, if needed */
9070     (*elements)[(*num_elements)++] = EL_EMPTY;
9071
9072   freeSetupFileList(setup_file_list);
9073   freeSetupFileHash(element_hash);
9074
9075 #if 0
9076   for (i = 0; i < *num_elements; i++)
9077     printf("editor: element '%s' [%d]\n",
9078            element_info[(*elements)[i]].token_name, (*elements)[i]);
9079 #endif
9080 }
9081
9082 static struct MusicFileInfo *get_music_file_info_ext(char *basename, int music,
9083                                                      boolean is_sound)
9084 {
9085   SetupFileHash *setup_file_hash = NULL;
9086   struct MusicFileInfo tmp_music_file_info, *new_music_file_info;
9087   char *filename_music, *filename_prefix, *filename_info;
9088   struct
9089   {
9090     char *token;
9091     char **value_ptr;
9092   }
9093   token_to_value_ptr[] =
9094   {
9095     { "title_header",   &tmp_music_file_info.title_header       },
9096     { "artist_header",  &tmp_music_file_info.artist_header      },
9097     { "album_header",   &tmp_music_file_info.album_header       },
9098     { "year_header",    &tmp_music_file_info.year_header        },
9099
9100     { "title",          &tmp_music_file_info.title              },
9101     { "artist",         &tmp_music_file_info.artist             },
9102     { "album",          &tmp_music_file_info.album              },
9103     { "year",           &tmp_music_file_info.year               },
9104
9105     { NULL,             NULL                                    },
9106   };
9107   int i;
9108
9109   filename_music = (is_sound ? getCustomSoundFilename(basename) :
9110                     getCustomMusicFilename(basename));
9111
9112   if (filename_music == NULL)
9113     return NULL;
9114
9115   /* ---------- try to replace file extension ---------- */
9116
9117   filename_prefix = getStringCopy(filename_music);
9118   if (strrchr(filename_prefix, '.') != NULL)
9119     *strrchr(filename_prefix, '.') = '\0';
9120   filename_info = getStringCat2(filename_prefix, ".txt");
9121
9122 #if 0
9123   printf("trying to load file '%s'...\n", filename_info);
9124 #endif
9125
9126   if (fileExists(filename_info))
9127     setup_file_hash = loadSetupFileHash(filename_info);
9128
9129   free(filename_prefix);
9130   free(filename_info);
9131
9132   if (setup_file_hash == NULL)
9133   {
9134     /* ---------- try to add file extension ---------- */
9135
9136     filename_prefix = getStringCopy(filename_music);
9137     filename_info = getStringCat2(filename_prefix, ".txt");
9138
9139 #if 0
9140     printf("trying to load file '%s'...\n", filename_info);
9141 #endif
9142
9143     if (fileExists(filename_info))
9144       setup_file_hash = loadSetupFileHash(filename_info);
9145
9146     free(filename_prefix);
9147     free(filename_info);
9148   }
9149
9150   if (setup_file_hash == NULL)
9151     return NULL;
9152
9153   /* ---------- music file info found ---------- */
9154
9155   clear_mem(&tmp_music_file_info, sizeof(struct MusicFileInfo));
9156
9157   for (i = 0; token_to_value_ptr[i].token != NULL; i++)
9158   {
9159     char *value = getHashEntry(setup_file_hash, token_to_value_ptr[i].token);
9160
9161     *token_to_value_ptr[i].value_ptr =
9162       getStringCopy(value != NULL && *value != '\0' ? value : UNKNOWN_NAME);
9163   }
9164
9165   tmp_music_file_info.basename = getStringCopy(basename);
9166   tmp_music_file_info.music = music;
9167   tmp_music_file_info.is_sound = is_sound;
9168
9169   new_music_file_info = checked_malloc(sizeof(struct MusicFileInfo));
9170   *new_music_file_info = tmp_music_file_info;
9171
9172   return new_music_file_info;
9173 }
9174
9175 static struct MusicFileInfo *get_music_file_info(char *basename, int music)
9176 {
9177   return get_music_file_info_ext(basename, music, FALSE);
9178 }
9179
9180 static struct MusicFileInfo *get_sound_file_info(char *basename, int sound)
9181 {
9182   return get_music_file_info_ext(basename, sound, TRUE);
9183 }
9184
9185 static boolean music_info_listed_ext(struct MusicFileInfo *list,
9186                                      char *basename, boolean is_sound)
9187 {
9188   for (; list != NULL; list = list->next)
9189     if (list->is_sound == is_sound && strEqual(list->basename, basename))
9190       return TRUE;
9191
9192   return FALSE;
9193 }
9194
9195 static boolean music_info_listed(struct MusicFileInfo *list, char *basename)
9196 {
9197   return music_info_listed_ext(list, basename, FALSE);
9198 }
9199
9200 static boolean sound_info_listed(struct MusicFileInfo *list, char *basename)
9201 {
9202   return music_info_listed_ext(list, basename, TRUE);
9203 }
9204
9205 void LoadMusicInfo()
9206 {
9207   char *music_directory = getCustomMusicDirectory();
9208   int num_music = getMusicListSize();
9209   int num_music_noconf = 0;
9210   int num_sounds = getSoundListSize();
9211   DIR *dir;
9212   struct dirent *dir_entry;
9213   struct FileInfo *music, *sound;
9214   struct MusicFileInfo *next, **new;
9215   int i;
9216
9217   while (music_file_info != NULL)
9218   {
9219     next = music_file_info->next;
9220
9221     checked_free(music_file_info->basename);
9222
9223     checked_free(music_file_info->title_header);
9224     checked_free(music_file_info->artist_header);
9225     checked_free(music_file_info->album_header);
9226     checked_free(music_file_info->year_header);
9227
9228     checked_free(music_file_info->title);
9229     checked_free(music_file_info->artist);
9230     checked_free(music_file_info->album);
9231     checked_free(music_file_info->year);
9232
9233     free(music_file_info);
9234
9235     music_file_info = next;
9236   }
9237
9238   new = &music_file_info;
9239
9240   for (i = 0; i < num_music; i++)
9241   {
9242     music = getMusicListEntry(i);
9243
9244     if (music->filename == NULL)
9245       continue;
9246
9247     if (strEqual(music->filename, UNDEFINED_FILENAME))
9248       continue;
9249
9250     /* a configured file may be not recognized as music */
9251     if (!FileIsMusic(music->filename))
9252       continue;
9253
9254 #if 0
9255     printf("::: -> '%s' (configured)\n", music->filename);
9256 #endif
9257
9258     if (!music_info_listed(music_file_info, music->filename))
9259     {
9260       *new = get_music_file_info(music->filename, i);
9261       if (*new != NULL)
9262         new = &(*new)->next;
9263     }
9264   }
9265
9266   if ((dir = opendir(music_directory)) == NULL)
9267   {
9268     Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
9269     return;
9270   }
9271
9272   while ((dir_entry = readdir(dir)) != NULL)    /* loop until last dir entry */
9273   {
9274     char *basename = dir_entry->d_name;
9275     boolean music_already_used = FALSE;
9276     int i;
9277
9278     /* skip all music files that are configured in music config file */
9279     for (i = 0; i < num_music; i++)
9280     {
9281       music = getMusicListEntry(i);
9282
9283       if (music->filename == NULL)
9284         continue;
9285
9286       if (strEqual(basename, music->filename))
9287       {
9288         music_already_used = TRUE;
9289         break;
9290       }
9291     }
9292
9293     if (music_already_used)
9294       continue;
9295
9296     if (!FileIsMusic(basename))
9297       continue;
9298
9299 #if 0
9300     printf("::: -> '%s' (found in directory)\n", basename);
9301 #endif
9302
9303     if (!music_info_listed(music_file_info, basename))
9304     {
9305       *new = get_music_file_info(basename, MAP_NOCONF_MUSIC(num_music_noconf));
9306       if (*new != NULL)
9307         new = &(*new)->next;
9308     }
9309
9310     num_music_noconf++;
9311   }
9312
9313   closedir(dir);
9314
9315   for (i = 0; i < num_sounds; i++)
9316   {
9317     sound = getSoundListEntry(i);
9318
9319     if (sound->filename == NULL)
9320       continue;
9321
9322     if (strEqual(sound->filename, UNDEFINED_FILENAME))
9323       continue;
9324
9325     /* a configured file may be not recognized as sound */
9326     if (!FileIsSound(sound->filename))
9327       continue;
9328
9329 #if 0
9330     printf("::: -> '%s' (configured)\n", sound->filename);
9331 #endif
9332
9333     if (!sound_info_listed(music_file_info, sound->filename))
9334     {
9335       *new = get_sound_file_info(sound->filename, i);
9336       if (*new != NULL)
9337         new = &(*new)->next;
9338     }
9339   }
9340
9341 #if 0
9342   for (next = music_file_info; next != NULL; next = next->next)
9343     printf("::: title == '%s'\n", next->title);
9344 #endif
9345 }
9346
9347 void add_helpanim_entry(int element, int action, int direction, int delay,
9348                         int *num_list_entries)
9349 {
9350   struct HelpAnimInfo *new_list_entry;
9351   (*num_list_entries)++;
9352
9353   helpanim_info =
9354     checked_realloc(helpanim_info,
9355                     *num_list_entries * sizeof(struct HelpAnimInfo));
9356   new_list_entry = &helpanim_info[*num_list_entries - 1];
9357
9358   new_list_entry->element = element;
9359   new_list_entry->action = action;
9360   new_list_entry->direction = direction;
9361   new_list_entry->delay = delay;
9362 }
9363
9364 void print_unknown_token(char *filename, char *token, int token_nr)
9365 {
9366   if (token_nr == 0)
9367   {
9368     Error(ERR_INFO_LINE, "-");
9369     Error(ERR_INFO, "warning: unknown token(s) found in config file:");
9370     Error(ERR_INFO, "- config file: '%s'", filename);
9371   }
9372
9373   Error(ERR_INFO, "- token: '%s'", token);
9374 }
9375
9376 void print_unknown_token_end(int token_nr)
9377 {
9378   if (token_nr > 0)
9379     Error(ERR_INFO_LINE, "-");
9380 }
9381
9382 void LoadHelpAnimInfo()
9383 {
9384   char *filename = getHelpAnimFilename();
9385   SetupFileList *setup_file_list = NULL, *list;
9386   SetupFileHash *element_hash, *action_hash, *direction_hash;
9387   int num_list_entries = 0;
9388   int num_unknown_tokens = 0;
9389   int i;
9390
9391   if (fileExists(filename))
9392     setup_file_list = loadSetupFileList(filename);
9393
9394   if (setup_file_list == NULL)
9395   {
9396     /* use reliable default values from static configuration */
9397     SetupFileList *insert_ptr;
9398
9399     insert_ptr = setup_file_list =
9400       newSetupFileList(helpanim_config[0].token,
9401                        helpanim_config[0].value);
9402
9403     for (i = 1; helpanim_config[i].token; i++)
9404       insert_ptr = addListEntry(insert_ptr,
9405                                 helpanim_config[i].token,
9406                                 helpanim_config[i].value);
9407   }
9408
9409   element_hash   = newSetupFileHash();
9410   action_hash    = newSetupFileHash();
9411   direction_hash = newSetupFileHash();
9412
9413   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
9414     setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
9415
9416   for (i = 0; i < NUM_ACTIONS; i++)
9417     setHashEntry(action_hash, element_action_info[i].suffix,
9418                  i_to_a(element_action_info[i].value));
9419
9420   /* do not store direction index (bit) here, but direction value! */
9421   for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
9422     setHashEntry(direction_hash, element_direction_info[i].suffix,
9423                  i_to_a(1 << element_direction_info[i].value));
9424
9425   for (list = setup_file_list; list != NULL; list = list->next)
9426   {
9427     char *element_token, *action_token, *direction_token;
9428     char *element_value, *action_value, *direction_value;
9429     int delay = atoi(list->value);
9430
9431     if (strEqual(list->token, "end"))
9432     {
9433       add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
9434
9435       continue;
9436     }
9437
9438     /* first try to break element into element/action/direction parts;
9439        if this does not work, also accept combined "element[.act][.dir]"
9440        elements (like "dynamite.active"), which are unique elements */
9441
9442     if (strchr(list->token, '.') == NULL)       /* token contains no '.' */
9443     {
9444       element_value = getHashEntry(element_hash, list->token);
9445       if (element_value != NULL)        /* element found */
9446         add_helpanim_entry(atoi(element_value), -1, -1, delay,
9447                            &num_list_entries);
9448       else
9449       {
9450         /* no further suffixes found -- this is not an element */
9451         print_unknown_token(filename, list->token, num_unknown_tokens++);
9452       }
9453
9454       continue;
9455     }
9456
9457     /* token has format "<prefix>.<something>" */
9458
9459     action_token = strchr(list->token, '.');    /* suffix may be action ... */
9460     direction_token = action_token;             /* ... or direction */
9461
9462     element_token = getStringCopy(list->token);
9463     *strchr(element_token, '.') = '\0';
9464
9465     element_value = getHashEntry(element_hash, element_token);
9466
9467     if (element_value == NULL)          /* this is no element */
9468     {
9469       element_value = getHashEntry(element_hash, list->token);
9470       if (element_value != NULL)        /* combined element found */
9471         add_helpanim_entry(atoi(element_value), -1, -1, delay,
9472                            &num_list_entries);
9473       else
9474         print_unknown_token(filename, list->token, num_unknown_tokens++);
9475
9476       free(element_token);
9477
9478       continue;
9479     }
9480
9481     action_value = getHashEntry(action_hash, action_token);
9482
9483     if (action_value != NULL)           /* action found */
9484     {
9485       add_helpanim_entry(atoi(element_value), atoi(action_value), -1, delay,
9486                     &num_list_entries);
9487
9488       free(element_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), -1, atoi(direction_value), delay,
9498                          &num_list_entries);
9499
9500       free(element_token);
9501
9502       continue;
9503     }
9504
9505     if (strchr(action_token + 1, '.') == NULL)
9506     {
9507       /* no further suffixes found -- this is not an action nor direction */
9508
9509       element_value = getHashEntry(element_hash, list->token);
9510       if (element_value != NULL)        /* combined element found */
9511         add_helpanim_entry(atoi(element_value), -1, -1, delay,
9512                            &num_list_entries);
9513       else
9514         print_unknown_token(filename, list->token, num_unknown_tokens++);
9515
9516       free(element_token);
9517
9518       continue;
9519     }
9520
9521     /* token has format "<prefix>.<suffix>.<something>" */
9522
9523     direction_token = strchr(action_token + 1, '.');
9524
9525     action_token = getStringCopy(action_token);
9526     *strchr(action_token + 1, '.') = '\0';
9527
9528     action_value = getHashEntry(action_hash, action_token);
9529
9530     if (action_value == NULL)           /* this is no action */
9531     {
9532       element_value = getHashEntry(element_hash, list->token);
9533       if (element_value != NULL)        /* combined element found */
9534         add_helpanim_entry(atoi(element_value), -1, -1, delay,
9535                            &num_list_entries);
9536       else
9537         print_unknown_token(filename, list->token, num_unknown_tokens++);
9538
9539       free(element_token);
9540       free(action_token);
9541
9542       continue;
9543     }
9544
9545     direction_value = getHashEntry(direction_hash, direction_token);
9546
9547     if (direction_value != NULL)        /* direction found */
9548     {
9549       add_helpanim_entry(atoi(element_value), atoi(action_value),
9550                          atoi(direction_value), delay, &num_list_entries);
9551
9552       free(element_token);
9553       free(action_token);
9554
9555       continue;
9556     }
9557
9558     /* this is no direction */
9559
9560     element_value = getHashEntry(element_hash, list->token);
9561     if (element_value != NULL)          /* combined element found */
9562       add_helpanim_entry(atoi(element_value), -1, -1, delay,
9563                          &num_list_entries);
9564     else
9565       print_unknown_token(filename, list->token, num_unknown_tokens++);
9566
9567     free(element_token);
9568     free(action_token);
9569   }
9570
9571   print_unknown_token_end(num_unknown_tokens);
9572
9573   add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
9574   add_helpanim_entry(HELPANIM_LIST_END,  -1, -1, -1, &num_list_entries);
9575
9576   freeSetupFileList(setup_file_list);
9577   freeSetupFileHash(element_hash);
9578   freeSetupFileHash(action_hash);
9579   freeSetupFileHash(direction_hash);
9580
9581 #if 0
9582   for (i = 0; i < num_list_entries; i++)
9583     printf("::: '%s': %d, %d, %d => %d\n",
9584            EL_NAME(helpanim_info[i].element),
9585            helpanim_info[i].element,
9586            helpanim_info[i].action,
9587            helpanim_info[i].direction,
9588            helpanim_info[i].delay);
9589 #endif
9590 }
9591
9592 void LoadHelpTextInfo()
9593 {
9594   char *filename = getHelpTextFilename();
9595   int i;
9596
9597   if (helptext_info != NULL)
9598   {
9599     freeSetupFileHash(helptext_info);
9600     helptext_info = NULL;
9601   }
9602
9603   if (fileExists(filename))
9604     helptext_info = loadSetupFileHash(filename);
9605
9606   if (helptext_info == NULL)
9607   {
9608     /* use reliable default values from static configuration */
9609     helptext_info = newSetupFileHash();
9610
9611     for (i = 0; helptext_config[i].token; i++)
9612       setHashEntry(helptext_info,
9613                    helptext_config[i].token,
9614                    helptext_config[i].value);
9615   }
9616
9617 #if 0
9618   BEGIN_HASH_ITERATION(helptext_info, itr)
9619   {
9620     printf("::: '%s' => '%s'\n",
9621            HASH_ITERATION_TOKEN(itr), HASH_ITERATION_VALUE(itr));
9622   }
9623   END_HASH_ITERATION(hash, itr)
9624 #endif
9625 }
9626
9627
9628 /* ------------------------------------------------------------------------- */
9629 /* convert levels                                                            */
9630 /* ------------------------------------------------------------------------- */
9631
9632 #define MAX_NUM_CONVERT_LEVELS          1000
9633
9634 void ConvertLevels()
9635 {
9636   static LevelDirTree *convert_leveldir = NULL;
9637   static int convert_level_nr = -1;
9638   static int num_levels_handled = 0;
9639   static int num_levels_converted = 0;
9640   static boolean levels_failed[MAX_NUM_CONVERT_LEVELS];
9641   int i;
9642
9643   convert_leveldir = getTreeInfoFromIdentifier(leveldir_first,
9644                                                global.convert_leveldir);
9645
9646   if (convert_leveldir == NULL)
9647     Error(ERR_EXIT, "no such level identifier: '%s'",
9648           global.convert_leveldir);
9649
9650   leveldir_current = convert_leveldir;
9651
9652   if (global.convert_level_nr != -1)
9653   {
9654     convert_leveldir->first_level = global.convert_level_nr;
9655     convert_leveldir->last_level  = global.convert_level_nr;
9656   }
9657
9658   convert_level_nr = convert_leveldir->first_level;
9659
9660   printf_line("=", 79);
9661   printf("Converting levels\n");
9662   printf_line("-", 79);
9663   printf("Level series identifier: '%s'\n", convert_leveldir->identifier);
9664   printf("Level series name:       '%s'\n", convert_leveldir->name);
9665   printf("Level series author:     '%s'\n", convert_leveldir->author);
9666   printf("Number of levels:        %d\n",   convert_leveldir->levels);
9667   printf_line("=", 79);
9668   printf("\n");
9669
9670   for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++)
9671     levels_failed[i] = FALSE;
9672
9673   while (convert_level_nr <= convert_leveldir->last_level)
9674   {
9675     char *level_filename;
9676     boolean new_level;
9677
9678     level_nr = convert_level_nr++;
9679
9680     printf("Level %03d: ", level_nr);
9681
9682     LoadLevel(level_nr);
9683     if (level.no_valid_file)
9684     {
9685       printf("(no level)\n");
9686       continue;
9687     }
9688
9689     printf("converting level ... ");
9690
9691     level_filename = getDefaultLevelFilename(level_nr);
9692     new_level = !fileExists(level_filename);
9693
9694     if (new_level)
9695     {
9696       SaveLevel(level_nr);
9697
9698       num_levels_converted++;
9699
9700       printf("converted.\n");
9701     }
9702     else
9703     {
9704       if (level_nr >= 0 && level_nr < MAX_NUM_CONVERT_LEVELS)
9705         levels_failed[level_nr] = TRUE;
9706
9707       printf("NOT CONVERTED -- LEVEL ALREADY EXISTS.\n");
9708     }
9709
9710     num_levels_handled++;
9711   }
9712
9713   printf("\n");
9714   printf_line("=", 79);
9715   printf("Number of levels handled: %d\n", num_levels_handled);
9716   printf("Number of levels converted: %d (%d%%)\n", num_levels_converted,
9717          (num_levels_handled ?
9718           num_levels_converted * 100 / num_levels_handled : 0));
9719   printf_line("-", 79);
9720   printf("Summary (for automatic parsing by scripts):\n");
9721   printf("LEVELDIR '%s', CONVERTED %d/%d (%d%%)",
9722          convert_leveldir->identifier, num_levels_converted,
9723          num_levels_handled,
9724          (num_levels_handled ?
9725           num_levels_converted * 100 / num_levels_handled : 0));
9726
9727   if (num_levels_handled != num_levels_converted)
9728   {
9729     printf(", FAILED:");
9730     for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++)
9731       if (levels_failed[i])
9732         printf(" %03d", i);
9733   }
9734
9735   printf("\n");
9736   printf_line("=", 79);
9737
9738   CloseAllAndExit(0);
9739 }
9740
9741
9742 /* ------------------------------------------------------------------------- */
9743 /* create and save images for use in level sketches (raw BMP format)         */
9744 /* ------------------------------------------------------------------------- */
9745
9746 void CreateLevelSketchImages()
9747 {
9748 #if defined(TARGET_SDL)
9749   Bitmap *bitmap1;
9750   Bitmap *bitmap2;
9751   int i;
9752
9753   bitmap1 = CreateBitmap(TILEX, TILEY, DEFAULT_DEPTH);
9754   bitmap2 = CreateBitmap(MINI_TILEX, MINI_TILEY, DEFAULT_DEPTH);
9755
9756   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9757   {
9758     Bitmap *src_bitmap;
9759     int src_x, src_y;
9760     int graphic = el2edimg(i);
9761     char basename1[16];
9762     char basename2[16];
9763     char *filename1;
9764     char *filename2;
9765
9766     sprintf(basename1, "%03d.bmp", i);
9767     sprintf(basename2, "%03ds.bmp", i);
9768
9769     filename1 = getPath2(global.create_images_dir, basename1);
9770     filename2 = getPath2(global.create_images_dir, basename2);
9771
9772     getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
9773     BlitBitmap(src_bitmap, bitmap1, src_x, src_y, TILEX, TILEY, 0, 0);
9774
9775     if (SDL_SaveBMP(bitmap1->surface, filename1) != 0)
9776       Error(ERR_EXIT, "cannot save level sketch image file '%s'", filename1);
9777
9778     getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
9779     BlitBitmap(src_bitmap, bitmap2, src_x, src_y, MINI_TILEX, MINI_TILEY, 0, 0);
9780
9781     if (SDL_SaveBMP(bitmap2->surface, filename2) != 0)
9782       Error(ERR_EXIT, "cannot save level sketch image file '%s'", filename2);
9783
9784     free(filename1);
9785     free(filename2);
9786
9787     if (options.debug)
9788       printf("%03d `%03d%c", i, i, (i % 10 < 9 ? ' ' : '\n'));
9789   }
9790
9791   FreeBitmap(bitmap1);
9792   FreeBitmap(bitmap2);
9793
9794   if (options.debug)
9795     printf("\n");
9796
9797   Error(ERR_INFO, "%d normal and small images created", NUM_FILE_ELEMENTS);
9798
9799   CloseAllAndExit(0);
9800 #endif
9801 }
9802
9803
9804 /* ------------------------------------------------------------------------- */
9805 /* create and save images for custom and group elements (raw BMP format)     */
9806 /* ------------------------------------------------------------------------- */
9807
9808 void CreateCustomElementImages()
9809 {
9810 #if defined(TARGET_SDL)
9811   char *filename = "graphics.classic/RocksCE.bmp";
9812   Bitmap *bitmap;
9813   Bitmap *src_bitmap;
9814   int dummy_graphic = IMG_CUSTOM_99;
9815   int yoffset_ce = 0;
9816   int yoffset_ge = (TILEY * NUM_CUSTOM_ELEMENTS / 16);
9817   int src_x, src_y;
9818   int i;
9819
9820   bitmap = CreateBitmap(TILEX * 16 * 2,
9821                         TILEY * (NUM_CUSTOM_ELEMENTS + NUM_GROUP_ELEMENTS) / 16,
9822                         DEFAULT_DEPTH);
9823
9824   getGraphicSource(dummy_graphic, 0, &src_bitmap, &src_x, &src_y);
9825
9826   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
9827   {
9828     int x = i % 16;
9829     int y = i / 16;
9830     int ii = i + 1;
9831     int j;
9832
9833     BlitBitmap(src_bitmap, bitmap, 0, 0, TILEX, TILEY,
9834                TILEX * x, TILEY * y + yoffset_ce);
9835
9836     BlitBitmap(src_bitmap, bitmap, 0, TILEY, TILEX, TILEY,
9837                TILEX * x + TILEX * 16, TILEY * y + yoffset_ce);
9838
9839     for (j = 2; j >= 0; j--)
9840     {
9841       int c = ii % 10;
9842
9843       BlitBitmap(src_bitmap, bitmap, TILEX + c * 7, 0, 6, 10,
9844                  TILEX * x + 6 + j * 7,
9845                  TILEY * y + 11 + yoffset_ce);
9846
9847       BlitBitmap(src_bitmap, bitmap, TILEX + c * 8, TILEY, 6, 10,
9848                  TILEX * 16 + TILEX * x + 6 + j * 8,
9849                  TILEY * y + 10 + yoffset_ce);
9850
9851       ii /= 10;
9852     }
9853   }
9854
9855   for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
9856   {
9857     int x = i % 16;
9858     int y = i / 16;
9859     int ii = i + 1;
9860     int j;
9861
9862     BlitBitmap(src_bitmap, bitmap, 0, 0, TILEX, TILEY,
9863                TILEX * x, TILEY * y + yoffset_ge);
9864
9865     BlitBitmap(src_bitmap, bitmap, 0, TILEY, TILEX, TILEY,
9866                TILEX * x + TILEX * 16, TILEY * y + yoffset_ge);
9867
9868     for (j = 1; j >= 0; j--)
9869     {
9870       int c = ii % 10;
9871
9872       BlitBitmap(src_bitmap, bitmap, TILEX + c * 10, 11, 10, 10,
9873                  TILEX * x + 6 + j * 10,
9874                  TILEY * y + 11 + yoffset_ge);
9875
9876       BlitBitmap(src_bitmap, bitmap, TILEX + c * 8, TILEY + 12, 6, 10,
9877                  TILEX * 16 + TILEX * x + 10 + j * 8,
9878                  TILEY * y + 10 + yoffset_ge);
9879
9880       ii /= 10;
9881     }
9882   }
9883
9884   if (SDL_SaveBMP(bitmap->surface, filename) != 0)
9885     Error(ERR_EXIT, "cannot save CE graphics file '%s'", filename);
9886
9887   FreeBitmap(bitmap);
9888
9889   CloseAllAndExit(0);
9890 #endif
9891 }
9892
9893 #if 0
9894 void CreateLevelSketchImages_TEST()
9895 {
9896   void CreateCustomElementImages()
9897 }
9898 #endif