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