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