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