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