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