rnd-20091024-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_INVISIBLE_WALL)
4178         element_new = 0x28;
4179       else
4180         element_new = 0x20;     /* map unknown elements to yellow "hardware" */
4181
4182       level_sp->playfield[x][y] = element_new;
4183     }
4184   }
4185
4186   header->InitialGravity = (level->initial_player_gravity[0] ? 1 : 0);
4187
4188   for (i = 0; i < SP_LEVEL_NAME_LEN; i++)
4189     header->LevelTitle[i] = level->name[i];
4190   /* !!! NO STRING TERMINATION IN SUPAPLEX VB CODE YET -- FIX THIS !!! */
4191
4192   header->InfotronsNeeded = level->gems_needed;
4193
4194   /* !!! ADD SPECIAL PORT DATABASE STUFF !!! */
4195 }
4196
4197 void CopyNativeLevel_SP_to_RND(struct LevelInfo *level)
4198 {
4199   struct LevelInfo_SP *level_sp = level->native_sp_level;
4200   LevelInfoType *header = &level_sp->header;
4201   int i, x, y;
4202
4203   level->fieldx = level_sp->width;
4204   level->fieldy = level_sp->height;
4205
4206   for (x = 0; x < level->fieldx; x++)
4207   {
4208     for (y = 0; y < level->fieldy; y++)
4209     {
4210       int element_old = level_sp->playfield[x][y];
4211       int element_new;
4212
4213       if (element_old <= 0x27)
4214         element_new = getMappedElement(EL_SP_START + element_old);
4215       else if (element_old == 0x28)
4216         element_new = EL_INVISIBLE_WALL;
4217       else
4218       {
4219         Error(ERR_WARN, "invalid element %d at position %d, %d",
4220               element_old, x, y);
4221
4222         element_new = EL_UNKNOWN;
4223       }
4224
4225       level->field[x][y] = element_new;
4226     }
4227   }
4228
4229   for (i = 0; i < MAX_PLAYERS; i++)
4230     level->initial_player_gravity[i] =
4231       (header->InitialGravity == 1 ? TRUE : FALSE);
4232
4233   for (i = 0; i < SP_LEVEL_NAME_LEN; i++)
4234     level->name[i] = header->LevelTitle[i];
4235   level->name[SP_LEVEL_NAME_LEN] = '\0';
4236
4237   level->gems_needed = header->InfotronsNeeded;
4238
4239   for (i = 0; i < header->SpecialPortCount; i++)
4240   {
4241     SpecialPortType *port = &header->SpecialPort[i];
4242     int port_location = port->PortLocation;
4243     int gravity = port->Gravity;
4244     int port_x, port_y, port_element;
4245
4246     port_x = (port_location / 2) % level->fieldx;
4247     port_y = (port_location / 2) / level->fieldx;
4248
4249     if (port_x < 0 || port_x >= level->fieldx ||
4250         port_y < 0 || port_y >= level->fieldy)
4251     {
4252       Error(ERR_WARN, "special port position (%d, %d) out of bounds",
4253             port_x, port_y);
4254
4255       continue;
4256     }
4257
4258     port_element = level->field[port_x][port_y];
4259
4260     if (port_element < EL_SP_GRAVITY_PORT_RIGHT ||
4261         port_element > EL_SP_GRAVITY_PORT_UP)
4262     {
4263       Error(ERR_WARN, "no special port at position (%d, %d)", port_x, port_y);
4264
4265       continue;
4266     }
4267
4268     /* change previous (wrong) gravity inverting special port to either
4269        gravity enabling special port or gravity disabling special port */
4270     level->field[port_x][port_y] +=
4271       (gravity == 1 ? EL_SP_GRAVITY_ON_PORT_RIGHT :
4272        EL_SP_GRAVITY_OFF_PORT_RIGHT) - EL_SP_GRAVITY_PORT_RIGHT;
4273   }
4274
4275   /* change special gravity ports without database entries to normal ports */
4276   for (x = 0; x < level->fieldx; x++)
4277     for (y = 0; y < level->fieldy; y++)
4278       if (level->field[x][y] >= EL_SP_GRAVITY_PORT_RIGHT &&
4279           level->field[x][y] <= EL_SP_GRAVITY_PORT_UP)
4280         level->field[x][y] += EL_SP_PORT_RIGHT - EL_SP_GRAVITY_PORT_RIGHT;
4281
4282   level->time = 0;                      /* no time limit */
4283   level->amoeba_speed = 0;
4284   level->time_magic_wall = 0;
4285   level->time_wheel = 0;
4286   level->amoeba_content = EL_EMPTY;
4287
4288 #if 1
4289   /* original Supaplex does not use score values -- use default values */
4290 #else
4291   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
4292     level->score[i] = 0;
4293 #endif
4294
4295   /* there are no yamyams in supaplex levels */
4296   for (i = 0; i < level->num_yamyam_contents; i++)
4297     for (x = 0; x < 3; x++)
4298       for (y = 0; y < 3; y++)
4299         level->yamyam_content[i].e[x][y] = EL_EMPTY;
4300 }
4301
4302 static void setTapeInfoToDefaults();
4303
4304 static void CopyNativeTape_SP_to_RND(struct LevelInfo *level)
4305 {
4306   struct LevelInfo_SP *level_sp = level->native_sp_level;
4307   struct DemoInfo_SP *demo = &level_sp->demo;
4308   int i;
4309
4310   /* always start with reliable default values */
4311   setTapeInfoToDefaults();
4312
4313   tape.level_nr = demo->level_nr;       /* (currently not used) */
4314   tape.length = demo->length - 1;       /* without "end of demo" byte */
4315   tape.random_seed = level_sp->header.DemoRandomSeed;
4316
4317   // tape.date = <SET FROM FILE DATE OF *.SP FILE>
4318
4319   for (i = 0; i < demo->length - 1; i++)
4320   {
4321     int demo_action = demo->data[i] & 0x0f;
4322     int demo_repeat = (demo->data[i] & 0xf0) >> 4;
4323
4324     tape.pos[i].action[0] = map_key_SP_to_RND(demo_action);
4325     tape.pos[i].delay = demo_repeat + 1;
4326   }
4327
4328   tape.length_seconds = GetTapeLength();
4329 }
4330
4331
4332 /* ------------------------------------------------------------------------- */
4333 /* functions for loading DC level                                            */
4334 /* ------------------------------------------------------------------------- */
4335
4336 #define DC_LEVEL_HEADER_SIZE            344
4337
4338 unsigned short getDecodedWord_DC(unsigned short data_encoded, boolean init)
4339 {
4340   static int last_data_encoded;
4341   static int offset1;
4342   static int offset2;
4343   int diff;
4344   int diff_hi, diff_lo;
4345   int data_hi, data_lo;
4346   unsigned short data_decoded;
4347
4348   if (init)
4349   {
4350     last_data_encoded = 0;
4351     offset1 = -1;
4352     offset2 = 0;
4353
4354     return 0;
4355   }
4356
4357   diff = data_encoded - last_data_encoded;
4358   diff_hi = diff & ~0xff;
4359   diff_lo = diff &  0xff;
4360
4361   offset2 += diff_lo;
4362
4363   data_hi = diff_hi - (offset1 << 8) + (offset2 & 0xff00);
4364   data_lo = (diff_lo + (data_hi >> 16)) & 0x00ff;
4365   data_hi = data_hi & 0xff00;
4366
4367   data_decoded = data_hi | data_lo;
4368
4369   last_data_encoded = data_encoded;
4370
4371   offset1 = (offset1 + 1) % 31;
4372   offset2 = offset2 & 0xff;
4373
4374   return data_decoded;
4375 }
4376
4377 int getMappedElement_DC(int element)
4378 {
4379   switch (element)
4380   {
4381     case 0x0000:
4382       element = EL_ROCK;
4383       break;
4384
4385       /* 0x0117 - 0x036e: (?) */
4386       /* EL_DIAMOND */
4387
4388       /* 0x042d - 0x0684: (?) */
4389       /* EL_EMERALD */
4390
4391     case 0x06f1:
4392       element = EL_NUT;
4393       break;
4394
4395     case 0x074c:
4396       element = EL_BOMB;
4397       break;
4398
4399     case 0x07a4:
4400       element = EL_PEARL;
4401       break;
4402
4403     case 0x0823:
4404       element = EL_CRYSTAL;
4405       break;
4406
4407     case 0x0e77:        /* quicksand (boulder) */
4408       element = EL_QUICKSAND_FAST_FULL;
4409       break;
4410
4411     case 0x0e99:        /* slow quicksand (boulder) */
4412       element = EL_QUICKSAND_FULL;
4413       break;
4414
4415     case 0x0ed2:
4416       element = EL_EM_EXIT_OPEN;
4417       break;
4418
4419     case 0x0ee3:
4420       element = EL_EM_EXIT_CLOSED;
4421       break;
4422
4423     case 0x0eeb:
4424       element = EL_EM_STEEL_EXIT_OPEN;
4425       break;
4426
4427     case 0x0efc:
4428       element = EL_EM_STEEL_EXIT_CLOSED;
4429       break;
4430
4431     case 0x0f4f:        /* dynamite (lit 1) */
4432       element = EL_EM_DYNAMITE_ACTIVE;
4433       break;
4434
4435     case 0x0f57:        /* dynamite (lit 2) */
4436       element = EL_EM_DYNAMITE_ACTIVE;
4437       break;
4438
4439     case 0x0f5f:        /* dynamite (lit 3) */
4440       element = EL_EM_DYNAMITE_ACTIVE;
4441       break;
4442
4443     case 0x0f67:        /* dynamite (lit 4) */
4444       element = EL_EM_DYNAMITE_ACTIVE;
4445       break;
4446
4447     case 0x0f81:
4448     case 0x0f82:
4449     case 0x0f83:
4450     case 0x0f84:
4451       element = EL_AMOEBA_WET;
4452       break;
4453
4454     case 0x0f85:
4455       element = EL_AMOEBA_DROP;
4456       break;
4457
4458     case 0x0fb9:
4459       element = EL_DC_MAGIC_WALL;
4460       break;
4461
4462     case 0x0fd0:
4463       element = EL_SPACESHIP_UP;
4464       break;
4465
4466     case 0x0fd9:
4467       element = EL_SPACESHIP_DOWN;
4468       break;
4469
4470     case 0x0ff1:
4471       element = EL_SPACESHIP_LEFT;
4472       break;
4473
4474     case 0x0ff9:
4475       element = EL_SPACESHIP_RIGHT;
4476       break;
4477
4478     case 0x1057:
4479       element = EL_BUG_UP;
4480       break;
4481
4482     case 0x1060:
4483       element = EL_BUG_DOWN;
4484       break;
4485
4486     case 0x1078:
4487       element = EL_BUG_LEFT;
4488       break;
4489
4490     case 0x1080:
4491       element = EL_BUG_RIGHT;
4492       break;
4493
4494     case 0x10de:
4495       element = EL_MOLE_UP;
4496       break;
4497
4498     case 0x10e7:
4499       element = EL_MOLE_DOWN;
4500       break;
4501
4502     case 0x10ff:
4503       element = EL_MOLE_LEFT;
4504       break;
4505
4506     case 0x1107:
4507       element = EL_MOLE_RIGHT;
4508       break;
4509
4510     case 0x11c0:
4511       element = EL_ROBOT;
4512       break;
4513
4514     case 0x13f5:
4515       element = EL_YAMYAM;
4516       break;
4517
4518     case 0x1425:
4519       element = EL_SWITCHGATE_OPEN;
4520       break;
4521
4522     case 0x1426:
4523       element = EL_SWITCHGATE_CLOSED;
4524       break;
4525
4526     case 0x1437:
4527       element = EL_DC_SWITCHGATE_SWITCH_UP;
4528       break;
4529
4530     case 0x143a:
4531       element = EL_TIMEGATE_CLOSED;
4532       break;
4533
4534     case 0x144c:        /* conveyor belt switch (green) */
4535       element = EL_CONVEYOR_BELT_3_SWITCH_MIDDLE;
4536       break;
4537
4538     case 0x144f:        /* conveyor belt switch (red) */
4539       element = EL_CONVEYOR_BELT_1_SWITCH_MIDDLE;
4540       break;
4541
4542     case 0x1452:        /* conveyor belt switch (blue) */
4543       element = EL_CONVEYOR_BELT_4_SWITCH_MIDDLE;
4544       break;
4545
4546     case 0x145b:
4547       element = EL_CONVEYOR_BELT_3_MIDDLE;
4548       break;
4549
4550     case 0x1463:
4551       element = EL_CONVEYOR_BELT_3_LEFT;
4552       break;
4553
4554     case 0x146b:
4555       element = EL_CONVEYOR_BELT_3_RIGHT;
4556       break;
4557
4558     case 0x1473:
4559       element = EL_CONVEYOR_BELT_1_MIDDLE;
4560       break;
4561
4562     case 0x147b:
4563       element = EL_CONVEYOR_BELT_1_LEFT;
4564       break;
4565
4566     case 0x1483:
4567       element = EL_CONVEYOR_BELT_1_RIGHT;
4568       break;
4569
4570     case 0x148b:
4571       element = EL_CONVEYOR_BELT_4_MIDDLE;
4572       break;
4573
4574     case 0x1493:
4575       element = EL_CONVEYOR_BELT_4_LEFT;
4576       break;
4577
4578     case 0x149b:
4579       element = EL_CONVEYOR_BELT_4_RIGHT;
4580       break;
4581
4582     case 0x14ac:
4583       element = EL_EXPANDABLE_WALL_HORIZONTAL;
4584       break;
4585
4586     case 0x14bd:
4587       element = EL_EXPANDABLE_WALL_VERTICAL;
4588       break;
4589
4590     case 0x14c6:
4591       element = EL_EXPANDABLE_WALL_ANY;
4592       break;
4593
4594     case 0x14ce:        /* growing steel wall (left/right) */
4595       element = EL_EXPANDABLE_STEELWALL_HORIZONTAL;
4596       break;
4597
4598     case 0x14df:        /* growing steel wall (up/down) */
4599       element = EL_EXPANDABLE_STEELWALL_VERTICAL;
4600       break;
4601
4602     case 0x14e8:        /* growing steel wall (up/down/left/right) */
4603       element = EL_EXPANDABLE_STEELWALL_ANY;
4604       break;
4605
4606     case 0x14e9:
4607       element = EL_SHIELD_DEADLY;
4608       break;
4609
4610     case 0x1501:
4611       element = EL_EXTRA_TIME;
4612       break;
4613
4614     case 0x154f:
4615       element = EL_ACID;
4616       break;
4617
4618     case 0x1577:
4619       element = EL_EMPTY_SPACE;
4620       break;
4621
4622     case 0x1578:        /* quicksand (empty) */
4623       element = EL_QUICKSAND_FAST_EMPTY;
4624       break;
4625
4626     case 0x1579:        /* slow quicksand (empty) */
4627       element = EL_QUICKSAND_EMPTY;
4628       break;
4629
4630       /* 0x157c - 0x158b: */
4631       /* EL_SAND */
4632
4633       /* 0x1590 - 0x159f: */
4634       /* EL_DC_LANDMINE */
4635
4636     case 0x15a0:
4637       element = EL_EM_DYNAMITE;
4638       break;
4639
4640     case 0x15a1:        /* key (red) */
4641       element = EL_EM_KEY_1;
4642       break;
4643
4644     case 0x15a2:        /* key (yellow) */
4645       element = EL_EM_KEY_2;
4646       break;
4647
4648     case 0x15a3:        /* key (blue) */
4649       element = EL_EM_KEY_4;
4650       break;
4651
4652     case 0x15a4:        /* key (green) */
4653       element = EL_EM_KEY_3;
4654       break;
4655
4656     case 0x15a5:        /* key (white) */
4657       element = EL_DC_KEY_WHITE;
4658       break;
4659
4660     case 0x15a6:
4661       element = EL_WALL_SLIPPERY;
4662       break;
4663
4664     case 0x15a7:
4665       element = EL_WALL;
4666       break;
4667
4668     case 0x15a8:        /* wall (not round) */
4669       element = EL_WALL;
4670       break;
4671
4672     case 0x15a9:        /* (blue) */
4673       element = EL_CHAR_A;
4674       break;
4675
4676     case 0x15aa:        /* (blue) */
4677       element = EL_CHAR_B;
4678       break;
4679
4680     case 0x15ab:        /* (blue) */
4681       element = EL_CHAR_C;
4682       break;
4683
4684     case 0x15ac:        /* (blue) */
4685       element = EL_CHAR_D;
4686       break;
4687
4688     case 0x15ad:        /* (blue) */
4689       element = EL_CHAR_E;
4690       break;
4691
4692     case 0x15ae:        /* (blue) */
4693       element = EL_CHAR_F;
4694       break;
4695
4696     case 0x15af:        /* (blue) */
4697       element = EL_CHAR_G;
4698       break;
4699
4700     case 0x15b0:        /* (blue) */
4701       element = EL_CHAR_H;
4702       break;
4703
4704     case 0x15b1:        /* (blue) */
4705       element = EL_CHAR_I;
4706       break;
4707
4708     case 0x15b2:        /* (blue) */
4709       element = EL_CHAR_J;
4710       break;
4711
4712     case 0x15b3:        /* (blue) */
4713       element = EL_CHAR_K;
4714       break;
4715
4716     case 0x15b4:        /* (blue) */
4717       element = EL_CHAR_L;
4718       break;
4719
4720     case 0x15b5:        /* (blue) */
4721       element = EL_CHAR_M;
4722       break;
4723
4724     case 0x15b6:        /* (blue) */
4725       element = EL_CHAR_N;
4726       break;
4727
4728     case 0x15b7:        /* (blue) */
4729       element = EL_CHAR_O;
4730       break;
4731
4732     case 0x15b8:        /* (blue) */
4733       element = EL_CHAR_P;
4734       break;
4735
4736     case 0x15b9:        /* (blue) */
4737       element = EL_CHAR_Q;
4738       break;
4739
4740     case 0x15ba:        /* (blue) */
4741       element = EL_CHAR_R;
4742       break;
4743
4744     case 0x15bb:        /* (blue) */
4745       element = EL_CHAR_S;
4746       break;
4747
4748     case 0x15bc:        /* (blue) */
4749       element = EL_CHAR_T;
4750       break;
4751
4752     case 0x15bd:        /* (blue) */
4753       element = EL_CHAR_U;
4754       break;
4755
4756     case 0x15be:        /* (blue) */
4757       element = EL_CHAR_V;
4758       break;
4759
4760     case 0x15bf:        /* (blue) */
4761       element = EL_CHAR_W;
4762       break;
4763
4764     case 0x15c0:        /* (blue) */
4765       element = EL_CHAR_X;
4766       break;
4767
4768     case 0x15c1:        /* (blue) */
4769       element = EL_CHAR_Y;
4770       break;
4771
4772     case 0x15c2:        /* (blue) */
4773       element = EL_CHAR_Z;
4774       break;
4775
4776     case 0x15c3:        /* (blue) */
4777       element = EL_CHAR_AUMLAUT;
4778       break;
4779
4780     case 0x15c4:        /* (blue) */
4781       element = EL_CHAR_OUMLAUT;
4782       break;
4783
4784     case 0x15c5:        /* (blue) */
4785       element = EL_CHAR_UUMLAUT;
4786       break;
4787
4788     case 0x15c6:        /* (blue) */
4789       element = EL_CHAR_0;
4790       break;
4791
4792     case 0x15c7:        /* (blue) */
4793       element = EL_CHAR_1;
4794       break;
4795
4796     case 0x15c8:        /* (blue) */
4797       element = EL_CHAR_2;
4798       break;
4799
4800     case 0x15c9:        /* (blue) */
4801       element = EL_CHAR_3;
4802       break;
4803
4804     case 0x15ca:        /* (blue) */
4805       element = EL_CHAR_4;
4806       break;
4807
4808     case 0x15cb:        /* (blue) */
4809       element = EL_CHAR_5;
4810       break;
4811
4812     case 0x15cc:        /* (blue) */
4813       element = EL_CHAR_6;
4814       break;
4815
4816     case 0x15cd:        /* (blue) */
4817       element = EL_CHAR_7;
4818       break;
4819
4820     case 0x15ce:        /* (blue) */
4821       element = EL_CHAR_8;
4822       break;
4823
4824     case 0x15cf:        /* (blue) */
4825       element = EL_CHAR_9;
4826       break;
4827
4828     case 0x15d0:        /* (blue) */
4829       element = EL_CHAR_PERIOD;
4830       break;
4831
4832     case 0x15d1:        /* (blue) */
4833       element = EL_CHAR_EXCLAM;
4834       break;
4835
4836     case 0x15d2:        /* (blue) */
4837       element = EL_CHAR_COLON;
4838       break;
4839
4840     case 0x15d3:        /* (blue) */
4841       element = EL_CHAR_LESS;
4842       break;
4843
4844     case 0x15d4:        /* (blue) */
4845       element = EL_CHAR_GREATER;
4846       break;
4847
4848     case 0x15d5:        /* (blue) */
4849       element = EL_CHAR_QUESTION;
4850       break;
4851
4852     case 0x15d6:        /* (blue) */
4853       element = EL_CHAR_COPYRIGHT;
4854       break;
4855
4856     case 0x15d7:        /* (blue) */
4857       element = EL_CHAR_UP;
4858       break;
4859
4860     case 0x15d8:        /* (blue) */
4861       element = EL_CHAR_DOWN;
4862       break;
4863
4864     case 0x15d9:        /* (blue) */
4865       element = EL_CHAR_BUTTON;
4866       break;
4867
4868     case 0x15da:        /* (blue) */
4869       element = EL_CHAR_PLUS;
4870       break;
4871
4872     case 0x15db:        /* (blue) */
4873       element = EL_CHAR_MINUS;
4874       break;
4875
4876     case 0x15dc:        /* (blue) */
4877       element = EL_CHAR_APOSTROPHE;
4878       break;
4879
4880     case 0x15dd:        /* (blue) */
4881       element = EL_CHAR_PARENLEFT;
4882       break;
4883
4884     case 0x15de:        /* (blue) */
4885       element = EL_CHAR_PARENRIGHT;
4886       break;
4887
4888     case 0x15df:        /* (green) */
4889       element = EL_CHAR_A;
4890       break;
4891
4892     case 0x15e0:        /* (green) */
4893       element = EL_CHAR_B;
4894       break;
4895
4896     case 0x15e1:        /* (green) */
4897       element = EL_CHAR_C;
4898       break;
4899
4900     case 0x15e2:        /* (green) */
4901       element = EL_CHAR_D;
4902       break;
4903
4904     case 0x15e3:        /* (green) */
4905       element = EL_CHAR_E;
4906       break;
4907
4908     case 0x15e4:        /* (green) */
4909       element = EL_CHAR_F;
4910       break;
4911
4912     case 0x15e5:        /* (green) */
4913       element = EL_CHAR_G;
4914       break;
4915
4916     case 0x15e6:        /* (green) */
4917       element = EL_CHAR_H;
4918       break;
4919
4920     case 0x15e7:        /* (green) */
4921       element = EL_CHAR_I;
4922       break;
4923
4924     case 0x15e8:        /* (green) */
4925       element = EL_CHAR_J;
4926       break;
4927
4928     case 0x15e9:        /* (green) */
4929       element = EL_CHAR_K;
4930       break;
4931
4932     case 0x15ea:        /* (green) */
4933       element = EL_CHAR_L;
4934       break;
4935
4936     case 0x15eb:        /* (green) */
4937       element = EL_CHAR_M;
4938       break;
4939
4940     case 0x15ec:        /* (green) */
4941       element = EL_CHAR_N;
4942       break;
4943
4944     case 0x15ed:        /* (green) */
4945       element = EL_CHAR_O;
4946       break;
4947
4948     case 0x15ee:        /* (green) */
4949       element = EL_CHAR_P;
4950       break;
4951
4952     case 0x15ef:        /* (green) */
4953       element = EL_CHAR_Q;
4954       break;
4955
4956     case 0x15f0:        /* (green) */
4957       element = EL_CHAR_R;
4958       break;
4959
4960     case 0x15f1:        /* (green) */
4961       element = EL_CHAR_S;
4962       break;
4963
4964     case 0x15f2:        /* (green) */
4965       element = EL_CHAR_T;
4966       break;
4967
4968     case 0x15f3:        /* (green) */
4969       element = EL_CHAR_U;
4970       break;
4971
4972     case 0x15f4:        /* (green) */
4973       element = EL_CHAR_V;
4974       break;
4975
4976     case 0x15f5:        /* (green) */
4977       element = EL_CHAR_W;
4978       break;
4979
4980     case 0x15f6:        /* (green) */
4981       element = EL_CHAR_X;
4982       break;
4983
4984     case 0x15f7:        /* (green) */
4985       element = EL_CHAR_Y;
4986       break;
4987
4988     case 0x15f8:        /* (green) */
4989       element = EL_CHAR_Z;
4990       break;
4991
4992     case 0x15f9:        /* (green) */
4993       element = EL_CHAR_AUMLAUT;
4994       break;
4995
4996     case 0x15fa:        /* (green) */
4997       element = EL_CHAR_OUMLAUT;
4998       break;
4999
5000     case 0x15fb:        /* (green) */
5001       element = EL_CHAR_UUMLAUT;
5002       break;
5003
5004     case 0x15fc:        /* (green) */
5005       element = EL_CHAR_0;
5006       break;
5007
5008     case 0x15fd:        /* (green) */
5009       element = EL_CHAR_1;
5010       break;
5011
5012     case 0x15fe:        /* (green) */
5013       element = EL_CHAR_2;
5014       break;
5015
5016     case 0x15ff:        /* (green) */
5017       element = EL_CHAR_3;
5018       break;
5019
5020     case 0x1600:        /* (green) */
5021       element = EL_CHAR_4;
5022       break;
5023
5024     case 0x1601:        /* (green) */
5025       element = EL_CHAR_5;
5026       break;
5027
5028     case 0x1602:        /* (green) */
5029       element = EL_CHAR_6;
5030       break;
5031
5032     case 0x1603:        /* (green) */
5033       element = EL_CHAR_7;
5034       break;
5035
5036     case 0x1604:        /* (green) */
5037       element = EL_CHAR_8;
5038       break;
5039
5040     case 0x1605:        /* (green) */
5041       element = EL_CHAR_9;
5042       break;
5043
5044     case 0x1606:        /* (green) */
5045       element = EL_CHAR_PERIOD;
5046       break;
5047
5048     case 0x1607:        /* (green) */
5049       element = EL_CHAR_EXCLAM;
5050       break;
5051
5052     case 0x1608:        /* (green) */
5053       element = EL_CHAR_COLON;
5054       break;
5055
5056     case 0x1609:        /* (green) */
5057       element = EL_CHAR_LESS;
5058       break;
5059
5060     case 0x160a:        /* (green) */
5061       element = EL_CHAR_GREATER;
5062       break;
5063
5064     case 0x160b:        /* (green) */
5065       element = EL_CHAR_QUESTION;
5066       break;
5067
5068     case 0x160c:        /* (green) */
5069       element = EL_CHAR_COPYRIGHT;
5070       break;
5071
5072     case 0x160d:        /* (green) */
5073       element = EL_CHAR_UP;
5074       break;
5075
5076     case 0x160e:        /* (green) */
5077       element = EL_CHAR_DOWN;
5078       break;
5079
5080     case 0x160f:        /* (green) */
5081       element = EL_CHAR_BUTTON;
5082       break;
5083
5084     case 0x1610:        /* (green) */
5085       element = EL_CHAR_PLUS;
5086       break;
5087
5088     case 0x1611:        /* (green) */
5089       element = EL_CHAR_MINUS;
5090       break;
5091
5092     case 0x1612:        /* (green) */
5093       element = EL_CHAR_APOSTROPHE;
5094       break;
5095
5096     case 0x1613:        /* (green) */
5097       element = EL_CHAR_PARENLEFT;
5098       break;
5099
5100     case 0x1614:        /* (green) */
5101       element = EL_CHAR_PARENRIGHT;
5102       break;
5103
5104     case 0x1615:        /* (blue steel) */
5105       element = EL_STEEL_CHAR_A;
5106       break;
5107
5108     case 0x1616:        /* (blue steel) */
5109       element = EL_STEEL_CHAR_B;
5110       break;
5111
5112     case 0x1617:        /* (blue steel) */
5113       element = EL_STEEL_CHAR_C;
5114       break;
5115
5116     case 0x1618:        /* (blue steel) */
5117       element = EL_STEEL_CHAR_D;
5118       break;
5119
5120     case 0x1619:        /* (blue steel) */
5121       element = EL_STEEL_CHAR_E;
5122       break;
5123
5124     case 0x161a:        /* (blue steel) */
5125       element = EL_STEEL_CHAR_F;
5126       break;
5127
5128     case 0x161b:        /* (blue steel) */
5129       element = EL_STEEL_CHAR_G;
5130       break;
5131
5132     case 0x161c:        /* (blue steel) */
5133       element = EL_STEEL_CHAR_H;
5134       break;
5135
5136     case 0x161d:        /* (blue steel) */
5137       element = EL_STEEL_CHAR_I;
5138       break;
5139
5140     case 0x161e:        /* (blue steel) */
5141       element = EL_STEEL_CHAR_J;
5142       break;
5143
5144     case 0x161f:        /* (blue steel) */
5145       element = EL_STEEL_CHAR_K;
5146       break;
5147
5148     case 0x1620:        /* (blue steel) */
5149       element = EL_STEEL_CHAR_L;
5150       break;
5151
5152     case 0x1621:        /* (blue steel) */
5153       element = EL_STEEL_CHAR_M;
5154       break;
5155
5156     case 0x1622:        /* (blue steel) */
5157       element = EL_STEEL_CHAR_N;
5158       break;
5159
5160     case 0x1623:        /* (blue steel) */
5161       element = EL_STEEL_CHAR_O;
5162       break;
5163
5164     case 0x1624:        /* (blue steel) */
5165       element = EL_STEEL_CHAR_P;
5166       break;
5167
5168     case 0x1625:        /* (blue steel) */
5169       element = EL_STEEL_CHAR_Q;
5170       break;
5171
5172     case 0x1626:        /* (blue steel) */
5173       element = EL_STEEL_CHAR_R;
5174       break;
5175
5176     case 0x1627:        /* (blue steel) */
5177       element = EL_STEEL_CHAR_S;
5178       break;
5179
5180     case 0x1628:        /* (blue steel) */
5181       element = EL_STEEL_CHAR_T;
5182       break;
5183
5184     case 0x1629:        /* (blue steel) */
5185       element = EL_STEEL_CHAR_U;
5186       break;
5187
5188     case 0x162a:        /* (blue steel) */
5189       element = EL_STEEL_CHAR_V;
5190       break;
5191
5192     case 0x162b:        /* (blue steel) */
5193       element = EL_STEEL_CHAR_W;
5194       break;
5195
5196     case 0x162c:        /* (blue steel) */
5197       element = EL_STEEL_CHAR_X;
5198       break;
5199
5200     case 0x162d:        /* (blue steel) */
5201       element = EL_STEEL_CHAR_Y;
5202       break;
5203
5204     case 0x162e:        /* (blue steel) */
5205       element = EL_STEEL_CHAR_Z;
5206       break;
5207
5208     case 0x162f:        /* (blue steel) */
5209       element = EL_STEEL_CHAR_AUMLAUT;
5210       break;
5211
5212     case 0x1630:        /* (blue steel) */
5213       element = EL_STEEL_CHAR_OUMLAUT;
5214       break;
5215
5216     case 0x1631:        /* (blue steel) */
5217       element = EL_STEEL_CHAR_UUMLAUT;
5218       break;
5219
5220     case 0x1632:        /* (blue steel) */
5221       element = EL_STEEL_CHAR_0;
5222       break;
5223
5224     case 0x1633:        /* (blue steel) */
5225       element = EL_STEEL_CHAR_1;
5226       break;
5227
5228     case 0x1634:        /* (blue steel) */
5229       element = EL_STEEL_CHAR_2;
5230       break;
5231
5232     case 0x1635:        /* (blue steel) */
5233       element = EL_STEEL_CHAR_3;
5234       break;
5235
5236     case 0x1636:        /* (blue steel) */
5237       element = EL_STEEL_CHAR_4;
5238       break;
5239
5240     case 0x1637:        /* (blue steel) */
5241       element = EL_STEEL_CHAR_5;
5242       break;
5243
5244     case 0x1638:        /* (blue steel) */
5245       element = EL_STEEL_CHAR_6;
5246       break;
5247
5248     case 0x1639:        /* (blue steel) */
5249       element = EL_STEEL_CHAR_7;
5250       break;
5251
5252     case 0x163a:        /* (blue steel) */
5253       element = EL_STEEL_CHAR_8;
5254       break;
5255
5256     case 0x163b:        /* (blue steel) */
5257       element = EL_STEEL_CHAR_9;
5258       break;
5259
5260     case 0x163c:        /* (blue steel) */
5261       element = EL_STEEL_CHAR_PERIOD;
5262       break;
5263
5264     case 0x163d:        /* (blue steel) */
5265       element = EL_STEEL_CHAR_EXCLAM;
5266       break;
5267
5268     case 0x163e:        /* (blue steel) */
5269       element = EL_STEEL_CHAR_COLON;
5270       break;
5271
5272     case 0x163f:        /* (blue steel) */
5273       element = EL_STEEL_CHAR_LESS;
5274       break;
5275
5276     case 0x1640:        /* (blue steel) */
5277       element = EL_STEEL_CHAR_GREATER;
5278       break;
5279
5280     case 0x1641:        /* (blue steel) */
5281       element = EL_STEEL_CHAR_QUESTION;
5282       break;
5283
5284     case 0x1642:        /* (blue steel) */
5285       element = EL_STEEL_CHAR_COPYRIGHT;
5286       break;
5287
5288     case 0x1643:        /* (blue steel) */
5289       element = EL_STEEL_CHAR_UP;
5290       break;
5291
5292     case 0x1644:        /* (blue steel) */
5293       element = EL_STEEL_CHAR_DOWN;
5294       break;
5295
5296     case 0x1645:        /* (blue steel) */
5297       element = EL_STEEL_CHAR_BUTTON;
5298       break;
5299
5300     case 0x1646:        /* (blue steel) */
5301       element = EL_STEEL_CHAR_PLUS;
5302       break;
5303
5304     case 0x1647:        /* (blue steel) */
5305       element = EL_STEEL_CHAR_MINUS;
5306       break;
5307
5308     case 0x1648:        /* (blue steel) */
5309       element = EL_STEEL_CHAR_APOSTROPHE;
5310       break;
5311
5312     case 0x1649:        /* (blue steel) */
5313       element = EL_STEEL_CHAR_PARENLEFT;
5314       break;
5315
5316     case 0x164a:        /* (blue steel) */
5317       element = EL_STEEL_CHAR_PARENRIGHT;
5318       break;
5319
5320     case 0x164b:        /* (green steel) */
5321       element = EL_STEEL_CHAR_A;
5322       break;
5323
5324     case 0x164c:        /* (green steel) */
5325       element = EL_STEEL_CHAR_B;
5326       break;
5327
5328     case 0x164d:        /* (green steel) */
5329       element = EL_STEEL_CHAR_C;
5330       break;
5331
5332     case 0x164e:        /* (green steel) */
5333       element = EL_STEEL_CHAR_D;
5334       break;
5335
5336     case 0x164f:        /* (green steel) */
5337       element = EL_STEEL_CHAR_E;
5338       break;
5339
5340     case 0x1650:        /* (green steel) */
5341       element = EL_STEEL_CHAR_F;
5342       break;
5343
5344     case 0x1651:        /* (green steel) */
5345       element = EL_STEEL_CHAR_G;
5346       break;
5347
5348     case 0x1652:        /* (green steel) */
5349       element = EL_STEEL_CHAR_H;
5350       break;
5351
5352     case 0x1653:        /* (green steel) */
5353       element = EL_STEEL_CHAR_I;
5354       break;
5355
5356     case 0x1654:        /* (green steel) */
5357       element = EL_STEEL_CHAR_J;
5358       break;
5359
5360     case 0x1655:        /* (green steel) */
5361       element = EL_STEEL_CHAR_K;
5362       break;
5363
5364     case 0x1656:        /* (green steel) */
5365       element = EL_STEEL_CHAR_L;
5366       break;
5367
5368     case 0x1657:        /* (green steel) */
5369       element = EL_STEEL_CHAR_M;
5370       break;
5371
5372     case 0x1658:        /* (green steel) */
5373       element = EL_STEEL_CHAR_N;
5374       break;
5375
5376     case 0x1659:        /* (green steel) */
5377       element = EL_STEEL_CHAR_O;
5378       break;
5379
5380     case 0x165a:        /* (green steel) */
5381       element = EL_STEEL_CHAR_P;
5382       break;
5383
5384     case 0x165b:        /* (green steel) */
5385       element = EL_STEEL_CHAR_Q;
5386       break;
5387
5388     case 0x165c:        /* (green steel) */
5389       element = EL_STEEL_CHAR_R;
5390       break;
5391
5392     case 0x165d:        /* (green steel) */
5393       element = EL_STEEL_CHAR_S;
5394       break;
5395
5396     case 0x165e:        /* (green steel) */
5397       element = EL_STEEL_CHAR_T;
5398       break;
5399
5400     case 0x165f:        /* (green steel) */
5401       element = EL_STEEL_CHAR_U;
5402       break;
5403
5404     case 0x1660:        /* (green steel) */
5405       element = EL_STEEL_CHAR_V;
5406       break;
5407
5408     case 0x1661:        /* (green steel) */
5409       element = EL_STEEL_CHAR_W;
5410       break;
5411
5412     case 0x1662:        /* (green steel) */
5413       element = EL_STEEL_CHAR_X;
5414       break;
5415
5416     case 0x1663:        /* (green steel) */
5417       element = EL_STEEL_CHAR_Y;
5418       break;
5419
5420     case 0x1664:        /* (green steel) */
5421       element = EL_STEEL_CHAR_Z;
5422       break;
5423
5424     case 0x1665:        /* (green steel) */
5425       element = EL_STEEL_CHAR_AUMLAUT;
5426       break;
5427
5428     case 0x1666:        /* (green steel) */
5429       element = EL_STEEL_CHAR_OUMLAUT;
5430       break;
5431
5432     case 0x1667:        /* (green steel) */
5433       element = EL_STEEL_CHAR_UUMLAUT;
5434       break;
5435
5436     case 0x1668:        /* (green steel) */
5437       element = EL_STEEL_CHAR_0;
5438       break;
5439
5440     case 0x1669:        /* (green steel) */
5441       element = EL_STEEL_CHAR_1;
5442       break;
5443
5444     case 0x166a:        /* (green steel) */
5445       element = EL_STEEL_CHAR_2;
5446       break;
5447
5448     case 0x166b:        /* (green steel) */
5449       element = EL_STEEL_CHAR_3;
5450       break;
5451
5452     case 0x166c:        /* (green steel) */
5453       element = EL_STEEL_CHAR_4;
5454       break;
5455
5456     case 0x166d:        /* (green steel) */
5457       element = EL_STEEL_CHAR_5;
5458       break;
5459
5460     case 0x166e:        /* (green steel) */
5461       element = EL_STEEL_CHAR_6;
5462       break;
5463
5464     case 0x166f:        /* (green steel) */
5465       element = EL_STEEL_CHAR_7;
5466       break;
5467
5468     case 0x1670:        /* (green steel) */
5469       element = EL_STEEL_CHAR_8;
5470       break;
5471
5472     case 0x1671:        /* (green steel) */
5473       element = EL_STEEL_CHAR_9;
5474       break;
5475
5476     case 0x1672:        /* (green steel) */
5477       element = EL_STEEL_CHAR_PERIOD;
5478       break;
5479
5480     case 0x1673:        /* (green steel) */
5481       element = EL_STEEL_CHAR_EXCLAM;
5482       break;
5483
5484     case 0x1674:        /* (green steel) */
5485       element = EL_STEEL_CHAR_COLON;
5486       break;
5487
5488     case 0x1675:        /* (green steel) */
5489       element = EL_STEEL_CHAR_LESS;
5490       break;
5491
5492     case 0x1676:        /* (green steel) */
5493       element = EL_STEEL_CHAR_GREATER;
5494       break;
5495
5496     case 0x1677:        /* (green steel) */
5497       element = EL_STEEL_CHAR_QUESTION;
5498       break;
5499
5500     case 0x1678:        /* (green steel) */
5501       element = EL_STEEL_CHAR_COPYRIGHT;
5502       break;
5503
5504     case 0x1679:        /* (green steel) */
5505       element = EL_STEEL_CHAR_UP;
5506       break;
5507
5508     case 0x167a:        /* (green steel) */
5509       element = EL_STEEL_CHAR_DOWN;
5510       break;
5511
5512     case 0x167b:        /* (green steel) */
5513       element = EL_STEEL_CHAR_BUTTON;
5514       break;
5515
5516     case 0x167c:        /* (green steel) */
5517       element = EL_STEEL_CHAR_PLUS;
5518       break;
5519
5520     case 0x167d:        /* (green steel) */
5521       element = EL_STEEL_CHAR_MINUS;
5522       break;
5523
5524     case 0x167e:        /* (green steel) */
5525       element = EL_STEEL_CHAR_APOSTROPHE;
5526       break;
5527
5528     case 0x167f:        /* (green steel) */
5529       element = EL_STEEL_CHAR_PARENLEFT;
5530       break;
5531
5532     case 0x1680:        /* (green steel) */
5533       element = EL_STEEL_CHAR_PARENRIGHT;
5534       break;
5535
5536     case 0x1681:        /* gate (red) */
5537       element = EL_EM_GATE_1;
5538       break;
5539
5540     case 0x1682:        /* secret gate (red) */
5541       element = EL_GATE_1_GRAY;
5542       break;
5543
5544     case 0x1683:        /* gate (yellow) */
5545       element = EL_EM_GATE_2;
5546       break;
5547
5548     case 0x1684:        /* secret gate (yellow) */
5549       element = EL_GATE_2_GRAY;
5550       break;
5551
5552     case 0x1685:        /* gate (blue) */
5553       element = EL_EM_GATE_4;
5554       break;
5555
5556     case 0x1686:        /* secret gate (blue) */
5557       element = EL_GATE_4_GRAY;
5558       break;
5559
5560     case 0x1687:        /* gate (green) */
5561       element = EL_EM_GATE_3;
5562       break;
5563
5564     case 0x1688:        /* secret gate (green) */
5565       element = EL_GATE_3_GRAY;
5566       break;
5567
5568     case 0x1689:        /* gate (white) */
5569       element = EL_DC_GATE_WHITE;
5570       break;
5571
5572     case 0x168a:        /* secret gate (white) */
5573       element = EL_DC_GATE_WHITE_GRAY;
5574       break;
5575
5576     case 0x168b:        /* secret gate (no key) */
5577       element = EL_DC_GATE_FAKE_GRAY;
5578       break;
5579
5580     case 0x168c:
5581       element = EL_ROBOT_WHEEL;
5582       break;
5583
5584     case 0x168d:
5585       element = EL_DC_TIMEGATE_SWITCH;
5586       break;
5587
5588     case 0x168e:
5589       element = EL_ACID_POOL_BOTTOM;
5590       break;
5591
5592     case 0x168f:
5593       element = EL_ACID_POOL_TOPLEFT;
5594       break;
5595
5596     case 0x1690:
5597       element = EL_ACID_POOL_TOPRIGHT;
5598       break;
5599
5600     case 0x1691:
5601       element = EL_ACID_POOL_BOTTOMLEFT;
5602       break;
5603
5604     case 0x1692:
5605       element = EL_ACID_POOL_BOTTOMRIGHT;
5606       break;
5607
5608     case 0x1693:
5609       element = EL_STEELWALL;
5610       break;
5611
5612     case 0x1694:
5613       element = EL_STEELWALL_SLIPPERY;
5614       break;
5615
5616     case 0x1695:        /* steel wall (not round) */
5617       element = EL_STEELWALL;
5618       break;
5619
5620     case 0x1696:        /* steel wall (left) */
5621       element = EL_DC_STEELWALL_1_LEFT;
5622       break;
5623
5624     case 0x1697:        /* steel wall (bottom) */
5625       element = EL_DC_STEELWALL_1_BOTTOM;
5626       break;
5627
5628     case 0x1698:        /* steel wall (right) */
5629       element = EL_DC_STEELWALL_1_RIGHT;
5630       break;
5631
5632     case 0x1699:        /* steel wall (top) */
5633       element = EL_DC_STEELWALL_1_TOP;
5634       break;
5635
5636     case 0x169a:        /* steel wall (left/bottom) */
5637       element = EL_DC_STEELWALL_1_BOTTOMLEFT;
5638       break;
5639
5640     case 0x169b:        /* steel wall (right/bottom) */
5641       element = EL_DC_STEELWALL_1_BOTTOMRIGHT;
5642       break;
5643
5644     case 0x169c:        /* steel wall (right/top) */
5645       element = EL_DC_STEELWALL_1_TOPRIGHT;
5646       break;
5647
5648     case 0x169d:        /* steel wall (left/top) */
5649       element = EL_DC_STEELWALL_1_TOPLEFT;
5650       break;
5651
5652     case 0x169e:        /* steel wall (right/bottom small) */
5653       element = EL_DC_STEELWALL_1_BOTTOMRIGHT_2;
5654       break;
5655
5656     case 0x169f:        /* steel wall (left/bottom small) */
5657       element = EL_DC_STEELWALL_1_BOTTOMLEFT_2;
5658       break;
5659
5660     case 0x16a0:        /* steel wall (right/top small) */
5661       element = EL_DC_STEELWALL_1_TOPRIGHT_2;
5662       break;
5663
5664     case 0x16a1:        /* steel wall (left/top small) */
5665       element = EL_DC_STEELWALL_1_TOPLEFT_2;
5666       break;
5667
5668     case 0x16a2:        /* steel wall (left/right) */
5669       element = EL_DC_STEELWALL_1_VERTICAL;
5670       break;
5671
5672     case 0x16a3:        /* steel wall (top/bottom) */
5673       element = EL_DC_STEELWALL_1_HORIZONTAL;
5674       break;
5675
5676     case 0x16a4:        /* steel wall 2 (left end) */
5677       element = EL_DC_STEELWALL_2_LEFT;
5678       break;
5679
5680     case 0x16a5:        /* steel wall 2 (right end) */
5681       element = EL_DC_STEELWALL_2_RIGHT;
5682       break;
5683
5684     case 0x16a6:        /* steel wall 2 (top end) */
5685       element = EL_DC_STEELWALL_2_TOP;
5686       break;
5687
5688     case 0x16a7:        /* steel wall 2 (bottom end) */
5689       element = EL_DC_STEELWALL_2_BOTTOM;
5690       break;
5691
5692     case 0x16a8:        /* steel wall 2 (left/right) */
5693       element = EL_DC_STEELWALL_2_HORIZONTAL;
5694       break;
5695
5696     case 0x16a9:        /* steel wall 2 (up/down) */
5697       element = EL_DC_STEELWALL_2_VERTICAL;
5698       break;
5699
5700     case 0x16aa:        /* steel wall 2 (mid) */
5701       element = EL_DC_STEELWALL_2_MIDDLE;
5702       break;
5703
5704     case 0x16ab:
5705       element = EL_SIGN_EXCLAMATION;
5706       break;
5707
5708     case 0x16ac:
5709       element = EL_SIGN_RADIOACTIVITY;
5710       break;
5711
5712     case 0x16ad:
5713       element = EL_SIGN_STOP;
5714       break;
5715
5716     case 0x16ae:
5717       element = EL_SIGN_WHEELCHAIR;
5718       break;
5719
5720     case 0x16af:
5721       element = EL_SIGN_PARKING;
5722       break;
5723
5724     case 0x16b0:
5725       element = EL_SIGN_NO_ENTRY;
5726       break;
5727
5728     case 0x16b1:
5729       element = EL_SIGN_HEART;
5730       break;
5731
5732     case 0x16b2:
5733       element = EL_SIGN_GIVE_WAY;
5734       break;
5735
5736     case 0x16b3:
5737       element = EL_SIGN_ENTRY_FORBIDDEN;
5738       break;
5739
5740     case 0x16b4:
5741       element = EL_SIGN_EMERGENCY_EXIT;
5742       break;
5743
5744     case 0x16b5:
5745       element = EL_SIGN_YIN_YANG;
5746       break;
5747
5748     case 0x16b6:
5749       element = EL_WALL_EMERALD;
5750       break;
5751
5752     case 0x16b7:
5753       element = EL_WALL_DIAMOND;
5754       break;
5755
5756     case 0x16b8:
5757       element = EL_WALL_PEARL;
5758       break;
5759
5760     case 0x16b9:
5761       element = EL_WALL_CRYSTAL;
5762       break;
5763
5764     case 0x16ba:
5765       element = EL_INVISIBLE_WALL;
5766       break;
5767
5768     case 0x16bb:
5769       element = EL_INVISIBLE_STEELWALL;
5770       break;
5771
5772       /* 0x16bc - 0x16cb: */
5773       /* EL_INVISIBLE_SAND */
5774
5775     case 0x16cc:
5776       element = EL_LIGHT_SWITCH;
5777       break;
5778
5779     case 0x16cd:
5780       element = EL_ENVELOPE_1;
5781       break;
5782
5783     default:
5784       if (element >= 0x0117 && element <= 0x036e)       /* (?) */
5785         element = EL_DIAMOND;
5786       else if (element >= 0x042d && element <= 0x0684)  /* (?) */
5787         element = EL_EMERALD;
5788       else if (element >= 0x157c && element <= 0x158b)
5789         element = EL_SAND;
5790       else if (element >= 0x1590 && element <= 0x159f)
5791         element = EL_DC_LANDMINE;
5792       else if (element >= 0x16bc && element <= 0x16cb)
5793         element = EL_INVISIBLE_SAND;
5794       else
5795       {
5796         Error(ERR_WARN, "unknown Diamond Caves element 0x%04x", element);
5797         element = EL_UNKNOWN;
5798       }
5799       break;
5800   }
5801
5802   return getMappedElement(element);
5803 }
5804
5805 #if 1
5806
5807 static void LoadLevelFromFileStream_DC(FILE *file, struct LevelInfo *level,
5808                                        int nr)
5809 {
5810   byte header[DC_LEVEL_HEADER_SIZE];
5811   int envelope_size;
5812   int envelope_header_pos = 62;
5813   int envelope_content_pos = 94;
5814   int level_name_pos = 251;
5815   int level_author_pos = 292;
5816   int envelope_header_len;
5817   int envelope_content_len;
5818   int level_name_len;
5819   int level_author_len;
5820   int fieldx, fieldy;
5821   int num_yamyam_contents;
5822   int i, x, y;
5823
5824   getDecodedWord_DC(0, TRUE);           /* initialize DC2 decoding engine */
5825
5826   for (i = 0; i < DC_LEVEL_HEADER_SIZE / 2; i++)
5827   {
5828     unsigned short header_word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
5829
5830     header[i * 2 + 0] = header_word >> 8;
5831     header[i * 2 + 1] = header_word & 0xff;
5832   }
5833
5834   /* read some values from level header to check level decoding integrity */
5835   fieldx = header[6] | (header[7] << 8);
5836   fieldy = header[8] | (header[9] << 8);
5837   num_yamyam_contents = header[60] | (header[61] << 8);
5838
5839   /* do some simple sanity checks to ensure that level was correctly decoded */
5840   if (fieldx < 1 || fieldx > 256 ||
5841       fieldy < 1 || fieldy > 256 ||
5842       num_yamyam_contents < 1 || num_yamyam_contents > 8)
5843   {
5844     level->no_valid_file = TRUE;
5845
5846     Error(ERR_WARN, "cannot decode level from stream -- using empty level");
5847
5848     return;
5849   }
5850
5851   /* maximum envelope header size is 31 bytes */
5852   envelope_header_len   = header[envelope_header_pos];
5853   /* maximum envelope content size is 110 (156?) bytes */
5854   envelope_content_len  = header[envelope_content_pos];
5855
5856   /* maximum level title size is 40 bytes */
5857   level_name_len        = MIN(header[level_name_pos],   MAX_LEVEL_NAME_LEN);
5858   /* maximum level author size is 30 (51?) bytes */
5859   level_author_len      = MIN(header[level_author_pos], MAX_LEVEL_AUTHOR_LEN);
5860
5861   envelope_size = 0;
5862
5863   for (i = 0; i < envelope_header_len; i++)
5864     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
5865       level->envelope[0].text[envelope_size++] =
5866         header[envelope_header_pos + 1 + i];
5867
5868   if (envelope_header_len > 0 && envelope_content_len > 0)
5869   {
5870     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
5871       level->envelope[0].text[envelope_size++] = '\n';
5872     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
5873       level->envelope[0].text[envelope_size++] = '\n';
5874   }
5875
5876   for (i = 0; i < envelope_content_len; i++)
5877     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
5878       level->envelope[0].text[envelope_size++] =
5879         header[envelope_content_pos + 1 + i];
5880
5881   level->envelope[0].text[envelope_size] = '\0';
5882
5883   level->envelope[0].xsize = MAX_ENVELOPE_XSIZE;
5884   level->envelope[0].ysize = 10;
5885   level->envelope[0].autowrap = TRUE;
5886   level->envelope[0].centered = TRUE;
5887
5888   for (i = 0; i < level_name_len; i++)
5889     level->name[i] = header[level_name_pos + 1 + i];
5890   level->name[level_name_len] = '\0';
5891
5892   for (i = 0; i < level_author_len; i++)
5893     level->author[i] = header[level_author_pos + 1 + i];
5894   level->author[level_author_len] = '\0';
5895
5896   num_yamyam_contents = header[60] | (header[61] << 8);
5897   level->num_yamyam_contents =
5898     MIN(MAX(MIN_ELEMENT_CONTENTS, num_yamyam_contents), MAX_ELEMENT_CONTENTS);
5899
5900   for (i = 0; i < num_yamyam_contents; i++)
5901   {
5902     for (y = 0; y < 3; y++) for (x = 0; x < 3; x++)
5903     {
5904       unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
5905 #if 1
5906       int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff);
5907 #else
5908       int element_dc = word;
5909 #endif
5910
5911       if (i < MAX_ELEMENT_CONTENTS)
5912         level->yamyam_content[i].e[x][y] = getMappedElement_DC(element_dc);
5913     }
5914   }
5915
5916   fieldx = header[6] | (header[7] << 8);
5917   fieldy = header[8] | (header[9] << 8);
5918   level->fieldx = MIN(MAX(MIN_LEV_FIELDX, fieldx), MAX_LEV_FIELDX);
5919   level->fieldy = MIN(MAX(MIN_LEV_FIELDY, fieldy), MAX_LEV_FIELDY);
5920
5921   for (y = 0; y < fieldy; y++) for (x = 0; x < fieldx; x++)
5922   {
5923     unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
5924 #if 1
5925     int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff);
5926 #else
5927     int element_dc = word;
5928 #endif
5929
5930     if (x < MAX_LEV_FIELDX && y < MAX_LEV_FIELDY)
5931       level->field[x][y] = getMappedElement_DC(element_dc);
5932   }
5933
5934   x = MIN(MAX(0, (header[10] | (header[11] << 8)) - 1), MAX_LEV_FIELDX - 1);
5935   y = MIN(MAX(0, (header[12] | (header[13] << 8)) - 1), MAX_LEV_FIELDY - 1);
5936   level->field[x][y] = EL_PLAYER_1;
5937
5938   x = MIN(MAX(0, (header[14] | (header[15] << 8)) - 1), MAX_LEV_FIELDX - 1);
5939   y = MIN(MAX(0, (header[16] | (header[17] << 8)) - 1), MAX_LEV_FIELDY - 1);
5940   level->field[x][y] = EL_PLAYER_2;
5941
5942   level->gems_needed            = header[18] | (header[19] << 8);
5943
5944   level->score[SC_EMERALD]      = header[20] | (header[21] << 8);
5945   level->score[SC_DIAMOND]      = header[22] | (header[23] << 8);
5946   level->score[SC_PEARL]        = header[24] | (header[25] << 8);
5947   level->score[SC_CRYSTAL]      = header[26] | (header[27] << 8);
5948   level->score[SC_NUT]          = header[28] | (header[29] << 8);
5949   level->score[SC_ROBOT]        = header[30] | (header[31] << 8);
5950   level->score[SC_SPACESHIP]    = header[32] | (header[33] << 8);
5951   level->score[SC_BUG]          = header[34] | (header[35] << 8);
5952   level->score[SC_YAMYAM]       = header[36] | (header[37] << 8);
5953   level->score[SC_DYNAMITE]     = header[38] | (header[39] << 8);
5954   level->score[SC_KEY]          = header[40] | (header[41] << 8);
5955   level->score[SC_TIME_BONUS]   = header[42] | (header[43] << 8);
5956
5957   level->time                   = header[44] | (header[45] << 8);
5958
5959   level->amoeba_speed           = header[46] | (header[47] << 8);
5960   level->time_light             = header[48] | (header[49] << 8);
5961   level->time_timegate          = header[50] | (header[51] << 8);
5962   level->time_wheel             = header[52] | (header[53] << 8);
5963   level->time_magic_wall        = header[54] | (header[55] << 8);
5964   level->extra_time             = header[56] | (header[57] << 8);
5965   level->shield_normal_time     = header[58] | (header[59] << 8);
5966
5967   /* Diamond Caves has the same (strange) behaviour as Emerald Mine that gems
5968      can slip down from flat walls, like normal walls and steel walls */
5969   level->em_slippery_gems = TRUE;
5970
5971 #if 0
5972   /* Diamond Caves II levels are always surrounded by indestructible wall, but
5973      not necessarily in a rectangular way -- fill with invisible steel wall */
5974
5975   /* !!! not always true !!! keep level and set BorderElement instead !!! */
5976
5977   for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
5978   {
5979 #if 1
5980     if ((x == 0 || x == level->fieldx - 1 ||
5981          y == 0 || y == level->fieldy - 1) &&
5982         level->field[x][y] == EL_EMPTY)
5983       level->field[x][y] = EL_INVISIBLE_STEELWALL;
5984 #else
5985     if ((x == 0 || x == level->fieldx - 1 ||
5986          y == 0 || y == level->fieldy - 1) &&
5987         level->field[x][y] == EL_EMPTY)
5988       FloodFillLevel(x, y, EL_INVISIBLE_STEELWALL,
5989                      level->field, level->fieldx, level->fieldy);
5990 #endif
5991   }
5992 #endif
5993 }
5994
5995 static void LoadLevelFromFileInfo_DC(struct LevelInfo *level,
5996                                      struct LevelFileInfo *level_file_info)
5997 {
5998   char *filename = level_file_info->filename;
5999   FILE *file;
6000   int num_magic_bytes = 8;
6001   char magic_bytes[num_magic_bytes + 1];
6002   int num_levels_to_skip = level_file_info->nr - leveldir_current->first_level;
6003
6004   if (!(file = fopen(filename, MODE_READ)))
6005   {
6006     level->no_valid_file = TRUE;
6007
6008     Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
6009
6010     return;
6011   }
6012
6013   // fseek(file, 0x0000, SEEK_SET);
6014
6015   if (level_file_info->packed)
6016   {
6017     /* read "magic bytes" from start of file */
6018     fgets(magic_bytes, num_magic_bytes + 1, file);
6019
6020     /* check "magic bytes" for correct file format */
6021     if (!strPrefix(magic_bytes, "DC2"))
6022     {
6023       level->no_valid_file = TRUE;
6024
6025       Error(ERR_WARN, "unknown DC level file '%s' -- using empty level",
6026             filename);
6027
6028       return;
6029     }
6030
6031     if (strPrefix(magic_bytes, "DC2Win95") ||
6032         strPrefix(magic_bytes, "DC2Win98"))
6033     {
6034       int position_first_level = 0x00fa;
6035       int extra_bytes = 4;
6036       int skip_bytes;
6037
6038       /* advance file stream to first level inside the level package */
6039       skip_bytes = position_first_level - num_magic_bytes - extra_bytes;
6040
6041       /* each block of level data is followed by block of non-level data */
6042       num_levels_to_skip *= 2;
6043
6044       /* at least skip header bytes, therefore use ">= 0" instead of "> 0" */
6045       while (num_levels_to_skip >= 0)
6046       {
6047         /* advance file stream to next level inside the level package */
6048         if (fseek(file, skip_bytes, SEEK_CUR) != 0)
6049         {
6050           level->no_valid_file = TRUE;
6051
6052           Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level",
6053                 filename);
6054
6055           return;
6056         }
6057
6058         /* skip apparently unused extra bytes following each level */
6059         ReadUnusedBytesFromFile(file, extra_bytes);
6060
6061         /* read size of next level in level package */
6062         skip_bytes = getFile32BitLE(file);
6063
6064         num_levels_to_skip--;
6065       }
6066     }
6067     else
6068     {
6069       level->no_valid_file = TRUE;
6070
6071       Error(ERR_WARN, "unknown DC2 level file '%s' -- using empty level",
6072             filename);
6073
6074       return;
6075     }
6076   }
6077
6078   LoadLevelFromFileStream_DC(file, level, level_file_info->nr);
6079
6080   fclose(file);
6081 }
6082
6083 #else
6084
6085 static void LoadLevelFromFileInfo_DC(struct LevelInfo *level,
6086                                      struct LevelFileInfo *level_file_info)
6087 {
6088   char *filename = level_file_info->filename;
6089   FILE *file;
6090 #if 0
6091   int nr = level_file_info->nr - leveldir_current->first_level;
6092 #endif
6093   byte header[DC_LEVEL_HEADER_SIZE];
6094   int envelope_size;
6095   int envelope_header_pos = 62;
6096   int envelope_content_pos = 94;
6097   int level_name_pos = 251;
6098   int level_author_pos = 292;
6099   int envelope_header_len;
6100   int envelope_content_len;
6101   int level_name_len;
6102   int level_author_len;
6103   int fieldx, fieldy;
6104   int num_yamyam_contents;
6105   int i, x, y;
6106
6107   if (!(file = fopen(filename, MODE_READ)))
6108   {
6109     level->no_valid_file = TRUE;
6110
6111     Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
6112
6113     return;
6114   }
6115
6116 #if 0
6117   /* position file stream to the requested level inside the level package */
6118   if (fseek(file, nr * SP_LEVEL_SIZE, SEEK_SET) != 0)
6119   {
6120     level->no_valid_file = TRUE;
6121
6122     Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level", filename);
6123
6124     return;
6125   }
6126 #endif
6127
6128   getDecodedWord_DC(0, TRUE);           /* initialize DC2 decoding engine */
6129
6130   for (i = 0; i < DC_LEVEL_HEADER_SIZE / 2; i++)
6131   {
6132     unsigned short header_word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
6133
6134     header[i * 2 + 0] = header_word >> 8;
6135     header[i * 2 + 1] = header_word & 0xff;
6136   }
6137
6138   /* read some values from level header to check level decoding integrity */
6139   fieldx = header[6] | (header[7] << 8);
6140   fieldy = header[8] | (header[9] << 8);
6141   num_yamyam_contents = header[60] | (header[61] << 8);
6142
6143   /* do some simple sanity checks to ensure that level was correctly decoded */
6144   if (fieldx < 1 || fieldx > 256 ||
6145       fieldy < 1 || fieldy > 256 ||
6146       num_yamyam_contents < 1 || num_yamyam_contents > 8)
6147   {
6148     level->no_valid_file = TRUE;
6149
6150     Error(ERR_WARN, "cannot read level from file '%s' -- using empty level",
6151           filename);
6152
6153     return;
6154   }
6155
6156   /* maximum envelope header size is 31 bytes */
6157   envelope_header_len   = header[envelope_header_pos];
6158   /* maximum envelope content size is 110 (156?) bytes */
6159   envelope_content_len  = header[envelope_content_pos];
6160
6161   /* maximum level title size is 40 bytes */
6162   level_name_len        = MIN(header[level_name_pos],   MAX_LEVEL_NAME_LEN);
6163   /* maximum level author size is 30 (51?) bytes */
6164   level_author_len      = MIN(header[level_author_pos], MAX_LEVEL_AUTHOR_LEN);
6165
6166   envelope_size = 0;
6167
6168   for (i = 0; i < envelope_header_len; i++)
6169     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
6170       level->envelope[0].text[envelope_size++] =
6171         header[envelope_header_pos + 1 + i];
6172
6173   if (envelope_header_len > 0 && envelope_content_len > 0)
6174   {
6175     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
6176       level->envelope[0].text[envelope_size++] = '\n';
6177     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
6178       level->envelope[0].text[envelope_size++] = '\n';
6179   }
6180
6181   for (i = 0; i < envelope_content_len; i++)
6182     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
6183       level->envelope[0].text[envelope_size++] =
6184         header[envelope_content_pos + 1 + i];
6185
6186   level->envelope[0].text[envelope_size] = '\0';
6187
6188   level->envelope[0].xsize = MAX_ENVELOPE_XSIZE;
6189   level->envelope[0].ysize = 10;
6190   level->envelope[0].autowrap = TRUE;
6191   level->envelope[0].centered = TRUE;
6192
6193   for (i = 0; i < level_name_len; i++)
6194     level->name[i] = header[level_name_pos + 1 + i];
6195   level->name[level_name_len] = '\0';
6196
6197   for (i = 0; i < level_author_len; i++)
6198     level->author[i] = header[level_author_pos + 1 + i];
6199   level->author[level_author_len] = '\0';
6200
6201   num_yamyam_contents = header[60] | (header[61] << 8);
6202   level->num_yamyam_contents =
6203     MIN(MAX(MIN_ELEMENT_CONTENTS, num_yamyam_contents), MAX_ELEMENT_CONTENTS);
6204
6205   for (i = 0; i < num_yamyam_contents; i++)
6206   {
6207     for (y = 0; y < 3; y++) for (x = 0; x < 3; x++)
6208     {
6209       unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
6210 #if 1
6211       int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff);
6212 #else
6213       int element_dc = word;
6214 #endif
6215
6216       if (i < MAX_ELEMENT_CONTENTS)
6217         level->yamyam_content[i].e[x][y] = getMappedElement_DC(element_dc);
6218     }
6219   }
6220
6221   fieldx = header[6] | (header[7] << 8);
6222   fieldy = header[8] | (header[9] << 8);
6223   level->fieldx = MIN(MAX(MIN_LEV_FIELDX, fieldx), MAX_LEV_FIELDX);
6224   level->fieldy = MIN(MAX(MIN_LEV_FIELDY, fieldy), MAX_LEV_FIELDY);
6225
6226   for (y = 0; y < fieldy; y++) for (x = 0; x < fieldx; x++)
6227   {
6228     unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
6229 #if 1
6230     int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff);
6231 #else
6232     int element_dc = word;
6233 #endif
6234
6235     if (x < MAX_LEV_FIELDX && y < MAX_LEV_FIELDY)
6236       level->field[x][y] = getMappedElement_DC(element_dc);
6237   }
6238
6239   x = MIN(MAX(0, (header[10] | (header[11] << 8)) - 1), MAX_LEV_FIELDX - 1);
6240   y = MIN(MAX(0, (header[12] | (header[13] << 8)) - 1), MAX_LEV_FIELDY - 1);
6241   level->field[x][y] = EL_PLAYER_1;
6242
6243   x = MIN(MAX(0, (header[14] | (header[15] << 8)) - 1), MAX_LEV_FIELDX - 1);
6244   y = MIN(MAX(0, (header[16] | (header[17] << 8)) - 1), MAX_LEV_FIELDY - 1);
6245   level->field[x][y] = EL_PLAYER_2;
6246
6247   level->gems_needed            = header[18] | (header[19] << 8);
6248
6249   level->score[SC_EMERALD]      = header[20] | (header[21] << 8);
6250   level->score[SC_DIAMOND]      = header[22] | (header[23] << 8);
6251   level->score[SC_PEARL]        = header[24] | (header[25] << 8);
6252   level->score[SC_CRYSTAL]      = header[26] | (header[27] << 8);
6253   level->score[SC_NUT]          = header[28] | (header[29] << 8);
6254   level->score[SC_ROBOT]        = header[30] | (header[31] << 8);
6255   level->score[SC_SPACESHIP]    = header[32] | (header[33] << 8);
6256   level->score[SC_BUG]          = header[34] | (header[35] << 8);
6257   level->score[SC_YAMYAM]       = header[36] | (header[37] << 8);
6258   level->score[SC_DYNAMITE]     = header[38] | (header[39] << 8);
6259   level->score[SC_KEY]          = header[40] | (header[41] << 8);
6260   level->score[SC_TIME_BONUS]   = header[42] | (header[43] << 8);
6261
6262   level->time                   = header[44] | (header[45] << 8);
6263
6264   level->amoeba_speed           = header[46] | (header[47] << 8);
6265   level->time_light             = header[48] | (header[49] << 8);
6266   level->time_timegate          = header[50] | (header[51] << 8);
6267   level->time_wheel             = header[52] | (header[53] << 8);
6268   level->time_magic_wall        = header[54] | (header[55] << 8);
6269   level->extra_time             = header[56] | (header[57] << 8);
6270   level->shield_normal_time     = header[58] | (header[59] << 8);
6271
6272   fclose(file);
6273
6274   /* Diamond Caves has the same (strange) behaviour as Emerald Mine that gems
6275      can slip down from flat walls, like normal walls and steel walls */
6276   level->em_slippery_gems = TRUE;
6277
6278 #if 0
6279   /* Diamond Caves II levels are always surrounded by indestructible wall, but
6280      not necessarily in a rectangular way -- fill with invisible steel wall */
6281
6282   /* !!! not always true !!! keep level and set BorderElement instead !!! */
6283
6284   for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
6285   {
6286 #if 1
6287     if ((x == 0 || x == level->fieldx - 1 ||
6288          y == 0 || y == level->fieldy - 1) &&
6289         level->field[x][y] == EL_EMPTY)
6290       level->field[x][y] = EL_INVISIBLE_STEELWALL;
6291 #else
6292     if ((x == 0 || x == level->fieldx - 1 ||
6293          y == 0 || y == level->fieldy - 1) &&
6294         level->field[x][y] == EL_EMPTY)
6295       FloodFillLevel(x, y, EL_INVISIBLE_STEELWALL,
6296                      level->field, level->fieldx, level->fieldy);
6297 #endif
6298   }
6299 #endif
6300 }
6301
6302 #endif
6303
6304
6305 /* ------------------------------------------------------------------------- */
6306 /* functions for handling native levels                                      */
6307 /* ------------------------------------------------------------------------- */
6308
6309 static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,
6310                                      struct LevelFileInfo *level_file_info)
6311 {
6312   if (!LoadNativeLevel_EM(level_file_info->filename))
6313     level->no_valid_file = TRUE;
6314 }
6315
6316 static void LoadLevelFromFileInfo_SP(struct LevelInfo *level,
6317                                      struct LevelFileInfo *level_file_info)
6318 {
6319   int pos = 0;
6320
6321   /* determine position of requested level inside level package */
6322   if (level_file_info->packed)
6323     pos = level_file_info->nr - leveldir_current->first_level;
6324
6325   if (!LoadNativeLevel_SP(level_file_info->filename, pos))
6326     level->no_valid_file = TRUE;
6327 }
6328
6329 void CopyNativeLevel_RND_to_Native(struct LevelInfo *level)
6330 {
6331   if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
6332     CopyNativeLevel_RND_to_EM(level);
6333   else if (level->game_engine_type == GAME_ENGINE_TYPE_SP)
6334     CopyNativeLevel_RND_to_SP(level);
6335 }
6336
6337 void CopyNativeLevel_Native_to_RND(struct LevelInfo *level)
6338 {
6339   if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
6340     CopyNativeLevel_EM_to_RND(level);
6341   else if (level->game_engine_type == GAME_ENGINE_TYPE_SP)
6342     CopyNativeLevel_SP_to_RND(level);
6343 }
6344
6345
6346 /* ------------------------------------------------------------------------- */
6347 /* functions for loading generic level                                       */
6348 /* ------------------------------------------------------------------------- */
6349
6350 void LoadLevelFromFileInfo(struct LevelInfo *level,
6351                            struct LevelFileInfo *level_file_info)
6352 {
6353   /* always start with reliable default values */
6354   setLevelInfoToDefaults(level);
6355
6356   switch (level_file_info->type)
6357   {
6358     case LEVEL_FILE_TYPE_RND:
6359       LoadLevelFromFileInfo_RND(level, level_file_info);
6360       break;
6361
6362     case LEVEL_FILE_TYPE_EM:
6363       LoadLevelFromFileInfo_EM(level, level_file_info);
6364       level->game_engine_type = GAME_ENGINE_TYPE_EM;
6365       break;
6366
6367     case LEVEL_FILE_TYPE_SP:
6368       LoadLevelFromFileInfo_SP(level, level_file_info);
6369       level->game_engine_type = GAME_ENGINE_TYPE_SP;
6370       break;
6371
6372     case LEVEL_FILE_TYPE_DC:
6373       LoadLevelFromFileInfo_DC(level, level_file_info);
6374       break;
6375
6376     default:
6377       LoadLevelFromFileInfo_RND(level, level_file_info);
6378       break;
6379   }
6380
6381   /* if level file is invalid, restore level structure to default values */
6382   if (level->no_valid_file)
6383     setLevelInfoToDefaults(level);
6384
6385   if (level->game_engine_type == GAME_ENGINE_TYPE_UNKNOWN)
6386     level->game_engine_type = GAME_ENGINE_TYPE_RND;
6387
6388   if (level_file_info->type != LEVEL_FILE_TYPE_RND)
6389     CopyNativeLevel_Native_to_RND(level);
6390 }
6391
6392 void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
6393 {
6394   static struct LevelFileInfo level_file_info;
6395
6396   /* always start with reliable default values */
6397   setFileInfoToDefaults(&level_file_info);
6398
6399   level_file_info.nr = 0;                       /* unknown level number */
6400   level_file_info.type = LEVEL_FILE_TYPE_RND;   /* no others supported yet */
6401   level_file_info.filename = filename;
6402
6403   LoadLevelFromFileInfo(level, &level_file_info);
6404 }
6405
6406 static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
6407 {
6408   int i, j;
6409
6410   if (leveldir_current == NULL)         /* only when dumping level */
6411     return;
6412
6413   /* all engine modifications also valid for levels which use latest engine */
6414   if (level->game_version < VERSION_IDENT(3,2,0,5))
6415   {
6416     /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */
6417     level->score[SC_TIME_BONUS] /= 10;
6418   }
6419
6420 #if 0
6421   leveldir_current->latest_engine = TRUE;       /* !!! TEST ONLY !!! */
6422 #endif
6423
6424   if (leveldir_current->latest_engine)
6425   {
6426     /* ---------- use latest game engine ----------------------------------- */
6427
6428     /* For all levels which are forced to use the latest game engine version
6429        (normally all but user contributed, private and undefined levels), set
6430        the game engine version to the actual version; this allows for actual
6431        corrections in the game engine to take effect for existing, converted
6432        levels (from "classic" or other existing games) to make the emulation
6433        of the corresponding game more accurate, while (hopefully) not breaking
6434        existing levels created from other players. */
6435
6436     level->game_version = GAME_VERSION_ACTUAL;
6437
6438     /* Set special EM style gems behaviour: EM style gems slip down from
6439        normal, steel and growing wall. As this is a more fundamental change,
6440        it seems better to set the default behaviour to "off" (as it is more
6441        natural) and make it configurable in the level editor (as a property
6442        of gem style elements). Already existing converted levels (neither
6443        private nor contributed levels) are changed to the new behaviour. */
6444
6445     if (level->file_version < FILE_VERSION_2_0)
6446       level->em_slippery_gems = TRUE;
6447
6448     return;
6449   }
6450
6451   /* ---------- use game engine the level was created with ----------------- */
6452
6453   /* For all levels which are not forced to use the latest game engine
6454      version (normally user contributed, private and undefined levels),
6455      use the version of the game engine the levels were created for.
6456
6457      Since 2.0.1, the game engine version is now directly stored
6458      in the level file (chunk "VERS"), so there is no need anymore
6459      to set the game version from the file version (except for old,
6460      pre-2.0 levels, where the game version is still taken from the
6461      file format version used to store the level -- see above). */
6462
6463   /* player was faster than enemies in 1.0.0 and before */
6464   if (level->file_version == FILE_VERSION_1_0)
6465     for (i = 0; i < MAX_PLAYERS; i++)
6466       level->initial_player_stepsize[i] = STEPSIZE_FAST;
6467
6468   /* default behaviour for EM style gems was "slippery" only in 2.0.1 */
6469   if (level->game_version == VERSION_IDENT(2,0,1,0))
6470     level->em_slippery_gems = TRUE;
6471
6472   /* springs could be pushed over pits before (pre-release version) 2.2.0 */
6473   if (level->game_version < VERSION_IDENT(2,2,0,0))
6474     level->use_spring_bug = TRUE;
6475
6476   if (level->game_version < VERSION_IDENT(3,2,0,5))
6477   {
6478     /* time orb caused limited time in endless time levels before 3.2.0-5 */
6479     level->use_time_orb_bug = TRUE;
6480
6481     /* default behaviour for snapping was "no snap delay" before 3.2.0-5 */
6482     level->block_snap_field = FALSE;
6483
6484     /* extra time score was same value as time left score before 3.2.0-5 */
6485     level->extra_time_score = level->score[SC_TIME_BONUS];
6486
6487 #if 0
6488     /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */
6489     level->score[SC_TIME_BONUS] /= 10;
6490 #endif
6491   }
6492
6493   if (level->game_version < VERSION_IDENT(3,2,0,7))
6494   {
6495     /* default behaviour for snapping was "not continuous" before 3.2.0-7 */
6496     level->continuous_snapping = FALSE;
6497   }
6498
6499   /* only few elements were able to actively move into acid before 3.1.0 */
6500   /* trigger settings did not exist before 3.1.0; set to default "any" */
6501   if (level->game_version < VERSION_IDENT(3,1,0,0))
6502   {
6503     /* correct "can move into acid" settings (all zero in old levels) */
6504
6505     level->can_move_into_acid_bits = 0; /* nothing can move into acid */
6506     level->dont_collide_with_bits = 0; /* nothing is deadly when colliding */
6507
6508     setMoveIntoAcidProperty(level, EL_ROBOT,     TRUE);
6509     setMoveIntoAcidProperty(level, EL_SATELLITE, TRUE);
6510     setMoveIntoAcidProperty(level, EL_PENGUIN,   TRUE);
6511     setMoveIntoAcidProperty(level, EL_BALLOON,   TRUE);
6512
6513     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6514       SET_PROPERTY(EL_CUSTOM_START + i, EP_CAN_MOVE_INTO_ACID, TRUE);
6515
6516     /* correct trigger settings (stored as zero == "none" in old levels) */
6517
6518     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6519     {
6520       int element = EL_CUSTOM_START + i;
6521       struct ElementInfo *ei = &element_info[element];
6522
6523       for (j = 0; j < ei->num_change_pages; j++)
6524       {
6525         struct ElementChangeInfo *change = &ei->change_page[j];
6526
6527         change->trigger_player = CH_PLAYER_ANY;
6528         change->trigger_page = CH_PAGE_ANY;
6529       }
6530     }
6531   }
6532
6533   /* try to detect and fix "Snake Bite" levels, which are broken with 3.2.0 */
6534   {
6535     int element = EL_CUSTOM_256;
6536     struct ElementInfo *ei = &element_info[element];
6537     struct ElementChangeInfo *change = &ei->change_page[0];
6538
6539     /* This is needed to fix a problem that was caused by a bugfix in function
6540        game.c/CreateFieldExt() introduced with 3.2.0 that corrects the behaviour
6541        when a custom element changes to EL_SOKOBAN_FIELD_PLAYER (before, it did
6542        not replace walkable elements, but instead just placed the player on it,
6543        without placing the Sokoban field under the player). Unfortunately, this
6544        breaks "Snake Bite" style levels when the snake is halfway through a door
6545        that just closes (the snake head is still alive and can be moved in this
6546        case). This can be fixed by replacing the EL_SOKOBAN_FIELD_PLAYER by the
6547        player (without Sokoban element) which then gets killed as designed). */
6548
6549     if ((strncmp(leveldir_current->identifier, "snake_bite", 10) == 0 ||
6550          strncmp(ei->description, "pause b4 death", 14) == 0) &&
6551         change->target_element == EL_SOKOBAN_FIELD_PLAYER)
6552       change->target_element = EL_PLAYER_1;
6553   }
6554
6555 #if 1
6556   /* try to detect and fix "Zelda" style levels, which are broken with 3.2.5 */
6557   if (level->game_version < VERSION_IDENT(3,2,5,0))
6558   {
6559     /* This is needed to fix a problem that was caused by a bugfix in function
6560        game.c/CheckTriggeredElementChangeExt() introduced with 3.2.5 that
6561        corrects the behaviour when a custom element changes to another custom
6562        element with a higher element number that has change actions defined.
6563        Normally, only one change per frame is allowed for custom elements.
6564        Therefore, it is checked if a custom element already changed in the
6565        current frame; if it did, subsequent changes are suppressed.
6566        Unfortunately, this is only checked for element changes, but not for
6567        change actions, which are still executed. As the function above loops
6568        through all custom elements from lower to higher, an element change
6569        resulting in a lower CE number won't be checked again, while a target
6570        element with a higher number will also be checked, and potential change
6571        actions will get executed for this CE, too (which is wrong), while
6572        further changes are ignored (which is correct). As this bugfix breaks
6573        Zelda II (and introduces graphical bugs to Zelda I, and also breaks a
6574        few other levels like Alan Bond's "FMV"), allow the previous, incorrect
6575        behaviour for existing levels and tapes that make use of this bug */
6576
6577     level->use_action_after_change_bug = TRUE;
6578   }
6579 #else
6580   /* !!! THIS DOES NOT FIX "Zelda I" (GRAPHICALLY) AND "Alan's FMV" LEVELS */
6581   /* try to detect and fix "Zelda II" levels, which are broken with 3.2.5 */
6582   {
6583     int element = EL_CUSTOM_16;
6584     struct ElementInfo *ei = &element_info[element];
6585
6586     /* This is needed to fix a problem that was caused by a bugfix in function
6587        game.c/CheckTriggeredElementChangeExt() introduced with 3.2.5 that
6588        corrects the behaviour when a custom element changes to another custom
6589        element with a higher element number that has change actions defined.
6590        Normally, only one change per frame is allowed for custom elements.
6591        Therefore, it is checked if a custom element already changed in the
6592        current frame; if it did, subsequent changes are suppressed.
6593        Unfortunately, this is only checked for element changes, but not for
6594        change actions, which are still executed. As the function above loops
6595        through all custom elements from lower to higher, an element change
6596        resulting in a lower CE number won't be checked again, while a target
6597        element with a higher number will also be checked, and potential change
6598        actions will get executed for this CE, too (which is wrong), while
6599        further changes are ignored (which is correct). As this bugfix breaks
6600        Zelda II (but no other levels), allow the previous, incorrect behaviour
6601        for this outstanding level set to not break the game or existing tapes */
6602
6603     if (strncmp(leveldir_current->identifier, "zelda2", 6) == 0 ||
6604         strncmp(ei->description, "scanline - row 1", 16) == 0)
6605       level->use_action_after_change_bug = TRUE;
6606   }
6607 #endif
6608
6609   /* not centering level after relocating player was default only in 3.2.3 */
6610   if (level->game_version == VERSION_IDENT(3,2,3,0))    /* (no pre-releases) */
6611     level->shifted_relocation = TRUE;
6612
6613   /* EM style elements always chain-exploded in R'n'D engine before 3.2.6 */
6614   if (level->game_version < VERSION_IDENT(3,2,6,0))
6615     level->em_explodes_by_fire = TRUE;
6616 }
6617
6618 static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
6619 {
6620   int i, j, x, y;
6621
6622   /* map custom element change events that have changed in newer versions
6623      (these following values were accidentally changed in version 3.0.1)
6624      (this seems to be needed only for 'ab_levelset3' and 'ab_levelset4') */
6625   if (level->game_version <= VERSION_IDENT(3,0,0,0))
6626   {
6627     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6628     {
6629       int element = EL_CUSTOM_START + i;
6630
6631       /* order of checking and copying events to be mapped is important */
6632       /* (do not change the start and end value -- they are constant) */
6633       for (j = CE_BY_OTHER_ACTION; j >= CE_VALUE_GETS_ZERO; j--)
6634       {
6635         if (HAS_CHANGE_EVENT(element, j - 2))
6636         {
6637           SET_CHANGE_EVENT(element, j - 2, FALSE);
6638           SET_CHANGE_EVENT(element, j, TRUE);
6639         }
6640       }
6641
6642       /* order of checking and copying events to be mapped is important */
6643       /* (do not change the start and end value -- they are constant) */
6644       for (j = CE_PLAYER_COLLECTS_X; j >= CE_HITTING_SOMETHING; j--)
6645       {
6646         if (HAS_CHANGE_EVENT(element, j - 1))
6647         {
6648           SET_CHANGE_EVENT(element, j - 1, FALSE);
6649           SET_CHANGE_EVENT(element, j, TRUE);
6650         }
6651       }
6652     }
6653   }
6654
6655   /* initialize "can_change" field for old levels with only one change page */
6656   if (level->game_version <= VERSION_IDENT(3,0,2,0))
6657   {
6658     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6659     {
6660       int element = EL_CUSTOM_START + i;
6661
6662       if (CAN_CHANGE(element))
6663         element_info[element].change->can_change = TRUE;
6664     }
6665   }
6666
6667   /* correct custom element values (for old levels without these options) */
6668   if (level->game_version < VERSION_IDENT(3,1,1,0))
6669   {
6670     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6671     {
6672       int element = EL_CUSTOM_START + i;
6673       struct ElementInfo *ei = &element_info[element];
6674
6675       if (ei->access_direction == MV_NO_DIRECTION)
6676         ei->access_direction = MV_ALL_DIRECTIONS;
6677     }
6678   }
6679
6680   /* correct custom element values (fix invalid values for all versions) */
6681   if (1)
6682   {
6683     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6684     {
6685       int element = EL_CUSTOM_START + i;
6686       struct ElementInfo *ei = &element_info[element];
6687
6688       for (j = 0; j < ei->num_change_pages; j++)
6689       {
6690         struct ElementChangeInfo *change = &ei->change_page[j];
6691
6692         if (change->trigger_player == CH_PLAYER_NONE)
6693           change->trigger_player = CH_PLAYER_ANY;
6694
6695         if (change->trigger_side == CH_SIDE_NONE)
6696           change->trigger_side = CH_SIDE_ANY;
6697       }
6698     }
6699   }
6700
6701   /* initialize "can_explode" field for old levels which did not store this */
6702   /* !!! CHECK THIS -- "<= 3,1,0,0" IS PROBABLY WRONG !!! */
6703   if (level->game_version <= VERSION_IDENT(3,1,0,0))
6704   {
6705     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6706     {
6707       int element = EL_CUSTOM_START + i;
6708
6709       if (EXPLODES_1X1_OLD(element))
6710         element_info[element].explosion_type = EXPLODES_1X1;
6711
6712       SET_PROPERTY(element, EP_CAN_EXPLODE, (EXPLODES_BY_FIRE(element) ||
6713                                              EXPLODES_SMASHED(element) ||
6714                                              EXPLODES_IMPACT(element)));
6715     }
6716   }
6717
6718   /* correct previously hard-coded move delay values for maze runner style */
6719   if (level->game_version < VERSION_IDENT(3,1,1,0))
6720   {
6721     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6722     {
6723       int element = EL_CUSTOM_START + i;
6724
6725       if (element_info[element].move_pattern & MV_MAZE_RUNNER_STYLE)
6726       {
6727         /* previously hard-coded and therefore ignored */
6728         element_info[element].move_delay_fixed = 9;
6729         element_info[element].move_delay_random = 0;
6730       }
6731     }
6732   }
6733
6734   /* map elements that have changed in newer versions */
6735   level->amoeba_content = getMappedElementByVersion(level->amoeba_content,
6736                                                     level->game_version);
6737   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
6738     for (x = 0; x < 3; x++)
6739       for (y = 0; y < 3; y++)
6740         level->yamyam_content[i].e[x][y] =
6741           getMappedElementByVersion(level->yamyam_content[i].e[x][y],
6742                                     level->game_version);
6743
6744   /* initialize element properties for level editor etc. */
6745   InitElementPropertiesEngine(level->game_version);
6746   InitElementPropertiesAfterLoading(level->game_version);
6747   InitElementPropertiesGfxElement();
6748 }
6749
6750 static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
6751 {
6752   int x, y;
6753
6754   /* map elements that have changed in newer versions */
6755   for (y = 0; y < level->fieldy; y++)
6756     for (x = 0; x < level->fieldx; x++)
6757       level->field[x][y] = getMappedElementByVersion(level->field[x][y],
6758                                                      level->game_version);
6759
6760   /* copy elements to runtime playfield array */
6761   for (x = 0; x < MAX_LEV_FIELDX; x++)
6762     for (y = 0; y < MAX_LEV_FIELDY; y++)
6763       Feld[x][y] = level->field[x][y];
6764
6765   /* initialize level size variables for faster access */
6766   lev_fieldx = level->fieldx;
6767   lev_fieldy = level->fieldy;
6768
6769   /* determine border element for this level */
6770   if (level->file_info.type == LEVEL_FILE_TYPE_DC)
6771     BorderElement = EL_EMPTY;   /* (in editor, SetBorderElement() is used) */
6772   else
6773     SetBorderElement();
6774 }
6775
6776 static void LoadLevel_InitNativeEngines(struct LevelInfo *level,char *filename)
6777 {
6778   struct LevelFileInfo *level_file_info = &level->file_info;
6779
6780   if (level_file_info->type == LEVEL_FILE_TYPE_RND)
6781     CopyNativeLevel_RND_to_Native(level);
6782 }
6783
6784 void LoadLevelTemplate(int nr)
6785 {
6786   char *filename;
6787
6788   setLevelFileInfo(&level_template.file_info, nr);
6789   filename = level_template.file_info.filename;
6790
6791   LoadLevelFromFileInfo(&level_template, &level_template.file_info);
6792
6793   LoadLevel_InitVersion(&level_template, filename);
6794   LoadLevel_InitElements(&level_template, filename);
6795
6796   ActivateLevelTemplate();
6797 }
6798
6799 void LoadLevel(int nr)
6800 {
6801   char *filename;
6802
6803   setLevelFileInfo(&level.file_info, nr);
6804   filename = level.file_info.filename;
6805
6806   LoadLevelFromFileInfo(&level, &level.file_info);
6807
6808   if (level.use_custom_template)
6809     LoadLevelTemplate(-1);
6810
6811   LoadLevel_InitVersion(&level, filename);
6812   LoadLevel_InitElements(&level, filename);
6813   LoadLevel_InitPlayfield(&level, filename);
6814
6815   LoadLevel_InitNativeEngines(&level, filename);
6816 }
6817
6818 static int SaveLevel_VERS(FILE *file, struct LevelInfo *level)
6819 {
6820   int chunk_size = 0;
6821
6822   chunk_size += putFileVersion(file, level->file_version);
6823   chunk_size += putFileVersion(file, level->game_version);
6824
6825   return chunk_size;
6826 }
6827
6828 static int SaveLevel_DATE(FILE *file, struct LevelInfo *level)
6829 {
6830   int chunk_size = 0;
6831
6832   chunk_size += putFile16BitBE(file, level->creation_date.year);
6833   chunk_size += putFile8Bit(file,    level->creation_date.month);
6834   chunk_size += putFile8Bit(file,    level->creation_date.day);
6835
6836   return chunk_size;
6837 }
6838
6839 #if 0
6840 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
6841 {
6842   int i, x, y;
6843
6844   putFile8Bit(file, level->fieldx);
6845   putFile8Bit(file, level->fieldy);
6846
6847   putFile16BitBE(file, level->time);
6848   putFile16BitBE(file, level->gems_needed);
6849
6850   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
6851     putFile8Bit(file, level->name[i]);
6852
6853   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
6854     putFile8Bit(file, level->score[i]);
6855
6856   for (i = 0; i < STD_ELEMENT_CONTENTS; i++)
6857     for (y = 0; y < 3; y++)
6858       for (x = 0; x < 3; x++)
6859         putFile8Bit(file, (level->encoding_16bit_yamyam ? EL_EMPTY :
6860                            level->yamyam_content[i].e[x][y]));
6861   putFile8Bit(file, level->amoeba_speed);
6862   putFile8Bit(file, level->time_magic_wall);
6863   putFile8Bit(file, level->time_wheel);
6864   putFile8Bit(file, (level->encoding_16bit_amoeba ? EL_EMPTY :
6865                      level->amoeba_content));
6866   putFile8Bit(file, (level->initial_player_stepsize == STEPSIZE_FAST ? 1 : 0));
6867   putFile8Bit(file, (level->initial_gravity ? 1 : 0));
6868   putFile8Bit(file, (level->encoding_16bit_field ? 1 : 0));
6869   putFile8Bit(file, (level->em_slippery_gems ? 1 : 0));
6870
6871   putFile8Bit(file, (level->use_custom_template ? 1 : 0));
6872
6873   putFile8Bit(file, (level->block_last_field ? 1 : 0));
6874   putFile8Bit(file, (level->sp_block_last_field ? 1 : 0));
6875   putFile32BitBE(file, level->can_move_into_acid_bits);
6876   putFile8Bit(file, level->dont_collide_with_bits);
6877
6878   putFile8Bit(file, (level->use_spring_bug ? 1 : 0));
6879   putFile8Bit(file, (level->use_step_counter ? 1 : 0));
6880
6881   putFile8Bit(file, (level->instant_relocation ? 1 : 0));
6882   putFile8Bit(file, (level->can_pass_to_walkable ? 1 : 0));
6883   putFile8Bit(file, (level->grow_into_diggable ? 1 : 0));
6884
6885   putFile8Bit(file, level->game_engine_type);
6886
6887   WriteUnusedBytesToFile(file, LEVEL_CHUNK_HEAD_UNUSED);
6888 }
6889 #endif
6890
6891 static int SaveLevel_NAME(FILE *file, struct LevelInfo *level)
6892 {
6893   int chunk_size = 0;
6894   int i;
6895
6896   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
6897     chunk_size += putFile8Bit(file, level->name[i]);
6898
6899   return chunk_size;
6900 }
6901
6902 static int SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
6903 {
6904   int chunk_size = 0;
6905   int i;
6906
6907   for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
6908     chunk_size += putFile8Bit(file, level->author[i]);
6909
6910   return chunk_size;
6911 }
6912
6913 #if 0
6914 static int SaveLevel_BODY(FILE *file, struct LevelInfo *level)
6915 {
6916   int chunk_size = 0;
6917   int x, y;
6918
6919   for (y = 0; y < level->fieldy; y++) 
6920     for (x = 0; x < level->fieldx; x++) 
6921       if (level->encoding_16bit_field)
6922         chunk_size += putFile16BitBE(file, level->field[x][y]);
6923       else
6924         chunk_size += putFile8Bit(file, level->field[x][y]);
6925
6926   return chunk_size;
6927 }
6928 #endif
6929
6930 static int SaveLevel_BODY(FILE *file, struct LevelInfo *level)
6931 {
6932   int chunk_size = 0;
6933   int x, y;
6934
6935   for (y = 0; y < level->fieldy; y++) 
6936     for (x = 0; x < level->fieldx; x++) 
6937       chunk_size += putFile16BitBE(file, level->field[x][y]);
6938
6939   return chunk_size;
6940 }
6941
6942 #if 0
6943 static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
6944 {
6945   int i, x, y;
6946
6947   putFile8Bit(file, EL_YAMYAM);
6948   putFile8Bit(file, level->num_yamyam_contents);
6949   putFile8Bit(file, 0);
6950   putFile8Bit(file, 0);
6951
6952   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
6953     for (y = 0; y < 3; y++)
6954       for (x = 0; x < 3; x++)
6955         if (level->encoding_16bit_field)
6956           putFile16BitBE(file, level->yamyam_content[i].e[x][y]);
6957         else
6958           putFile8Bit(file, level->yamyam_content[i].e[x][y]);
6959 }
6960 #endif
6961
6962 #if 0
6963 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
6964 {
6965   int i, x, y;
6966   int num_contents, content_xsize, content_ysize;
6967   int content_array[MAX_ELEMENT_CONTENTS][3][3];
6968
6969   if (element == EL_YAMYAM)
6970   {
6971     num_contents = level->num_yamyam_contents;
6972     content_xsize = 3;
6973     content_ysize = 3;
6974
6975     for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
6976       for (y = 0; y < 3; y++)
6977         for (x = 0; x < 3; x++)
6978           content_array[i][x][y] = level->yamyam_content[i].e[x][y];
6979   }
6980   else if (element == EL_BD_AMOEBA)
6981   {
6982     num_contents = 1;
6983     content_xsize = 1;
6984     content_ysize = 1;
6985
6986     for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
6987       for (y = 0; y < 3; y++)
6988         for (x = 0; x < 3; x++)
6989           content_array[i][x][y] = EL_EMPTY;
6990     content_array[0][0][0] = level->amoeba_content;
6991   }
6992   else
6993   {
6994     /* chunk header already written -- write empty chunk data */
6995     WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_SIZE);
6996
6997     Error(ERR_WARN, "cannot save content for element '%d'", element);
6998     return;
6999   }
7000
7001   putFile16BitBE(file, element);
7002   putFile8Bit(file, num_contents);
7003   putFile8Bit(file, content_xsize);
7004   putFile8Bit(file, content_ysize);
7005
7006   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED);
7007
7008   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
7009     for (y = 0; y < 3; y++)
7010       for (x = 0; x < 3; x++)
7011         putFile16BitBE(file, content_array[i][x][y]);
7012 }
7013 #endif
7014
7015 #if 0
7016 static int SaveLevel_CNT3(FILE *file, struct LevelInfo *level, int element)
7017 {
7018   int envelope_nr = element - EL_ENVELOPE_1;
7019   int envelope_len = strlen(level->envelope_text[envelope_nr]) + 1;
7020   int chunk_size = 0;
7021   int i;
7022
7023   chunk_size += putFile16BitBE(file, element);
7024   chunk_size += putFile16BitBE(file, envelope_len);
7025   chunk_size += putFile8Bit(file, level->envelope_xsize[envelope_nr]);
7026   chunk_size += putFile8Bit(file, level->envelope_ysize[envelope_nr]);
7027
7028   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT3_UNUSED);
7029   chunk_size += LEVEL_CHUNK_CNT3_UNUSED;
7030
7031   for (i = 0; i < envelope_len; i++)
7032     chunk_size += putFile8Bit(file, level->envelope_text[envelope_nr][i]);
7033
7034   return chunk_size;
7035 }
7036 #endif
7037
7038 #if 0
7039 static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level,
7040                            int num_changed_custom_elements)
7041 {
7042   int i, check = 0;
7043
7044   putFile16BitBE(file, num_changed_custom_elements);
7045
7046   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
7047   {
7048     int element = EL_CUSTOM_START + i;
7049
7050     struct ElementInfo *ei = &element_info[element];
7051
7052     if (ei->properties[EP_BITFIELD_BASE_NR] != EP_BITMASK_DEFAULT)
7053     {
7054       if (check < num_changed_custom_elements)
7055       {
7056         putFile16BitBE(file, element);
7057         putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
7058       }
7059
7060       check++;
7061     }
7062   }
7063
7064   if (check != num_changed_custom_elements)     /* should not happen */
7065     Error(ERR_WARN, "inconsistent number of custom element properties");
7066 }
7067 #endif
7068
7069 #if 0
7070 static void SaveLevel_CUS2(FILE *file, struct LevelInfo *level,
7071                            int num_changed_custom_elements)
7072 {
7073   int i, check = 0;
7074
7075   putFile16BitBE(file, num_changed_custom_elements);
7076
7077   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
7078   {
7079     int element = EL_CUSTOM_START + i;
7080
7081     if (element_info[element].change->target_element != EL_EMPTY_SPACE)
7082     {
7083       if (check < num_changed_custom_elements)
7084       {
7085         putFile16BitBE(file, element);
7086         putFile16BitBE(file, element_info[element].change->target_element);
7087       }
7088
7089       check++;
7090     }
7091   }
7092
7093   if (check != num_changed_custom_elements)     /* should not happen */
7094     Error(ERR_WARN, "inconsistent number of custom target elements");
7095 }
7096 #endif
7097
7098 #if 0
7099 static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
7100                            int num_changed_custom_elements)
7101 {
7102   int i, j, x, y, check = 0;
7103
7104   putFile16BitBE(file, num_changed_custom_elements);
7105
7106   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
7107   {
7108     int element = EL_CUSTOM_START + i;
7109     struct ElementInfo *ei = &element_info[element];
7110
7111     if (ei->modified_settings)
7112     {
7113       if (check < num_changed_custom_elements)
7114       {
7115         putFile16BitBE(file, element);
7116
7117         for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++)
7118           putFile8Bit(file, ei->description[j]);
7119
7120         putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
7121
7122         /* some free bytes for future properties and padding */
7123         WriteUnusedBytesToFile(file, 7);
7124
7125         putFile8Bit(file, ei->use_gfx_element);
7126         putFile16BitBE(file, ei->gfx_element_initial);
7127
7128         putFile8Bit(file, ei->collect_score_initial);
7129         putFile8Bit(file, ei->collect_count_initial);
7130
7131         putFile16BitBE(file, ei->push_delay_fixed);
7132         putFile16BitBE(file, ei->push_delay_random);
7133         putFile16BitBE(file, ei->move_delay_fixed);
7134         putFile16BitBE(file, ei->move_delay_random);
7135
7136         putFile16BitBE(file, ei->move_pattern);
7137         putFile8Bit(file, ei->move_direction_initial);
7138         putFile8Bit(file, ei->move_stepsize);
7139
7140         for (y = 0; y < 3; y++)
7141           for (x = 0; x < 3; x++)
7142             putFile16BitBE(file, ei->content.e[x][y]);
7143
7144         putFile32BitBE(file, ei->change->events);
7145
7146         putFile16BitBE(file, ei->change->target_element);
7147
7148         putFile16BitBE(file, ei->change->delay_fixed);
7149         putFile16BitBE(file, ei->change->delay_random);
7150         putFile16BitBE(file, ei->change->delay_frames);
7151
7152         putFile16BitBE(file, ei->change->initial_trigger_element);
7153
7154         putFile8Bit(file, ei->change->explode);
7155         putFile8Bit(file, ei->change->use_target_content);
7156         putFile8Bit(file, ei->change->only_if_complete);
7157         putFile8Bit(file, ei->change->use_random_replace);
7158
7159         putFile8Bit(file, ei->change->random_percentage);
7160         putFile8Bit(file, ei->change->replace_when);
7161
7162         for (y = 0; y < 3; y++)
7163           for (x = 0; x < 3; x++)
7164             putFile16BitBE(file, ei->change->content.e[x][y]);
7165
7166         putFile8Bit(file, ei->slippery_type);
7167
7168         /* some free bytes for future properties and padding */
7169         WriteUnusedBytesToFile(file, LEVEL_CPART_CUS3_UNUSED);
7170       }
7171
7172       check++;
7173     }
7174   }
7175
7176   if (check != num_changed_custom_elements)     /* should not happen */
7177     Error(ERR_WARN, "inconsistent number of custom element properties");
7178 }
7179 #endif
7180
7181 #if 0
7182 static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
7183 {
7184   struct ElementInfo *ei = &element_info[element];
7185   int i, j, x, y;
7186
7187   /* ---------- custom element base property values (96 bytes) ------------- */
7188
7189   putFile16BitBE(file, element);
7190
7191   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
7192     putFile8Bit(file, ei->description[i]);
7193
7194   putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
7195
7196   WriteUnusedBytesToFile(file, 4);      /* reserved for more base properties */
7197
7198   putFile8Bit(file, ei->num_change_pages);
7199
7200   putFile16BitBE(file, ei->ce_value_fixed_initial);
7201   putFile16BitBE(file, ei->ce_value_random_initial);
7202   putFile8Bit(file, ei->use_last_ce_value);
7203
7204   putFile8Bit(file, ei->use_gfx_element);
7205   putFile16BitBE(file, ei->gfx_element_initial);
7206
7207   putFile8Bit(file, ei->collect_score_initial);
7208   putFile8Bit(file, ei->collect_count_initial);
7209
7210   putFile8Bit(file, ei->drop_delay_fixed);
7211   putFile8Bit(file, ei->push_delay_fixed);
7212   putFile8Bit(file, ei->drop_delay_random);
7213   putFile8Bit(file, ei->push_delay_random);
7214   putFile16BitBE(file, ei->move_delay_fixed);
7215   putFile16BitBE(file, ei->move_delay_random);
7216
7217   /* bits 0 - 15 of "move_pattern" ... */
7218   putFile16BitBE(file, ei->move_pattern & 0xffff);
7219   putFile8Bit(file, ei->move_direction_initial);
7220   putFile8Bit(file, ei->move_stepsize);
7221
7222   putFile8Bit(file, ei->slippery_type);
7223
7224   for (y = 0; y < 3; y++)
7225     for (x = 0; x < 3; x++)
7226       putFile16BitBE(file, ei->content.e[x][y]);
7227
7228   putFile16BitBE(file, ei->move_enter_element);
7229   putFile16BitBE(file, ei->move_leave_element);
7230   putFile8Bit(file, ei->move_leave_type);
7231
7232   /* ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible) */
7233   putFile16BitBE(file, (ei->move_pattern >> 16) & 0xffff);
7234
7235   putFile8Bit(file, ei->access_direction);
7236
7237   putFile8Bit(file, ei->explosion_delay);
7238   putFile8Bit(file, ei->ignition_delay);
7239   putFile8Bit(file, ei->explosion_type);
7240
7241   /* some free bytes for future custom property values and padding */
7242   WriteUnusedBytesToFile(file, 1);
7243
7244   /* ---------- change page property values (48 bytes) --------------------- */
7245
7246   for (i = 0; i < ei->num_change_pages; i++)
7247   {
7248     struct ElementChangeInfo *change = &ei->change_page[i];
7249     unsigned int event_bits;
7250
7251     /* bits 0 - 31 of "has_event[]" ... */
7252     event_bits = 0;
7253     for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
7254       if (change->has_event[j])
7255         event_bits |= (1 << j);
7256     putFile32BitBE(file, event_bits);
7257
7258     putFile16BitBE(file, change->target_element);
7259
7260     putFile16BitBE(file, change->delay_fixed);
7261     putFile16BitBE(file, change->delay_random);
7262     putFile16BitBE(file, change->delay_frames);
7263
7264     putFile16BitBE(file, change->initial_trigger_element);
7265
7266     putFile8Bit(file, change->explode);
7267     putFile8Bit(file, change->use_target_content);
7268     putFile8Bit(file, change->only_if_complete);
7269     putFile8Bit(file, change->use_random_replace);
7270
7271     putFile8Bit(file, change->random_percentage);
7272     putFile8Bit(file, change->replace_when);
7273
7274     for (y = 0; y < 3; y++)
7275       for (x = 0; x < 3; x++)
7276         putFile16BitBE(file, change->target_content.e[x][y]);
7277
7278     putFile8Bit(file, change->can_change);
7279
7280     putFile8Bit(file, change->trigger_side);
7281
7282     putFile8Bit(file, change->trigger_player);
7283     putFile8Bit(file, (change->trigger_page == CH_PAGE_ANY ? CH_PAGE_ANY_FILE :
7284                        log_2(change->trigger_page)));
7285
7286     putFile8Bit(file, change->has_action);
7287     putFile8Bit(file, change->action_type);
7288     putFile8Bit(file, change->action_mode);
7289     putFile16BitBE(file, change->action_arg);
7290
7291     /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */
7292     event_bits = 0;
7293     for (j = 32; j < NUM_CHANGE_EVENTS; j++)
7294       if (change->has_event[j])
7295         event_bits |= (1 << (j - 32));
7296     putFile8Bit(file, event_bits);
7297   }
7298 }
7299 #endif
7300
7301 #if 0
7302 static void SaveLevel_GRP1(FILE *file, struct LevelInfo *level, int element)
7303 {
7304   struct ElementInfo *ei = &element_info[element];
7305   struct ElementGroupInfo *group = ei->group;
7306   int i;
7307
7308   putFile16BitBE(file, element);
7309
7310   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
7311     putFile8Bit(file, ei->description[i]);
7312
7313   putFile8Bit(file, group->num_elements);
7314
7315   putFile8Bit(file, ei->use_gfx_element);
7316   putFile16BitBE(file, ei->gfx_element_initial);
7317
7318   putFile8Bit(file, group->choice_mode);
7319
7320   /* some free bytes for future values and padding */
7321   WriteUnusedBytesToFile(file, 3);
7322
7323   for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
7324     putFile16BitBE(file, group->element[i]);
7325 }
7326 #endif
7327
7328 static int SaveLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *entry,
7329                                 boolean write_element)
7330 {
7331   int save_type = entry->save_type;
7332   int data_type = entry->data_type;
7333   int conf_type = entry->conf_type;
7334   int byte_mask = conf_type & CONF_MASK_BYTES;
7335   int element = entry->element;
7336   int default_value = entry->default_value;
7337   int num_bytes = 0;
7338   boolean modified = FALSE;
7339
7340   if (byte_mask != CONF_MASK_MULTI_BYTES)
7341   {
7342     void *value_ptr = entry->value;
7343     int value = (data_type == TYPE_BOOLEAN ? *(boolean *)value_ptr :
7344                  *(int *)value_ptr);
7345
7346     /* check if any settings have been modified before saving them */
7347     if (value != default_value)
7348       modified = TRUE;
7349
7350     /* do not save if explicitly told or if unmodified default settings */
7351     if ((save_type == SAVE_CONF_NEVER) ||
7352         (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
7353       return 0;
7354
7355     if (write_element)
7356       num_bytes += putFile16BitBE(file, element);
7357
7358     num_bytes += putFile8Bit(file, conf_type);
7359     num_bytes += (byte_mask == CONF_MASK_1_BYTE ? putFile8Bit   (file, value) :
7360                   byte_mask == CONF_MASK_2_BYTE ? putFile16BitBE(file, value) :
7361                   byte_mask == CONF_MASK_4_BYTE ? putFile32BitBE(file, value) :
7362                   0);
7363   }
7364   else if (data_type == TYPE_STRING)
7365   {
7366     char *default_string = entry->default_string;
7367     char *string = (char *)(entry->value);
7368     int string_length = strlen(string);
7369     int i;
7370
7371     /* check if any settings have been modified before saving them */
7372     if (!strEqual(string, default_string))
7373       modified = TRUE;
7374
7375     /* do not save if explicitly told or if unmodified default settings */
7376     if ((save_type == SAVE_CONF_NEVER) ||
7377         (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
7378       return 0;
7379
7380     if (write_element)
7381       num_bytes += putFile16BitBE(file, element);
7382
7383     num_bytes += putFile8Bit(file, conf_type);
7384     num_bytes += putFile16BitBE(file, string_length);
7385
7386     for (i = 0; i < string_length; i++)
7387       num_bytes += putFile8Bit(file, string[i]);
7388   }
7389   else if (data_type == TYPE_ELEMENT_LIST)
7390   {
7391     int *element_array = (int *)(entry->value);
7392     int num_elements = *(int *)(entry->num_entities);
7393     int i;
7394
7395     /* check if any settings have been modified before saving them */
7396     for (i = 0; i < num_elements; i++)
7397       if (element_array[i] != default_value)
7398         modified = TRUE;
7399
7400     /* do not save if explicitly told or if unmodified default settings */
7401     if ((save_type == SAVE_CONF_NEVER) ||
7402         (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
7403       return 0;
7404
7405     if (write_element)
7406       num_bytes += putFile16BitBE(file, element);
7407
7408     num_bytes += putFile8Bit(file, conf_type);
7409     num_bytes += putFile16BitBE(file, num_elements * CONF_ELEMENT_NUM_BYTES);
7410
7411     for (i = 0; i < num_elements; i++)
7412       num_bytes += putFile16BitBE(file, element_array[i]);
7413   }
7414   else if (data_type == TYPE_CONTENT_LIST)
7415   {
7416     struct Content *content = (struct Content *)(entry->value);
7417     int num_contents = *(int *)(entry->num_entities);
7418     int i, x, y;
7419
7420     /* check if any settings have been modified before saving them */
7421     for (i = 0; i < num_contents; i++)
7422       for (y = 0; y < 3; y++)
7423         for (x = 0; x < 3; x++)
7424           if (content[i].e[x][y] != default_value)
7425             modified = TRUE;
7426
7427     /* do not save if explicitly told or if unmodified default settings */
7428     if ((save_type == SAVE_CONF_NEVER) ||
7429         (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
7430       return 0;
7431
7432     if (write_element)
7433       num_bytes += putFile16BitBE(file, element);
7434
7435     num_bytes += putFile8Bit(file, conf_type);
7436     num_bytes += putFile16BitBE(file, num_contents * CONF_CONTENT_NUM_BYTES);
7437
7438     for (i = 0; i < num_contents; i++)
7439       for (y = 0; y < 3; y++)
7440         for (x = 0; x < 3; x++)
7441           num_bytes += putFile16BitBE(file, content[i].e[x][y]);
7442   }
7443
7444   return num_bytes;
7445 }
7446
7447 static int SaveLevel_INFO(FILE *file, struct LevelInfo *level)
7448 {
7449   int chunk_size = 0;
7450   int i;
7451
7452   li = *level;          /* copy level data into temporary buffer */
7453
7454   for (i = 0; chunk_config_INFO[i].data_type != -1; i++)
7455     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_INFO[i], FALSE);
7456
7457   return chunk_size;
7458 }
7459
7460 static int SaveLevel_ELEM(FILE *file, struct LevelInfo *level)
7461 {
7462   int chunk_size = 0;
7463   int i;
7464
7465   li = *level;          /* copy level data into temporary buffer */
7466
7467   for (i = 0; chunk_config_ELEM[i].data_type != -1; i++)
7468     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_ELEM[i], TRUE);
7469
7470   return chunk_size;
7471 }
7472
7473 static int SaveLevel_NOTE(FILE *file, struct LevelInfo *level, int element)
7474 {
7475   int envelope_nr = element - EL_ENVELOPE_1;
7476   int chunk_size = 0;
7477   int i;
7478
7479   chunk_size += putFile16BitBE(file, element);
7480
7481   /* copy envelope data into temporary buffer */
7482   xx_envelope = level->envelope[envelope_nr];
7483
7484   for (i = 0; chunk_config_NOTE[i].data_type != -1; i++)
7485     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_NOTE[i], FALSE);
7486
7487   return chunk_size;
7488 }
7489
7490 static int SaveLevel_CUSX(FILE *file, struct LevelInfo *level, int element)
7491 {
7492   struct ElementInfo *ei = &element_info[element];
7493   int chunk_size = 0;
7494   int i, j;
7495
7496   chunk_size += putFile16BitBE(file, element);
7497
7498   xx_ei = *ei;          /* copy element data into temporary buffer */
7499
7500   /* set default description string for this specific element */
7501   strcpy(xx_default_description, getDefaultElementDescription(ei));
7502
7503 #if 0
7504   /* set (fixed) number of content areas (may be wrong by broken level file) */
7505   /* (this is now directly corrected for broken level files after loading) */
7506   xx_num_contents = 1;
7507 #endif
7508
7509   for (i = 0; chunk_config_CUSX_base[i].data_type != -1; i++)
7510     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_CUSX_base[i], FALSE);
7511
7512   for (i = 0; i < ei->num_change_pages; i++)
7513   {
7514     struct ElementChangeInfo *change = &ei->change_page[i];
7515
7516     xx_current_change_page = i;
7517
7518     xx_change = *change;        /* copy change data into temporary buffer */
7519
7520     resetEventBits();
7521     setEventBitsFromEventFlags(change);
7522
7523     for (j = 0; chunk_config_CUSX_change[j].data_type != -1; j++)
7524       chunk_size += SaveLevel_MicroChunk(file, &chunk_config_CUSX_change[j],
7525                                          FALSE);
7526   }
7527
7528   return chunk_size;
7529 }
7530
7531 static int SaveLevel_GRPX(FILE *file, struct LevelInfo *level, int element)
7532 {
7533   struct ElementInfo *ei = &element_info[element];
7534   struct ElementGroupInfo *group = ei->group;
7535   int chunk_size = 0;
7536   int i;
7537
7538   chunk_size += putFile16BitBE(file, element);
7539
7540   xx_ei = *ei;          /* copy element data into temporary buffer */
7541   xx_group = *group;    /* copy group data into temporary buffer */
7542
7543   /* set default description string for this specific element */
7544   strcpy(xx_default_description, getDefaultElementDescription(ei));
7545
7546   for (i = 0; chunk_config_GRPX[i].data_type != -1; i++)
7547     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_GRPX[i], FALSE);
7548
7549   return chunk_size;
7550 }
7551
7552 static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
7553 {
7554   int chunk_size;
7555   int i;
7556   FILE *file;
7557
7558   if (!(file = fopen(filename, MODE_WRITE)))
7559   {
7560     Error(ERR_WARN, "cannot save level file '%s'", filename);
7561     return;
7562   }
7563
7564   level->file_version = FILE_VERSION_ACTUAL;
7565   level->game_version = GAME_VERSION_ACTUAL;
7566
7567   level->creation_date = getCurrentDate();
7568
7569   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
7570   putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
7571
7572   chunk_size = SaveLevel_VERS(NULL, level);
7573   putFileChunkBE(file, "VERS", chunk_size);
7574   SaveLevel_VERS(file, level);
7575
7576   chunk_size = SaveLevel_DATE(NULL, level);
7577   putFileChunkBE(file, "DATE", chunk_size);
7578   SaveLevel_DATE(file, level);
7579
7580   chunk_size = SaveLevel_NAME(NULL, level);
7581   putFileChunkBE(file, "NAME", chunk_size);
7582   SaveLevel_NAME(file, level);
7583
7584   chunk_size = SaveLevel_AUTH(NULL, level);
7585   putFileChunkBE(file, "AUTH", chunk_size);
7586   SaveLevel_AUTH(file, level);
7587
7588   chunk_size = SaveLevel_INFO(NULL, level);
7589   putFileChunkBE(file, "INFO", chunk_size);
7590   SaveLevel_INFO(file, level);
7591
7592   chunk_size = SaveLevel_BODY(NULL, level);
7593   putFileChunkBE(file, "BODY", chunk_size);
7594   SaveLevel_BODY(file, level);
7595
7596   chunk_size = SaveLevel_ELEM(NULL, level);
7597   if (chunk_size > LEVEL_CHUNK_ELEM_UNCHANGED)          /* save if changed */
7598   {
7599     putFileChunkBE(file, "ELEM", chunk_size);
7600     SaveLevel_ELEM(file, level);
7601   }
7602
7603   for (i = 0; i < NUM_ENVELOPES; i++)
7604   {
7605     int element = EL_ENVELOPE_1 + i;
7606
7607     chunk_size = SaveLevel_NOTE(NULL, level, element);
7608     if (chunk_size > LEVEL_CHUNK_NOTE_UNCHANGED)        /* save if changed */
7609     {
7610       putFileChunkBE(file, "NOTE", chunk_size);
7611       SaveLevel_NOTE(file, level, element);
7612     }
7613   }
7614
7615   /* if not using template level, check for non-default custom/group elements */
7616   if (!level->use_custom_template)
7617   {
7618     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
7619     {
7620       int element = EL_CUSTOM_START + i;
7621
7622       chunk_size = SaveLevel_CUSX(NULL, level, element);
7623       if (chunk_size > LEVEL_CHUNK_CUSX_UNCHANGED)      /* save if changed */
7624       {
7625         putFileChunkBE(file, "CUSX", chunk_size);
7626         SaveLevel_CUSX(file, level, element);
7627       }
7628     }
7629
7630     for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
7631     {
7632       int element = EL_GROUP_START + i;
7633
7634       chunk_size = SaveLevel_GRPX(NULL, level, element);
7635       if (chunk_size > LEVEL_CHUNK_GRPX_UNCHANGED)      /* save if changed */
7636       {
7637         putFileChunkBE(file, "GRPX", chunk_size);
7638         SaveLevel_GRPX(file, level, element);
7639       }
7640     }
7641   }
7642
7643   fclose(file);
7644
7645   SetFilePermissions(filename, PERMS_PRIVATE);
7646 }
7647
7648 void SaveLevel(int nr)
7649 {
7650   char *filename = getDefaultLevelFilename(nr);
7651
7652   SaveLevelFromFilename(&level, filename);
7653 }
7654
7655 void SaveLevelTemplate()
7656 {
7657   char *filename = getDefaultLevelFilename(-1);
7658
7659   SaveLevelFromFilename(&level, filename);
7660 }
7661
7662 boolean SaveLevelChecked(int nr)
7663 {
7664   char *filename = getDefaultLevelFilename(nr);
7665   boolean new_level = !fileExists(filename);
7666   boolean level_saved = FALSE;
7667
7668   if (new_level || Request("Save this level and kill the old ?", REQ_ASK))
7669   {
7670     SaveLevel(nr);
7671
7672     if (new_level)
7673       Request("Level saved !", REQ_CONFIRM);
7674
7675     level_saved = TRUE;
7676   }
7677
7678   return level_saved;
7679 }
7680
7681 void DumpLevel(struct LevelInfo *level)
7682 {
7683   if (level->no_valid_file)
7684   {
7685     Error(ERR_WARN, "cannot dump -- no valid level file found");
7686
7687     return;
7688   }
7689
7690   printf_line("-", 79);
7691   printf("Level xxx (file version %08d, game version %08d)\n",
7692          level->file_version, level->game_version);
7693   printf_line("-", 79);
7694
7695   printf("Level author: '%s'\n", level->author);
7696   printf("Level title:  '%s'\n", level->name);
7697   printf("\n");
7698   printf("Playfield size: %d x %d\n", level->fieldx, level->fieldy);
7699   printf("\n");
7700   printf("Level time:  %d seconds\n", level->time);
7701   printf("Gems needed: %d\n", level->gems_needed);
7702   printf("\n");
7703   printf("Time for magic wall: %d seconds\n", level->time_magic_wall);
7704   printf("Time for wheel:      %d seconds\n", level->time_wheel);
7705   printf("Time for light:      %d seconds\n", level->time_light);
7706   printf("Time for timegate:   %d seconds\n", level->time_timegate);
7707   printf("\n");
7708   printf("Amoeba speed: %d\n", level->amoeba_speed);
7709   printf("\n");
7710
7711   printf("EM style slippery gems:      %s\n", (level->em_slippery_gems ? "yes" : "no"));
7712   printf("Player blocks last field:    %s\n", (level->block_last_field ? "yes" : "no"));
7713   printf("SP player blocks last field: %s\n", (level->sp_block_last_field ? "yes" : "no"));
7714   printf("use spring bug: %s\n", (level->use_spring_bug ? "yes" : "no"));
7715   printf("use step counter: %s\n", (level->use_step_counter ? "yes" : "no"));
7716
7717   printf_line("-", 79);
7718 }
7719
7720
7721 /* ========================================================================= */
7722 /* tape file functions                                                       */
7723 /* ========================================================================= */
7724
7725 static void setTapeInfoToDefaults()
7726 {
7727   int i;
7728
7729   /* always start with reliable default values (empty tape) */
7730   TapeErase();
7731
7732   /* default values (also for pre-1.2 tapes) with only the first player */
7733   tape.player_participates[0] = TRUE;
7734   for (i = 1; i < MAX_PLAYERS; i++)
7735     tape.player_participates[i] = FALSE;
7736
7737   /* at least one (default: the first) player participates in every tape */
7738   tape.num_participating_players = 1;
7739
7740   tape.level_nr = level_nr;
7741   tape.counter = 0;
7742   tape.changed = FALSE;
7743
7744   tape.recording = FALSE;
7745   tape.playing = FALSE;
7746   tape.pausing = FALSE;
7747
7748   tape.no_valid_file = FALSE;
7749 }
7750
7751 static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
7752 {
7753   tape->file_version = getFileVersion(file);
7754   tape->game_version = getFileVersion(file);
7755
7756   return chunk_size;
7757 }
7758
7759 static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
7760 {
7761   int i;
7762
7763   tape->random_seed = getFile32BitBE(file);
7764   tape->date        = getFile32BitBE(file);
7765   tape->length      = getFile32BitBE(file);
7766
7767   /* read header fields that are new since version 1.2 */
7768   if (tape->file_version >= FILE_VERSION_1_2)
7769   {
7770     byte store_participating_players = getFile8Bit(file);
7771     int engine_version;
7772
7773     /* since version 1.2, tapes store which players participate in the tape */
7774     tape->num_participating_players = 0;
7775     for (i = 0; i < MAX_PLAYERS; i++)
7776     {
7777       tape->player_participates[i] = FALSE;
7778
7779       if (store_participating_players & (1 << i))
7780       {
7781         tape->player_participates[i] = TRUE;
7782         tape->num_participating_players++;
7783       }
7784     }
7785
7786     ReadUnusedBytesFromFile(file, TAPE_CHUNK_HEAD_UNUSED);
7787
7788     engine_version = getFileVersion(file);
7789     if (engine_version > 0)
7790       tape->engine_version = engine_version;
7791     else
7792       tape->engine_version = tape->game_version;
7793   }
7794
7795   return chunk_size;
7796 }
7797
7798 static int LoadTape_INFO(FILE *file, int chunk_size, struct TapeInfo *tape)
7799 {
7800   int level_identifier_size;
7801   int i;
7802
7803   level_identifier_size = getFile16BitBE(file);
7804
7805   tape->level_identifier =
7806     checked_realloc(tape->level_identifier, level_identifier_size);
7807
7808   for (i = 0; i < level_identifier_size; i++)
7809     tape->level_identifier[i] = getFile8Bit(file);
7810
7811   tape->level_nr = getFile16BitBE(file);
7812
7813   chunk_size = 2 + level_identifier_size + 2;
7814
7815   return chunk_size;
7816 }
7817
7818 static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
7819 {
7820   int i, j;
7821   int chunk_size_expected =
7822     (tape->num_participating_players + 1) * tape->length;
7823
7824   if (chunk_size_expected != chunk_size)
7825   {
7826     ReadUnusedBytesFromFile(file, chunk_size);
7827     return chunk_size_expected;
7828   }
7829
7830   for (i = 0; i < tape->length; i++)
7831   {
7832     if (i >= MAX_TAPE_LEN)
7833       break;
7834
7835     for (j = 0; j < MAX_PLAYERS; j++)
7836     {
7837       tape->pos[i].action[j] = MV_NONE;
7838
7839       if (tape->player_participates[j])
7840         tape->pos[i].action[j] = getFile8Bit(file);
7841     }
7842
7843     tape->pos[i].delay = getFile8Bit(file);
7844
7845     if (tape->file_version == FILE_VERSION_1_0)
7846     {
7847       /* eliminate possible diagonal moves in old tapes */
7848       /* this is only for backward compatibility */
7849
7850       byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
7851       byte action = tape->pos[i].action[0];
7852       int k, num_moves = 0;
7853
7854       for (k = 0; k<4; k++)
7855       {
7856         if (action & joy_dir[k])
7857         {
7858           tape->pos[i + num_moves].action[0] = joy_dir[k];
7859           if (num_moves > 0)
7860             tape->pos[i + num_moves].delay = 0;
7861           num_moves++;
7862         }
7863       }
7864
7865       if (num_moves > 1)
7866       {
7867         num_moves--;
7868         i += num_moves;
7869         tape->length += num_moves;
7870       }
7871     }
7872     else if (tape->file_version < FILE_VERSION_2_0)
7873     {
7874       /* convert pre-2.0 tapes to new tape format */
7875
7876       if (tape->pos[i].delay > 1)
7877       {
7878         /* action part */
7879         tape->pos[i + 1] = tape->pos[i];
7880         tape->pos[i + 1].delay = 1;
7881
7882         /* delay part */
7883         for (j = 0; j < MAX_PLAYERS; j++)
7884           tape->pos[i].action[j] = MV_NONE;
7885         tape->pos[i].delay--;
7886
7887         i++;
7888         tape->length++;
7889       }
7890     }
7891
7892     if (feof(file))
7893       break;
7894   }
7895
7896   if (i != tape->length)
7897     chunk_size = (tape->num_participating_players + 1) * i;
7898
7899   return chunk_size;
7900 }
7901
7902 void LoadTapeFromFilename(char *filename)
7903 {
7904   char cookie[MAX_LINE_LEN];
7905   char chunk_name[CHUNK_ID_LEN + 1];
7906   FILE *file;
7907   int chunk_size;
7908
7909   /* always start with reliable default values */
7910   setTapeInfoToDefaults();
7911
7912   if (!(file = fopen(filename, MODE_READ)))
7913   {
7914     tape.no_valid_file = TRUE;
7915
7916     return;
7917   }
7918
7919   getFileChunkBE(file, chunk_name, NULL);
7920   if (strEqual(chunk_name, "RND1"))
7921   {
7922     getFile32BitBE(file);               /* not used */
7923
7924     getFileChunkBE(file, chunk_name, NULL);
7925     if (!strEqual(chunk_name, "TAPE"))
7926     {
7927       tape.no_valid_file = TRUE;
7928
7929       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
7930       fclose(file);
7931       return;
7932     }
7933   }
7934   else  /* check for pre-2.0 file format with cookie string */
7935   {
7936     strcpy(cookie, chunk_name);
7937     fgets(&cookie[4], MAX_LINE_LEN - 4, file);
7938     if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
7939       cookie[strlen(cookie) - 1] = '\0';
7940
7941     if (!checkCookieString(cookie, TAPE_COOKIE_TMPL))
7942     {
7943       tape.no_valid_file = TRUE;
7944
7945       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
7946       fclose(file);
7947       return;
7948     }
7949
7950     if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1)
7951     {
7952       tape.no_valid_file = TRUE;
7953
7954       Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
7955       fclose(file);
7956       return;
7957     }
7958
7959     /* pre-2.0 tape files have no game version, so use file version here */
7960     tape.game_version = tape.file_version;
7961   }
7962
7963   if (tape.file_version < FILE_VERSION_1_2)
7964   {
7965     /* tape files from versions before 1.2.0 without chunk structure */
7966     LoadTape_HEAD(file, TAPE_CHUNK_HEAD_SIZE, &tape);
7967     LoadTape_BODY(file, 2 * tape.length,      &tape);
7968   }
7969   else
7970   {
7971     static struct
7972     {
7973       char *name;
7974       int size;
7975       int (*loader)(FILE *, int, struct TapeInfo *);
7976     }
7977     chunk_info[] =
7978     {
7979       { "VERS", TAPE_CHUNK_VERS_SIZE,   LoadTape_VERS },
7980       { "HEAD", TAPE_CHUNK_HEAD_SIZE,   LoadTape_HEAD },
7981       { "INFO", -1,                     LoadTape_INFO },
7982       { "BODY", -1,                     LoadTape_BODY },
7983       {  NULL,  0,                      NULL }
7984     };
7985
7986     while (getFileChunkBE(file, chunk_name, &chunk_size))
7987     {
7988       int i = 0;
7989
7990       while (chunk_info[i].name != NULL &&
7991              !strEqual(chunk_name, chunk_info[i].name))
7992         i++;
7993
7994       if (chunk_info[i].name == NULL)
7995       {
7996         Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'",
7997               chunk_name, filename);
7998         ReadUnusedBytesFromFile(file, chunk_size);
7999       }
8000       else if (chunk_info[i].size != -1 &&
8001                chunk_info[i].size != chunk_size)
8002       {
8003         Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
8004               chunk_size, chunk_name, filename);
8005         ReadUnusedBytesFromFile(file, chunk_size);
8006       }
8007       else
8008       {
8009         /* call function to load this tape chunk */
8010         int chunk_size_expected =
8011           (chunk_info[i].loader)(file, chunk_size, &tape);
8012
8013         /* the size of some chunks cannot be checked before reading other
8014            chunks first (like "HEAD" and "BODY") that contain some header
8015            information, so check them here */
8016         if (chunk_size_expected != chunk_size)
8017         {
8018           Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
8019                 chunk_size, chunk_name, filename);
8020         }
8021       }
8022     }
8023   }
8024
8025   fclose(file);
8026
8027   tape.length_seconds = GetTapeLength();
8028
8029 #if 0
8030   printf("::: tape file version: %d\n", tape.file_version);
8031   printf("::: tape game version: %d\n", tape.game_version);
8032   printf("::: tape engine version: %d\n", tape.engine_version);
8033 #endif
8034 }
8035
8036 void LoadTape(int nr)
8037 {
8038   char *filename = getTapeFilename(nr);
8039
8040   LoadTapeFromFilename(filename);
8041 }
8042
8043 void LoadSolutionTape(int nr)
8044 {
8045   char *filename = getSolutionTapeFilename(nr);
8046
8047   LoadTapeFromFilename(filename);
8048
8049 #if 1
8050   if (TAPE_IS_EMPTY(tape) &&
8051       level.game_engine_type == GAME_ENGINE_TYPE_SP &&
8052       level.native_sp_level->demo.is_available)
8053     CopyNativeTape_SP_to_RND(&level);
8054 #endif
8055 }
8056
8057 static void SaveTape_VERS(FILE *file, struct TapeInfo *tape)
8058 {
8059   putFileVersion(file, tape->file_version);
8060   putFileVersion(file, tape->game_version);
8061 }
8062
8063 static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
8064 {
8065   int i;
8066   byte store_participating_players = 0;
8067
8068   /* set bits for participating players for compact storage */
8069   for (i = 0; i < MAX_PLAYERS; i++)
8070     if (tape->player_participates[i])
8071       store_participating_players |= (1 << i);
8072
8073   putFile32BitBE(file, tape->random_seed);
8074   putFile32BitBE(file, tape->date);
8075   putFile32BitBE(file, tape->length);
8076
8077   putFile8Bit(file, store_participating_players);
8078
8079   /* unused bytes not at the end here for 4-byte alignment of engine_version */
8080   WriteUnusedBytesToFile(file, TAPE_CHUNK_HEAD_UNUSED);
8081
8082   putFileVersion(file, tape->engine_version);
8083 }
8084
8085 static void SaveTape_INFO(FILE *file, struct TapeInfo *tape)
8086 {
8087   int level_identifier_size = strlen(tape->level_identifier) + 1;
8088   int i;
8089
8090   putFile16BitBE(file, level_identifier_size);
8091
8092   for (i = 0; i < level_identifier_size; i++)
8093     putFile8Bit(file, tape->level_identifier[i]);
8094
8095   putFile16BitBE(file, tape->level_nr);
8096 }
8097
8098 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
8099 {
8100   int i, j;
8101
8102   for (i = 0; i < tape->length; i++)
8103   {
8104     for (j = 0; j < MAX_PLAYERS; j++)
8105       if (tape->player_participates[j])
8106         putFile8Bit(file, tape->pos[i].action[j]);
8107
8108     putFile8Bit(file, tape->pos[i].delay);
8109   }
8110 }
8111
8112 void SaveTape(int nr)
8113 {
8114   char *filename = getTapeFilename(nr);
8115   FILE *file;
8116 #if 0
8117   boolean new_tape = TRUE;
8118 #endif
8119   int num_participating_players = 0;
8120   int info_chunk_size;
8121   int body_chunk_size;
8122   int i;
8123
8124   InitTapeDirectory(leveldir_current->subdir);
8125
8126 #if 0
8127   /* if a tape still exists, ask to overwrite it */
8128   if (fileExists(filename))
8129   {
8130     new_tape = FALSE;
8131     if (!Request("Replace old tape ?", REQ_ASK))
8132       return;
8133   }
8134 #endif
8135
8136   if (!(file = fopen(filename, MODE_WRITE)))
8137   {
8138     Error(ERR_WARN, "cannot save level recording file '%s'", filename);
8139     return;
8140   }
8141
8142   tape.file_version = FILE_VERSION_ACTUAL;
8143   tape.game_version = GAME_VERSION_ACTUAL;
8144
8145   /* count number of participating players  */
8146   for (i = 0; i < MAX_PLAYERS; i++)
8147     if (tape.player_participates[i])
8148       num_participating_players++;
8149
8150   info_chunk_size = 2 + (strlen(tape.level_identifier) + 1) + 2;
8151   body_chunk_size = (num_participating_players + 1) * tape.length;
8152
8153   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
8154   putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
8155
8156   putFileChunkBE(file, "VERS", TAPE_CHUNK_VERS_SIZE);
8157   SaveTape_VERS(file, &tape);
8158
8159   putFileChunkBE(file, "HEAD", TAPE_CHUNK_HEAD_SIZE);
8160   SaveTape_HEAD(file, &tape);
8161
8162   putFileChunkBE(file, "INFO", info_chunk_size);
8163   SaveTape_INFO(file, &tape);
8164
8165   putFileChunkBE(file, "BODY", body_chunk_size);
8166   SaveTape_BODY(file, &tape);
8167
8168   fclose(file);
8169
8170   SetFilePermissions(filename, PERMS_PRIVATE);
8171
8172   tape.changed = FALSE;
8173
8174 #if 0
8175   if (new_tape)
8176     Request("Tape saved !", REQ_CONFIRM);
8177 #endif
8178 }
8179
8180 boolean SaveTapeChecked(int nr)
8181 {
8182   char *filename = getTapeFilename(nr);
8183   boolean new_tape = !fileExists(filename);
8184   boolean tape_saved = FALSE;
8185
8186   if (new_tape || Request("Replace old tape ?", REQ_ASK))
8187   {
8188     SaveTape(nr);
8189
8190     if (new_tape)
8191       Request("Tape saved !", REQ_CONFIRM);
8192
8193     tape_saved = TRUE;
8194   }
8195
8196   return tape_saved;
8197 }
8198
8199 void DumpTape(struct TapeInfo *tape)
8200 {
8201   int tape_frame_counter;
8202   int i, j;
8203
8204   if (tape->no_valid_file)
8205   {
8206     Error(ERR_WARN, "cannot dump -- no valid tape file found");
8207
8208     return;
8209   }
8210
8211   printf_line("-", 79);
8212   printf("Tape of Level %03d (file version %08d, game version %08d)\n",
8213          tape->level_nr, tape->file_version, tape->game_version);
8214   printf("                  (effective engine version %08d)\n",
8215          tape->engine_version);
8216   printf("Level series identifier: '%s'\n", tape->level_identifier);
8217   printf_line("-", 79);
8218
8219   tape_frame_counter = 0;
8220
8221   for (i = 0; i < tape->length; i++)
8222   {
8223     if (i >= MAX_TAPE_LEN)
8224       break;
8225
8226     printf("%04d: ", i);
8227
8228     for (j = 0; j < MAX_PLAYERS; j++)
8229     {
8230       if (tape->player_participates[j])
8231       {
8232         int action = tape->pos[i].action[j];
8233
8234         printf("%d:%02x ", j, action);
8235         printf("[%c%c%c%c|%c%c] - ",
8236                (action & JOY_LEFT ? '<' : ' '),
8237                (action & JOY_RIGHT ? '>' : ' '),
8238                (action & JOY_UP ? '^' : ' '),
8239                (action & JOY_DOWN ? 'v' : ' '),
8240                (action & JOY_BUTTON_1 ? '1' : ' '),
8241                (action & JOY_BUTTON_2 ? '2' : ' '));
8242       }
8243     }
8244
8245     printf("(%03d) ", tape->pos[i].delay);
8246     printf("[%05d]\n", tape_frame_counter);
8247
8248     tape_frame_counter += tape->pos[i].delay;
8249   }
8250
8251   printf_line("-", 79);
8252 }
8253
8254
8255 /* ========================================================================= */
8256 /* score file functions                                                      */
8257 /* ========================================================================= */
8258
8259 void LoadScore(int nr)
8260 {
8261   int i;
8262   char *filename = getScoreFilename(nr);
8263   char cookie[MAX_LINE_LEN];
8264   char line[MAX_LINE_LEN];
8265   char *line_ptr;
8266   FILE *file;
8267
8268   /* always start with reliable default values */
8269   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
8270   {
8271     strcpy(highscore[i].Name, EMPTY_PLAYER_NAME);
8272     highscore[i].Score = 0;
8273   }
8274
8275   if (!(file = fopen(filename, MODE_READ)))
8276     return;
8277
8278   /* check file identifier */
8279   fgets(cookie, MAX_LINE_LEN, file);
8280   if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
8281     cookie[strlen(cookie) - 1] = '\0';
8282
8283   if (!checkCookieString(cookie, SCORE_COOKIE))
8284   {
8285     Error(ERR_WARN, "unknown format of score file '%s'", filename);
8286     fclose(file);
8287     return;
8288   }
8289
8290   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
8291   {
8292     fscanf(file, "%d", &highscore[i].Score);
8293     fgets(line, MAX_LINE_LEN, file);
8294
8295     if (line[strlen(line) - 1] == '\n')
8296       line[strlen(line) - 1] = '\0';
8297
8298     for (line_ptr = line; *line_ptr; line_ptr++)
8299     {
8300       if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
8301       {
8302         strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN);
8303         highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0';
8304         break;
8305       }
8306     }
8307   }
8308
8309   fclose(file);
8310 }
8311
8312 void SaveScore(int nr)
8313 {
8314   int i;
8315   char *filename = getScoreFilename(nr);
8316   FILE *file;
8317
8318   InitScoreDirectory(leveldir_current->subdir);
8319
8320   if (!(file = fopen(filename, MODE_WRITE)))
8321   {
8322     Error(ERR_WARN, "cannot save score for level %d", nr);
8323     return;
8324   }
8325
8326   fprintf(file, "%s\n\n", SCORE_COOKIE);
8327
8328   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
8329     fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name);
8330
8331   fclose(file);
8332
8333   SetFilePermissions(filename, PERMS_PUBLIC);
8334 }
8335
8336
8337 /* ========================================================================= */
8338 /* setup file functions                                                      */
8339 /* ========================================================================= */
8340
8341 #define TOKEN_STR_PLAYER_PREFIX                 "player_"
8342
8343 /* global setup */
8344 #define SETUP_TOKEN_PLAYER_NAME                 0
8345 #define SETUP_TOKEN_SOUND                       1
8346 #define SETUP_TOKEN_SOUND_LOOPS                 2
8347 #define SETUP_TOKEN_SOUND_MUSIC                 3
8348 #define SETUP_TOKEN_SOUND_SIMPLE                4
8349 #define SETUP_TOKEN_TOONS                       5
8350 #define SETUP_TOKEN_SCROLL_DELAY                6
8351 #define SETUP_TOKEN_SCROLL_DELAY_VALUE          7
8352 #define SETUP_TOKEN_SOFT_SCROLLING              8
8353 #define SETUP_TOKEN_FADE_SCREENS                9
8354 #define SETUP_TOKEN_AUTORECORD                  10
8355 #define SETUP_TOKEN_SHOW_TITLESCREEN            11
8356 #define SETUP_TOKEN_QUICK_DOORS                 12
8357 #define SETUP_TOKEN_TEAM_MODE                   13
8358 #define SETUP_TOKEN_HANDICAP                    14
8359 #define SETUP_TOKEN_SKIP_LEVELS                 15
8360 #define SETUP_TOKEN_TIME_LIMIT                  16
8361 #define SETUP_TOKEN_FULLSCREEN                  17
8362 #define SETUP_TOKEN_FULLSCREEN_MODE             18
8363 #define SETUP_TOKEN_ASK_ON_ESCAPE               19
8364 #define SETUP_TOKEN_ASK_ON_ESCAPE_EDITOR        20
8365 #define SETUP_TOKEN_QUICK_SWITCH                21
8366 #define SETUP_TOKEN_INPUT_ON_FOCUS              22
8367 #define SETUP_TOKEN_PREFER_AGA_GRAPHICS         23
8368 #define SETUP_TOKEN_GAME_FRAME_DELAY            24
8369 #define SETUP_TOKEN_GRAPHICS_SET                25
8370 #define SETUP_TOKEN_SOUNDS_SET                  26
8371 #define SETUP_TOKEN_MUSIC_SET                   27
8372 #define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS     28
8373 #define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS       29
8374 #define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC        30
8375
8376 #define NUM_GLOBAL_SETUP_TOKENS                 31
8377
8378 /* editor setup */
8379 #define SETUP_TOKEN_EDITOR_EL_BOULDERDASH       0
8380 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE      1
8381 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE_CLUB 2
8382 #define SETUP_TOKEN_EDITOR_EL_MORE              3
8383 #define SETUP_TOKEN_EDITOR_EL_SOKOBAN           4
8384 #define SETUP_TOKEN_EDITOR_EL_SUPAPLEX          5
8385 #define SETUP_TOKEN_EDITOR_EL_DIAMOND_CAVES     6
8386 #define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH    7
8387 #define SETUP_TOKEN_EDITOR_EL_CHARS             8
8388 #define SETUP_TOKEN_EDITOR_EL_STEEL_CHARS       9
8389 #define SETUP_TOKEN_EDITOR_EL_CUSTOM            10
8390 #define SETUP_TOKEN_EDITOR_EL_HEADLINES         11
8391 #define SETUP_TOKEN_EDITOR_EL_USER_DEFINED      12
8392 #define SETUP_TOKEN_EDITOR_EL_DYNAMIC           13
8393 #define SETUP_TOKEN_EDITOR_EL_BY_GAME           14
8394 #define SETUP_TOKEN_EDITOR_EL_BY_TYPE           15
8395 #define SETUP_TOKEN_EDITOR_SHOW_ELEMENT_TOKEN   16
8396
8397 #define NUM_EDITOR_SETUP_TOKENS                 17
8398
8399 /* editor cascade setup */
8400 #define SETUP_TOKEN_EDITOR_CASCADE_BD           0
8401 #define SETUP_TOKEN_EDITOR_CASCADE_EM           1
8402 #define SETUP_TOKEN_EDITOR_CASCADE_EMC          2
8403 #define SETUP_TOKEN_EDITOR_CASCADE_RND          3
8404 #define SETUP_TOKEN_EDITOR_CASCADE_SB           4
8405 #define SETUP_TOKEN_EDITOR_CASCADE_SP           5
8406 #define SETUP_TOKEN_EDITOR_CASCADE_DC           6
8407 #define SETUP_TOKEN_EDITOR_CASCADE_DX           7
8408 #define SETUP_TOKEN_EDITOR_CASCADE_TEXT         8
8409 #define SETUP_TOKEN_EDITOR_CASCADE_STEELTEXT    9
8410 #define SETUP_TOKEN_EDITOR_CASCADE_CE           10
8411 #define SETUP_TOKEN_EDITOR_CASCADE_GE           11
8412 #define SETUP_TOKEN_EDITOR_CASCADE_REF          12
8413 #define SETUP_TOKEN_EDITOR_CASCADE_USER         13
8414 #define SETUP_TOKEN_EDITOR_CASCADE_DYNAMIC      14
8415
8416 #define NUM_EDITOR_CASCADE_SETUP_TOKENS         15
8417
8418 /* shortcut setup */
8419 #define SETUP_TOKEN_SHORTCUT_SAVE_GAME          0
8420 #define SETUP_TOKEN_SHORTCUT_LOAD_GAME          1
8421 #define SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE       2
8422 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_1     3
8423 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_2     4
8424 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_3     5
8425 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_4     6
8426 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_ALL   7
8427
8428 #define NUM_SHORTCUT_SETUP_TOKENS               8
8429
8430 /* player setup */
8431 #define SETUP_TOKEN_PLAYER_USE_JOYSTICK         0
8432 #define SETUP_TOKEN_PLAYER_JOY_DEVICE_NAME      1
8433 #define SETUP_TOKEN_PLAYER_JOY_XLEFT            2
8434 #define SETUP_TOKEN_PLAYER_JOY_XMIDDLE          3
8435 #define SETUP_TOKEN_PLAYER_JOY_XRIGHT           4
8436 #define SETUP_TOKEN_PLAYER_JOY_YUPPER           5
8437 #define SETUP_TOKEN_PLAYER_JOY_YMIDDLE          6
8438 #define SETUP_TOKEN_PLAYER_JOY_YLOWER           7
8439 #define SETUP_TOKEN_PLAYER_JOY_SNAP             8
8440 #define SETUP_TOKEN_PLAYER_JOY_DROP             9
8441 #define SETUP_TOKEN_PLAYER_KEY_LEFT             10
8442 #define SETUP_TOKEN_PLAYER_KEY_RIGHT            11
8443 #define SETUP_TOKEN_PLAYER_KEY_UP               12
8444 #define SETUP_TOKEN_PLAYER_KEY_DOWN             13
8445 #define SETUP_TOKEN_PLAYER_KEY_SNAP             14
8446 #define SETUP_TOKEN_PLAYER_KEY_DROP             15
8447
8448 #define NUM_PLAYER_SETUP_TOKENS                 16
8449
8450 /* system setup */
8451 #define SETUP_TOKEN_SYSTEM_SDL_VIDEODRIVER      0
8452 #define SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER      1
8453 #define SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE  2
8454
8455 #define NUM_SYSTEM_SETUP_TOKENS                 3
8456
8457 /* options setup */
8458 #define SETUP_TOKEN_OPTIONS_VERBOSE             0
8459
8460 #define NUM_OPTIONS_SETUP_TOKENS                1
8461
8462
8463 static struct SetupInfo si;
8464 static struct SetupEditorInfo sei;
8465 static struct SetupEditorCascadeInfo seci;
8466 static struct SetupShortcutInfo ssi;
8467 static struct SetupInputInfo sii;
8468 static struct SetupSystemInfo syi;
8469 static struct OptionInfo soi;
8470
8471 static struct TokenInfo global_setup_tokens[] =
8472 {
8473   { TYPE_STRING, &si.player_name,       "player_name"                   },
8474   { TYPE_SWITCH, &si.sound,             "sound"                         },
8475   { TYPE_SWITCH, &si.sound_loops,       "repeating_sound_loops"         },
8476   { TYPE_SWITCH, &si.sound_music,       "background_music"              },
8477   { TYPE_SWITCH, &si.sound_simple,      "simple_sound_effects"          },
8478   { TYPE_SWITCH, &si.toons,             "toons"                         },
8479   { TYPE_SWITCH, &si.scroll_delay,      "scroll_delay"                  },
8480   { TYPE_INTEGER,&si.scroll_delay_value,"scroll_delay_value"            },
8481   { TYPE_SWITCH, &si.soft_scrolling,    "soft_scrolling"                },
8482   { TYPE_SWITCH, &si.fade_screens,      "fade_screens"                  },
8483   { TYPE_SWITCH, &si.autorecord,        "automatic_tape_recording"      },
8484   { TYPE_SWITCH, &si.show_titlescreen,  "show_titlescreen"              },
8485   { TYPE_SWITCH, &si.quick_doors,       "quick_doors"                   },
8486   { TYPE_SWITCH, &si.team_mode,         "team_mode"                     },
8487   { TYPE_SWITCH, &si.handicap,          "handicap"                      },
8488   { TYPE_SWITCH, &si.skip_levels,       "skip_levels"                   },
8489   { TYPE_SWITCH, &si.time_limit,        "time_limit"                    },
8490   { TYPE_SWITCH, &si.fullscreen,        "fullscreen"                    },
8491   { TYPE_STRING, &si.fullscreen_mode,   "fullscreen_mode"               },
8492   { TYPE_SWITCH, &si.ask_on_escape,     "ask_on_escape"                 },
8493   { TYPE_SWITCH, &si.ask_on_escape_editor, "ask_on_escape_editor"       },
8494   { TYPE_SWITCH, &si.quick_switch,      "quick_player_switch"           },
8495   { TYPE_SWITCH, &si.input_on_focus,    "input_on_focus"                },
8496   { TYPE_SWITCH, &si.prefer_aga_graphics, "prefer_aga_graphics"         },
8497   { TYPE_INTEGER,&si.game_frame_delay,  "game_frame_delay"              },
8498   { TYPE_STRING, &si.graphics_set,      "graphics_set"                  },
8499   { TYPE_STRING, &si.sounds_set,        "sounds_set"                    },
8500   { TYPE_STRING, &si.music_set,         "music_set"                     },
8501   { TYPE_SWITCH3,&si.override_level_graphics, "override_level_graphics" },
8502   { TYPE_SWITCH3,&si.override_level_sounds,   "override_level_sounds"   },
8503   { TYPE_SWITCH3,&si.override_level_music,    "override_level_music"    },
8504 };
8505
8506 static boolean not_used = FALSE;
8507 static struct TokenInfo editor_setup_tokens[] =
8508 {
8509 #if 1
8510   { TYPE_SWITCH, &not_used,             "editor.el_boulderdash"         },
8511   { TYPE_SWITCH, &not_used,             "editor.el_emerald_mine"        },
8512   { TYPE_SWITCH, &not_used,             "editor.el_emerald_mine_club"   },
8513   { TYPE_SWITCH, &not_used,             "editor.el_more"                },
8514   { TYPE_SWITCH, &not_used,             "editor.el_sokoban"             },
8515   { TYPE_SWITCH, &not_used,             "editor.el_supaplex"            },
8516   { TYPE_SWITCH, &not_used,             "editor.el_diamond_caves"       },
8517   { TYPE_SWITCH, &not_used,             "editor.el_dx_boulderdash"      },
8518 #else
8519   { TYPE_SWITCH, &sei.el_boulderdash,   "editor.el_boulderdash"         },
8520   { TYPE_SWITCH, &sei.el_emerald_mine,  "editor.el_emerald_mine"        },
8521   { TYPE_SWITCH, &sei.el_emerald_mine_club,"editor.el_emerald_mine_club"},
8522   { TYPE_SWITCH, &sei.el_more,          "editor.el_more"                },
8523   { TYPE_SWITCH, &sei.el_sokoban,       "editor.el_sokoban"             },
8524   { TYPE_SWITCH, &sei.el_supaplex,      "editor.el_supaplex"            },
8525   { TYPE_SWITCH, &sei.el_diamond_caves, "editor.el_diamond_caves"       },
8526   { TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash"      },
8527 #endif
8528   { TYPE_SWITCH, &sei.el_chars,         "editor.el_chars"               },
8529   { TYPE_SWITCH, &sei.el_steel_chars,   "editor.el_steel_chars"         },
8530   { TYPE_SWITCH, &sei.el_custom,        "editor.el_custom"              },
8531 #if 1
8532   { TYPE_SWITCH, &not_used,             "editor.el_headlines"           },
8533 #else
8534   { TYPE_SWITCH, &sei.el_headlines,     "editor.el_headlines"           },
8535 #endif
8536   { TYPE_SWITCH, &sei.el_user_defined,  "editor.el_user_defined"        },
8537   { TYPE_SWITCH, &sei.el_dynamic,       "editor.el_dynamic"             },
8538   { TYPE_SWITCH, &sei.el_by_game,       "editor.el_by_game"             },
8539   { TYPE_SWITCH, &sei.el_by_type,       "editor.el_by_type"             },
8540   { TYPE_SWITCH, &sei.show_element_token,"editor.show_element_token"    },
8541 };
8542
8543 static struct TokenInfo editor_cascade_setup_tokens[] =
8544 {
8545   { TYPE_SWITCH, &seci.el_bd,           "editor.cascade.el_bd"          },
8546   { TYPE_SWITCH, &seci.el_em,           "editor.cascade.el_em"          },
8547   { TYPE_SWITCH, &seci.el_emc,          "editor.cascade.el_emc"         },
8548   { TYPE_SWITCH, &seci.el_rnd,          "editor.cascade.el_rnd"         },
8549   { TYPE_SWITCH, &seci.el_sb,           "editor.cascade.el_sb"          },
8550   { TYPE_SWITCH, &seci.el_sp,           "editor.cascade.el_sp"          },
8551   { TYPE_SWITCH, &seci.el_dc,           "editor.cascade.el_dc"          },
8552   { TYPE_SWITCH, &seci.el_dx,           "editor.cascade.el_dx"          },
8553   { TYPE_SWITCH, &seci.el_chars,        "editor.cascade.el_chars"       },
8554   { TYPE_SWITCH, &seci.el_steel_chars,  "editor.cascade.el_steel_chars" },
8555   { TYPE_SWITCH, &seci.el_ce,           "editor.cascade.el_ce"          },
8556   { TYPE_SWITCH, &seci.el_ge,           "editor.cascade.el_ge"          },
8557   { TYPE_SWITCH, &seci.el_ref,          "editor.cascade.el_ref"         },
8558   { TYPE_SWITCH, &seci.el_user,         "editor.cascade.el_user"        },
8559   { TYPE_SWITCH, &seci.el_dynamic,      "editor.cascade.el_dynamic"     },
8560 };
8561
8562 static struct TokenInfo shortcut_setup_tokens[] =
8563 {
8564   { TYPE_KEY_X11, &ssi.save_game,       "shortcut.save_game"            },
8565   { TYPE_KEY_X11, &ssi.load_game,       "shortcut.load_game"            },
8566   { TYPE_KEY_X11, &ssi.toggle_pause,    "shortcut.toggle_pause"         },
8567   { TYPE_KEY_X11, &ssi.focus_player[0], "shortcut.focus_player_1"       },
8568   { TYPE_KEY_X11, &ssi.focus_player[1], "shortcut.focus_player_2"       },
8569   { TYPE_KEY_X11, &ssi.focus_player[2], "shortcut.focus_player_3"       },
8570   { TYPE_KEY_X11, &ssi.focus_player[3], "shortcut.focus_player_4"       },
8571   { TYPE_KEY_X11, &ssi.focus_player_all,"shortcut.focus_player_all"     },
8572 };
8573
8574 static struct TokenInfo player_setup_tokens[] =
8575 {
8576   { TYPE_BOOLEAN, &sii.use_joystick,    ".use_joystick"                 },
8577   { TYPE_STRING,  &sii.joy.device_name, ".joy.device_name"              },
8578   { TYPE_INTEGER, &sii.joy.xleft,       ".joy.xleft"                    },
8579   { TYPE_INTEGER, &sii.joy.xmiddle,     ".joy.xmiddle"                  },
8580   { TYPE_INTEGER, &sii.joy.xright,      ".joy.xright"                   },
8581   { TYPE_INTEGER, &sii.joy.yupper,      ".joy.yupper"                   },
8582   { TYPE_INTEGER, &sii.joy.ymiddle,     ".joy.ymiddle"                  },
8583   { TYPE_INTEGER, &sii.joy.ylower,      ".joy.ylower"                   },
8584   { TYPE_INTEGER, &sii.joy.snap,        ".joy.snap_field"               },
8585   { TYPE_INTEGER, &sii.joy.drop,        ".joy.place_bomb"               },
8586   { TYPE_KEY_X11, &sii.key.left,        ".key.move_left"                },
8587   { TYPE_KEY_X11, &sii.key.right,       ".key.move_right"               },
8588   { TYPE_KEY_X11, &sii.key.up,          ".key.move_up"                  },
8589   { TYPE_KEY_X11, &sii.key.down,        ".key.move_down"                },
8590   { TYPE_KEY_X11, &sii.key.snap,        ".key.snap_field"               },
8591   { TYPE_KEY_X11, &sii.key.drop,        ".key.place_bomb"               },
8592 };
8593
8594 static struct TokenInfo system_setup_tokens[] =
8595 {
8596   { TYPE_STRING,  &syi.sdl_videodriver, "system.sdl_videodriver"        },
8597   { TYPE_STRING,  &syi.sdl_audiodriver, "system.sdl_audiodriver"        },
8598   { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size" },
8599 };
8600
8601 static struct TokenInfo options_setup_tokens[] =
8602 {
8603   { TYPE_BOOLEAN, &soi.verbose,         "options.verbose"               },
8604 };
8605
8606 static char *get_corrected_login_name(char *login_name)
8607 {
8608   /* needed because player name must be a fixed length string */
8609   char *login_name_new = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
8610
8611   strncpy(login_name_new, login_name, MAX_PLAYER_NAME_LEN);
8612   login_name_new[MAX_PLAYER_NAME_LEN] = '\0';
8613
8614   if (strlen(login_name) > MAX_PLAYER_NAME_LEN)         /* name has been cut */
8615     if (strchr(login_name_new, ' '))
8616       *strchr(login_name_new, ' ') = '\0';
8617
8618   return login_name_new;
8619 }
8620
8621 static void setSetupInfoToDefaults(struct SetupInfo *si)
8622 {
8623   int i;
8624
8625   si->player_name = get_corrected_login_name(getLoginName());
8626
8627   si->sound = TRUE;
8628   si->sound_loops = TRUE;
8629   si->sound_music = TRUE;
8630   si->sound_simple = TRUE;
8631   si->toons = TRUE;
8632   si->scroll_delay = TRUE;
8633   si->scroll_delay_value = STD_SCROLL_DELAY;
8634   si->soft_scrolling = TRUE;
8635   si->fade_screens = TRUE;
8636   si->autorecord = TRUE;
8637   si->show_titlescreen = TRUE;
8638   si->quick_doors = FALSE;
8639   si->team_mode = FALSE;
8640   si->handicap = TRUE;
8641   si->skip_levels = TRUE;
8642   si->time_limit = TRUE;
8643   si->fullscreen = FALSE;
8644   si->fullscreen_mode = getStringCopy(DEFAULT_FULLSCREEN_MODE);
8645   si->ask_on_escape = TRUE;
8646   si->ask_on_escape_editor = TRUE;
8647   si->quick_switch = FALSE;
8648   si->input_on_focus = FALSE;
8649   si->prefer_aga_graphics = TRUE;
8650   si->game_frame_delay = GAME_FRAME_DELAY;
8651
8652   si->graphics_set = getStringCopy(GFX_DEFAULT_SUBDIR);
8653   si->sounds_set = getStringCopy(SND_DEFAULT_SUBDIR);
8654   si->music_set = getStringCopy(MUS_DEFAULT_SUBDIR);
8655   si->override_level_graphics = FALSE;
8656   si->override_level_sounds = FALSE;
8657   si->override_level_music = FALSE;
8658
8659   si->editor.el_boulderdash             = TRUE;
8660   si->editor.el_emerald_mine            = TRUE;
8661   si->editor.el_emerald_mine_club       = TRUE;
8662   si->editor.el_more                    = TRUE;
8663   si->editor.el_sokoban                 = TRUE;
8664   si->editor.el_supaplex                = TRUE;
8665   si->editor.el_diamond_caves           = TRUE;
8666   si->editor.el_dx_boulderdash          = TRUE;
8667   si->editor.el_chars                   = TRUE;
8668   si->editor.el_steel_chars             = TRUE;
8669   si->editor.el_custom                  = TRUE;
8670
8671   si->editor.el_headlines = TRUE;
8672   si->editor.el_user_defined = FALSE;
8673   si->editor.el_dynamic = TRUE;
8674
8675   si->editor.show_element_token = FALSE;
8676
8677   si->shortcut.save_game        = DEFAULT_KEY_SAVE_GAME;
8678   si->shortcut.load_game        = DEFAULT_KEY_LOAD_GAME;
8679   si->shortcut.toggle_pause     = DEFAULT_KEY_TOGGLE_PAUSE;
8680
8681   si->shortcut.focus_player[0]  = DEFAULT_KEY_FOCUS_PLAYER_1;
8682   si->shortcut.focus_player[1]  = DEFAULT_KEY_FOCUS_PLAYER_2;
8683   si->shortcut.focus_player[2]  = DEFAULT_KEY_FOCUS_PLAYER_3;
8684   si->shortcut.focus_player[3]  = DEFAULT_KEY_FOCUS_PLAYER_4;
8685   si->shortcut.focus_player_all = DEFAULT_KEY_FOCUS_PLAYER_ALL;
8686
8687   for (i = 0; i < MAX_PLAYERS; i++)
8688   {
8689     si->input[i].use_joystick = FALSE;
8690     si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
8691     si->input[i].joy.xleft   = JOYSTICK_XLEFT;
8692     si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
8693     si->input[i].joy.xright  = JOYSTICK_XRIGHT;
8694     si->input[i].joy.yupper  = JOYSTICK_YUPPER;
8695     si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
8696     si->input[i].joy.ylower  = JOYSTICK_YLOWER;
8697     si->input[i].joy.snap  = (i == 0 ? JOY_BUTTON_1 : 0);
8698     si->input[i].joy.drop  = (i == 0 ? JOY_BUTTON_2 : 0);
8699     si->input[i].key.left  = (i == 0 ? DEFAULT_KEY_LEFT  : KSYM_UNDEFINED);
8700     si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
8701     si->input[i].key.up    = (i == 0 ? DEFAULT_KEY_UP    : KSYM_UNDEFINED);
8702     si->input[i].key.down  = (i == 0 ? DEFAULT_KEY_DOWN  : KSYM_UNDEFINED);
8703     si->input[i].key.snap  = (i == 0 ? DEFAULT_KEY_SNAP  : KSYM_UNDEFINED);
8704     si->input[i].key.drop  = (i == 0 ? DEFAULT_KEY_DROP  : KSYM_UNDEFINED);
8705   }
8706
8707   si->system.sdl_videodriver = getStringCopy(ARG_DEFAULT);
8708   si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT);
8709   si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
8710
8711   si->options.verbose = FALSE;
8712
8713 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
8714   si->handicap = FALSE;
8715   si->fullscreen = TRUE;
8716   si->override_level_graphics = AUTO;
8717   si->override_level_sounds = AUTO;
8718   si->override_level_music = AUTO;
8719 #endif
8720 }
8721
8722 static void setSetupInfoToDefaults_EditorCascade(struct SetupInfo *si)
8723 {
8724   si->editor_cascade.el_bd              = TRUE;
8725   si->editor_cascade.el_em              = TRUE;
8726   si->editor_cascade.el_emc             = TRUE;
8727   si->editor_cascade.el_rnd             = TRUE;
8728   si->editor_cascade.el_sb              = TRUE;
8729   si->editor_cascade.el_sp              = TRUE;
8730   si->editor_cascade.el_dc              = TRUE;
8731   si->editor_cascade.el_dx              = TRUE;
8732
8733   si->editor_cascade.el_chars           = FALSE;
8734   si->editor_cascade.el_steel_chars     = FALSE;
8735   si->editor_cascade.el_ce              = FALSE;
8736   si->editor_cascade.el_ge              = FALSE;
8737   si->editor_cascade.el_ref             = FALSE;
8738   si->editor_cascade.el_user            = FALSE;
8739   si->editor_cascade.el_dynamic         = FALSE;
8740 }
8741
8742 static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
8743 {
8744   int i, pnr;
8745
8746   if (!setup_file_hash)
8747     return;
8748
8749   /* global setup */
8750   si = setup;
8751   for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
8752     setSetupInfo(global_setup_tokens, i,
8753                  getHashEntry(setup_file_hash, global_setup_tokens[i].text));
8754   setup = si;
8755
8756   /* editor setup */
8757   sei = setup.editor;
8758   for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
8759     setSetupInfo(editor_setup_tokens, i,
8760                  getHashEntry(setup_file_hash,editor_setup_tokens[i].text));
8761   setup.editor = sei;
8762
8763   /* shortcut setup */
8764   ssi = setup.shortcut;
8765   for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
8766     setSetupInfo(shortcut_setup_tokens, i,
8767                  getHashEntry(setup_file_hash,shortcut_setup_tokens[i].text));
8768   setup.shortcut = ssi;
8769
8770   /* player setup */
8771   for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
8772   {
8773     char prefix[30];
8774
8775     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
8776
8777     sii = setup.input[pnr];
8778     for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
8779     {
8780       char full_token[100];
8781
8782       sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
8783       setSetupInfo(player_setup_tokens, i,
8784                    getHashEntry(setup_file_hash, full_token));
8785     }
8786     setup.input[pnr] = sii;
8787   }
8788
8789   /* system setup */
8790   syi = setup.system;
8791   for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
8792     setSetupInfo(system_setup_tokens, i,
8793                  getHashEntry(setup_file_hash, system_setup_tokens[i].text));
8794   setup.system = syi;
8795
8796   /* options setup */
8797   soi = setup.options;
8798   for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
8799     setSetupInfo(options_setup_tokens, i,
8800                  getHashEntry(setup_file_hash, options_setup_tokens[i].text));
8801   setup.options = soi;
8802 }
8803
8804 static void decodeSetupFileHash_EditorCascade(SetupFileHash *setup_file_hash)
8805 {
8806   int i;
8807
8808   if (!setup_file_hash)
8809     return;
8810
8811   /* editor cascade setup */
8812   seci = setup.editor_cascade;
8813   for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
8814     setSetupInfo(editor_cascade_setup_tokens, i,
8815                  getHashEntry(setup_file_hash,
8816                               editor_cascade_setup_tokens[i].text));
8817   setup.editor_cascade = seci;
8818 }
8819
8820 void LoadSetup()
8821 {
8822   char *filename = getSetupFilename();
8823   SetupFileHash *setup_file_hash = NULL;
8824
8825   /* always start with reliable default values */
8826   setSetupInfoToDefaults(&setup);
8827
8828   setup_file_hash = loadSetupFileHash(filename);
8829
8830   if (setup_file_hash)
8831   {
8832     char *player_name_new;
8833
8834     checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP"));
8835     decodeSetupFileHash(setup_file_hash);
8836
8837     freeSetupFileHash(setup_file_hash);
8838
8839     /* needed to work around problems with fixed length strings */
8840     player_name_new = get_corrected_login_name(setup.player_name);
8841     free(setup.player_name);
8842     setup.player_name = player_name_new;
8843
8844     /* "scroll_delay: on(3) / off(0)" was replaced by scroll delay value */
8845     if (setup.scroll_delay == FALSE)
8846     {
8847       setup.scroll_delay_value = MIN_SCROLL_DELAY;
8848       setup.scroll_delay = TRUE;                        /* now always "on" */
8849     }
8850
8851     /* make sure that scroll delay value stays inside valid range */
8852     setup.scroll_delay_value =
8853       MIN(MAX(MIN_SCROLL_DELAY, setup.scroll_delay_value), MAX_SCROLL_DELAY);
8854   }
8855   else
8856     Error(ERR_WARN, "using default setup values");
8857 }
8858
8859 void LoadSetup_EditorCascade()
8860 {
8861   char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
8862   SetupFileHash *setup_file_hash = NULL;
8863
8864   /* always start with reliable default values */
8865   setSetupInfoToDefaults_EditorCascade(&setup);
8866
8867   setup_file_hash = loadSetupFileHash(filename);
8868
8869   if (setup_file_hash)
8870   {
8871     checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP"));
8872     decodeSetupFileHash_EditorCascade(setup_file_hash);
8873
8874     freeSetupFileHash(setup_file_hash);
8875   }
8876
8877   free(filename);
8878 }
8879
8880 void SaveSetup()
8881 {
8882   char *filename = getSetupFilename();
8883   FILE *file;
8884   int i, pnr;
8885
8886   InitUserDataDirectory();
8887
8888   if (!(file = fopen(filename, MODE_WRITE)))
8889   {
8890     Error(ERR_WARN, "cannot write setup file '%s'", filename);
8891     return;
8892   }
8893
8894   fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
8895                                                getCookie("SETUP")));
8896   fprintf(file, "\n");
8897
8898   /* global setup */
8899   si = setup;
8900   for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
8901   {
8902     /* just to make things nicer :) */
8903     if (i == SETUP_TOKEN_PLAYER_NAME + 1 ||
8904         i == SETUP_TOKEN_GRAPHICS_SET)
8905       fprintf(file, "\n");
8906
8907     fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
8908   }
8909
8910   /* editor setup */
8911   sei = setup.editor;
8912   fprintf(file, "\n");
8913   for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
8914     fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i));
8915
8916   /* shortcut setup */
8917   ssi = setup.shortcut;
8918   fprintf(file, "\n");
8919   for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
8920     fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
8921
8922   /* player setup */
8923   for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
8924   {
8925     char prefix[30];
8926
8927     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
8928     fprintf(file, "\n");
8929
8930     sii = setup.input[pnr];
8931     for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
8932       fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
8933   }
8934
8935   /* system setup */
8936   syi = setup.system;
8937   fprintf(file, "\n");
8938   for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
8939     fprintf(file, "%s\n", getSetupLine(system_setup_tokens, "", i));
8940
8941   /* options setup */
8942   soi = setup.options;
8943   fprintf(file, "\n");
8944   for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
8945     fprintf(file, "%s\n", getSetupLine(options_setup_tokens, "", i));
8946
8947   fclose(file);
8948
8949   SetFilePermissions(filename, PERMS_PRIVATE);
8950 }
8951
8952 void SaveSetup_EditorCascade()
8953 {
8954   char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
8955   FILE *file;
8956   int i;
8957
8958   InitUserDataDirectory();
8959
8960   if (!(file = fopen(filename, MODE_WRITE)))
8961   {
8962     Error(ERR_WARN, "cannot write editor cascade state file '%s'", filename);
8963     free(filename);
8964     return;
8965   }
8966
8967   fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
8968                                                getCookie("SETUP")));
8969   fprintf(file, "\n");
8970
8971   seci = setup.editor_cascade;
8972   fprintf(file, "\n");
8973   for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
8974     fprintf(file, "%s\n", getSetupLine(editor_cascade_setup_tokens, "", i));
8975
8976   fclose(file);
8977
8978   SetFilePermissions(filename, PERMS_PRIVATE);
8979
8980   free(filename);
8981 }
8982
8983 void LoadCustomElementDescriptions()
8984 {
8985   char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
8986   SetupFileHash *setup_file_hash;
8987   int i;
8988
8989   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
8990   {
8991     if (element_info[i].custom_description != NULL)
8992     {
8993       free(element_info[i].custom_description);
8994       element_info[i].custom_description = NULL;
8995     }
8996   }
8997
8998   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
8999     return;
9000
9001   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9002   {
9003     char *token = getStringCat2(element_info[i].token_name, ".name");
9004     char *value = getHashEntry(setup_file_hash, token);
9005
9006     if (value != NULL)
9007       element_info[i].custom_description = getStringCopy(value);
9008
9009     free(token);
9010   }
9011
9012   freeSetupFileHash(setup_file_hash);
9013 }
9014
9015 static int getElementFromToken(char *token)
9016 {
9017 #if 1
9018   char *value = getHashEntry(element_token_hash, token);
9019
9020   if (value != NULL)
9021     return atoi(value);
9022 #else
9023   int i;
9024
9025   /* !!! OPTIMIZE THIS BY USING HASH !!! */
9026   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
9027     if (strEqual(token, element_info[i].token_name))
9028       return i;
9029 #endif
9030
9031   Error(ERR_WARN, "unknown element token '%s'", token);
9032
9033   return EL_UNDEFINED;
9034 }
9035
9036 static int get_token_parameter_value(char *token, char *value_raw)
9037 {
9038   char *suffix;
9039
9040   if (token == NULL || value_raw == NULL)
9041     return ARG_UNDEFINED_VALUE;
9042
9043   suffix = strrchr(token, '.');
9044   if (suffix == NULL)
9045     suffix = token;
9046
9047 #if 1
9048   if (strEqual(suffix, ".element"))
9049     return getElementFromToken(value_raw);
9050 #endif
9051
9052 #if 0
9053   if (strncmp(suffix, ".font", 5) == 0)
9054   {
9055     int i;
9056
9057     /* !!! OPTIMIZE THIS BY USING HASH !!! */
9058     for (i = 0; i < NUM_FONTS; i++)
9059       if (strEqual(value_raw, font_info[i].token_name))
9060         return i;
9061
9062     /* if font not found, use reliable default value */
9063     return FONT_INITIAL_1;
9064   }
9065 #endif
9066
9067   /* !!! USE CORRECT VALUE TYPE (currently works also for TYPE_BOOLEAN) !!! */
9068   return get_parameter_value(value_raw, suffix, TYPE_INTEGER);
9069 }
9070
9071 void InitMenuDesignSettings_Static()
9072 {
9073 #if 0
9074   static SetupFileHash *image_config_hash = NULL;
9075 #endif
9076   int i;
9077
9078 #if 0
9079   if (image_config_hash == NULL)
9080   {
9081     image_config_hash = newSetupFileHash();
9082
9083     for (i = 0; image_config[i].token != NULL; i++)
9084       setHashEntry(image_config_hash,
9085                    image_config[i].token,
9086                    image_config[i].value);
9087   }
9088 #endif
9089
9090 #if 1
9091   /* always start with reliable default values from static default config */
9092   for (i = 0; image_config_vars[i].token != NULL; i++)
9093   {
9094     char *value = getHashEntry(image_config_hash, image_config_vars[i].token);
9095
9096     if (value != NULL)
9097       *image_config_vars[i].value =
9098         get_token_parameter_value(image_config_vars[i].token, value);
9099   }
9100
9101 #else
9102
9103   int j;
9104
9105   /* always start with reliable default values from static default config */
9106   for (i = 0; image_config_vars[i].token != NULL; i++)
9107     for (j = 0; image_config[j].token != NULL; j++)
9108       if (strEqual(image_config_vars[i].token, image_config[j].token))
9109         *image_config_vars[i].value =
9110           get_token_parameter_value(image_config_vars[i].token,
9111                                     image_config[j].value);
9112 #endif
9113 }
9114
9115 static void InitMenuDesignSettings_SpecialPreProcessing()
9116 {
9117   int i;
9118
9119   /* the following initializes hierarchical values from static configuration */
9120
9121   /* special case: initialize "ARG_DEFAULT" values in static default config */
9122   /* (e.g., initialize "[titlemessage].fade_mode" from "[title].fade_mode") */
9123   titlemessage_initial_default.fade_mode  = title_initial_default.fade_mode;
9124   titlemessage_initial_default.fade_delay = title_initial_default.fade_delay;
9125   titlemessage_initial_default.post_delay = title_initial_default.post_delay;
9126   titlemessage_initial_default.auto_delay = title_initial_default.auto_delay;
9127   titlemessage_default.fade_mode  = title_default.fade_mode;
9128   titlemessage_default.fade_delay = title_default.fade_delay;
9129   titlemessage_default.post_delay = title_default.post_delay;
9130   titlemessage_default.auto_delay = title_default.auto_delay;
9131
9132   /* special case: initialize "ARG_DEFAULT" values in static default config */
9133   /* (e.g., init "titlemessage_1.fade_mode" from "[titlemessage].fade_mode") */
9134   for (i = 0; i < MAX_NUM_TITLE_MESSAGES; i++)
9135   {
9136     titlemessage_initial[i] = titlemessage_initial_default;
9137     titlemessage[i] = titlemessage_default;
9138   }
9139
9140   /* special case: initialize "ARG_DEFAULT" values in static default config */
9141   /* (eg, init "menu.enter_screen.SCORES.xyz" from "menu.enter_screen.xyz") */
9142   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
9143   {
9144     menu.enter_screen[i] = menu.enter_screen[GFX_SPECIAL_ARG_DEFAULT];
9145     menu.leave_screen[i] = menu.leave_screen[GFX_SPECIAL_ARG_DEFAULT];
9146   }
9147 }
9148
9149 static void InitMenuDesignSettings_SpecialPostProcessing()
9150 {
9151   /* special case: initialize later added SETUP list size from LEVELS value */
9152   if (menu.list_size[GAME_MODE_SETUP] == -1)
9153     menu.list_size[GAME_MODE_SETUP] = menu.list_size[GAME_MODE_LEVELS];
9154 }
9155
9156 static void LoadMenuDesignSettingsFromFilename(char *filename)
9157 {
9158   static struct TitleMessageInfo tmi;
9159   static struct TokenInfo titlemessage_tokens[] =
9160   {
9161     { TYPE_INTEGER,     &tmi.x,                 ".x"                    },
9162     { TYPE_INTEGER,     &tmi.y,                 ".y"                    },
9163     { TYPE_INTEGER,     &tmi.width,             ".width"                },
9164     { TYPE_INTEGER,     &tmi.height,            ".height"               },
9165     { TYPE_INTEGER,     &tmi.chars,             ".chars"                },
9166     { TYPE_INTEGER,     &tmi.lines,             ".lines"                },
9167     { TYPE_INTEGER,     &tmi.align,             ".align"                },
9168     { TYPE_INTEGER,     &tmi.valign,            ".valign"               },
9169     { TYPE_INTEGER,     &tmi.font,              ".font"                 },
9170     { TYPE_BOOLEAN,     &tmi.autowrap,          ".autowrap"             },
9171     { TYPE_BOOLEAN,     &tmi.centered,          ".centered"             },
9172     { TYPE_BOOLEAN,     &tmi.parse_comments,    ".parse_comments"       },
9173     { TYPE_INTEGER,     &tmi.sort_priority,     ".sort_priority"        },
9174     { TYPE_INTEGER,     &tmi.fade_mode,         ".fade_mode"            },
9175     { TYPE_INTEGER,     &tmi.fade_delay,        ".fade_delay"           },
9176     { TYPE_INTEGER,     &tmi.post_delay,        ".post_delay"           },
9177     { TYPE_INTEGER,     &tmi.auto_delay,        ".auto_delay"           },
9178
9179     { -1,               NULL,                   NULL                    }
9180   };
9181   static struct
9182   {
9183     struct TitleMessageInfo *array;
9184     char *text;
9185   }
9186   titlemessage_arrays[] =
9187   {
9188     { titlemessage_initial,             "[titlemessage_initial]"        },
9189     { titlemessage,                     "[titlemessage]"                },
9190
9191     { NULL,                             NULL                            }
9192   };
9193   SetupFileHash *setup_file_hash;
9194   int i, j, k;
9195
9196 #if 0
9197   printf("LoadMenuDesignSettings from file '%s' ...\n", filename);
9198 #endif
9199
9200   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
9201     return;
9202
9203   /* the following initializes hierarchical values from dynamic configuration */
9204
9205   /* special case: initialize with default values that may be overwritten */
9206   /* (e.g., init "menu.draw_xoffset.INFO" from "menu.draw_xoffset") */
9207   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
9208   {
9209     char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset");
9210     char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset");
9211     char *value_3 = getHashEntry(setup_file_hash, "menu.list_size");
9212
9213     if (value_1 != NULL)
9214       menu.draw_xoffset[i] = get_integer_from_string(value_1);
9215     if (value_2 != NULL)
9216       menu.draw_yoffset[i] = get_integer_from_string(value_2);
9217     if (value_3 != NULL)
9218       menu.list_size[i] = get_integer_from_string(value_3);
9219   }
9220
9221   /* special case: initialize with default values that may be overwritten */
9222   /* (eg, init "menu.draw_xoffset.INFO[XXX]" from "menu.draw_xoffset.INFO") */
9223   for (i = 0; i < NUM_SPECIAL_GFX_INFO_ARGS; i++)
9224   {
9225     char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset.INFO");
9226     char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset.INFO");
9227
9228     if (value_1 != NULL)
9229       menu.draw_xoffset_info[i] = get_integer_from_string(value_1);
9230     if (value_2 != NULL)
9231       menu.draw_yoffset_info[i] = get_integer_from_string(value_2);
9232   }
9233
9234   /* special case: initialize with default values that may be overwritten */
9235   /* (eg, init "menu.draw_xoffset.SETUP[XXX]" from "menu.draw_xoffset.SETUP") */
9236   for (i = 0; i < NUM_SPECIAL_GFX_SETUP_ARGS; i++)
9237   {
9238     char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset.SETUP");
9239     char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset.SETUP");
9240
9241     if (value_1 != NULL)
9242       menu.draw_xoffset_setup[i] = get_integer_from_string(value_1);
9243     if (value_2 != NULL)
9244       menu.draw_yoffset_setup[i] = get_integer_from_string(value_2);
9245   }
9246
9247   /* special case: initialize with default values that may be overwritten */
9248   /* (eg, init "menu.enter_screen.SCORES.xyz" from "menu.enter_screen.xyz") */
9249   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
9250   {
9251     char *token_1 = "menu.enter_screen.fade_mode";
9252     char *token_2 = "menu.enter_screen.fade_delay";
9253     char *token_3 = "menu.enter_screen.post_delay";
9254     char *token_4 = "menu.leave_screen.fade_mode";
9255     char *token_5 = "menu.leave_screen.fade_delay";
9256     char *token_6 = "menu.leave_screen.post_delay";
9257     char *value_1 = getHashEntry(setup_file_hash, token_1);
9258     char *value_2 = getHashEntry(setup_file_hash, token_2);
9259     char *value_3 = getHashEntry(setup_file_hash, token_3);
9260     char *value_4 = getHashEntry(setup_file_hash, token_4);
9261     char *value_5 = getHashEntry(setup_file_hash, token_5);
9262     char *value_6 = getHashEntry(setup_file_hash, token_6);
9263
9264     if (value_1 != NULL)
9265       menu.enter_screen[i].fade_mode = get_token_parameter_value(token_1,
9266                                                                  value_1);
9267     if (value_2 != NULL)
9268       menu.enter_screen[i].fade_delay = get_token_parameter_value(token_2,
9269                                                                   value_2);
9270     if (value_3 != NULL)
9271       menu.enter_screen[i].post_delay = get_token_parameter_value(token_3,
9272                                                                   value_3);
9273     if (value_4 != NULL)
9274       menu.leave_screen[i].fade_mode = get_token_parameter_value(token_4,
9275                                                                  value_4);
9276     if (value_5 != NULL)
9277       menu.leave_screen[i].fade_delay = get_token_parameter_value(token_5,
9278                                                                   value_5);
9279     if (value_6 != NULL)
9280       menu.leave_screen[i].post_delay = get_token_parameter_value(token_6,
9281                                                                   value_6);
9282   }
9283
9284   /* special case: initialize with default values that may be overwritten */
9285   /* (e.g., init "titlemessage_1.fade_mode" from "[titlemessage].fade_mode") */
9286   for (i = 0; titlemessage_arrays[i].array != NULL; i++)
9287   {
9288     struct TitleMessageInfo *array = titlemessage_arrays[i].array;
9289     char *base_token = titlemessage_arrays[i].text;
9290
9291     for (j = 0; titlemessage_tokens[j].type != -1; j++)
9292     {
9293       char *token = getStringCat2(base_token, titlemessage_tokens[j].text);
9294       char *value = getHashEntry(setup_file_hash, token);
9295
9296       if (value != NULL)
9297       {
9298         int parameter_value = get_token_parameter_value(token, value);
9299
9300         for (k = 0; k < MAX_NUM_TITLE_MESSAGES; k++)
9301         {
9302           tmi = array[k];
9303
9304           if (titlemessage_tokens[j].type == TYPE_INTEGER)
9305             *(boolean *)titlemessage_tokens[j].value = (boolean)parameter_value;
9306           else
9307             *(int     *)titlemessage_tokens[j].value = (int)parameter_value;
9308
9309           array[k] = tmi;
9310         }
9311       }
9312
9313       free(token);
9314     }
9315   }
9316
9317   /* read (and overwrite with) values that may be specified in config file */
9318   for (i = 0; image_config_vars[i].token != NULL; i++)
9319   {
9320     char *value = getHashEntry(setup_file_hash, image_config_vars[i].token);
9321
9322     /* (ignore definitions set to "[DEFAULT]" which are already initialized) */
9323     if (value != NULL && !strEqual(value, ARG_DEFAULT))
9324       *image_config_vars[i].value =
9325         get_token_parameter_value(image_config_vars[i].token, value);
9326   }
9327
9328   freeSetupFileHash(setup_file_hash);
9329 }
9330
9331 void LoadMenuDesignSettings()
9332 {
9333   char *filename_base = UNDEFINED_FILENAME, *filename_local;
9334
9335   InitMenuDesignSettings_Static();
9336   InitMenuDesignSettings_SpecialPreProcessing();
9337
9338 #if 1
9339   if (!GFX_OVERRIDE_ARTWORK(ARTWORK_TYPE_GRAPHICS))
9340 #else
9341   if (!SETUP_OVERRIDE_ARTWORK(setup, ARTWORK_TYPE_GRAPHICS))
9342 #endif
9343   {
9344     /* first look for special settings configured in level series config */
9345     filename_base = getCustomArtworkLevelConfigFilename(ARTWORK_TYPE_GRAPHICS);
9346
9347     if (fileExists(filename_base))
9348       LoadMenuDesignSettingsFromFilename(filename_base);
9349   }
9350
9351   filename_local = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
9352
9353   if (filename_local != NULL && !strEqual(filename_base, filename_local))
9354     LoadMenuDesignSettingsFromFilename(filename_local);
9355
9356   InitMenuDesignSettings_SpecialPostProcessing();
9357 }
9358
9359 void LoadUserDefinedEditorElementList(int **elements, int *num_elements)
9360 {
9361   char *filename = getEditorSetupFilename();
9362   SetupFileList *setup_file_list, *list;
9363   SetupFileHash *element_hash;
9364   int num_unknown_tokens = 0;
9365   int i;
9366
9367   if ((setup_file_list = loadSetupFileList(filename)) == NULL)
9368     return;
9369
9370   element_hash = newSetupFileHash();
9371
9372   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9373     setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
9374
9375   /* determined size may be larger than needed (due to unknown elements) */
9376   *num_elements = 0;
9377   for (list = setup_file_list; list != NULL; list = list->next)
9378     (*num_elements)++;
9379
9380   /* add space for up to 3 more elements for padding that may be needed */
9381   *num_elements += 3;
9382
9383   /* free memory for old list of elements, if needed */
9384   checked_free(*elements);
9385
9386   /* allocate memory for new list of elements */
9387   *elements = checked_malloc(*num_elements * sizeof(int));
9388
9389   *num_elements = 0;
9390   for (list = setup_file_list; list != NULL; list = list->next)
9391   {
9392     char *value = getHashEntry(element_hash, list->token);
9393
9394     if (value == NULL)          /* try to find obsolete token mapping */
9395     {
9396       char *mapped_token = get_mapped_token(list->token);
9397
9398       if (mapped_token != NULL)
9399       {
9400         value = getHashEntry(element_hash, mapped_token);
9401
9402         free(mapped_token);
9403       }
9404     }
9405
9406     if (value != NULL)
9407     {
9408       (*elements)[(*num_elements)++] = atoi(value);
9409     }
9410     else
9411     {
9412       if (num_unknown_tokens == 0)
9413       {
9414         Error(ERR_INFO_LINE, "-");
9415         Error(ERR_INFO, "warning: unknown token(s) found in config file:");
9416         Error(ERR_INFO, "- config file: '%s'", filename);
9417
9418         num_unknown_tokens++;
9419       }
9420
9421       Error(ERR_INFO, "- token: '%s'", list->token);
9422     }
9423   }
9424
9425   if (num_unknown_tokens > 0)
9426     Error(ERR_INFO_LINE, "-");
9427
9428   while (*num_elements % 4)     /* pad with empty elements, if needed */
9429     (*elements)[(*num_elements)++] = EL_EMPTY;
9430
9431   freeSetupFileList(setup_file_list);
9432   freeSetupFileHash(element_hash);
9433
9434 #if 0
9435   for (i = 0; i < *num_elements; i++)
9436     printf("editor: element '%s' [%d]\n",
9437            element_info[(*elements)[i]].token_name, (*elements)[i]);
9438 #endif
9439 }
9440
9441 static struct MusicFileInfo *get_music_file_info_ext(char *basename, int music,
9442                                                      boolean is_sound)
9443 {
9444   SetupFileHash *setup_file_hash = NULL;
9445   struct MusicFileInfo tmp_music_file_info, *new_music_file_info;
9446   char *filename_music, *filename_prefix, *filename_info;
9447   struct
9448   {
9449     char *token;
9450     char **value_ptr;
9451   }
9452   token_to_value_ptr[] =
9453   {
9454     { "title_header",   &tmp_music_file_info.title_header       },
9455     { "artist_header",  &tmp_music_file_info.artist_header      },
9456     { "album_header",   &tmp_music_file_info.album_header       },
9457     { "year_header",    &tmp_music_file_info.year_header        },
9458
9459     { "title",          &tmp_music_file_info.title              },
9460     { "artist",         &tmp_music_file_info.artist             },
9461     { "album",          &tmp_music_file_info.album              },
9462     { "year",           &tmp_music_file_info.year               },
9463
9464     { NULL,             NULL                                    },
9465   };
9466   int i;
9467
9468   filename_music = (is_sound ? getCustomSoundFilename(basename) :
9469                     getCustomMusicFilename(basename));
9470
9471   if (filename_music == NULL)
9472     return NULL;
9473
9474   /* ---------- try to replace file extension ---------- */
9475
9476   filename_prefix = getStringCopy(filename_music);
9477   if (strrchr(filename_prefix, '.') != NULL)
9478     *strrchr(filename_prefix, '.') = '\0';
9479   filename_info = getStringCat2(filename_prefix, ".txt");
9480
9481 #if 0
9482   printf("trying to load file '%s'...\n", filename_info);
9483 #endif
9484
9485   if (fileExists(filename_info))
9486     setup_file_hash = loadSetupFileHash(filename_info);
9487
9488   free(filename_prefix);
9489   free(filename_info);
9490
9491   if (setup_file_hash == NULL)
9492   {
9493     /* ---------- try to add file extension ---------- */
9494
9495     filename_prefix = getStringCopy(filename_music);
9496     filename_info = getStringCat2(filename_prefix, ".txt");
9497
9498 #if 0
9499     printf("trying to load file '%s'...\n", filename_info);
9500 #endif
9501
9502     if (fileExists(filename_info))
9503       setup_file_hash = loadSetupFileHash(filename_info);
9504
9505     free(filename_prefix);
9506     free(filename_info);
9507   }
9508
9509   if (setup_file_hash == NULL)
9510     return NULL;
9511
9512   /* ---------- music file info found ---------- */
9513
9514   clear_mem(&tmp_music_file_info, sizeof(struct MusicFileInfo));
9515
9516   for (i = 0; token_to_value_ptr[i].token != NULL; i++)
9517   {
9518     char *value = getHashEntry(setup_file_hash, token_to_value_ptr[i].token);
9519
9520     *token_to_value_ptr[i].value_ptr =
9521       getStringCopy(value != NULL && *value != '\0' ? value : UNKNOWN_NAME);
9522   }
9523
9524   tmp_music_file_info.basename = getStringCopy(basename);
9525   tmp_music_file_info.music = music;
9526   tmp_music_file_info.is_sound = is_sound;
9527
9528   new_music_file_info = checked_malloc(sizeof(struct MusicFileInfo));
9529   *new_music_file_info = tmp_music_file_info;
9530
9531   return new_music_file_info;
9532 }
9533
9534 static struct MusicFileInfo *get_music_file_info(char *basename, int music)
9535 {
9536   return get_music_file_info_ext(basename, music, FALSE);
9537 }
9538
9539 static struct MusicFileInfo *get_sound_file_info(char *basename, int sound)
9540 {
9541   return get_music_file_info_ext(basename, sound, TRUE);
9542 }
9543
9544 static boolean music_info_listed_ext(struct MusicFileInfo *list,
9545                                      char *basename, boolean is_sound)
9546 {
9547   for (; list != NULL; list = list->next)
9548     if (list->is_sound == is_sound && strEqual(list->basename, basename))
9549       return TRUE;
9550
9551   return FALSE;
9552 }
9553
9554 static boolean music_info_listed(struct MusicFileInfo *list, char *basename)
9555 {
9556   return music_info_listed_ext(list, basename, FALSE);
9557 }
9558
9559 static boolean sound_info_listed(struct MusicFileInfo *list, char *basename)
9560 {
9561   return music_info_listed_ext(list, basename, TRUE);
9562 }
9563
9564 void LoadMusicInfo()
9565 {
9566   char *music_directory = getCustomMusicDirectory();
9567   int num_music = getMusicListSize();
9568   int num_music_noconf = 0;
9569   int num_sounds = getSoundListSize();
9570   DIR *dir;
9571   struct dirent *dir_entry;
9572   struct FileInfo *music, *sound;
9573   struct MusicFileInfo *next, **new;
9574   int i;
9575
9576   while (music_file_info != NULL)
9577   {
9578     next = music_file_info->next;
9579
9580     checked_free(music_file_info->basename);
9581
9582     checked_free(music_file_info->title_header);
9583     checked_free(music_file_info->artist_header);
9584     checked_free(music_file_info->album_header);
9585     checked_free(music_file_info->year_header);
9586
9587     checked_free(music_file_info->title);
9588     checked_free(music_file_info->artist);
9589     checked_free(music_file_info->album);
9590     checked_free(music_file_info->year);
9591
9592     free(music_file_info);
9593
9594     music_file_info = next;
9595   }
9596
9597   new = &music_file_info;
9598
9599   for (i = 0; i < num_music; i++)
9600   {
9601     music = getMusicListEntry(i);
9602
9603     if (music->filename == NULL)
9604       continue;
9605
9606     if (strEqual(music->filename, UNDEFINED_FILENAME))
9607       continue;
9608
9609     /* a configured file may be not recognized as music */
9610     if (!FileIsMusic(music->filename))
9611       continue;
9612
9613 #if 0
9614     printf("::: -> '%s' (configured)\n", music->filename);
9615 #endif
9616
9617     if (!music_info_listed(music_file_info, music->filename))
9618     {
9619       *new = get_music_file_info(music->filename, i);
9620       if (*new != NULL)
9621         new = &(*new)->next;
9622     }
9623   }
9624
9625   if ((dir = opendir(music_directory)) == NULL)
9626   {
9627     Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
9628     return;
9629   }
9630
9631   while ((dir_entry = readdir(dir)) != NULL)    /* loop until last dir entry */
9632   {
9633     char *basename = dir_entry->d_name;
9634     boolean music_already_used = FALSE;
9635     int i;
9636
9637     /* skip all music files that are configured in music config file */
9638     for (i = 0; i < num_music; i++)
9639     {
9640       music = getMusicListEntry(i);
9641
9642       if (music->filename == NULL)
9643         continue;
9644
9645       if (strEqual(basename, music->filename))
9646       {
9647         music_already_used = TRUE;
9648         break;
9649       }
9650     }
9651
9652     if (music_already_used)
9653       continue;
9654
9655     if (!FileIsMusic(basename))
9656       continue;
9657
9658 #if 0
9659     printf("::: -> '%s' (found in directory)\n", basename);
9660 #endif
9661
9662     if (!music_info_listed(music_file_info, basename))
9663     {
9664       *new = get_music_file_info(basename, MAP_NOCONF_MUSIC(num_music_noconf));
9665       if (*new != NULL)
9666         new = &(*new)->next;
9667     }
9668
9669     num_music_noconf++;
9670   }
9671
9672   closedir(dir);
9673
9674   for (i = 0; i < num_sounds; i++)
9675   {
9676     sound = getSoundListEntry(i);
9677
9678     if (sound->filename == NULL)
9679       continue;
9680
9681     if (strEqual(sound->filename, UNDEFINED_FILENAME))
9682       continue;
9683
9684     /* a configured file may be not recognized as sound */
9685     if (!FileIsSound(sound->filename))
9686       continue;
9687
9688 #if 0
9689     printf("::: -> '%s' (configured)\n", sound->filename);
9690 #endif
9691
9692     if (!sound_info_listed(music_file_info, sound->filename))
9693     {
9694       *new = get_sound_file_info(sound->filename, i);
9695       if (*new != NULL)
9696         new = &(*new)->next;
9697     }
9698   }
9699
9700 #if 0
9701   for (next = music_file_info; next != NULL; next = next->next)
9702     printf("::: title == '%s'\n", next->title);
9703 #endif
9704 }
9705
9706 void add_helpanim_entry(int element, int action, int direction, int delay,
9707                         int *num_list_entries)
9708 {
9709   struct HelpAnimInfo *new_list_entry;
9710   (*num_list_entries)++;
9711
9712   helpanim_info =
9713     checked_realloc(helpanim_info,
9714                     *num_list_entries * sizeof(struct HelpAnimInfo));
9715   new_list_entry = &helpanim_info[*num_list_entries - 1];
9716
9717   new_list_entry->element = element;
9718   new_list_entry->action = action;
9719   new_list_entry->direction = direction;
9720   new_list_entry->delay = delay;
9721 }
9722
9723 void print_unknown_token(char *filename, char *token, int token_nr)
9724 {
9725   if (token_nr == 0)
9726   {
9727     Error(ERR_INFO_LINE, "-");
9728     Error(ERR_INFO, "warning: unknown token(s) found in config file:");
9729     Error(ERR_INFO, "- config file: '%s'", filename);
9730   }
9731
9732   Error(ERR_INFO, "- token: '%s'", token);
9733 }
9734
9735 void print_unknown_token_end(int token_nr)
9736 {
9737   if (token_nr > 0)
9738     Error(ERR_INFO_LINE, "-");
9739 }
9740
9741 void LoadHelpAnimInfo()
9742 {
9743   char *filename = getHelpAnimFilename();
9744   SetupFileList *setup_file_list = NULL, *list;
9745   SetupFileHash *element_hash, *action_hash, *direction_hash;
9746   int num_list_entries = 0;
9747   int num_unknown_tokens = 0;
9748   int i;
9749
9750   if (fileExists(filename))
9751     setup_file_list = loadSetupFileList(filename);
9752
9753   if (setup_file_list == NULL)
9754   {
9755     /* use reliable default values from static configuration */
9756     SetupFileList *insert_ptr;
9757
9758     insert_ptr = setup_file_list =
9759       newSetupFileList(helpanim_config[0].token,
9760                        helpanim_config[0].value);
9761
9762     for (i = 1; helpanim_config[i].token; i++)
9763       insert_ptr = addListEntry(insert_ptr,
9764                                 helpanim_config[i].token,
9765                                 helpanim_config[i].value);
9766   }
9767
9768   element_hash   = newSetupFileHash();
9769   action_hash    = newSetupFileHash();
9770   direction_hash = newSetupFileHash();
9771
9772   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
9773     setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
9774
9775   for (i = 0; i < NUM_ACTIONS; i++)
9776     setHashEntry(action_hash, element_action_info[i].suffix,
9777                  i_to_a(element_action_info[i].value));
9778
9779   /* do not store direction index (bit) here, but direction value! */
9780   for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
9781     setHashEntry(direction_hash, element_direction_info[i].suffix,
9782                  i_to_a(1 << element_direction_info[i].value));
9783
9784   for (list = setup_file_list; list != NULL; list = list->next)
9785   {
9786     char *element_token, *action_token, *direction_token;
9787     char *element_value, *action_value, *direction_value;
9788     int delay = atoi(list->value);
9789
9790     if (strEqual(list->token, "end"))
9791     {
9792       add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
9793
9794       continue;
9795     }
9796
9797     /* first try to break element into element/action/direction parts;
9798        if this does not work, also accept combined "element[.act][.dir]"
9799        elements (like "dynamite.active"), which are unique elements */
9800
9801     if (strchr(list->token, '.') == NULL)       /* token contains no '.' */
9802     {
9803       element_value = getHashEntry(element_hash, list->token);
9804       if (element_value != NULL)        /* element found */
9805         add_helpanim_entry(atoi(element_value), -1, -1, delay,
9806                            &num_list_entries);
9807       else
9808       {
9809         /* no further suffixes found -- this is not an element */
9810         print_unknown_token(filename, list->token, num_unknown_tokens++);
9811       }
9812
9813       continue;
9814     }
9815
9816     /* token has format "<prefix>.<something>" */
9817
9818     action_token = strchr(list->token, '.');    /* suffix may be action ... */
9819     direction_token = action_token;             /* ... or direction */
9820
9821     element_token = getStringCopy(list->token);
9822     *strchr(element_token, '.') = '\0';
9823
9824     element_value = getHashEntry(element_hash, element_token);
9825
9826     if (element_value == NULL)          /* this is no element */
9827     {
9828       element_value = getHashEntry(element_hash, list->token);
9829       if (element_value != NULL)        /* combined element found */
9830         add_helpanim_entry(atoi(element_value), -1, -1, delay,
9831                            &num_list_entries);
9832       else
9833         print_unknown_token(filename, list->token, num_unknown_tokens++);
9834
9835       free(element_token);
9836
9837       continue;
9838     }
9839
9840     action_value = getHashEntry(action_hash, action_token);
9841
9842     if (action_value != NULL)           /* action found */
9843     {
9844       add_helpanim_entry(atoi(element_value), atoi(action_value), -1, delay,
9845                     &num_list_entries);
9846
9847       free(element_token);
9848
9849       continue;
9850     }
9851
9852     direction_value = getHashEntry(direction_hash, direction_token);
9853
9854     if (direction_value != NULL)        /* direction found */
9855     {
9856       add_helpanim_entry(atoi(element_value), -1, atoi(direction_value), delay,
9857                          &num_list_entries);
9858
9859       free(element_token);
9860
9861       continue;
9862     }
9863
9864     if (strchr(action_token + 1, '.') == NULL)
9865     {
9866       /* no further suffixes found -- this is not an action nor direction */
9867
9868       element_value = getHashEntry(element_hash, list->token);
9869       if (element_value != NULL)        /* combined element found */
9870         add_helpanim_entry(atoi(element_value), -1, -1, delay,
9871                            &num_list_entries);
9872       else
9873         print_unknown_token(filename, list->token, num_unknown_tokens++);
9874
9875       free(element_token);
9876
9877       continue;
9878     }
9879
9880     /* token has format "<prefix>.<suffix>.<something>" */
9881
9882     direction_token = strchr(action_token + 1, '.');
9883
9884     action_token = getStringCopy(action_token);
9885     *strchr(action_token + 1, '.') = '\0';
9886
9887     action_value = getHashEntry(action_hash, action_token);
9888
9889     if (action_value == NULL)           /* this is no action */
9890     {
9891       element_value = getHashEntry(element_hash, list->token);
9892       if (element_value != NULL)        /* combined element found */
9893         add_helpanim_entry(atoi(element_value), -1, -1, delay,
9894                            &num_list_entries);
9895       else
9896         print_unknown_token(filename, list->token, num_unknown_tokens++);
9897
9898       free(element_token);
9899       free(action_token);
9900
9901       continue;
9902     }
9903
9904     direction_value = getHashEntry(direction_hash, direction_token);
9905
9906     if (direction_value != NULL)        /* direction found */
9907     {
9908       add_helpanim_entry(atoi(element_value), atoi(action_value),
9909                          atoi(direction_value), delay, &num_list_entries);
9910
9911       free(element_token);
9912       free(action_token);
9913
9914       continue;
9915     }
9916
9917     /* this is no direction */
9918
9919     element_value = getHashEntry(element_hash, list->token);
9920     if (element_value != NULL)          /* combined element found */
9921       add_helpanim_entry(atoi(element_value), -1, -1, delay,
9922                          &num_list_entries);
9923     else
9924       print_unknown_token(filename, list->token, num_unknown_tokens++);
9925
9926     free(element_token);
9927     free(action_token);
9928   }
9929
9930   print_unknown_token_end(num_unknown_tokens);
9931
9932   add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
9933   add_helpanim_entry(HELPANIM_LIST_END,  -1, -1, -1, &num_list_entries);
9934
9935   freeSetupFileList(setup_file_list);
9936   freeSetupFileHash(element_hash);
9937   freeSetupFileHash(action_hash);
9938   freeSetupFileHash(direction_hash);
9939
9940 #if 0
9941   for (i = 0; i < num_list_entries; i++)
9942     printf("::: '%s': %d, %d, %d => %d\n",
9943            EL_NAME(helpanim_info[i].element),
9944            helpanim_info[i].element,
9945            helpanim_info[i].action,
9946            helpanim_info[i].direction,
9947            helpanim_info[i].delay);
9948 #endif
9949 }
9950
9951 void LoadHelpTextInfo()
9952 {
9953   char *filename = getHelpTextFilename();
9954   int i;
9955
9956   if (helptext_info != NULL)
9957   {
9958     freeSetupFileHash(helptext_info);
9959     helptext_info = NULL;
9960   }
9961
9962   if (fileExists(filename))
9963     helptext_info = loadSetupFileHash(filename);
9964
9965   if (helptext_info == NULL)
9966   {
9967     /* use reliable default values from static configuration */
9968     helptext_info = newSetupFileHash();
9969
9970     for (i = 0; helptext_config[i].token; i++)
9971       setHashEntry(helptext_info,
9972                    helptext_config[i].token,
9973                    helptext_config[i].value);
9974   }
9975
9976 #if 0
9977   BEGIN_HASH_ITERATION(helptext_info, itr)
9978   {
9979     printf("::: '%s' => '%s'\n",
9980            HASH_ITERATION_TOKEN(itr), HASH_ITERATION_VALUE(itr));
9981   }
9982   END_HASH_ITERATION(hash, itr)
9983 #endif
9984 }
9985
9986
9987 /* ------------------------------------------------------------------------- */
9988 /* convert levels                                                            */
9989 /* ------------------------------------------------------------------------- */
9990
9991 #define MAX_NUM_CONVERT_LEVELS          1000
9992
9993 void ConvertLevels()
9994 {
9995   static LevelDirTree *convert_leveldir = NULL;
9996   static int convert_level_nr = -1;
9997   static int num_levels_handled = 0;
9998   static int num_levels_converted = 0;
9999   static boolean levels_failed[MAX_NUM_CONVERT_LEVELS];
10000   int i;
10001
10002   convert_leveldir = getTreeInfoFromIdentifier(leveldir_first,
10003                                                global.convert_leveldir);
10004
10005   if (convert_leveldir == NULL)
10006     Error(ERR_EXIT, "no such level identifier: '%s'",
10007           global.convert_leveldir);
10008
10009   leveldir_current = convert_leveldir;
10010
10011   if (global.convert_level_nr != -1)
10012   {
10013     convert_leveldir->first_level = global.convert_level_nr;
10014     convert_leveldir->last_level  = global.convert_level_nr;
10015   }
10016
10017   convert_level_nr = convert_leveldir->first_level;
10018
10019   printf_line("=", 79);
10020   printf("Converting levels\n");
10021   printf_line("-", 79);
10022   printf("Level series identifier: '%s'\n", convert_leveldir->identifier);
10023   printf("Level series name:       '%s'\n", convert_leveldir->name);
10024   printf("Level series author:     '%s'\n", convert_leveldir->author);
10025   printf("Number of levels:        %d\n",   convert_leveldir->levels);
10026   printf_line("=", 79);
10027   printf("\n");
10028
10029   for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++)
10030     levels_failed[i] = FALSE;
10031
10032   while (convert_level_nr <= convert_leveldir->last_level)
10033   {
10034     char *level_filename;
10035     boolean new_level;
10036
10037     level_nr = convert_level_nr++;
10038
10039     printf("Level %03d: ", level_nr);
10040
10041     LoadLevel(level_nr);
10042     if (level.no_valid_file)
10043     {
10044       printf("(no level)\n");
10045       continue;
10046     }
10047
10048     printf("converting level ... ");
10049
10050     level_filename = getDefaultLevelFilename(level_nr);
10051     new_level = !fileExists(level_filename);
10052
10053     if (new_level)
10054     {
10055       SaveLevel(level_nr);
10056
10057       num_levels_converted++;
10058
10059       printf("converted.\n");
10060     }
10061     else
10062     {
10063       if (level_nr >= 0 && level_nr < MAX_NUM_CONVERT_LEVELS)
10064         levels_failed[level_nr] = TRUE;
10065
10066       printf("NOT CONVERTED -- LEVEL ALREADY EXISTS.\n");
10067     }
10068
10069     num_levels_handled++;
10070   }
10071
10072   printf("\n");
10073   printf_line("=", 79);
10074   printf("Number of levels handled: %d\n", num_levels_handled);
10075   printf("Number of levels converted: %d (%d%%)\n", num_levels_converted,
10076          (num_levels_handled ?
10077           num_levels_converted * 100 / num_levels_handled : 0));
10078   printf_line("-", 79);
10079   printf("Summary (for automatic parsing by scripts):\n");
10080   printf("LEVELDIR '%s', CONVERTED %d/%d (%d%%)",
10081          convert_leveldir->identifier, num_levels_converted,
10082          num_levels_handled,
10083          (num_levels_handled ?
10084           num_levels_converted * 100 / num_levels_handled : 0));
10085
10086   if (num_levels_handled != num_levels_converted)
10087   {
10088     printf(", FAILED:");
10089     for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++)
10090       if (levels_failed[i])
10091         printf(" %03d", i);
10092   }
10093
10094   printf("\n");
10095   printf_line("=", 79);
10096
10097   CloseAllAndExit(0);
10098 }
10099
10100
10101 /* ------------------------------------------------------------------------- */
10102 /* create and save images for use in level sketches (raw BMP format)         */
10103 /* ------------------------------------------------------------------------- */
10104
10105 void CreateLevelSketchImages()
10106 {
10107 #if defined(TARGET_SDL)
10108   Bitmap *bitmap1;
10109   Bitmap *bitmap2;
10110   int i;
10111
10112   InitElementPropertiesGfxElement();
10113
10114   bitmap1 = CreateBitmap(TILEX, TILEY, DEFAULT_DEPTH);
10115   bitmap2 = CreateBitmap(MINI_TILEX, MINI_TILEY, DEFAULT_DEPTH);
10116
10117   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
10118   {
10119     Bitmap *src_bitmap;
10120     int src_x, src_y;
10121     int element = getMappedElement(i);
10122     int graphic = el2edimg(element);
10123     char basename1[16];
10124     char basename2[16];
10125     char *filename1;
10126     char *filename2;
10127
10128     sprintf(basename1, "%03d.bmp", i);
10129     sprintf(basename2, "%03ds.bmp", i);
10130
10131     filename1 = getPath2(global.create_images_dir, basename1);
10132     filename2 = getPath2(global.create_images_dir, basename2);
10133
10134     getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
10135     BlitBitmap(src_bitmap, bitmap1, src_x, src_y, TILEX, TILEY, 0, 0);
10136
10137     if (SDL_SaveBMP(bitmap1->surface, filename1) != 0)
10138       Error(ERR_EXIT, "cannot save level sketch image file '%s'", filename1);
10139
10140     getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
10141     BlitBitmap(src_bitmap, bitmap2, src_x, src_y, MINI_TILEX, MINI_TILEY, 0, 0);
10142
10143     if (SDL_SaveBMP(bitmap2->surface, filename2) != 0)
10144       Error(ERR_EXIT, "cannot save level sketch image file '%s'", filename2);
10145
10146     free(filename1);
10147     free(filename2);
10148
10149     if (options.debug)
10150       printf("%03d `%03d%c", i, i, (i % 10 < 9 ? ' ' : '\n'));
10151   }
10152
10153   FreeBitmap(bitmap1);
10154   FreeBitmap(bitmap2);
10155
10156   if (options.debug)
10157     printf("\n");
10158
10159   Error(ERR_INFO, "%d normal and small images created", NUM_FILE_ELEMENTS);
10160
10161   CloseAllAndExit(0);
10162 #endif
10163 }
10164
10165
10166 /* ------------------------------------------------------------------------- */
10167 /* create and save images for custom and group elements (raw BMP format)     */
10168 /* ------------------------------------------------------------------------- */
10169
10170 void CreateCustomElementImages()
10171 {
10172 #if defined(TARGET_SDL)
10173   char *filename = "graphics.classic/RocksCE.bmp";
10174   Bitmap *bitmap;
10175   Bitmap *src_bitmap;
10176   int dummy_graphic = IMG_CUSTOM_99;
10177   int yoffset_ce = 0;
10178   int yoffset_ge = (TILEY * NUM_CUSTOM_ELEMENTS / 16);
10179   int src_x, src_y;
10180   int i;
10181
10182   bitmap = CreateBitmap(TILEX * 16 * 2,
10183                         TILEY * (NUM_CUSTOM_ELEMENTS + NUM_GROUP_ELEMENTS) / 16,
10184                         DEFAULT_DEPTH);
10185
10186   getGraphicSource(dummy_graphic, 0, &src_bitmap, &src_x, &src_y);
10187
10188   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
10189   {
10190     int x = i % 16;
10191     int y = i / 16;
10192     int ii = i + 1;
10193     int j;
10194
10195     BlitBitmap(src_bitmap, bitmap, 0, 0, TILEX, TILEY,
10196                TILEX * x, TILEY * y + yoffset_ce);
10197
10198     BlitBitmap(src_bitmap, bitmap, 0, TILEY, TILEX, TILEY,
10199                TILEX * x + TILEX * 16, TILEY * y + yoffset_ce);
10200
10201     for (j = 2; j >= 0; j--)
10202     {
10203       int c = ii % 10;
10204
10205       BlitBitmap(src_bitmap, bitmap, TILEX + c * 7, 0, 6, 10,
10206                  TILEX * x + 6 + j * 7,
10207                  TILEY * y + 11 + yoffset_ce);
10208
10209       BlitBitmap(src_bitmap, bitmap, TILEX + c * 8, TILEY, 6, 10,
10210                  TILEX * 16 + TILEX * x + 6 + j * 8,
10211                  TILEY * y + 10 + yoffset_ce);
10212
10213       ii /= 10;
10214     }
10215   }
10216
10217   for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
10218   {
10219     int x = i % 16;
10220     int y = i / 16;
10221     int ii = i + 1;
10222     int j;
10223
10224     BlitBitmap(src_bitmap, bitmap, 0, 0, TILEX, TILEY,
10225                TILEX * x, TILEY * y + yoffset_ge);
10226
10227     BlitBitmap(src_bitmap, bitmap, 0, TILEY, TILEX, TILEY,
10228                TILEX * x + TILEX * 16, TILEY * y + yoffset_ge);
10229
10230     for (j = 1; j >= 0; j--)
10231     {
10232       int c = ii % 10;
10233
10234       BlitBitmap(src_bitmap, bitmap, TILEX + c * 10, 11, 10, 10,
10235                  TILEX * x + 6 + j * 10,
10236                  TILEY * y + 11 + yoffset_ge);
10237
10238       BlitBitmap(src_bitmap, bitmap, TILEX + c * 8, TILEY + 12, 6, 10,
10239                  TILEX * 16 + TILEX * x + 10 + j * 8,
10240                  TILEY * y + 10 + yoffset_ge);
10241
10242       ii /= 10;
10243     }
10244   }
10245
10246   if (SDL_SaveBMP(bitmap->surface, filename) != 0)
10247     Error(ERR_EXIT, "cannot save CE graphics file '%s'", filename);
10248
10249   FreeBitmap(bitmap);
10250
10251   CloseAllAndExit(0);
10252 #endif
10253 }
10254
10255 #if 0
10256 void CreateLevelSketchImages_TEST()
10257 {
10258   void CreateCustomElementImages()
10259 }
10260 #endif