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