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