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