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