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