rnd-20090925-1-src
[rocksndiamonds.git] / src / files.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * files.c                                                  *
12 ***********************************************************/
13
14 #include <ctype.h>
15 #include <sys/stat.h>
16 #include <dirent.h>
17 #include <math.h>
18
19 #include "libgame/libgame.h"
20
21 #include "files.h"
22 #include "init.h"
23 #include "tools.h"
24 #include "tape.h"
25
26
27 #define CHUNK_ID_LEN            4       /* IFF style chunk id length  */
28 #define CHUNK_SIZE_UNDEFINED    0       /* undefined chunk size == 0  */
29 #define CHUNK_SIZE_NONE         -1      /* do not write chunk size    */
30
31 #define LEVEL_CHUNK_NAME_SIZE   MAX_LEVEL_NAME_LEN
32 #define LEVEL_CHUNK_AUTH_SIZE   MAX_LEVEL_AUTHOR_LEN
33
34 #define LEVEL_CHUNK_VERS_SIZE   8       /* size of file version chunk */
35 #define LEVEL_CHUNK_DATE_SIZE   4       /* size of file date chunk    */
36 #define LEVEL_CHUNK_HEAD_SIZE   80      /* size of level file header  */
37 #define LEVEL_CHUNK_HEAD_UNUSED 0       /* unused level header bytes  */
38 #define LEVEL_CHUNK_CNT2_SIZE   160     /* size of level CNT2 chunk   */
39 #define LEVEL_CHUNK_CNT2_UNUSED 11      /* unused CNT2 chunk bytes    */
40 #define LEVEL_CHUNK_CNT3_HEADER 16      /* size of level CNT3 header  */
41 #define LEVEL_CHUNK_CNT3_UNUSED 10      /* unused CNT3 chunk bytes    */
42 #define LEVEL_CPART_CUS3_SIZE   134     /* size of CUS3 chunk part    */
43 #define LEVEL_CPART_CUS3_UNUSED 15      /* unused CUS3 bytes / part   */
44 #define LEVEL_CHUNK_GRP1_SIZE   74      /* size of level GRP1 chunk   */
45
46 /* (element number, number of change pages, change page number) */
47 #define LEVEL_CHUNK_CUSX_UNCHANGED      (2 + (1 + 1) + (1 + 1))
48
49 /* (element number only) */
50 #define LEVEL_CHUNK_GRPX_UNCHANGED      2
51 #define LEVEL_CHUNK_NOTE_UNCHANGED      2
52
53 /* (nothing at all if unchanged) */
54 #define LEVEL_CHUNK_ELEM_UNCHANGED      0
55
56 #define TAPE_CHUNK_VERS_SIZE    8       /* size of file version chunk */
57 #define TAPE_CHUNK_HEAD_SIZE    20      /* size of tape file header   */
58 #define TAPE_CHUNK_HEAD_UNUSED  3       /* unused tape header bytes   */
59
60 #define LEVEL_CHUNK_CNT3_SIZE(x)         (LEVEL_CHUNK_CNT3_HEADER + (x))
61 #define LEVEL_CHUNK_CUS3_SIZE(x)         (2 + (x) * LEVEL_CPART_CUS3_SIZE)
62 #define LEVEL_CHUNK_CUS4_SIZE(x)         (96 + (x) * 48)
63
64 /* file identifier strings */
65 #define LEVEL_COOKIE_TMPL               "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x"
66 #define TAPE_COOKIE_TMPL                "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
67 #define SCORE_COOKIE                    "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
68
69 /* values for deciding when (not) to save configuration data */
70 #define SAVE_CONF_NEVER                 0
71 #define SAVE_CONF_ALWAYS                1
72 #define SAVE_CONF_WHEN_CHANGED          -1
73
74 /* values for chunks using micro chunks */
75 #define CONF_MASK_1_BYTE                0x00
76 #define CONF_MASK_2_BYTE                0x40
77 #define CONF_MASK_4_BYTE                0x80
78 #define CONF_MASK_MULTI_BYTES           0xc0
79
80 #define CONF_MASK_BYTES                 0xc0
81 #define CONF_MASK_TOKEN                 0x3f
82
83 #define CONF_VALUE_1_BYTE(x)            (CONF_MASK_1_BYTE       | (x))
84 #define CONF_VALUE_2_BYTE(x)            (CONF_MASK_2_BYTE       | (x))
85 #define CONF_VALUE_4_BYTE(x)            (CONF_MASK_4_BYTE       | (x))
86 #define CONF_VALUE_MULTI_BYTES(x)       (CONF_MASK_MULTI_BYTES  | (x))
87
88 /* these definitions are just for convenience of use and readability */
89 #define CONF_VALUE_8_BIT(x)             CONF_VALUE_1_BYTE(x)
90 #define CONF_VALUE_16_BIT(x)            CONF_VALUE_2_BYTE(x)
91 #define CONF_VALUE_32_BIT(x)            CONF_VALUE_4_BYTE(x)
92 #define CONF_VALUE_BYTES(x)             CONF_VALUE_MULTI_BYTES(x)
93
94 #define CONF_VALUE_NUM_BYTES(x)         ((x) == CONF_MASK_1_BYTE ? 1 :  \
95                                          (x) == CONF_MASK_2_BYTE ? 2 :  \
96                                          (x) == CONF_MASK_4_BYTE ? 4 : 0)
97
98 #define CONF_CONTENT_NUM_ELEMENTS       (3 * 3)
99 #define CONF_CONTENT_NUM_BYTES          (CONF_CONTENT_NUM_ELEMENTS * 2)
100 #define CONF_ELEMENT_NUM_BYTES          (2)
101
102 #define CONF_ENTITY_NUM_BYTES(t)        ((t) == TYPE_ELEMENT ||         \
103                                          (t) == TYPE_ELEMENT_LIST ?     \
104                                          CONF_ELEMENT_NUM_BYTES :       \
105                                          (t) == TYPE_CONTENT ||         \
106                                          (t) == TYPE_CONTENT_LIST ?     \
107                                          CONF_CONTENT_NUM_BYTES : 1)
108
109 #define CONF_ELEMENT_BYTE_POS(i)        ((i) * CONF_ELEMENT_NUM_BYTES)
110 #define CONF_ELEMENTS_ELEMENT(b,i)     ((b[CONF_ELEMENT_BYTE_POS(i)] << 8) |  \
111                                         (b[CONF_ELEMENT_BYTE_POS(i) + 1]))
112
113 #define CONF_CONTENT_ELEMENT_POS(c,x,y) ((c) * CONF_CONTENT_NUM_ELEMENTS +    \
114                                          (y) * 3 + (x))
115 #define CONF_CONTENT_BYTE_POS(c,x,y)    (CONF_CONTENT_ELEMENT_POS(c,x,y) *    \
116                                          CONF_ELEMENT_NUM_BYTES)
117 #define CONF_CONTENTS_ELEMENT(b,c,x,y) ((b[CONF_CONTENT_BYTE_POS(c,x,y)]<< 8)|\
118                                         (b[CONF_CONTENT_BYTE_POS(c,x,y) + 1]))
119
120 /* temporary variables used to store pointers to structure members */
121 static struct LevelInfo li;
122 static struct ElementInfo xx_ei, yy_ei;
123 static struct ElementChangeInfo xx_change;
124 static struct ElementGroupInfo xx_group;
125 static struct EnvelopeInfo xx_envelope;
126 static unsigned int xx_event_bits[NUM_CE_BITFIELDS];
127 static char xx_default_description[MAX_ELEMENT_NAME_LEN + 1];
128 static int xx_num_contents;
129 static int xx_current_change_page;
130 static char xx_default_string_empty[1] = "";
131 static int xx_string_length_unused;
132
133 struct LevelFileConfigInfo
134 {
135   int element;                  /* element for which data is to be stored */
136   int save_type;                /* save data always, never or when changed */
137   int data_type;                /* data type (used internally, not stored) */
138   int conf_type;                /* micro chunk identifier (stored in file) */
139
140   /* (mandatory) */
141   void *value;                  /* variable that holds the data to be stored */
142   int default_value;            /* initial default value for this variable */
143
144   /* (optional) */
145   void *value_copy;             /* variable that holds the data to be copied */
146   void *num_entities;           /* number of entities for multi-byte data */
147   int default_num_entities;     /* default number of entities for this data */
148   int max_num_entities;         /* maximal number of entities for this data */
149   char *default_string;         /* optional default string for string data */
150 };
151
152 static struct LevelFileConfigInfo chunk_config_INFO[] =
153 {
154   /* ---------- values not related to single elements ----------------------- */
155
156   {
157     -1,                                 SAVE_CONF_ALWAYS,
158     TYPE_INTEGER,                       CONF_VALUE_8_BIT(1),
159     &li.game_engine_type,               GAME_ENGINE_TYPE_RND
160   },
161
162   {
163     -1,                                 SAVE_CONF_ALWAYS,
164     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
165     &li.fieldx,                         STD_LEV_FIELDX
166   },
167   {
168     -1,                                 SAVE_CONF_ALWAYS,
169     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
170     &li.fieldy,                         STD_LEV_FIELDY
171   },
172
173   {
174     -1,                                 SAVE_CONF_ALWAYS,
175     TYPE_INTEGER,                       CONF_VALUE_16_BIT(3),
176     &li.time,                           100
177   },
178
179   {
180     -1,                                 SAVE_CONF_ALWAYS,
181     TYPE_INTEGER,                       CONF_VALUE_16_BIT(4),
182     &li.gems_needed,                    0
183   },
184
185   {
186     -1,                                 -1,
187     TYPE_INTEGER,                       CONF_VALUE_32_BIT(2),
188     &li.random_seed,                    0
189   },
190
191   {
192     -1,                                 -1,
193     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(2),
194     &li.use_step_counter,               FALSE
195   },
196
197   {
198     -1,                                 -1,
199     TYPE_BITFIELD,                      CONF_VALUE_8_BIT(4),
200     &li.wind_direction_initial,         MV_NONE
201   },
202
203   {
204     -1,                                 -1,
205     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(5),
206     &li.em_slippery_gems,               FALSE
207   },
208
209   {
210     -1,                                 -1,
211     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(6),
212     &li.use_custom_template,            FALSE
213   },
214
215   {
216     -1,                                 -1,
217     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(1),
218     &li.can_move_into_acid_bits,        ~0      /* default: everything can */
219   },
220
221   {
222     -1,                                 -1,
223     TYPE_BITFIELD,                      CONF_VALUE_8_BIT(7),
224     &li.dont_collide_with_bits,         ~0      /* default: always deadly */
225   },
226
227   {
228     -1,                                 -1,
229     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(8),
230     &li.em_explodes_by_fire,            FALSE
231   },
232
233   {
234     -1,                                 -1,
235     TYPE_INTEGER,                       CONF_VALUE_16_BIT(5),
236     &li.score[SC_TIME_BONUS],           1
237   },
238
239   {
240     -1,                                 -1,
241     -1,                                 -1,
242     NULL,                               -1
243   }
244 };
245
246 static struct LevelFileConfigInfo chunk_config_ELEM[] =
247 {
248   /* (these values are the same for each player) */
249   {
250     EL_PLAYER_1,                        -1,
251     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
252     &li.block_last_field,               FALSE   /* default case for EM levels */
253   },
254   {
255     EL_PLAYER_1,                        -1,
256     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(2),
257     &li.sp_block_last_field,            TRUE    /* default case for SP levels */
258   },
259   {
260     EL_PLAYER_1,                        -1,
261     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(3),
262     &li.instant_relocation,             FALSE
263   },
264   {
265     EL_PLAYER_1,                        -1,
266     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(4),
267     &li.can_pass_to_walkable,           FALSE
268   },
269   {
270     EL_PLAYER_1,                        -1,
271     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(5),
272     &li.block_snap_field,               TRUE
273   },
274   {
275     EL_PLAYER_1,                        -1,
276     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(6),
277     &li.continuous_snapping,            TRUE
278   },
279   {
280     EL_PLAYER_1,                        -1,
281     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(12),
282     &li.shifted_relocation,             FALSE
283   },
284
285   /* (these values are different for each player) */
286   {
287     EL_PLAYER_1,                        -1,
288     TYPE_INTEGER,                       CONF_VALUE_8_BIT(7),
289     &li.initial_player_stepsize[0],     STEPSIZE_NORMAL
290   },
291   {
292     EL_PLAYER_1,                        -1,
293     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(8),
294     &li.initial_player_gravity[0],      FALSE
295   },
296   {
297     EL_PLAYER_1,                        -1,
298     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(9),
299     &li.use_start_element[0],           FALSE
300   },
301   {
302     EL_PLAYER_1,                        -1,
303     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
304     &li.start_element[0],               EL_PLAYER_1
305   },
306   {
307     EL_PLAYER_1,                        -1,
308     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(10),
309     &li.use_artwork_element[0],         FALSE
310   },
311   {
312     EL_PLAYER_1,                        -1,
313     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(2),
314     &li.artwork_element[0],             EL_PLAYER_1
315   },
316   {
317     EL_PLAYER_1,                        -1,
318     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(11),
319     &li.use_explosion_element[0],       FALSE
320   },
321   {
322     EL_PLAYER_1,                        -1,
323     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(3),
324     &li.explosion_element[0],           EL_PLAYER_1
325   },
326   {
327     EL_PLAYER_1,                        -1,
328     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(13),
329     &li.use_initial_inventory[0],       FALSE
330   },
331   {
332     EL_PLAYER_1,                        -1,
333     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(14),
334     &li.initial_inventory_size[0],      1
335   },
336   {
337     EL_PLAYER_1,                        -1,
338     TYPE_ELEMENT_LIST,                  CONF_VALUE_BYTES(1),
339     &li.initial_inventory_content[0][0],EL_EMPTY, NULL,
340     &li.initial_inventory_size[0],      1, MAX_INITIAL_INVENTORY_SIZE
341   },
342
343   {
344     EL_PLAYER_2,                        -1,
345     TYPE_INTEGER,                       CONF_VALUE_8_BIT(7),
346     &li.initial_player_stepsize[1],     STEPSIZE_NORMAL
347   },
348   {
349     EL_PLAYER_2,                        -1,
350     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(8),
351     &li.initial_player_gravity[1],      FALSE
352   },
353   {
354     EL_PLAYER_2,                        -1,
355     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(9),
356     &li.use_start_element[1],           FALSE
357   },
358   {
359     EL_PLAYER_2,                        -1,
360     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
361     &li.start_element[1],               EL_PLAYER_2
362   },
363   {
364     EL_PLAYER_2,                        -1,
365     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(10),
366     &li.use_artwork_element[1],         FALSE
367   },
368   {
369     EL_PLAYER_2,                        -1,
370     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(2),
371     &li.artwork_element[1],             EL_PLAYER_2
372   },
373   {
374     EL_PLAYER_2,                        -1,
375     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(11),
376     &li.use_explosion_element[1],       FALSE
377   },
378   {
379     EL_PLAYER_2,                        -1,
380     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(3),
381     &li.explosion_element[1],           EL_PLAYER_2
382   },
383   {
384     EL_PLAYER_2,                        -1,
385     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(13),
386     &li.use_initial_inventory[1],       FALSE
387   },
388   {
389     EL_PLAYER_2,                        -1,
390     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(14),
391     &li.initial_inventory_size[1],      1
392   },
393   {
394     EL_PLAYER_2,                        -1,
395     TYPE_ELEMENT_LIST,                  CONF_VALUE_BYTES(1),
396     &li.initial_inventory_content[1][0],EL_EMPTY, NULL,
397     &li.initial_inventory_size[1],      1, MAX_INITIAL_INVENTORY_SIZE
398   },
399
400   {
401     EL_PLAYER_3,                        -1,
402     TYPE_INTEGER,                       CONF_VALUE_8_BIT(7),
403     &li.initial_player_stepsize[2],     STEPSIZE_NORMAL
404   },
405   {
406     EL_PLAYER_3,                        -1,
407     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(8),
408     &li.initial_player_gravity[2],      FALSE
409   },
410   {
411     EL_PLAYER_3,                        -1,
412     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(9),
413     &li.use_start_element[2],           FALSE
414   },
415   {
416     EL_PLAYER_3,                        -1,
417     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
418     &li.start_element[2],               EL_PLAYER_3
419   },
420   {
421     EL_PLAYER_3,                        -1,
422     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(10),
423     &li.use_artwork_element[2],         FALSE
424   },
425   {
426     EL_PLAYER_3,                        -1,
427     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(2),
428     &li.artwork_element[2],             EL_PLAYER_3
429   },
430   {
431     EL_PLAYER_3,                        -1,
432     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(11),
433     &li.use_explosion_element[2],       FALSE
434   },
435   {
436     EL_PLAYER_3,                        -1,
437     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(3),
438     &li.explosion_element[2],           EL_PLAYER_3
439   },
440   {
441     EL_PLAYER_3,                        -1,
442     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(13),
443     &li.use_initial_inventory[2],       FALSE
444   },
445   {
446     EL_PLAYER_3,                        -1,
447     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(14),
448     &li.initial_inventory_size[2],      1
449   },
450   {
451     EL_PLAYER_3,                        -1,
452     TYPE_ELEMENT_LIST,                  CONF_VALUE_BYTES(1),
453     &li.initial_inventory_content[2][0],EL_EMPTY, NULL,
454     &li.initial_inventory_size[2],      1, MAX_INITIAL_INVENTORY_SIZE
455   },
456
457   {
458     EL_PLAYER_4,                        -1,
459     TYPE_INTEGER,                       CONF_VALUE_8_BIT(7),
460     &li.initial_player_stepsize[3],     STEPSIZE_NORMAL
461   },
462   {
463     EL_PLAYER_4,                        -1,
464     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(8),
465     &li.initial_player_gravity[3],      FALSE
466   },
467   {
468     EL_PLAYER_4,                        -1,
469     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(9),
470     &li.use_start_element[3],           FALSE
471   },
472   {
473     EL_PLAYER_4,                        -1,
474     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
475     &li.start_element[3],               EL_PLAYER_4
476   },
477   {
478     EL_PLAYER_4,                        -1,
479     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(10),
480     &li.use_artwork_element[3],         FALSE
481   },
482   {
483     EL_PLAYER_4,                        -1,
484     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(2),
485     &li.artwork_element[3],             EL_PLAYER_4
486   },
487   {
488     EL_PLAYER_4,                        -1,
489     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(11),
490     &li.use_explosion_element[3],       FALSE
491   },
492   {
493     EL_PLAYER_4,                        -1,
494     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(3),
495     &li.explosion_element[3],           EL_PLAYER_4
496   },
497   {
498     EL_PLAYER_4,                        -1,
499     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(13),
500     &li.use_initial_inventory[3],       FALSE
501   },
502   {
503     EL_PLAYER_4,                        -1,
504     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(14),
505     &li.initial_inventory_size[3],      1
506   },
507   {
508     EL_PLAYER_4,                        -1,
509     TYPE_ELEMENT_LIST,                  CONF_VALUE_BYTES(1),
510     &li.initial_inventory_content[3][0],EL_EMPTY, NULL,
511     &li.initial_inventory_size[3],      1, MAX_INITIAL_INVENTORY_SIZE
512   },
513
514   {
515     EL_EMERALD,                         -1,
516     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
517     &li.score[SC_EMERALD],              10
518   },
519
520   {
521     EL_DIAMOND,                         -1,
522     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
523     &li.score[SC_DIAMOND],              10
524   },
525
526   {
527     EL_BUG,                             -1,
528     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
529     &li.score[SC_BUG],                  10
530   },
531
532   {
533     EL_SPACESHIP,                       -1,
534     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
535     &li.score[SC_SPACESHIP],            10
536   },
537
538   {
539     EL_PACMAN,                          -1,
540     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
541     &li.score[SC_PACMAN],               10
542   },
543
544   {
545     EL_NUT,                             -1,
546     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
547     &li.score[SC_NUT],                  10
548   },
549
550   {
551     EL_DYNAMITE,                        -1,
552     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
553     &li.score[SC_DYNAMITE],             10
554   },
555
556   {
557     EL_KEY_1,                           -1,
558     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
559     &li.score[SC_KEY],                  10
560   },
561
562   {
563     EL_PEARL,                           -1,
564     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
565     &li.score[SC_PEARL],                10
566   },
567
568   {
569     EL_CRYSTAL,                         -1,
570     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
571     &li.score[SC_CRYSTAL],              10
572   },
573
574   {
575     EL_BD_AMOEBA,                       -1,
576     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
577     &li.amoeba_content,                 EL_DIAMOND
578   },
579   {
580     EL_BD_AMOEBA,                       -1,
581     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
582     &li.amoeba_speed,                   10
583   },
584   {
585     EL_BD_AMOEBA,                       -1,
586     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
587     &li.grow_into_diggable,             TRUE
588   },
589
590   {
591     EL_YAMYAM,                          -1,
592     TYPE_CONTENT_LIST,                  CONF_VALUE_BYTES(1),
593     &li.yamyam_content,                 EL_ROCK, NULL,
594     &li.num_yamyam_contents,            4, MAX_ELEMENT_CONTENTS
595   },
596   {
597     EL_YAMYAM,                          -1,
598     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
599     &li.score[SC_YAMYAM],               10
600   },
601
602   {
603     EL_ROBOT,                           -1,
604     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
605     &li.score[SC_ROBOT],                10
606   },
607   {
608     EL_ROBOT,                           -1,
609     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
610     &li.slurp_score,                    10
611   },
612
613   {
614     EL_ROBOT_WHEEL,                     -1,
615     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
616     &li.time_wheel,                     10
617   },
618
619   {
620     EL_MAGIC_WALL,                      -1,
621     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
622     &li.time_magic_wall,                10
623   },
624
625   {
626     EL_GAME_OF_LIFE,                    -1,
627     TYPE_INTEGER,                       CONF_VALUE_8_BIT(1),
628     &li.game_of_life[0],                2
629   },
630   {
631     EL_GAME_OF_LIFE,                    -1,
632     TYPE_INTEGER,                       CONF_VALUE_8_BIT(2),
633     &li.game_of_life[1],                3
634   },
635   {
636     EL_GAME_OF_LIFE,                    -1,
637     TYPE_INTEGER,                       CONF_VALUE_8_BIT(3),
638     &li.game_of_life[2],                3
639   },
640   {
641     EL_GAME_OF_LIFE,                    -1,
642     TYPE_INTEGER,                       CONF_VALUE_8_BIT(4),
643     &li.game_of_life[3],                3
644   },
645
646   {
647     EL_BIOMAZE,                         -1,
648     TYPE_INTEGER,                       CONF_VALUE_8_BIT(1),
649     &li.biomaze[0],                     2
650   },
651   {
652     EL_BIOMAZE,                         -1,
653     TYPE_INTEGER,                       CONF_VALUE_8_BIT(2),
654     &li.biomaze[1],                     3
655   },
656   {
657     EL_BIOMAZE,                         -1,
658     TYPE_INTEGER,                       CONF_VALUE_8_BIT(3),
659     &li.biomaze[2],                     3
660   },
661   {
662     EL_BIOMAZE,                         -1,
663     TYPE_INTEGER,                       CONF_VALUE_8_BIT(4),
664     &li.biomaze[3],                     3
665   },
666
667   {
668     EL_TIMEGATE_SWITCH,                 -1,
669     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
670     &li.time_timegate,                  10
671   },
672
673   {
674     EL_LIGHT_SWITCH_ACTIVE,             -1,
675     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
676     &li.time_light,                     10
677   },
678
679   {
680     EL_SHIELD_NORMAL,                   -1,
681     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
682     &li.shield_normal_time,             10
683   },
684   {
685     EL_SHIELD_NORMAL,                   -1,
686     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
687     &li.score[SC_SHIELD],               10
688   },
689
690   {
691     EL_SHIELD_DEADLY,                   -1,
692     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
693     &li.shield_deadly_time,             10
694   },
695   {
696     EL_SHIELD_DEADLY,                   -1,
697     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
698     &li.score[SC_SHIELD],               10
699   },
700
701   {
702     EL_EXTRA_TIME,                      -1,
703     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
704     &li.extra_time,                     10
705   },
706   {
707     EL_EXTRA_TIME,                      -1,
708     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
709     &li.extra_time_score,               10
710   },
711
712   {
713     EL_TIME_ORB_FULL,                   -1,
714     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
715     &li.time_orb_time,                  10
716   },
717   {
718     EL_TIME_ORB_FULL,                   -1,
719     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
720     &li.use_time_orb_bug,               FALSE
721   },
722
723   {
724     EL_SPRING,                          -1,
725     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
726     &li.use_spring_bug,                 FALSE
727   },
728
729   {
730     EL_EMC_ANDROID,                     -1,
731     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
732     &li.android_move_time,              10
733   },
734   {
735     EL_EMC_ANDROID,                     -1,
736     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
737     &li.android_clone_time,             10
738   },
739   {
740     EL_EMC_ANDROID,                     -1,
741     TYPE_ELEMENT_LIST,                  CONF_VALUE_BYTES(1),
742     &li.android_clone_element[0],       EL_EMPTY, NULL,
743     &li.num_android_clone_elements,     1, MAX_ANDROID_ELEMENTS
744   },
745
746   {
747     EL_EMC_LENSES,                      -1,
748     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
749     &li.lenses_score,                   10
750   },
751   {
752     EL_EMC_LENSES,                      -1,
753     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
754     &li.lenses_time,                    10
755   },
756
757   {
758     EL_EMC_MAGNIFIER,                   -1,
759     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
760     &li.magnify_score,                  10
761   },
762   {
763     EL_EMC_MAGNIFIER,                   -1,
764     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
765     &li.magnify_time,                   10
766   },
767
768   {
769     EL_EMC_MAGIC_BALL,                  -1,
770     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
771     &li.ball_time,                      10
772   },
773   {
774     EL_EMC_MAGIC_BALL,                  -1,
775     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
776     &li.ball_random,                    FALSE
777   },
778   {
779     EL_EMC_MAGIC_BALL,                  -1,
780     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(2),
781     &li.ball_state_initial,             FALSE
782   },
783   {
784     EL_EMC_MAGIC_BALL,                  -1,
785     TYPE_CONTENT_LIST,                  CONF_VALUE_BYTES(1),
786     &li.ball_content,                   EL_EMPTY, NULL,
787     &li.num_ball_contents,              4, MAX_ELEMENT_CONTENTS
788   },
789
790   /* ---------- unused values ----------------------------------------------- */
791
792   {
793     EL_UNKNOWN,                         SAVE_CONF_NEVER,
794     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
795     &li.score[SC_UNKNOWN_14],           10
796   },
797   {
798     EL_UNKNOWN,                         SAVE_CONF_NEVER,
799     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
800     &li.score[SC_UNKNOWN_15],           10
801   },
802
803   {
804     -1,                                 -1,
805     -1,                                 -1,
806     NULL,                               -1
807   }
808 };
809
810 static struct LevelFileConfigInfo chunk_config_NOTE[] =
811 {
812   {
813     -1,                                 -1,
814     TYPE_INTEGER,                       CONF_VALUE_8_BIT(1),
815     &xx_envelope.xsize,                 MAX_ENVELOPE_XSIZE,
816   },
817   {
818     -1,                                 -1,
819     TYPE_INTEGER,                       CONF_VALUE_8_BIT(2),
820     &xx_envelope.ysize,                 MAX_ENVELOPE_YSIZE,
821   },
822
823   {
824     -1,                                 -1,
825     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(3),
826     &xx_envelope.autowrap,              FALSE
827   },
828   {
829     -1,                                 -1,
830     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(4),
831     &xx_envelope.centered,              FALSE
832   },
833
834   {
835     -1,                                 -1,
836     TYPE_STRING,                        CONF_VALUE_BYTES(1),
837     &xx_envelope.text,                  -1, NULL,
838     &xx_string_length_unused,           -1, MAX_ENVELOPE_TEXT_LEN,
839     &xx_default_string_empty[0]
840   },
841
842   {
843     -1,                                 -1,
844     -1,                                 -1,
845     NULL,                               -1
846   }
847 };
848
849 static struct LevelFileConfigInfo chunk_config_CUSX_base[] =
850 {
851   {
852     -1,                                 -1,
853     TYPE_STRING,                        CONF_VALUE_BYTES(1),
854     &xx_ei.description[0],              -1,
855     &yy_ei.description[0],
856     &xx_string_length_unused,           -1, MAX_ELEMENT_NAME_LEN,
857     &xx_default_description[0]
858   },
859
860   {
861     -1,                                 -1,
862     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(1),
863     &xx_ei.properties[EP_BITFIELD_BASE_NR], EP_BITMASK_BASE_DEFAULT,
864     &yy_ei.properties[EP_BITFIELD_BASE_NR]
865   },
866 #if 0
867   /* (reserved) */
868   {
869     -1,                                 -1,
870     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(2),
871     &xx_ei.properties[EP_BITFIELD_BASE_NR + 1], EP_BITMASK_DEFAULT,
872     &yy_ei.properties[EP_BITFIELD_BASE_NR + 1]
873   },
874 #endif
875
876   {
877     -1,                                 -1,
878     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
879     &xx_ei.use_gfx_element,             FALSE,
880     &yy_ei.use_gfx_element
881   },
882   {
883     -1,                                 -1,
884     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
885     &xx_ei.gfx_element_initial,         EL_EMPTY_SPACE,
886     &yy_ei.gfx_element_initial
887   },
888
889   {
890     -1,                                 -1,
891     TYPE_BITFIELD,                      CONF_VALUE_8_BIT(2),
892     &xx_ei.access_direction,            MV_ALL_DIRECTIONS,
893     &yy_ei.access_direction
894   },
895
896   {
897     -1,                                 -1,
898     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
899     &xx_ei.collect_score_initial,       10,
900     &yy_ei.collect_score_initial
901   },
902   {
903     -1,                                 -1,
904     TYPE_INTEGER,                       CONF_VALUE_16_BIT(3),
905     &xx_ei.collect_count_initial,       1,
906     &yy_ei.collect_count_initial
907   },
908
909   {
910     -1,                                 -1,
911     TYPE_INTEGER,                       CONF_VALUE_16_BIT(4),
912     &xx_ei.ce_value_fixed_initial,      0,
913     &yy_ei.ce_value_fixed_initial
914   },
915   {
916     -1,                                 -1,
917     TYPE_INTEGER,                       CONF_VALUE_16_BIT(5),
918     &xx_ei.ce_value_random_initial,     0,
919     &yy_ei.ce_value_random_initial
920   },
921   {
922     -1,                                 -1,
923     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(3),
924     &xx_ei.use_last_ce_value,           FALSE,
925     &yy_ei.use_last_ce_value
926   },
927
928   {
929     -1,                                 -1,
930     TYPE_INTEGER,                       CONF_VALUE_16_BIT(6),
931     &xx_ei.push_delay_fixed,            8,
932     &yy_ei.push_delay_fixed
933   },
934   {
935     -1,                                 -1,
936     TYPE_INTEGER,                       CONF_VALUE_16_BIT(7),
937     &xx_ei.push_delay_random,           8,
938     &yy_ei.push_delay_random
939   },
940   {
941     -1,                                 -1,
942     TYPE_INTEGER,                       CONF_VALUE_16_BIT(8),
943     &xx_ei.drop_delay_fixed,            0,
944     &yy_ei.drop_delay_fixed
945   },
946   {
947     -1,                                 -1,
948     TYPE_INTEGER,                       CONF_VALUE_16_BIT(9),
949     &xx_ei.drop_delay_random,           0,
950     &yy_ei.drop_delay_random
951   },
952   {
953     -1,                                 -1,
954     TYPE_INTEGER,                       CONF_VALUE_16_BIT(10),
955     &xx_ei.move_delay_fixed,            0,
956     &yy_ei.move_delay_fixed
957   },
958   {
959     -1,                                 -1,
960     TYPE_INTEGER,                       CONF_VALUE_16_BIT(11),
961     &xx_ei.move_delay_random,           0,
962     &yy_ei.move_delay_random
963   },
964
965   {
966     -1,                                 -1,
967     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(3),
968     &xx_ei.move_pattern,                MV_ALL_DIRECTIONS,
969     &yy_ei.move_pattern
970   },
971   {
972     -1,                                 -1,
973     TYPE_BITFIELD,                      CONF_VALUE_8_BIT(4),
974     &xx_ei.move_direction_initial,      MV_START_AUTOMATIC,
975     &yy_ei.move_direction_initial
976   },
977   {
978     -1,                                 -1,
979     TYPE_INTEGER,                       CONF_VALUE_8_BIT(5),
980     &xx_ei.move_stepsize,               TILEX / 8,
981     &yy_ei.move_stepsize
982   },
983
984   {
985     -1,                                 -1,
986     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(12),
987     &xx_ei.move_enter_element,          EL_EMPTY_SPACE,
988     &yy_ei.move_enter_element
989   },
990   {
991     -1,                                 -1,
992     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(13),
993     &xx_ei.move_leave_element,          EL_EMPTY_SPACE,
994     &yy_ei.move_leave_element
995   },
996   {
997     -1,                                 -1,
998     TYPE_INTEGER,                       CONF_VALUE_8_BIT(6),
999     &xx_ei.move_leave_type,             LEAVE_TYPE_UNLIMITED,
1000     &yy_ei.move_leave_type
1001   },
1002
1003   {
1004     -1,                                 -1,
1005     TYPE_INTEGER,                       CONF_VALUE_8_BIT(7),
1006     &xx_ei.slippery_type,               SLIPPERY_ANY_RANDOM,
1007     &yy_ei.slippery_type
1008   },
1009
1010   {
1011     -1,                                 -1,
1012     TYPE_INTEGER,                       CONF_VALUE_8_BIT(8),
1013     &xx_ei.explosion_type,              EXPLODES_3X3,
1014     &yy_ei.explosion_type
1015   },
1016   {
1017     -1,                                 -1,
1018     TYPE_INTEGER,                       CONF_VALUE_16_BIT(14),
1019     &xx_ei.explosion_delay,             16,
1020     &yy_ei.explosion_delay
1021   },
1022   {
1023     -1,                                 -1,
1024     TYPE_INTEGER,                       CONF_VALUE_16_BIT(15),
1025     &xx_ei.ignition_delay,              8,
1026     &yy_ei.ignition_delay
1027   },
1028
1029   {
1030     -1,                                 -1,
1031     TYPE_CONTENT_LIST,                  CONF_VALUE_BYTES(2),
1032     &xx_ei.content,                     EL_EMPTY_SPACE,
1033     &yy_ei.content,
1034     &xx_num_contents,                   1, 1
1035   },
1036
1037   /* ---------- "num_change_pages" must be the last entry ------------------- */
1038
1039   {
1040     -1,                                 SAVE_CONF_ALWAYS,
1041     TYPE_INTEGER,                       CONF_VALUE_8_BIT(9),
1042     &xx_ei.num_change_pages,            1,
1043     &yy_ei.num_change_pages
1044   },
1045
1046   {
1047     -1,                                 -1,
1048     -1,                                 -1,
1049     NULL,                               -1,
1050     NULL
1051   }
1052 };
1053
1054 static struct LevelFileConfigInfo chunk_config_CUSX_change[] =
1055 {
1056   /* ---------- "current_change_page" must be the first entry --------------- */
1057
1058   {
1059     -1,                                 SAVE_CONF_ALWAYS,
1060     TYPE_INTEGER,                       CONF_VALUE_8_BIT(1),
1061     &xx_current_change_page,            -1
1062   },
1063
1064   /* ---------- (the remaining entries can be in any order) ----------------- */
1065
1066   {
1067     -1,                                 -1,
1068     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(2),
1069     &xx_change.can_change,              FALSE
1070   },
1071
1072   {
1073     -1,                                 -1,
1074     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(1),
1075     &xx_event_bits[0],                  0
1076   },
1077   {
1078     -1,                                 -1,
1079     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(2),
1080     &xx_event_bits[1],                  0
1081   },
1082
1083   {
1084     -1,                                 -1,
1085     TYPE_BITFIELD,                      CONF_VALUE_8_BIT(3),
1086     &xx_change.trigger_player,          CH_PLAYER_ANY
1087   },
1088   {
1089     -1,                                 -1,
1090     TYPE_BITFIELD,                      CONF_VALUE_8_BIT(4),
1091     &xx_change.trigger_side,            CH_SIDE_ANY
1092   },
1093   {
1094     -1,                                 -1,
1095     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(3),
1096     &xx_change.trigger_page,            CH_PAGE_ANY
1097   },
1098
1099   {
1100     -1,                                 -1,
1101     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
1102     &xx_change.target_element,          EL_EMPTY_SPACE
1103   },
1104
1105   {
1106     -1,                                 -1,
1107     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
1108     &xx_change.delay_fixed,             0
1109   },
1110   {
1111     -1,                                 -1,
1112     TYPE_INTEGER,                       CONF_VALUE_16_BIT(3),
1113     &xx_change.delay_random,            0
1114   },
1115   {
1116     -1,                                 -1,
1117     TYPE_INTEGER,                       CONF_VALUE_16_BIT(4),
1118     &xx_change.delay_frames,            FRAMES_PER_SECOND
1119   },
1120
1121   {
1122     -1,                                 -1,
1123     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(5),
1124     &xx_change.initial_trigger_element, EL_EMPTY_SPACE
1125   },
1126
1127   {
1128     -1,                                 -1,
1129     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(6),
1130     &xx_change.explode,                 FALSE
1131   },
1132   {
1133     -1,                                 -1,
1134     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(7),
1135     &xx_change.use_target_content,      FALSE
1136   },
1137   {
1138     -1,                                 -1,
1139     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(8),
1140     &xx_change.only_if_complete,        FALSE
1141   },
1142   {
1143     -1,                                 -1,
1144     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(9),
1145     &xx_change.use_random_replace,      FALSE
1146   },
1147   {
1148     -1,                                 -1,
1149     TYPE_INTEGER,                       CONF_VALUE_8_BIT(10),
1150     &xx_change.random_percentage,       100
1151   },
1152   {
1153     -1,                                 -1,
1154     TYPE_INTEGER,                       CONF_VALUE_8_BIT(11),
1155     &xx_change.replace_when,            CP_WHEN_EMPTY
1156   },
1157
1158   {
1159     -1,                                 -1,
1160     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(12),
1161     &xx_change.has_action,              FALSE
1162   },
1163   {
1164     -1,                                 -1,
1165     TYPE_INTEGER,                       CONF_VALUE_8_BIT(13),
1166     &xx_change.action_type,             CA_NO_ACTION
1167   },
1168   {
1169     -1,                                 -1,
1170     TYPE_INTEGER,                       CONF_VALUE_8_BIT(14),
1171     &xx_change.action_mode,             CA_MODE_UNDEFINED
1172   },
1173   {
1174     -1,                                 -1,
1175     TYPE_INTEGER,                       CONF_VALUE_16_BIT(6),
1176     &xx_change.action_arg,              CA_ARG_UNDEFINED
1177   },
1178
1179   {
1180     -1,                                 -1,
1181     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(7),
1182     &xx_change.action_element,          EL_EMPTY_SPACE
1183   },
1184
1185   {
1186     -1,                                 -1,
1187     TYPE_CONTENT_LIST,                  CONF_VALUE_BYTES(1),
1188     &xx_change.target_content,          EL_EMPTY_SPACE, NULL,
1189     &xx_num_contents,                   1, 1
1190   },
1191
1192   {
1193     -1,                                 -1,
1194     -1,                                 -1,
1195     NULL,                               -1
1196   }
1197 };
1198
1199 static struct LevelFileConfigInfo chunk_config_GRPX[] =
1200 {
1201   {
1202     -1,                                 -1,
1203     TYPE_STRING,                        CONF_VALUE_BYTES(1),
1204     &xx_ei.description[0],              -1, NULL,
1205     &xx_string_length_unused,           -1, MAX_ELEMENT_NAME_LEN,
1206     &xx_default_description[0]
1207   },
1208
1209   {
1210     -1,                                 -1,
1211     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
1212     &xx_ei.use_gfx_element,             FALSE
1213   },
1214   {
1215     -1,                                 -1,
1216     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
1217     &xx_ei.gfx_element_initial,         EL_EMPTY_SPACE
1218   },
1219
1220   {
1221     -1,                                 -1,
1222     TYPE_INTEGER,                       CONF_VALUE_8_BIT(2),
1223     &xx_group.choice_mode,              ANIM_RANDOM
1224   },
1225
1226   {
1227     -1,                                 -1,
1228     TYPE_ELEMENT_LIST,                  CONF_VALUE_BYTES(2),
1229     &xx_group.element[0],               EL_EMPTY_SPACE, NULL,
1230     &xx_group.num_elements,             1, MAX_ELEMENTS_IN_GROUP
1231   },
1232
1233   {
1234     -1,                                 -1,
1235     -1,                                 -1,
1236     NULL,                               -1
1237   }
1238 };
1239
1240 static struct LevelFileConfigInfo chunk_config_CONF[] =         /* (OBSOLETE) */
1241 {
1242   {
1243     EL_PLAYER_1,                        -1,
1244     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(9),
1245     &li.block_snap_field,               TRUE
1246   },
1247   {
1248     EL_PLAYER_1,                        -1,
1249     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(13),
1250     &li.continuous_snapping,            TRUE
1251   },
1252   {
1253     EL_PLAYER_1,                        -1,
1254     TYPE_INTEGER,                       CONF_VALUE_8_BIT(1),
1255     &li.initial_player_stepsize[0],     STEPSIZE_NORMAL
1256   },
1257   {
1258     EL_PLAYER_1,                        -1,
1259     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(10),
1260     &li.use_start_element[0],           FALSE
1261   },
1262   {
1263     EL_PLAYER_1,                        -1,
1264     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
1265     &li.start_element[0],               EL_PLAYER_1
1266   },
1267   {
1268     EL_PLAYER_1,                        -1,
1269     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(11),
1270     &li.use_artwork_element[0],         FALSE
1271   },
1272   {
1273     EL_PLAYER_1,                        -1,
1274     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(2),
1275     &li.artwork_element[0],             EL_PLAYER_1
1276   },
1277   {
1278     EL_PLAYER_1,                        -1,
1279     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(12),
1280     &li.use_explosion_element[0],       FALSE
1281   },
1282   {
1283     EL_PLAYER_1,                        -1,
1284     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(3),
1285     &li.explosion_element[0],           EL_PLAYER_1
1286   },
1287
1288   {
1289     -1,                                 -1,
1290     -1,                                 -1,
1291     NULL,                               -1
1292   }
1293 };
1294
1295 static struct
1296 {
1297   int filetype;
1298   char *id;
1299 }
1300 filetype_id_list[] =
1301 {
1302   { LEVEL_FILE_TYPE_RND,        "RND"   },
1303   { LEVEL_FILE_TYPE_BD,         "BD"    },
1304   { LEVEL_FILE_TYPE_EM,         "EM"    },
1305   { LEVEL_FILE_TYPE_SP,         "SP"    },
1306   { LEVEL_FILE_TYPE_DX,         "DX"    },
1307   { LEVEL_FILE_TYPE_SB,         "SB"    },
1308   { LEVEL_FILE_TYPE_DC,         "DC"    },
1309   { -1,                         NULL    },
1310 };
1311
1312
1313 /* ========================================================================= */
1314 /* level file functions                                                      */
1315 /* ========================================================================= */
1316
1317 static 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 (level_file_info->packed &&
4017       fseek(file, nr * SP_LEVEL_SIZE, SEEK_SET) != 0)
4018   {
4019     level->no_valid_file = TRUE;
4020
4021     Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level", filename);
4022
4023     return;
4024   }
4025
4026   /* there exist Supaplex level package files with multi-part levels which
4027      can be detected as follows: instead of leading and trailing dashes ('-')
4028      to pad the level name, they have leading and trailing numbers which are
4029      the x and y coordinations of the current part of the multi-part level;
4030      if there are '?' characters instead of numbers on the left or right side
4031      of the level name, the multi-part level consists of only horizontal or
4032      vertical parts */
4033
4034   for (l = nr; l < NUM_SUPAPLEX_LEVELS_PER_PACKAGE; l++)
4035   {
4036     LoadLevelFromFileStream_SP(file, level, l);
4037
4038     /* check if this level is a part of a bigger multi-part level */
4039
4040     name_first = level->name[0];
4041     name_last  = level->name[SP_LEVEL_NAME_LEN - 1];
4042
4043     is_multipart_level =
4044       ((name_first == '?' || (name_first >= '0' && name_first <= '9')) &&
4045        (name_last  == '?' || (name_last  >= '0' && name_last  <= '9')));
4046
4047     is_first_part =
4048       ((name_first == '?' || name_first == '1') &&
4049        (name_last  == '?' || name_last  == '1'));
4050
4051     /* correct leading multipart level meta information in level name */
4052     for (i = 0; i < SP_LEVEL_NAME_LEN && level->name[i] == name_first; i++)
4053       level->name[i] = '-';
4054
4055     /* correct trailing multipart level meta information in level name */
4056     for (i = SP_LEVEL_NAME_LEN - 1; i >= 0 && level->name[i] == name_last; i--)
4057       level->name[i] = '-';
4058
4059     /* ---------- check for normal single level ---------- */
4060
4061     if (!reading_multipart_level && !is_multipart_level)
4062     {
4063       /* the current level is simply a normal single-part level, and we are
4064          not reading a multi-part level yet, so return the level as it is */
4065
4066       break;
4067     }
4068
4069     /* ---------- check for empty level (unused multi-part) ---------- */
4070
4071     if (!reading_multipart_level && is_multipart_level && !is_first_part)
4072     {
4073       /* this is a part of a multi-part level, but not the first part
4074          (and we are not already reading parts of a multi-part level);
4075          in this case, use an empty level instead of the single part */
4076
4077       use_empty_level = TRUE;
4078
4079       break;
4080     }
4081
4082     /* ---------- check for finished multi-part level ---------- */
4083
4084     if (reading_multipart_level &&
4085         (!is_multipart_level ||
4086          !strEqual(level->name, multipart_level.name)))
4087     {
4088       /* we are already reading parts of a multi-part level, but this level is
4089          either not a multi-part level, or a part of a different multi-part
4090          level; in both cases, the multi-part level seems to be complete */
4091
4092       break;
4093     }
4094
4095     /* ---------- here we have one part of a multi-part level ---------- */
4096
4097     reading_multipart_level = TRUE;
4098
4099     if (is_first_part)  /* start with first part of new multi-part level */
4100     {
4101       /* copy level info structure from first part */
4102       multipart_level = *level;
4103
4104       /* clear playfield of new multi-part level */
4105       for (y = 0; y < MAX_LEV_FIELDY; y++)
4106         for (x = 0; x < MAX_LEV_FIELDX; x++)
4107           multipart_level.field[x][y] = EL_EMPTY;
4108     }
4109
4110     if (name_first == '?')
4111       name_first = '1';
4112     if (name_last == '?')
4113       name_last = '1';
4114
4115     multipart_xpos = (int)(name_first - '0');
4116     multipart_ypos = (int)(name_last  - '0');
4117
4118 #if 0
4119     printf("----------> part (%d/%d) of multi-part level '%s'\n",
4120            multipart_xpos, multipart_ypos, multipart_level.name);
4121 #endif
4122
4123     if (multipart_xpos * SP_LEVEL_XSIZE > MAX_LEV_FIELDX ||
4124         multipart_ypos * SP_LEVEL_YSIZE > MAX_LEV_FIELDY)
4125     {
4126       Error(ERR_WARN, "multi-part level is too big -- ignoring part of it");
4127
4128       break;
4129     }
4130
4131     multipart_level.fieldx = MAX(multipart_level.fieldx,
4132                                  multipart_xpos * SP_LEVEL_XSIZE);
4133     multipart_level.fieldy = MAX(multipart_level.fieldy,
4134                                  multipart_ypos * SP_LEVEL_YSIZE);
4135
4136     /* copy level part at the right position of multi-part level */
4137     for (y = 0; y < SP_LEVEL_YSIZE; y++)
4138     {
4139       for (x = 0; x < SP_LEVEL_XSIZE; x++)
4140       {
4141         int start_x = (multipart_xpos - 1) * SP_LEVEL_XSIZE;
4142         int start_y = (multipart_ypos - 1) * SP_LEVEL_YSIZE;
4143
4144         multipart_level.field[start_x + x][start_y + y] = level->field[x][y];
4145       }
4146     }
4147   }
4148
4149   fclose(file);
4150
4151   if (use_empty_level)
4152   {
4153     setLevelInfoToDefaults(level);
4154
4155     level->fieldx = SP_LEVEL_XSIZE;
4156     level->fieldy = SP_LEVEL_YSIZE;
4157
4158     for (y = 0; y < SP_LEVEL_YSIZE; y++)
4159       for (x = 0; x < SP_LEVEL_XSIZE; x++)
4160         level->field[x][y] = EL_EMPTY;
4161
4162     strcpy(level->name, "-------- EMPTY --------");
4163
4164     Error(ERR_WARN, "single part of multi-part level -- using empty level");
4165   }
4166
4167   if (reading_multipart_level)
4168     *level = multipart_level;
4169 }
4170
4171
4172 #define DC_LEVEL_HEADER_SIZE            344
4173
4174 unsigned short getDecodedWord_DC(unsigned short data_encoded, boolean init)
4175 {
4176   static int last_data_encoded;
4177   static int offset1;
4178   static int offset2;
4179   int diff;
4180   int diff_hi, diff_lo;
4181   int data_hi, data_lo;
4182   unsigned short data_decoded;
4183
4184   if (init)
4185   {
4186     last_data_encoded = 0;
4187     offset1 = -1;
4188     offset2 = 0;
4189
4190     return 0;
4191   }
4192
4193   diff = data_encoded - last_data_encoded;
4194   diff_hi = diff & ~0xff;
4195   diff_lo = diff &  0xff;
4196
4197   offset2 += diff_lo;
4198
4199   data_hi = diff_hi - (offset1 << 8) + (offset2 & 0xff00);
4200   data_lo = (diff_lo + (data_hi >> 16)) & 0x00ff;
4201   data_hi = data_hi & 0xff00;
4202
4203   data_decoded = data_hi | data_lo;
4204
4205   last_data_encoded = data_encoded;
4206
4207   offset1 = (offset1 + 1) % 31;
4208   offset2 = offset2 & 0xff;
4209
4210   return data_decoded;
4211 }
4212
4213 int getMappedElement_DC(int element)
4214 {
4215   switch (element)
4216   {
4217     case 0x0000:
4218       element = EL_ROCK;
4219       break;
4220
4221       /* 0x0117 - 0x036e: (?) */
4222       /* EL_DIAMOND */
4223
4224       /* 0x042d - 0x0684: (?) */
4225       /* EL_EMERALD */
4226
4227     case 0x06f1:
4228       element = EL_NUT;
4229       break;
4230
4231     case 0x074c:
4232       element = EL_BOMB;
4233       break;
4234
4235     case 0x07a4:
4236       element = EL_PEARL;
4237       break;
4238
4239     case 0x0823:
4240       element = EL_CRYSTAL;
4241       break;
4242
4243     case 0x0e77:        /* quicksand (boulder) */
4244       element = EL_QUICKSAND_FAST_FULL;
4245       break;
4246
4247     case 0x0e99:        /* slow quicksand (boulder) */
4248       element = EL_QUICKSAND_FULL;
4249       break;
4250
4251     case 0x0ed2:
4252       element = EL_EM_EXIT_OPEN;
4253       break;
4254
4255     case 0x0ee3:
4256       element = EL_EM_EXIT_CLOSED;
4257       break;
4258
4259     case 0x0eeb:
4260       element = EL_EM_STEEL_EXIT_OPEN;
4261       break;
4262
4263     case 0x0efc:
4264       element = EL_EM_STEEL_EXIT_CLOSED;
4265       break;
4266
4267     case 0x0f4f:        /* dynamite (lit 1) */
4268       element = EL_EM_DYNAMITE_ACTIVE;
4269       break;
4270
4271     case 0x0f57:        /* dynamite (lit 2) */
4272       element = EL_EM_DYNAMITE_ACTIVE;
4273       break;
4274
4275     case 0x0f5f:        /* dynamite (lit 3) */
4276       element = EL_EM_DYNAMITE_ACTIVE;
4277       break;
4278
4279     case 0x0f67:        /* dynamite (lit 4) */
4280       element = EL_EM_DYNAMITE_ACTIVE;
4281       break;
4282
4283     case 0x0f81:
4284     case 0x0f82:
4285     case 0x0f83:
4286     case 0x0f84:
4287       element = EL_AMOEBA_WET;
4288       break;
4289
4290     case 0x0f85:
4291       element = EL_AMOEBA_DROP;
4292       break;
4293
4294     case 0x0fb9:
4295       element = EL_DC_MAGIC_WALL;
4296       break;
4297
4298     case 0x0fd0:
4299       element = EL_SPACESHIP_UP;
4300       break;
4301
4302     case 0x0fd9:
4303       element = EL_SPACESHIP_DOWN;
4304       break;
4305
4306     case 0x0ff1:
4307       element = EL_SPACESHIP_LEFT;
4308       break;
4309
4310     case 0x0ff9:
4311       element = EL_SPACESHIP_RIGHT;
4312       break;
4313
4314     case 0x1057:
4315       element = EL_BUG_UP;
4316       break;
4317
4318     case 0x1060:
4319       element = EL_BUG_DOWN;
4320       break;
4321
4322     case 0x1078:
4323       element = EL_BUG_LEFT;
4324       break;
4325
4326     case 0x1080:
4327       element = EL_BUG_RIGHT;
4328       break;
4329
4330     case 0x10de:
4331       element = EL_MOLE_UP;
4332       break;
4333
4334     case 0x10e7:
4335       element = EL_MOLE_DOWN;
4336       break;
4337
4338     case 0x10ff:
4339       element = EL_MOLE_LEFT;
4340       break;
4341
4342     case 0x1107:
4343       element = EL_MOLE_RIGHT;
4344       break;
4345
4346     case 0x11c0:
4347       element = EL_ROBOT;
4348       break;
4349
4350     case 0x13f5:
4351       element = EL_YAMYAM;
4352       break;
4353
4354     case 0x1425:
4355       element = EL_SWITCHGATE_OPEN;
4356       break;
4357
4358     case 0x1426:
4359       element = EL_SWITCHGATE_CLOSED;
4360       break;
4361
4362     case 0x1437:
4363       element = EL_DC_SWITCHGATE_SWITCH_UP;
4364       break;
4365
4366     case 0x143a:
4367       element = EL_TIMEGATE_CLOSED;
4368       break;
4369
4370     case 0x144c:        /* conveyor belt switch (green) */
4371       element = EL_CONVEYOR_BELT_3_SWITCH_MIDDLE;
4372       break;
4373
4374     case 0x144f:        /* conveyor belt switch (red) */
4375       element = EL_CONVEYOR_BELT_1_SWITCH_MIDDLE;
4376       break;
4377
4378     case 0x1452:        /* conveyor belt switch (blue) */
4379       element = EL_CONVEYOR_BELT_4_SWITCH_MIDDLE;
4380       break;
4381
4382     case 0x145b:
4383       element = EL_CONVEYOR_BELT_3_MIDDLE;
4384       break;
4385
4386     case 0x1463:
4387       element = EL_CONVEYOR_BELT_3_LEFT;
4388       break;
4389
4390     case 0x146b:
4391       element = EL_CONVEYOR_BELT_3_RIGHT;
4392       break;
4393
4394     case 0x1473:
4395       element = EL_CONVEYOR_BELT_1_MIDDLE;
4396       break;
4397
4398     case 0x147b:
4399       element = EL_CONVEYOR_BELT_1_LEFT;
4400       break;
4401
4402     case 0x1483:
4403       element = EL_CONVEYOR_BELT_1_RIGHT;
4404       break;
4405
4406     case 0x148b:
4407       element = EL_CONVEYOR_BELT_4_MIDDLE;
4408       break;
4409
4410     case 0x1493:
4411       element = EL_CONVEYOR_BELT_4_LEFT;
4412       break;
4413
4414     case 0x149b:
4415       element = EL_CONVEYOR_BELT_4_RIGHT;
4416       break;
4417
4418     case 0x14ac:
4419       element = EL_EXPANDABLE_WALL_HORIZONTAL;
4420       break;
4421
4422     case 0x14bd:
4423       element = EL_EXPANDABLE_WALL_VERTICAL;
4424       break;
4425
4426     case 0x14c6:
4427       element = EL_EXPANDABLE_WALL_ANY;
4428       break;
4429
4430     case 0x14ce:        /* growing steel wall (left/right) */
4431       element = EL_EXPANDABLE_STEELWALL_HORIZONTAL;
4432       break;
4433
4434     case 0x14df:        /* growing steel wall (up/down) */
4435       element = EL_EXPANDABLE_STEELWALL_VERTICAL;
4436       break;
4437
4438     case 0x14e8:        /* growing steel wall (up/down/left/right) */
4439       element = EL_EXPANDABLE_STEELWALL_ANY;
4440       break;
4441
4442     case 0x14e9:
4443       element = EL_SHIELD_DEADLY;
4444       break;
4445
4446     case 0x1501:
4447       element = EL_EXTRA_TIME;
4448       break;
4449
4450     case 0x154f:
4451       element = EL_ACID;
4452       break;
4453
4454     case 0x1577:
4455       element = EL_EMPTY_SPACE;
4456       break;
4457
4458     case 0x1578:        /* quicksand (empty) */
4459       element = EL_QUICKSAND_FAST_EMPTY;
4460       break;
4461
4462     case 0x1579:        /* slow quicksand (empty) */
4463       element = EL_QUICKSAND_EMPTY;
4464       break;
4465
4466       /* 0x157c - 0x158b: */
4467       /* EL_SAND */
4468
4469       /* 0x1590 - 0x159f: */
4470       /* EL_DC_LANDMINE */
4471
4472     case 0x15a0:
4473       element = EL_EM_DYNAMITE;
4474       break;
4475
4476     case 0x15a1:        /* key (red) */
4477       element = EL_EM_KEY_1;
4478       break;
4479
4480     case 0x15a2:        /* key (yellow) */
4481       element = EL_EM_KEY_2;
4482       break;
4483
4484     case 0x15a3:        /* key (blue) */
4485       element = EL_EM_KEY_4;
4486       break;
4487
4488     case 0x15a4:        /* key (green) */
4489       element = EL_EM_KEY_3;
4490       break;
4491
4492     case 0x15a5:        /* key (white) */
4493       element = EL_DC_KEY_WHITE;
4494       break;
4495
4496     case 0x15a6:
4497       element = EL_WALL_SLIPPERY;
4498       break;
4499
4500     case 0x15a7:
4501       element = EL_WALL;
4502       break;
4503
4504     case 0x15a8:        /* wall (not round) */
4505       element = EL_WALL;
4506       break;
4507
4508     case 0x15a9:        /* (blue) */
4509       element = EL_CHAR_A;
4510       break;
4511
4512     case 0x15aa:        /* (blue) */
4513       element = EL_CHAR_B;
4514       break;
4515
4516     case 0x15ab:        /* (blue) */
4517       element = EL_CHAR_C;
4518       break;
4519
4520     case 0x15ac:        /* (blue) */
4521       element = EL_CHAR_D;
4522       break;
4523
4524     case 0x15ad:        /* (blue) */
4525       element = EL_CHAR_E;
4526       break;
4527
4528     case 0x15ae:        /* (blue) */
4529       element = EL_CHAR_F;
4530       break;
4531
4532     case 0x15af:        /* (blue) */
4533       element = EL_CHAR_G;
4534       break;
4535
4536     case 0x15b0:        /* (blue) */
4537       element = EL_CHAR_H;
4538       break;
4539
4540     case 0x15b1:        /* (blue) */
4541       element = EL_CHAR_I;
4542       break;
4543
4544     case 0x15b2:        /* (blue) */
4545       element = EL_CHAR_J;
4546       break;
4547
4548     case 0x15b3:        /* (blue) */
4549       element = EL_CHAR_K;
4550       break;
4551
4552     case 0x15b4:        /* (blue) */
4553       element = EL_CHAR_L;
4554       break;
4555
4556     case 0x15b5:        /* (blue) */
4557       element = EL_CHAR_M;
4558       break;
4559
4560     case 0x15b6:        /* (blue) */
4561       element = EL_CHAR_N;
4562       break;
4563
4564     case 0x15b7:        /* (blue) */
4565       element = EL_CHAR_O;
4566       break;
4567
4568     case 0x15b8:        /* (blue) */
4569       element = EL_CHAR_P;
4570       break;
4571
4572     case 0x15b9:        /* (blue) */
4573       element = EL_CHAR_Q;
4574       break;
4575
4576     case 0x15ba:        /* (blue) */
4577       element = EL_CHAR_R;
4578       break;
4579
4580     case 0x15bb:        /* (blue) */
4581       element = EL_CHAR_S;
4582       break;
4583
4584     case 0x15bc:        /* (blue) */
4585       element = EL_CHAR_T;
4586       break;
4587
4588     case 0x15bd:        /* (blue) */
4589       element = EL_CHAR_U;
4590       break;
4591
4592     case 0x15be:        /* (blue) */
4593       element = EL_CHAR_V;
4594       break;
4595
4596     case 0x15bf:        /* (blue) */
4597       element = EL_CHAR_W;
4598       break;
4599
4600     case 0x15c0:        /* (blue) */
4601       element = EL_CHAR_X;
4602       break;
4603
4604     case 0x15c1:        /* (blue) */
4605       element = EL_CHAR_Y;
4606       break;
4607
4608     case 0x15c2:        /* (blue) */
4609       element = EL_CHAR_Z;
4610       break;
4611
4612     case 0x15c3:        /* (blue) */
4613       element = EL_CHAR_AUMLAUT;
4614       break;
4615
4616     case 0x15c4:        /* (blue) */
4617       element = EL_CHAR_OUMLAUT;
4618       break;
4619
4620     case 0x15c5:        /* (blue) */
4621       element = EL_CHAR_UUMLAUT;
4622       break;
4623
4624     case 0x15c6:        /* (blue) */
4625       element = EL_CHAR_0;
4626       break;
4627
4628     case 0x15c7:        /* (blue) */
4629       element = EL_CHAR_1;
4630       break;
4631
4632     case 0x15c8:        /* (blue) */
4633       element = EL_CHAR_2;
4634       break;
4635
4636     case 0x15c9:        /* (blue) */
4637       element = EL_CHAR_3;
4638       break;
4639
4640     case 0x15ca:        /* (blue) */
4641       element = EL_CHAR_4;
4642       break;
4643
4644     case 0x15cb:        /* (blue) */
4645       element = EL_CHAR_5;
4646       break;
4647
4648     case 0x15cc:        /* (blue) */
4649       element = EL_CHAR_6;
4650       break;
4651
4652     case 0x15cd:        /* (blue) */
4653       element = EL_CHAR_7;
4654       break;
4655
4656     case 0x15ce:        /* (blue) */
4657       element = EL_CHAR_8;
4658       break;
4659
4660     case 0x15cf:        /* (blue) */
4661       element = EL_CHAR_9;
4662       break;
4663
4664     case 0x15d0:        /* (blue) */
4665       element = EL_CHAR_PERIOD;
4666       break;
4667
4668     case 0x15d1:        /* (blue) */
4669       element = EL_CHAR_EXCLAM;
4670       break;
4671
4672     case 0x15d2:        /* (blue) */
4673       element = EL_CHAR_COLON;
4674       break;
4675
4676     case 0x15d3:        /* (blue) */
4677       element = EL_CHAR_LESS;
4678       break;
4679
4680     case 0x15d4:        /* (blue) */
4681       element = EL_CHAR_GREATER;
4682       break;
4683
4684     case 0x15d5:        /* (blue) */
4685       element = EL_CHAR_QUESTION;
4686       break;
4687
4688     case 0x15d6:        /* (blue) */
4689       element = EL_CHAR_COPYRIGHT;
4690       break;
4691
4692     case 0x15d7:        /* (blue) */
4693       element = EL_CHAR_UP;
4694       break;
4695
4696     case 0x15d8:        /* (blue) */
4697       element = EL_CHAR_DOWN;
4698       break;
4699
4700     case 0x15d9:        /* (blue) */
4701       element = EL_CHAR_BUTTON;
4702       break;
4703
4704     case 0x15da:        /* (blue) */
4705       element = EL_CHAR_PLUS;
4706       break;
4707
4708     case 0x15db:        /* (blue) */
4709       element = EL_CHAR_MINUS;
4710       break;
4711
4712     case 0x15dc:        /* (blue) */
4713       element = EL_CHAR_APOSTROPHE;
4714       break;
4715
4716     case 0x15dd:        /* (blue) */
4717       element = EL_CHAR_PARENLEFT;
4718       break;
4719
4720     case 0x15de:        /* (blue) */
4721       element = EL_CHAR_PARENRIGHT;
4722       break;
4723
4724     case 0x15df:        /* (green) */
4725       element = EL_CHAR_A;
4726       break;
4727
4728     case 0x15e0:        /* (green) */
4729       element = EL_CHAR_B;
4730       break;
4731
4732     case 0x15e1:        /* (green) */
4733       element = EL_CHAR_C;
4734       break;
4735
4736     case 0x15e2:        /* (green) */
4737       element = EL_CHAR_D;
4738       break;
4739
4740     case 0x15e3:        /* (green) */
4741       element = EL_CHAR_E;
4742       break;
4743
4744     case 0x15e4:        /* (green) */
4745       element = EL_CHAR_F;
4746       break;
4747
4748     case 0x15e5:        /* (green) */
4749       element = EL_CHAR_G;
4750       break;
4751
4752     case 0x15e6:        /* (green) */
4753       element = EL_CHAR_H;
4754       break;
4755
4756     case 0x15e7:        /* (green) */
4757       element = EL_CHAR_I;
4758       break;
4759
4760     case 0x15e8:        /* (green) */
4761       element = EL_CHAR_J;
4762       break;
4763
4764     case 0x15e9:        /* (green) */
4765       element = EL_CHAR_K;
4766       break;
4767
4768     case 0x15ea:        /* (green) */
4769       element = EL_CHAR_L;
4770       break;
4771
4772     case 0x15eb:        /* (green) */
4773       element = EL_CHAR_M;
4774       break;
4775
4776     case 0x15ec:        /* (green) */
4777       element = EL_CHAR_N;
4778       break;
4779
4780     case 0x15ed:        /* (green) */
4781       element = EL_CHAR_O;
4782       break;
4783
4784     case 0x15ee:        /* (green) */
4785       element = EL_CHAR_P;
4786       break;
4787
4788     case 0x15ef:        /* (green) */
4789       element = EL_CHAR_Q;
4790       break;
4791
4792     case 0x15f0:        /* (green) */
4793       element = EL_CHAR_R;
4794       break;
4795
4796     case 0x15f1:        /* (green) */
4797       element = EL_CHAR_S;
4798       break;
4799
4800     case 0x15f2:        /* (green) */
4801       element = EL_CHAR_T;
4802       break;
4803
4804     case 0x15f3:        /* (green) */
4805       element = EL_CHAR_U;
4806       break;
4807
4808     case 0x15f4:        /* (green) */
4809       element = EL_CHAR_V;
4810       break;
4811
4812     case 0x15f5:        /* (green) */
4813       element = EL_CHAR_W;
4814       break;
4815
4816     case 0x15f6:        /* (green) */
4817       element = EL_CHAR_X;
4818       break;
4819
4820     case 0x15f7:        /* (green) */
4821       element = EL_CHAR_Y;
4822       break;
4823
4824     case 0x15f8:        /* (green) */
4825       element = EL_CHAR_Z;
4826       break;
4827
4828     case 0x15f9:        /* (green) */
4829       element = EL_CHAR_AUMLAUT;
4830       break;
4831
4832     case 0x15fa:        /* (green) */
4833       element = EL_CHAR_OUMLAUT;
4834       break;
4835
4836     case 0x15fb:        /* (green) */
4837       element = EL_CHAR_UUMLAUT;
4838       break;
4839
4840     case 0x15fc:        /* (green) */
4841       element = EL_CHAR_0;
4842       break;
4843
4844     case 0x15fd:        /* (green) */
4845       element = EL_CHAR_1;
4846       break;
4847
4848     case 0x15fe:        /* (green) */
4849       element = EL_CHAR_2;
4850       break;
4851
4852     case 0x15ff:        /* (green) */
4853       element = EL_CHAR_3;
4854       break;
4855
4856     case 0x1600:        /* (green) */
4857       element = EL_CHAR_4;
4858       break;
4859
4860     case 0x1601:        /* (green) */
4861       element = EL_CHAR_5;
4862       break;
4863
4864     case 0x1602:        /* (green) */
4865       element = EL_CHAR_6;
4866       break;
4867
4868     case 0x1603:        /* (green) */
4869       element = EL_CHAR_7;
4870       break;
4871
4872     case 0x1604:        /* (green) */
4873       element = EL_CHAR_8;
4874       break;
4875
4876     case 0x1605:        /* (green) */
4877       element = EL_CHAR_9;
4878       break;
4879
4880     case 0x1606:        /* (green) */
4881       element = EL_CHAR_PERIOD;
4882       break;
4883
4884     case 0x1607:        /* (green) */
4885       element = EL_CHAR_EXCLAM;
4886       break;
4887
4888     case 0x1608:        /* (green) */
4889       element = EL_CHAR_COLON;
4890       break;
4891
4892     case 0x1609:        /* (green) */
4893       element = EL_CHAR_LESS;
4894       break;
4895
4896     case 0x160a:        /* (green) */
4897       element = EL_CHAR_GREATER;
4898       break;
4899
4900     case 0x160b:        /* (green) */
4901       element = EL_CHAR_QUESTION;
4902       break;
4903
4904     case 0x160c:        /* (green) */
4905       element = EL_CHAR_COPYRIGHT;
4906       break;
4907
4908     case 0x160d:        /* (green) */
4909       element = EL_CHAR_UP;
4910       break;
4911
4912     case 0x160e:        /* (green) */
4913       element = EL_CHAR_DOWN;
4914       break;
4915
4916     case 0x160f:        /* (green) */
4917       element = EL_CHAR_BUTTON;
4918       break;
4919
4920     case 0x1610:        /* (green) */
4921       element = EL_CHAR_PLUS;
4922       break;
4923
4924     case 0x1611:        /* (green) */
4925       element = EL_CHAR_MINUS;
4926       break;
4927
4928     case 0x1612:        /* (green) */
4929       element = EL_CHAR_APOSTROPHE;
4930       break;
4931
4932     case 0x1613:        /* (green) */
4933       element = EL_CHAR_PARENLEFT;
4934       break;
4935
4936     case 0x1614:        /* (green) */
4937       element = EL_CHAR_PARENRIGHT;
4938       break;
4939
4940     case 0x1615:        /* (blue steel) */
4941       element = EL_STEEL_CHAR_A;
4942       break;
4943
4944     case 0x1616:        /* (blue steel) */
4945       element = EL_STEEL_CHAR_B;
4946       break;
4947
4948     case 0x1617:        /* (blue steel) */
4949       element = EL_STEEL_CHAR_C;
4950       break;
4951
4952     case 0x1618:        /* (blue steel) */
4953       element = EL_STEEL_CHAR_D;
4954       break;
4955
4956     case 0x1619:        /* (blue steel) */
4957       element = EL_STEEL_CHAR_E;
4958       break;
4959
4960     case 0x161a:        /* (blue steel) */
4961       element = EL_STEEL_CHAR_F;
4962       break;
4963
4964     case 0x161b:        /* (blue steel) */
4965       element = EL_STEEL_CHAR_G;
4966       break;
4967
4968     case 0x161c:        /* (blue steel) */
4969       element = EL_STEEL_CHAR_H;
4970       break;
4971
4972     case 0x161d:        /* (blue steel) */
4973       element = EL_STEEL_CHAR_I;
4974       break;
4975
4976     case 0x161e:        /* (blue steel) */
4977       element = EL_STEEL_CHAR_J;
4978       break;
4979
4980     case 0x161f:        /* (blue steel) */
4981       element = EL_STEEL_CHAR_K;
4982       break;
4983
4984     case 0x1620:        /* (blue steel) */
4985       element = EL_STEEL_CHAR_L;
4986       break;
4987
4988     case 0x1621:        /* (blue steel) */
4989       element = EL_STEEL_CHAR_M;
4990       break;
4991
4992     case 0x1622:        /* (blue steel) */
4993       element = EL_STEEL_CHAR_N;
4994       break;
4995
4996     case 0x1623:        /* (blue steel) */
4997       element = EL_STEEL_CHAR_O;
4998       break;
4999
5000     case 0x1624:        /* (blue steel) */
5001       element = EL_STEEL_CHAR_P;
5002       break;
5003
5004     case 0x1625:        /* (blue steel) */
5005       element = EL_STEEL_CHAR_Q;
5006       break;
5007
5008     case 0x1626:        /* (blue steel) */
5009       element = EL_STEEL_CHAR_R;
5010       break;
5011
5012     case 0x1627:        /* (blue steel) */
5013       element = EL_STEEL_CHAR_S;
5014       break;
5015
5016     case 0x1628:        /* (blue steel) */
5017       element = EL_STEEL_CHAR_T;
5018       break;
5019
5020     case 0x1629:        /* (blue steel) */
5021       element = EL_STEEL_CHAR_U;
5022       break;
5023
5024     case 0x162a:        /* (blue steel) */
5025       element = EL_STEEL_CHAR_V;
5026       break;
5027
5028     case 0x162b:        /* (blue steel) */
5029       element = EL_STEEL_CHAR_W;
5030       break;
5031
5032     case 0x162c:        /* (blue steel) */
5033       element = EL_STEEL_CHAR_X;
5034       break;
5035
5036     case 0x162d:        /* (blue steel) */
5037       element = EL_STEEL_CHAR_Y;
5038       break;
5039
5040     case 0x162e:        /* (blue steel) */
5041       element = EL_STEEL_CHAR_Z;
5042       break;
5043
5044     case 0x162f:        /* (blue steel) */
5045       element = EL_STEEL_CHAR_AUMLAUT;
5046       break;
5047
5048     case 0x1630:        /* (blue steel) */
5049       element = EL_STEEL_CHAR_OUMLAUT;
5050       break;
5051
5052     case 0x1631:        /* (blue steel) */
5053       element = EL_STEEL_CHAR_UUMLAUT;
5054       break;
5055
5056     case 0x1632:        /* (blue steel) */
5057       element = EL_STEEL_CHAR_0;
5058       break;
5059
5060     case 0x1633:        /* (blue steel) */
5061       element = EL_STEEL_CHAR_1;
5062       break;
5063
5064     case 0x1634:        /* (blue steel) */
5065       element = EL_STEEL_CHAR_2;
5066       break;
5067
5068     case 0x1635:        /* (blue steel) */
5069       element = EL_STEEL_CHAR_3;
5070       break;
5071
5072     case 0x1636:        /* (blue steel) */
5073       element = EL_STEEL_CHAR_4;
5074       break;
5075
5076     case 0x1637:        /* (blue steel) */
5077       element = EL_STEEL_CHAR_5;
5078       break;
5079
5080     case 0x1638:        /* (blue steel) */
5081       element = EL_STEEL_CHAR_6;
5082       break;
5083
5084     case 0x1639:        /* (blue steel) */
5085       element = EL_STEEL_CHAR_7;
5086       break;
5087
5088     case 0x163a:        /* (blue steel) */
5089       element = EL_STEEL_CHAR_8;
5090       break;
5091
5092     case 0x163b:        /* (blue steel) */
5093       element = EL_STEEL_CHAR_9;
5094       break;
5095
5096     case 0x163c:        /* (blue steel) */
5097       element = EL_STEEL_CHAR_PERIOD;
5098       break;
5099
5100     case 0x163d:        /* (blue steel) */
5101       element = EL_STEEL_CHAR_EXCLAM;
5102       break;
5103
5104     case 0x163e:        /* (blue steel) */
5105       element = EL_STEEL_CHAR_COLON;
5106       break;
5107
5108     case 0x163f:        /* (blue steel) */
5109       element = EL_STEEL_CHAR_LESS;
5110       break;
5111
5112     case 0x1640:        /* (blue steel) */
5113       element = EL_STEEL_CHAR_GREATER;
5114       break;
5115
5116     case 0x1641:        /* (blue steel) */
5117       element = EL_STEEL_CHAR_QUESTION;
5118       break;
5119
5120     case 0x1642:        /* (blue steel) */
5121       element = EL_STEEL_CHAR_COPYRIGHT;
5122       break;
5123
5124     case 0x1643:        /* (blue steel) */
5125       element = EL_STEEL_CHAR_UP;
5126       break;
5127
5128     case 0x1644:        /* (blue steel) */
5129       element = EL_STEEL_CHAR_DOWN;
5130       break;
5131
5132     case 0x1645:        /* (blue steel) */
5133       element = EL_STEEL_CHAR_BUTTON;
5134       break;
5135
5136     case 0x1646:        /* (blue steel) */
5137       element = EL_STEEL_CHAR_PLUS;
5138       break;
5139
5140     case 0x1647:        /* (blue steel) */
5141       element = EL_STEEL_CHAR_MINUS;
5142       break;
5143
5144     case 0x1648:        /* (blue steel) */
5145       element = EL_STEEL_CHAR_APOSTROPHE;
5146       break;
5147
5148     case 0x1649:        /* (blue steel) */
5149       element = EL_STEEL_CHAR_PARENLEFT;
5150       break;
5151
5152     case 0x164a:        /* (blue steel) */
5153       element = EL_STEEL_CHAR_PARENRIGHT;
5154       break;
5155
5156     case 0x164b:        /* (green steel) */
5157       element = EL_STEEL_CHAR_A;
5158       break;
5159
5160     case 0x164c:        /* (green steel) */
5161       element = EL_STEEL_CHAR_B;
5162       break;
5163
5164     case 0x164d:        /* (green steel) */
5165       element = EL_STEEL_CHAR_C;
5166       break;
5167
5168     case 0x164e:        /* (green steel) */
5169       element = EL_STEEL_CHAR_D;
5170       break;
5171
5172     case 0x164f:        /* (green steel) */
5173       element = EL_STEEL_CHAR_E;
5174       break;
5175
5176     case 0x1650:        /* (green steel) */
5177       element = EL_STEEL_CHAR_F;
5178       break;
5179
5180     case 0x1651:        /* (green steel) */
5181       element = EL_STEEL_CHAR_G;
5182       break;
5183
5184     case 0x1652:        /* (green steel) */
5185       element = EL_STEEL_CHAR_H;
5186       break;
5187
5188     case 0x1653:        /* (green steel) */
5189       element = EL_STEEL_CHAR_I;
5190       break;
5191
5192     case 0x1654:        /* (green steel) */
5193       element = EL_STEEL_CHAR_J;
5194       break;
5195
5196     case 0x1655:        /* (green steel) */
5197       element = EL_STEEL_CHAR_K;
5198       break;
5199
5200     case 0x1656:        /* (green steel) */
5201       element = EL_STEEL_CHAR_L;
5202       break;
5203
5204     case 0x1657:        /* (green steel) */
5205       element = EL_STEEL_CHAR_M;
5206       break;
5207
5208     case 0x1658:        /* (green steel) */
5209       element = EL_STEEL_CHAR_N;
5210       break;
5211
5212     case 0x1659:        /* (green steel) */
5213       element = EL_STEEL_CHAR_O;
5214       break;
5215
5216     case 0x165a:        /* (green steel) */
5217       element = EL_STEEL_CHAR_P;
5218       break;
5219
5220     case 0x165b:        /* (green steel) */
5221       element = EL_STEEL_CHAR_Q;
5222       break;
5223
5224     case 0x165c:        /* (green steel) */
5225       element = EL_STEEL_CHAR_R;
5226       break;
5227
5228     case 0x165d:        /* (green steel) */
5229       element = EL_STEEL_CHAR_S;
5230       break;
5231
5232     case 0x165e:        /* (green steel) */
5233       element = EL_STEEL_CHAR_T;
5234       break;
5235
5236     case 0x165f:        /* (green steel) */
5237       element = EL_STEEL_CHAR_U;
5238       break;
5239
5240     case 0x1660:        /* (green steel) */
5241       element = EL_STEEL_CHAR_V;
5242       break;
5243
5244     case 0x1661:        /* (green steel) */
5245       element = EL_STEEL_CHAR_W;
5246       break;
5247
5248     case 0x1662:        /* (green steel) */
5249       element = EL_STEEL_CHAR_X;
5250       break;
5251
5252     case 0x1663:        /* (green steel) */
5253       element = EL_STEEL_CHAR_Y;
5254       break;
5255
5256     case 0x1664:        /* (green steel) */
5257       element = EL_STEEL_CHAR_Z;
5258       break;
5259
5260     case 0x1665:        /* (green steel) */
5261       element = EL_STEEL_CHAR_AUMLAUT;
5262       break;
5263
5264     case 0x1666:        /* (green steel) */
5265       element = EL_STEEL_CHAR_OUMLAUT;
5266       break;
5267
5268     case 0x1667:        /* (green steel) */
5269       element = EL_STEEL_CHAR_UUMLAUT;
5270       break;
5271
5272     case 0x1668:        /* (green steel) */
5273       element = EL_STEEL_CHAR_0;
5274       break;
5275
5276     case 0x1669:        /* (green steel) */
5277       element = EL_STEEL_CHAR_1;
5278       break;
5279
5280     case 0x166a:        /* (green steel) */
5281       element = EL_STEEL_CHAR_2;
5282       break;
5283
5284     case 0x166b:        /* (green steel) */
5285       element = EL_STEEL_CHAR_3;
5286       break;
5287
5288     case 0x166c:        /* (green steel) */
5289       element = EL_STEEL_CHAR_4;
5290       break;
5291
5292     case 0x166d:        /* (green steel) */
5293       element = EL_STEEL_CHAR_5;
5294       break;
5295
5296     case 0x166e:        /* (green steel) */
5297       element = EL_STEEL_CHAR_6;
5298       break;
5299
5300     case 0x166f:        /* (green steel) */
5301       element = EL_STEEL_CHAR_7;
5302       break;
5303
5304     case 0x1670:        /* (green steel) */
5305       element = EL_STEEL_CHAR_8;
5306       break;
5307
5308     case 0x1671:        /* (green steel) */
5309       element = EL_STEEL_CHAR_9;
5310       break;
5311
5312     case 0x1672:        /* (green steel) */
5313       element = EL_STEEL_CHAR_PERIOD;
5314       break;
5315
5316     case 0x1673:        /* (green steel) */
5317       element = EL_STEEL_CHAR_EXCLAM;
5318       break;
5319
5320     case 0x1674:        /* (green steel) */
5321       element = EL_STEEL_CHAR_COLON;
5322       break;
5323
5324     case 0x1675:        /* (green steel) */
5325       element = EL_STEEL_CHAR_LESS;
5326       break;
5327
5328     case 0x1676:        /* (green steel) */
5329       element = EL_STEEL_CHAR_GREATER;
5330       break;
5331
5332     case 0x1677:        /* (green steel) */
5333       element = EL_STEEL_CHAR_QUESTION;
5334       break;
5335
5336     case 0x1678:        /* (green steel) */
5337       element = EL_STEEL_CHAR_COPYRIGHT;
5338       break;
5339
5340     case 0x1679:        /* (green steel) */
5341       element = EL_STEEL_CHAR_UP;
5342       break;
5343
5344     case 0x167a:        /* (green steel) */
5345       element = EL_STEEL_CHAR_DOWN;
5346       break;
5347
5348     case 0x167b:        /* (green steel) */
5349       element = EL_STEEL_CHAR_BUTTON;
5350       break;
5351
5352     case 0x167c:        /* (green steel) */
5353       element = EL_STEEL_CHAR_PLUS;
5354       break;
5355
5356     case 0x167d:        /* (green steel) */
5357       element = EL_STEEL_CHAR_MINUS;
5358       break;
5359
5360     case 0x167e:        /* (green steel) */
5361       element = EL_STEEL_CHAR_APOSTROPHE;
5362       break;
5363
5364     case 0x167f:        /* (green steel) */
5365       element = EL_STEEL_CHAR_PARENLEFT;
5366       break;
5367
5368     case 0x1680:        /* (green steel) */
5369       element = EL_STEEL_CHAR_PARENRIGHT;
5370       break;
5371
5372     case 0x1681:        /* gate (red) */
5373       element = EL_EM_GATE_1;
5374       break;
5375
5376     case 0x1682:        /* secret gate (red) */
5377       element = EL_GATE_1_GRAY;
5378       break;
5379
5380     case 0x1683:        /* gate (yellow) */
5381       element = EL_EM_GATE_2;
5382       break;
5383
5384     case 0x1684:        /* secret gate (yellow) */
5385       element = EL_GATE_2_GRAY;
5386       break;
5387
5388     case 0x1685:        /* gate (blue) */
5389       element = EL_EM_GATE_4;
5390       break;
5391
5392     case 0x1686:        /* secret gate (blue) */
5393       element = EL_GATE_4_GRAY;
5394       break;
5395
5396     case 0x1687:        /* gate (green) */
5397       element = EL_EM_GATE_3;
5398       break;
5399
5400     case 0x1688:        /* secret gate (green) */
5401       element = EL_GATE_3_GRAY;
5402       break;
5403
5404     case 0x1689:        /* gate (white) */
5405       element = EL_DC_GATE_WHITE;
5406       break;
5407
5408     case 0x168a:        /* secret gate (white) */
5409       element = EL_DC_GATE_WHITE_GRAY;
5410       break;
5411
5412     case 0x168b:        /* secret gate (no key) */
5413       element = EL_DC_GATE_FAKE_GRAY;
5414       break;
5415
5416     case 0x168c:
5417       element = EL_ROBOT_WHEEL;
5418       break;
5419
5420     case 0x168d:
5421       element = EL_DC_TIMEGATE_SWITCH;
5422       break;
5423
5424     case 0x168e:
5425       element = EL_ACID_POOL_BOTTOM;
5426       break;
5427
5428     case 0x168f:
5429       element = EL_ACID_POOL_TOPLEFT;
5430       break;
5431
5432     case 0x1690:
5433       element = EL_ACID_POOL_TOPRIGHT;
5434       break;
5435
5436     case 0x1691:
5437       element = EL_ACID_POOL_BOTTOMLEFT;
5438       break;
5439
5440     case 0x1692:
5441       element = EL_ACID_POOL_BOTTOMRIGHT;
5442       break;
5443
5444     case 0x1693:
5445       element = EL_STEELWALL;
5446       break;
5447
5448     case 0x1694:
5449       element = EL_STEELWALL_SLIPPERY;
5450       break;
5451
5452     case 0x1695:        /* steel wall (not round) */
5453       element = EL_STEELWALL;
5454       break;
5455
5456     case 0x1696:        /* steel wall (left) */
5457       element = EL_DC_STEELWALL_1_LEFT;
5458       break;
5459
5460     case 0x1697:        /* steel wall (bottom) */
5461       element = EL_DC_STEELWALL_1_BOTTOM;
5462       break;
5463
5464     case 0x1698:        /* steel wall (right) */
5465       element = EL_DC_STEELWALL_1_RIGHT;
5466       break;
5467
5468     case 0x1699:        /* steel wall (top) */
5469       element = EL_DC_STEELWALL_1_TOP;
5470       break;
5471
5472     case 0x169a:        /* steel wall (left/bottom) */
5473       element = EL_DC_STEELWALL_1_BOTTOMLEFT;
5474       break;
5475
5476     case 0x169b:        /* steel wall (right/bottom) */
5477       element = EL_DC_STEELWALL_1_BOTTOMRIGHT;
5478       break;
5479
5480     case 0x169c:        /* steel wall (right/top) */
5481       element = EL_DC_STEELWALL_1_TOPRIGHT;
5482       break;
5483
5484     case 0x169d:        /* steel wall (left/top) */
5485       element = EL_DC_STEELWALL_1_TOPLEFT;
5486       break;
5487
5488     case 0x169e:        /* steel wall (right/bottom small) */
5489       element = EL_DC_STEELWALL_1_BOTTOMRIGHT_2;
5490       break;
5491
5492     case 0x169f:        /* steel wall (left/bottom small) */
5493       element = EL_DC_STEELWALL_1_BOTTOMLEFT_2;
5494       break;
5495
5496     case 0x16a0:        /* steel wall (right/top small) */
5497       element = EL_DC_STEELWALL_1_TOPRIGHT_2;
5498       break;
5499
5500     case 0x16a1:        /* steel wall (left/top small) */
5501       element = EL_DC_STEELWALL_1_TOPLEFT_2;
5502       break;
5503
5504     case 0x16a2:        /* steel wall (left/right) */
5505       element = EL_DC_STEELWALL_1_VERTICAL;
5506       break;
5507
5508     case 0x16a3:        /* steel wall (top/bottom) */
5509       element = EL_DC_STEELWALL_1_HORIZONTAL;
5510       break;
5511
5512     case 0x16a4:        /* steel wall 2 (left end) */
5513       element = EL_DC_STEELWALL_2_LEFT;
5514       break;
5515
5516     case 0x16a5:        /* steel wall 2 (right end) */
5517       element = EL_DC_STEELWALL_2_RIGHT;
5518       break;
5519
5520     case 0x16a6:        /* steel wall 2 (top end) */
5521       element = EL_DC_STEELWALL_2_TOP;
5522       break;
5523
5524     case 0x16a7:        /* steel wall 2 (bottom end) */
5525       element = EL_DC_STEELWALL_2_BOTTOM;
5526       break;
5527
5528     case 0x16a8:        /* steel wall 2 (left/right) */
5529       element = EL_DC_STEELWALL_2_HORIZONTAL;
5530       break;
5531
5532     case 0x16a9:        /* steel wall 2 (up/down) */
5533       element = EL_DC_STEELWALL_2_VERTICAL;
5534       break;
5535
5536     case 0x16aa:        /* steel wall 2 (mid) */
5537       element = EL_DC_STEELWALL_2_MIDDLE;
5538       break;
5539
5540     case 0x16ab:
5541       element = EL_SIGN_EXCLAMATION;
5542       break;
5543
5544     case 0x16ac:
5545       element = EL_SIGN_RADIOACTIVITY;
5546       break;
5547
5548     case 0x16ad:
5549       element = EL_SIGN_STOP;
5550       break;
5551
5552     case 0x16ae:
5553       element = EL_SIGN_WHEELCHAIR;
5554       break;
5555
5556     case 0x16af:
5557       element = EL_SIGN_PARKING;
5558       break;
5559
5560     case 0x16b0:
5561       element = EL_SIGN_NO_ENTRY;
5562       break;
5563
5564     case 0x16b1:
5565       element = EL_SIGN_HEART;
5566       break;
5567
5568     case 0x16b2:
5569       element = EL_SIGN_GIVE_WAY;
5570       break;
5571
5572     case 0x16b3:
5573       element = EL_SIGN_ENTRY_FORBIDDEN;
5574       break;
5575
5576     case 0x16b4:
5577       element = EL_SIGN_EMERGENCY_EXIT;
5578       break;
5579
5580     case 0x16b5:
5581       element = EL_SIGN_YIN_YANG;
5582       break;
5583
5584     case 0x16b6:
5585       element = EL_WALL_EMERALD;
5586       break;
5587
5588     case 0x16b7:
5589       element = EL_WALL_DIAMOND;
5590       break;
5591
5592     case 0x16b8:
5593       element = EL_WALL_PEARL;
5594       break;
5595
5596     case 0x16b9:
5597       element = EL_WALL_CRYSTAL;
5598       break;
5599
5600     case 0x16ba:
5601       element = EL_INVISIBLE_WALL;
5602       break;
5603
5604     case 0x16bb:
5605       element = EL_INVISIBLE_STEELWALL;
5606       break;
5607
5608       /* 0x16bc - 0x16cb: */
5609       /* EL_INVISIBLE_SAND */
5610
5611     case 0x16cc:
5612       element = EL_LIGHT_SWITCH;
5613       break;
5614
5615     case 0x16cd:
5616       element = EL_ENVELOPE_1;
5617       break;
5618
5619     default:
5620       if (element >= 0x0117 && element <= 0x036e)       /* (?) */
5621         element = EL_DIAMOND;
5622       else if (element >= 0x042d && element <= 0x0684)  /* (?) */
5623         element = EL_EMERALD;
5624       else if (element >= 0x157c && element <= 0x158b)
5625         element = EL_SAND;
5626       else if (element >= 0x1590 && element <= 0x159f)
5627         element = EL_DC_LANDMINE;
5628       else if (element >= 0x16bc && element <= 0x16cb)
5629         element = EL_INVISIBLE_SAND;
5630       else
5631       {
5632         Error(ERR_WARN, "unknown Diamond Caves element 0x%04x", element);
5633         element = EL_UNKNOWN;
5634       }
5635       break;
5636   }
5637
5638   return getMappedElement(element);
5639 }
5640
5641 #if 1
5642
5643 static void LoadLevelFromFileStream_DC(FILE *file, struct LevelInfo *level,
5644                                        int nr)
5645 {
5646   byte header[DC_LEVEL_HEADER_SIZE];
5647   int envelope_size;
5648   int envelope_header_pos = 62;
5649   int envelope_content_pos = 94;
5650   int level_name_pos = 251;
5651   int level_author_pos = 292;
5652   int envelope_header_len;
5653   int envelope_content_len;
5654   int level_name_len;
5655   int level_author_len;
5656   int fieldx, fieldy;
5657   int num_yamyam_contents;
5658   int i, x, y;
5659
5660   getDecodedWord_DC(0, TRUE);           /* initialize DC2 decoding engine */
5661
5662   for (i = 0; i < DC_LEVEL_HEADER_SIZE / 2; i++)
5663   {
5664     unsigned short header_word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
5665
5666     header[i * 2 + 0] = header_word >> 8;
5667     header[i * 2 + 1] = header_word & 0xff;
5668   }
5669
5670   /* read some values from level header to check level decoding integrity */
5671   fieldx = header[6] | (header[7] << 8);
5672   fieldy = header[8] | (header[9] << 8);
5673   num_yamyam_contents = header[60] | (header[61] << 8);
5674
5675   /* do some simple sanity checks to ensure that level was correctly decoded */
5676   if (fieldx < 1 || fieldx > 256 ||
5677       fieldy < 1 || fieldy > 256 ||
5678       num_yamyam_contents < 1 || num_yamyam_contents > 8)
5679   {
5680     level->no_valid_file = TRUE;
5681
5682     Error(ERR_WARN, "cannot decode level from stream -- using empty level");
5683
5684     return;
5685   }
5686
5687   /* maximum envelope header size is 31 bytes */
5688   envelope_header_len   = header[envelope_header_pos];
5689   /* maximum envelope content size is 110 (156?) bytes */
5690   envelope_content_len  = header[envelope_content_pos];
5691
5692   /* maximum level title size is 40 bytes */
5693   level_name_len        = MIN(header[level_name_pos],   MAX_LEVEL_NAME_LEN);
5694   /* maximum level author size is 30 (51?) bytes */
5695   level_author_len      = MIN(header[level_author_pos], MAX_LEVEL_AUTHOR_LEN);
5696
5697   envelope_size = 0;
5698
5699   for (i = 0; i < envelope_header_len; i++)
5700     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
5701       level->envelope[0].text[envelope_size++] =
5702         header[envelope_header_pos + 1 + i];
5703
5704   if (envelope_header_len > 0 && envelope_content_len > 0)
5705   {
5706     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
5707       level->envelope[0].text[envelope_size++] = '\n';
5708     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
5709       level->envelope[0].text[envelope_size++] = '\n';
5710   }
5711
5712   for (i = 0; i < envelope_content_len; i++)
5713     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
5714       level->envelope[0].text[envelope_size++] =
5715         header[envelope_content_pos + 1 + i];
5716
5717   level->envelope[0].text[envelope_size] = '\0';
5718
5719   level->envelope[0].xsize = MAX_ENVELOPE_XSIZE;
5720   level->envelope[0].ysize = 10;
5721   level->envelope[0].autowrap = TRUE;
5722   level->envelope[0].centered = TRUE;
5723
5724   for (i = 0; i < level_name_len; i++)
5725     level->name[i] = header[level_name_pos + 1 + i];
5726   level->name[level_name_len] = '\0';
5727
5728   for (i = 0; i < level_author_len; i++)
5729     level->author[i] = header[level_author_pos + 1 + i];
5730   level->author[level_author_len] = '\0';
5731
5732   num_yamyam_contents = header[60] | (header[61] << 8);
5733   level->num_yamyam_contents =
5734     MIN(MAX(MIN_ELEMENT_CONTENTS, num_yamyam_contents), MAX_ELEMENT_CONTENTS);
5735
5736   for (i = 0; i < num_yamyam_contents; i++)
5737   {
5738     for (y = 0; y < 3; y++) for (x = 0; x < 3; x++)
5739     {
5740       unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
5741 #if 1
5742       int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff);
5743 #else
5744       int element_dc = word;
5745 #endif
5746
5747       if (i < MAX_ELEMENT_CONTENTS)
5748         level->yamyam_content[i].e[x][y] = getMappedElement_DC(element_dc);
5749     }
5750   }
5751
5752   fieldx = header[6] | (header[7] << 8);
5753   fieldy = header[8] | (header[9] << 8);
5754   level->fieldx = MIN(MAX(MIN_LEV_FIELDX, fieldx), MAX_LEV_FIELDX);
5755   level->fieldy = MIN(MAX(MIN_LEV_FIELDY, fieldy), MAX_LEV_FIELDY);
5756
5757   for (y = 0; y < fieldy; y++) for (x = 0; x < fieldx; x++)
5758   {
5759     unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
5760 #if 1
5761     int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff);
5762 #else
5763     int element_dc = word;
5764 #endif
5765
5766     if (x < MAX_LEV_FIELDX && y < MAX_LEV_FIELDY)
5767       level->field[x][y] = getMappedElement_DC(element_dc);
5768   }
5769
5770   x = MIN(MAX(0, (header[10] | (header[11] << 8)) - 1), MAX_LEV_FIELDX - 1);
5771   y = MIN(MAX(0, (header[12] | (header[13] << 8)) - 1), MAX_LEV_FIELDY - 1);
5772   level->field[x][y] = EL_PLAYER_1;
5773
5774   x = MIN(MAX(0, (header[14] | (header[15] << 8)) - 1), MAX_LEV_FIELDX - 1);
5775   y = MIN(MAX(0, (header[16] | (header[17] << 8)) - 1), MAX_LEV_FIELDY - 1);
5776   level->field[x][y] = EL_PLAYER_2;
5777
5778   level->gems_needed            = header[18] | (header[19] << 8);
5779
5780   level->score[SC_EMERALD]      = header[20] | (header[21] << 8);
5781   level->score[SC_DIAMOND]      = header[22] | (header[23] << 8);
5782   level->score[SC_PEARL]        = header[24] | (header[25] << 8);
5783   level->score[SC_CRYSTAL]      = header[26] | (header[27] << 8);
5784   level->score[SC_NUT]          = header[28] | (header[29] << 8);
5785   level->score[SC_ROBOT]        = header[30] | (header[31] << 8);
5786   level->score[SC_SPACESHIP]    = header[32] | (header[33] << 8);
5787   level->score[SC_BUG]          = header[34] | (header[35] << 8);
5788   level->score[SC_YAMYAM]       = header[36] | (header[37] << 8);
5789   level->score[SC_DYNAMITE]     = header[38] | (header[39] << 8);
5790   level->score[SC_KEY]          = header[40] | (header[41] << 8);
5791   level->score[SC_TIME_BONUS]   = header[42] | (header[43] << 8);
5792
5793   level->time                   = header[44] | (header[45] << 8);
5794
5795   level->amoeba_speed           = header[46] | (header[47] << 8);
5796   level->time_light             = header[48] | (header[49] << 8);
5797   level->time_timegate          = header[50] | (header[51] << 8);
5798   level->time_wheel             = header[52] | (header[53] << 8);
5799   level->time_magic_wall        = header[54] | (header[55] << 8);
5800   level->extra_time             = header[56] | (header[57] << 8);
5801   level->shield_normal_time     = header[58] | (header[59] << 8);
5802
5803   /* Diamond Caves has the same (strange) behaviour as Emerald Mine that gems
5804      can slip down from flat walls, like normal walls and steel walls */
5805   level->em_slippery_gems = TRUE;
5806
5807 #if 0
5808   /* Diamond Caves II levels are always surrounded by indestructible wall, but
5809      not necessarily in a rectangular way -- fill with invisible steel wall */
5810
5811   /* !!! not always true !!! keep level and set BorderElement instead !!! */
5812
5813   for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
5814   {
5815 #if 1
5816     if ((x == 0 || x == level->fieldx - 1 ||
5817          y == 0 || y == level->fieldy - 1) &&
5818         level->field[x][y] == EL_EMPTY)
5819       level->field[x][y] = EL_INVISIBLE_STEELWALL;
5820 #else
5821     if ((x == 0 || x == level->fieldx - 1 ||
5822          y == 0 || y == level->fieldy - 1) &&
5823         level->field[x][y] == EL_EMPTY)
5824       FloodFillLevel(x, y, EL_INVISIBLE_STEELWALL,
5825                      level->field, level->fieldx, level->fieldy);
5826 #endif
5827   }
5828 #endif
5829 }
5830
5831 static void LoadLevelFromFileInfo_DC(struct LevelInfo *level,
5832                                      struct LevelFileInfo *level_file_info)
5833 {
5834   char *filename = level_file_info->filename;
5835   FILE *file;
5836   int num_magic_bytes = 8;
5837   char magic_bytes[num_magic_bytes + 1];
5838   int num_levels_to_skip = level_file_info->nr - leveldir_current->first_level;
5839
5840   if (!(file = fopen(filename, MODE_READ)))
5841   {
5842     level->no_valid_file = TRUE;
5843
5844     Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
5845
5846     return;
5847   }
5848
5849   // fseek(file, 0x0000, SEEK_SET);
5850
5851   if (level_file_info->packed)
5852   {
5853     /* read "magic bytes" from start of file */
5854     fgets(magic_bytes, num_magic_bytes + 1, file);
5855
5856     /* check "magic bytes" for correct file format */
5857     if (!strPrefix(magic_bytes, "DC2"))
5858     {
5859       level->no_valid_file = TRUE;
5860
5861       Error(ERR_WARN, "unknown DC level file '%s' -- using empty level",
5862             filename);
5863
5864       return;
5865     }
5866
5867     if (strPrefix(magic_bytes, "DC2Win95") ||
5868         strPrefix(magic_bytes, "DC2Win98"))
5869     {
5870       int position_first_level = 0x00fa;
5871       int extra_bytes = 4;
5872       int skip_bytes;
5873
5874       /* advance file stream to first level inside the level package */
5875       skip_bytes = position_first_level - num_magic_bytes - extra_bytes;
5876
5877       /* each block of level data is followed by block of non-level data */
5878       num_levels_to_skip *= 2;
5879
5880       /* at least skip header bytes, therefore use ">= 0" instead of "> 0" */
5881       while (num_levels_to_skip >= 0)
5882       {
5883         /* advance file stream to next level inside the level package */
5884         if (fseek(file, skip_bytes, SEEK_CUR) != 0)
5885         {
5886           level->no_valid_file = TRUE;
5887
5888           Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level",
5889                 filename);
5890
5891           return;
5892         }
5893
5894         /* skip apparently unused extra bytes following each level */
5895         ReadUnusedBytesFromFile(file, extra_bytes);
5896
5897         /* read size of next level in level package */
5898         skip_bytes = getFile32BitLE(file);
5899
5900         num_levels_to_skip--;
5901       }
5902     }
5903     else
5904     {
5905       level->no_valid_file = TRUE;
5906
5907       Error(ERR_WARN, "unknown DC2 level file '%s' -- using empty level",
5908             filename);
5909
5910       return;
5911     }
5912   }
5913
5914   LoadLevelFromFileStream_DC(file, level, level_file_info->nr);
5915
5916   fclose(file);
5917 }
5918
5919 #else
5920
5921 static void LoadLevelFromFileInfo_DC(struct LevelInfo *level,
5922                                      struct LevelFileInfo *level_file_info)
5923 {
5924   char *filename = level_file_info->filename;
5925   FILE *file;
5926 #if 0
5927   int nr = level_file_info->nr - leveldir_current->first_level;
5928 #endif
5929   byte header[DC_LEVEL_HEADER_SIZE];
5930   int envelope_size;
5931   int envelope_header_pos = 62;
5932   int envelope_content_pos = 94;
5933   int level_name_pos = 251;
5934   int level_author_pos = 292;
5935   int envelope_header_len;
5936   int envelope_content_len;
5937   int level_name_len;
5938   int level_author_len;
5939   int fieldx, fieldy;
5940   int num_yamyam_contents;
5941   int i, x, y;
5942
5943   if (!(file = fopen(filename, MODE_READ)))
5944   {
5945     level->no_valid_file = TRUE;
5946
5947     Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
5948
5949     return;
5950   }
5951
5952 #if 0
5953   /* position file stream to the requested level inside the level package */
5954   if (fseek(file, nr * SP_LEVEL_SIZE, SEEK_SET) != 0)
5955   {
5956     level->no_valid_file = TRUE;
5957
5958     Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level", filename);
5959
5960     return;
5961   }
5962 #endif
5963
5964   getDecodedWord_DC(0, TRUE);           /* initialize DC2 decoding engine */
5965
5966   for (i = 0; i < DC_LEVEL_HEADER_SIZE / 2; i++)
5967   {
5968     unsigned short header_word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
5969
5970     header[i * 2 + 0] = header_word >> 8;
5971     header[i * 2 + 1] = header_word & 0xff;
5972   }
5973
5974   /* read some values from level header to check level decoding integrity */
5975   fieldx = header[6] | (header[7] << 8);
5976   fieldy = header[8] | (header[9] << 8);
5977   num_yamyam_contents = header[60] | (header[61] << 8);
5978
5979   /* do some simple sanity checks to ensure that level was correctly decoded */
5980   if (fieldx < 1 || fieldx > 256 ||
5981       fieldy < 1 || fieldy > 256 ||
5982       num_yamyam_contents < 1 || num_yamyam_contents > 8)
5983   {
5984     level->no_valid_file = TRUE;
5985
5986     Error(ERR_WARN, "cannot read level from file '%s' -- using empty level",
5987           filename);
5988
5989     return;
5990   }
5991
5992   /* maximum envelope header size is 31 bytes */
5993   envelope_header_len   = header[envelope_header_pos];
5994   /* maximum envelope content size is 110 (156?) bytes */
5995   envelope_content_len  = header[envelope_content_pos];
5996
5997   /* maximum level title size is 40 bytes */
5998   level_name_len        = MIN(header[level_name_pos],   MAX_LEVEL_NAME_LEN);
5999   /* maximum level author size is 30 (51?) bytes */
6000   level_author_len      = MIN(header[level_author_pos], MAX_LEVEL_AUTHOR_LEN);
6001
6002   envelope_size = 0;
6003
6004   for (i = 0; i < envelope_header_len; i++)
6005     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
6006       level->envelope[0].text[envelope_size++] =
6007         header[envelope_header_pos + 1 + i];
6008
6009   if (envelope_header_len > 0 && envelope_content_len > 0)
6010   {
6011     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
6012       level->envelope[0].text[envelope_size++] = '\n';
6013     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
6014       level->envelope[0].text[envelope_size++] = '\n';
6015   }
6016
6017   for (i = 0; i < envelope_content_len; i++)
6018     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
6019       level->envelope[0].text[envelope_size++] =
6020         header[envelope_content_pos + 1 + i];
6021
6022   level->envelope[0].text[envelope_size] = '\0';
6023
6024   level->envelope[0].xsize = MAX_ENVELOPE_XSIZE;
6025   level->envelope[0].ysize = 10;
6026   level->envelope[0].autowrap = TRUE;
6027   level->envelope[0].centered = TRUE;
6028
6029   for (i = 0; i < level_name_len; i++)
6030     level->name[i] = header[level_name_pos + 1 + i];
6031   level->name[level_name_len] = '\0';
6032
6033   for (i = 0; i < level_author_len; i++)
6034     level->author[i] = header[level_author_pos + 1 + i];
6035   level->author[level_author_len] = '\0';
6036
6037   num_yamyam_contents = header[60] | (header[61] << 8);
6038   level->num_yamyam_contents =
6039     MIN(MAX(MIN_ELEMENT_CONTENTS, num_yamyam_contents), MAX_ELEMENT_CONTENTS);
6040
6041   for (i = 0; i < num_yamyam_contents; i++)
6042   {
6043     for (y = 0; y < 3; y++) for (x = 0; x < 3; x++)
6044     {
6045       unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
6046 #if 1
6047       int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff);
6048 #else
6049       int element_dc = word;
6050 #endif
6051
6052       if (i < MAX_ELEMENT_CONTENTS)
6053         level->yamyam_content[i].e[x][y] = getMappedElement_DC(element_dc);
6054     }
6055   }
6056
6057   fieldx = header[6] | (header[7] << 8);
6058   fieldy = header[8] | (header[9] << 8);
6059   level->fieldx = MIN(MAX(MIN_LEV_FIELDX, fieldx), MAX_LEV_FIELDX);
6060   level->fieldy = MIN(MAX(MIN_LEV_FIELDY, fieldy), MAX_LEV_FIELDY);
6061
6062   for (y = 0; y < fieldy; y++) for (x = 0; x < fieldx; x++)
6063   {
6064     unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
6065 #if 1
6066     int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff);
6067 #else
6068     int element_dc = word;
6069 #endif
6070
6071     if (x < MAX_LEV_FIELDX && y < MAX_LEV_FIELDY)
6072       level->field[x][y] = getMappedElement_DC(element_dc);
6073   }
6074
6075   x = MIN(MAX(0, (header[10] | (header[11] << 8)) - 1), MAX_LEV_FIELDX - 1);
6076   y = MIN(MAX(0, (header[12] | (header[13] << 8)) - 1), MAX_LEV_FIELDY - 1);
6077   level->field[x][y] = EL_PLAYER_1;
6078
6079   x = MIN(MAX(0, (header[14] | (header[15] << 8)) - 1), MAX_LEV_FIELDX - 1);
6080   y = MIN(MAX(0, (header[16] | (header[17] << 8)) - 1), MAX_LEV_FIELDY - 1);
6081   level->field[x][y] = EL_PLAYER_2;
6082
6083   level->gems_needed            = header[18] | (header[19] << 8);
6084
6085   level->score[SC_EMERALD]      = header[20] | (header[21] << 8);
6086   level->score[SC_DIAMOND]      = header[22] | (header[23] << 8);
6087   level->score[SC_PEARL]        = header[24] | (header[25] << 8);
6088   level->score[SC_CRYSTAL]      = header[26] | (header[27] << 8);
6089   level->score[SC_NUT]          = header[28] | (header[29] << 8);
6090   level->score[SC_ROBOT]        = header[30] | (header[31] << 8);
6091   level->score[SC_SPACESHIP]    = header[32] | (header[33] << 8);
6092   level->score[SC_BUG]          = header[34] | (header[35] << 8);
6093   level->score[SC_YAMYAM]       = header[36] | (header[37] << 8);
6094   level->score[SC_DYNAMITE]     = header[38] | (header[39] << 8);
6095   level->score[SC_KEY]          = header[40] | (header[41] << 8);
6096   level->score[SC_TIME_BONUS]   = header[42] | (header[43] << 8);
6097
6098   level->time                   = header[44] | (header[45] << 8);
6099
6100   level->amoeba_speed           = header[46] | (header[47] << 8);
6101   level->time_light             = header[48] | (header[49] << 8);
6102   level->time_timegate          = header[50] | (header[51] << 8);
6103   level->time_wheel             = header[52] | (header[53] << 8);
6104   level->time_magic_wall        = header[54] | (header[55] << 8);
6105   level->extra_time             = header[56] | (header[57] << 8);
6106   level->shield_normal_time     = header[58] | (header[59] << 8);
6107
6108   fclose(file);
6109
6110   /* Diamond Caves has the same (strange) behaviour as Emerald Mine that gems
6111      can slip down from flat walls, like normal walls and steel walls */
6112   level->em_slippery_gems = TRUE;
6113
6114 #if 0
6115   /* Diamond Caves II levels are always surrounded by indestructible wall, but
6116      not necessarily in a rectangular way -- fill with invisible steel wall */
6117
6118   /* !!! not always true !!! keep level and set BorderElement instead !!! */
6119
6120   for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
6121   {
6122 #if 1
6123     if ((x == 0 || x == level->fieldx - 1 ||
6124          y == 0 || y == level->fieldy - 1) &&
6125         level->field[x][y] == EL_EMPTY)
6126       level->field[x][y] = EL_INVISIBLE_STEELWALL;
6127 #else
6128     if ((x == 0 || x == level->fieldx - 1 ||
6129          y == 0 || y == level->fieldy - 1) &&
6130         level->field[x][y] == EL_EMPTY)
6131       FloodFillLevel(x, y, EL_INVISIBLE_STEELWALL,
6132                      level->field, level->fieldx, level->fieldy);
6133 #endif
6134   }
6135 #endif
6136 }
6137
6138 #endif
6139
6140
6141 /* ------------------------------------------------------------------------- */
6142 /* functions for loading generic level                                       */
6143 /* ------------------------------------------------------------------------- */
6144
6145 void LoadLevelFromFileInfo(struct LevelInfo *level,
6146                            struct LevelFileInfo *level_file_info)
6147 {
6148   /* always start with reliable default values */
6149   setLevelInfoToDefaults(level);
6150
6151   switch (level_file_info->type)
6152   {
6153     case LEVEL_FILE_TYPE_RND:
6154       LoadLevelFromFileInfo_RND(level, level_file_info);
6155       break;
6156
6157     case LEVEL_FILE_TYPE_EM:
6158       LoadLevelFromFileInfo_EM(level, level_file_info);
6159       level->game_engine_type = GAME_ENGINE_TYPE_EM;
6160       break;
6161
6162     case LEVEL_FILE_TYPE_SP:
6163       LoadLevelFromFileInfo_SP(level, level_file_info);
6164 #if 1
6165       level->game_engine_type = GAME_ENGINE_TYPE_SP;
6166 #endif
6167       break;
6168
6169     case LEVEL_FILE_TYPE_DC:
6170       LoadLevelFromFileInfo_DC(level, level_file_info);
6171       break;
6172
6173     default:
6174       LoadLevelFromFileInfo_RND(level, level_file_info);
6175       break;
6176   }
6177
6178   /* if level file is invalid, restore level structure to default values */
6179   if (level->no_valid_file)
6180     setLevelInfoToDefaults(level);
6181
6182   if (level->game_engine_type == GAME_ENGINE_TYPE_UNKNOWN)
6183     level->game_engine_type = GAME_ENGINE_TYPE_RND;
6184
6185   if (level_file_info->type != LEVEL_FILE_TYPE_RND)
6186     CopyNativeLevel_Native_to_RND(level);
6187 }
6188
6189 void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
6190 {
6191   static struct LevelFileInfo level_file_info;
6192
6193   /* always start with reliable default values */
6194   setFileInfoToDefaults(&level_file_info);
6195
6196   level_file_info.nr = 0;                       /* unknown level number */
6197   level_file_info.type = LEVEL_FILE_TYPE_RND;   /* no others supported yet */
6198   level_file_info.filename = filename;
6199
6200   LoadLevelFromFileInfo(level, &level_file_info);
6201 }
6202
6203 static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
6204 {
6205   int i, j;
6206
6207   if (leveldir_current == NULL)         /* only when dumping level */
6208     return;
6209
6210   /* all engine modifications also valid for levels which use latest engine */
6211   if (level->game_version < VERSION_IDENT(3,2,0,5))
6212   {
6213     /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */
6214     level->score[SC_TIME_BONUS] /= 10;
6215   }
6216
6217 #if 0
6218   leveldir_current->latest_engine = TRUE;       /* !!! TEST ONLY !!! */
6219 #endif
6220
6221   if (leveldir_current->latest_engine)
6222   {
6223     /* ---------- use latest game engine ----------------------------------- */
6224
6225     /* For all levels which are forced to use the latest game engine version
6226        (normally all but user contributed, private and undefined levels), set
6227        the game engine version to the actual version; this allows for actual
6228        corrections in the game engine to take effect for existing, converted
6229        levels (from "classic" or other existing games) to make the emulation
6230        of the corresponding game more accurate, while (hopefully) not breaking
6231        existing levels created from other players. */
6232
6233     level->game_version = GAME_VERSION_ACTUAL;
6234
6235     /* Set special EM style gems behaviour: EM style gems slip down from
6236        normal, steel and growing wall. As this is a more fundamental change,
6237        it seems better to set the default behaviour to "off" (as it is more
6238        natural) and make it configurable in the level editor (as a property
6239        of gem style elements). Already existing converted levels (neither
6240        private nor contributed levels) are changed to the new behaviour. */
6241
6242     if (level->file_version < FILE_VERSION_2_0)
6243       level->em_slippery_gems = TRUE;
6244
6245     return;
6246   }
6247
6248   /* ---------- use game engine the level was created with ----------------- */
6249
6250   /* For all levels which are not forced to use the latest game engine
6251      version (normally user contributed, private and undefined levels),
6252      use the version of the game engine the levels were created for.
6253
6254      Since 2.0.1, the game engine version is now directly stored
6255      in the level file (chunk "VERS"), so there is no need anymore
6256      to set the game version from the file version (except for old,
6257      pre-2.0 levels, where the game version is still taken from the
6258      file format version used to store the level -- see above). */
6259
6260   /* player was faster than enemies in 1.0.0 and before */
6261   if (level->file_version == FILE_VERSION_1_0)
6262     for (i = 0; i < MAX_PLAYERS; i++)
6263       level->initial_player_stepsize[i] = STEPSIZE_FAST;
6264
6265   /* default behaviour for EM style gems was "slippery" only in 2.0.1 */
6266   if (level->game_version == VERSION_IDENT(2,0,1,0))
6267     level->em_slippery_gems = TRUE;
6268
6269   /* springs could be pushed over pits before (pre-release version) 2.2.0 */
6270   if (level->game_version < VERSION_IDENT(2,2,0,0))
6271     level->use_spring_bug = TRUE;
6272
6273   if (level->game_version < VERSION_IDENT(3,2,0,5))
6274   {
6275     /* time orb caused limited time in endless time levels before 3.2.0-5 */
6276     level->use_time_orb_bug = TRUE;
6277
6278     /* default behaviour for snapping was "no snap delay" before 3.2.0-5 */
6279     level->block_snap_field = FALSE;
6280
6281     /* extra time score was same value as time left score before 3.2.0-5 */
6282     level->extra_time_score = level->score[SC_TIME_BONUS];
6283
6284 #if 0
6285     /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */
6286     level->score[SC_TIME_BONUS] /= 10;
6287 #endif
6288   }
6289
6290   if (level->game_version < VERSION_IDENT(3,2,0,7))
6291   {
6292     /* default behaviour for snapping was "not continuous" before 3.2.0-7 */
6293     level->continuous_snapping = FALSE;
6294   }
6295
6296   /* only few elements were able to actively move into acid before 3.1.0 */
6297   /* trigger settings did not exist before 3.1.0; set to default "any" */
6298   if (level->game_version < VERSION_IDENT(3,1,0,0))
6299   {
6300     /* correct "can move into acid" settings (all zero in old levels) */
6301
6302     level->can_move_into_acid_bits = 0; /* nothing can move into acid */
6303     level->dont_collide_with_bits = 0; /* nothing is deadly when colliding */
6304
6305     setMoveIntoAcidProperty(level, EL_ROBOT,     TRUE);
6306     setMoveIntoAcidProperty(level, EL_SATELLITE, TRUE);
6307     setMoveIntoAcidProperty(level, EL_PENGUIN,   TRUE);
6308     setMoveIntoAcidProperty(level, EL_BALLOON,   TRUE);
6309
6310     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6311       SET_PROPERTY(EL_CUSTOM_START + i, EP_CAN_MOVE_INTO_ACID, TRUE);
6312
6313     /* correct trigger settings (stored as zero == "none" in old levels) */
6314
6315     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6316     {
6317       int element = EL_CUSTOM_START + i;
6318       struct ElementInfo *ei = &element_info[element];
6319
6320       for (j = 0; j < ei->num_change_pages; j++)
6321       {
6322         struct ElementChangeInfo *change = &ei->change_page[j];
6323
6324         change->trigger_player = CH_PLAYER_ANY;
6325         change->trigger_page = CH_PAGE_ANY;
6326       }
6327     }
6328   }
6329
6330   /* try to detect and fix "Snake Bite" levels, which are broken with 3.2.0 */
6331   {
6332     int element = EL_CUSTOM_256;
6333     struct ElementInfo *ei = &element_info[element];
6334     struct ElementChangeInfo *change = &ei->change_page[0];
6335
6336     /* This is needed to fix a problem that was caused by a bugfix in function
6337        game.c/CreateFieldExt() introduced with 3.2.0 that corrects the behaviour
6338        when a custom element changes to EL_SOKOBAN_FIELD_PLAYER (before, it did
6339        not replace walkable elements, but instead just placed the player on it,
6340        without placing the Sokoban field under the player). Unfortunately, this
6341        breaks "Snake Bite" style levels when the snake is halfway through a door
6342        that just closes (the snake head is still alive and can be moved in this
6343        case). This can be fixed by replacing the EL_SOKOBAN_FIELD_PLAYER by the
6344        player (without Sokoban element) which then gets killed as designed). */
6345
6346     if ((strncmp(leveldir_current->identifier, "snake_bite", 10) == 0 ||
6347          strncmp(ei->description, "pause b4 death", 14) == 0) &&
6348         change->target_element == EL_SOKOBAN_FIELD_PLAYER)
6349       change->target_element = EL_PLAYER_1;
6350   }
6351
6352 #if 1
6353   /* try to detect and fix "Zelda" style levels, which are broken with 3.2.5 */
6354   if (level->game_version < VERSION_IDENT(3,2,5,0))
6355   {
6356     /* This is needed to fix a problem that was caused by a bugfix in function
6357        game.c/CheckTriggeredElementChangeExt() introduced with 3.2.5 that
6358        corrects the behaviour when a custom element changes to another custom
6359        element with a higher element number that has change actions defined.
6360        Normally, only one change per frame is allowed for custom elements.
6361        Therefore, it is checked if a custom element already changed in the
6362        current frame; if it did, subsequent changes are suppressed.
6363        Unfortunately, this is only checked for element changes, but not for
6364        change actions, which are still executed. As the function above loops
6365        through all custom elements from lower to higher, an element change
6366        resulting in a lower CE number won't be checked again, while a target
6367        element with a higher number will also be checked, and potential change
6368        actions will get executed for this CE, too (which is wrong), while
6369        further changes are ignored (which is correct). As this bugfix breaks
6370        Zelda II (and introduces graphical bugs to Zelda I, and also breaks a
6371        few other levels like Alan Bond's "FMV"), allow the previous, incorrect
6372        behaviour for existing levels and tapes that make use of this bug */
6373
6374     level->use_action_after_change_bug = TRUE;
6375   }
6376 #else
6377   /* !!! THIS DOES NOT FIX "Zelda I" (GRAPHICALLY) AND "Alan's FMV" LEVELS */
6378   /* try to detect and fix "Zelda II" levels, which are broken with 3.2.5 */
6379   {
6380     int element = EL_CUSTOM_16;
6381     struct ElementInfo *ei = &element_info[element];
6382
6383     /* This is needed to fix a problem that was caused by a bugfix in function
6384        game.c/CheckTriggeredElementChangeExt() introduced with 3.2.5 that
6385        corrects the behaviour when a custom element changes to another custom
6386        element with a higher element number that has change actions defined.
6387        Normally, only one change per frame is allowed for custom elements.
6388        Therefore, it is checked if a custom element already changed in the
6389        current frame; if it did, subsequent changes are suppressed.
6390        Unfortunately, this is only checked for element changes, but not for
6391        change actions, which are still executed. As the function above loops
6392        through all custom elements from lower to higher, an element change
6393        resulting in a lower CE number won't be checked again, while a target
6394        element with a higher number will also be checked, and potential change
6395        actions will get executed for this CE, too (which is wrong), while
6396        further changes are ignored (which is correct). As this bugfix breaks
6397        Zelda II (but no other levels), allow the previous, incorrect behaviour
6398        for this outstanding level set to not break the game or existing tapes */
6399
6400     if (strncmp(leveldir_current->identifier, "zelda2", 6) == 0 ||
6401         strncmp(ei->description, "scanline - row 1", 16) == 0)
6402       level->use_action_after_change_bug = TRUE;
6403   }
6404 #endif
6405
6406   /* not centering level after relocating player was default only in 3.2.3 */
6407   if (level->game_version == VERSION_IDENT(3,2,3,0))    /* (no pre-releases) */
6408     level->shifted_relocation = TRUE;
6409
6410   /* EM style elements always chain-exploded in R'n'D engine before 3.2.6 */
6411   if (level->game_version < VERSION_IDENT(3,2,6,0))
6412     level->em_explodes_by_fire = TRUE;
6413 }
6414
6415 static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
6416 {
6417   int i, j, x, y;
6418
6419   /* map custom element change events that have changed in newer versions
6420      (these following values were accidentally changed in version 3.0.1)
6421      (this seems to be needed only for 'ab_levelset3' and 'ab_levelset4') */
6422   if (level->game_version <= VERSION_IDENT(3,0,0,0))
6423   {
6424     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6425     {
6426       int element = EL_CUSTOM_START + i;
6427
6428       /* order of checking and copying events to be mapped is important */
6429       /* (do not change the start and end value -- they are constant) */
6430       for (j = CE_BY_OTHER_ACTION; j >= CE_VALUE_GETS_ZERO; j--)
6431       {
6432         if (HAS_CHANGE_EVENT(element, j - 2))
6433         {
6434           SET_CHANGE_EVENT(element, j - 2, FALSE);
6435           SET_CHANGE_EVENT(element, j, TRUE);
6436         }
6437       }
6438
6439       /* order of checking and copying events to be mapped is important */
6440       /* (do not change the start and end value -- they are constant) */
6441       for (j = CE_PLAYER_COLLECTS_X; j >= CE_HITTING_SOMETHING; j--)
6442       {
6443         if (HAS_CHANGE_EVENT(element, j - 1))
6444         {
6445           SET_CHANGE_EVENT(element, j - 1, FALSE);
6446           SET_CHANGE_EVENT(element, j, TRUE);
6447         }
6448       }
6449     }
6450   }
6451
6452   /* initialize "can_change" field for old levels with only one change page */
6453   if (level->game_version <= VERSION_IDENT(3,0,2,0))
6454   {
6455     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6456     {
6457       int element = EL_CUSTOM_START + i;
6458
6459       if (CAN_CHANGE(element))
6460         element_info[element].change->can_change = TRUE;
6461     }
6462   }
6463
6464   /* correct custom element values (for old levels without these options) */
6465   if (level->game_version < VERSION_IDENT(3,1,1,0))
6466   {
6467     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6468     {
6469       int element = EL_CUSTOM_START + i;
6470       struct ElementInfo *ei = &element_info[element];
6471
6472       if (ei->access_direction == MV_NO_DIRECTION)
6473         ei->access_direction = MV_ALL_DIRECTIONS;
6474     }
6475   }
6476
6477   /* correct custom element values (fix invalid values for all versions) */
6478   if (1)
6479   {
6480     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6481     {
6482       int element = EL_CUSTOM_START + i;
6483       struct ElementInfo *ei = &element_info[element];
6484
6485       for (j = 0; j < ei->num_change_pages; j++)
6486       {
6487         struct ElementChangeInfo *change = &ei->change_page[j];
6488
6489         if (change->trigger_player == CH_PLAYER_NONE)
6490           change->trigger_player = CH_PLAYER_ANY;
6491
6492         if (change->trigger_side == CH_SIDE_NONE)
6493           change->trigger_side = CH_SIDE_ANY;
6494       }
6495     }
6496   }
6497
6498   /* initialize "can_explode" field for old levels which did not store this */
6499   /* !!! CHECK THIS -- "<= 3,1,0,0" IS PROBABLY WRONG !!! */
6500   if (level->game_version <= VERSION_IDENT(3,1,0,0))
6501   {
6502     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6503     {
6504       int element = EL_CUSTOM_START + i;
6505
6506       if (EXPLODES_1X1_OLD(element))
6507         element_info[element].explosion_type = EXPLODES_1X1;
6508
6509       SET_PROPERTY(element, EP_CAN_EXPLODE, (EXPLODES_BY_FIRE(element) ||
6510                                              EXPLODES_SMASHED(element) ||
6511                                              EXPLODES_IMPACT(element)));
6512     }
6513   }
6514
6515   /* correct previously hard-coded move delay values for maze runner style */
6516   if (level->game_version < VERSION_IDENT(3,1,1,0))
6517   {
6518     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6519     {
6520       int element = EL_CUSTOM_START + i;
6521
6522       if (element_info[element].move_pattern & MV_MAZE_RUNNER_STYLE)
6523       {
6524         /* previously hard-coded and therefore ignored */
6525         element_info[element].move_delay_fixed = 9;
6526         element_info[element].move_delay_random = 0;
6527       }
6528     }
6529   }
6530
6531   /* map elements that have changed in newer versions */
6532   level->amoeba_content = getMappedElementByVersion(level->amoeba_content,
6533                                                     level->game_version);
6534   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
6535     for (x = 0; x < 3; x++)
6536       for (y = 0; y < 3; y++)
6537         level->yamyam_content[i].e[x][y] =
6538           getMappedElementByVersion(level->yamyam_content[i].e[x][y],
6539                                     level->game_version);
6540
6541   /* initialize element properties for level editor etc. */
6542   InitElementPropertiesEngine(level->game_version);
6543   InitElementPropertiesAfterLoading(level->game_version);
6544   InitElementPropertiesGfxElement();
6545 }
6546
6547 static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
6548 {
6549   int x, y;
6550
6551   /* map elements that have changed in newer versions */
6552   for (y = 0; y < level->fieldy; y++)
6553     for (x = 0; x < level->fieldx; x++)
6554       level->field[x][y] = getMappedElementByVersion(level->field[x][y],
6555                                                      level->game_version);
6556
6557   /* copy elements to runtime playfield array */
6558   for (x = 0; x < MAX_LEV_FIELDX; x++)
6559     for (y = 0; y < MAX_LEV_FIELDY; y++)
6560       Feld[x][y] = level->field[x][y];
6561
6562   /* initialize level size variables for faster access */
6563   lev_fieldx = level->fieldx;
6564   lev_fieldy = level->fieldy;
6565
6566   /* determine border element for this level */
6567   if (level->file_info.type == LEVEL_FILE_TYPE_DC)
6568     BorderElement = EL_EMPTY;   /* (in editor, SetBorderElement() is used) */
6569   else
6570     SetBorderElement();
6571 }
6572
6573 static void LoadLevel_InitNativeEngines(struct LevelInfo *level,char *filename)
6574 {
6575   struct LevelFileInfo *level_file_info = &level->file_info;
6576
6577   if (level_file_info->type == LEVEL_FILE_TYPE_RND)
6578     CopyNativeLevel_RND_to_Native(level);
6579 }
6580
6581 void LoadLevelTemplate(int nr)
6582 {
6583   char *filename;
6584
6585   setLevelFileInfo(&level_template.file_info, nr);
6586   filename = level_template.file_info.filename;
6587
6588   LoadLevelFromFileInfo(&level_template, &level_template.file_info);
6589
6590   LoadLevel_InitVersion(&level_template, filename);
6591   LoadLevel_InitElements(&level_template, filename);
6592
6593   ActivateLevelTemplate();
6594 }
6595
6596 void LoadLevel(int nr)
6597 {
6598   char *filename;
6599
6600   setLevelFileInfo(&level.file_info, nr);
6601   filename = level.file_info.filename;
6602
6603   LoadLevelFromFileInfo(&level, &level.file_info);
6604
6605   if (level.use_custom_template)
6606     LoadLevelTemplate(-1);
6607
6608   LoadLevel_InitVersion(&level, filename);
6609   LoadLevel_InitElements(&level, filename);
6610   LoadLevel_InitPlayfield(&level, filename);
6611
6612   LoadLevel_InitNativeEngines(&level, filename);
6613 }
6614
6615 static int SaveLevel_VERS(FILE *file, struct LevelInfo *level)
6616 {
6617   int chunk_size = 0;
6618
6619   chunk_size += putFileVersion(file, level->file_version);
6620   chunk_size += putFileVersion(file, level->game_version);
6621
6622   return chunk_size;
6623 }
6624
6625 static int SaveLevel_DATE(FILE *file, struct LevelInfo *level)
6626 {
6627   int chunk_size = 0;
6628
6629   chunk_size += putFile16BitBE(file, level->creation_date.year);
6630   chunk_size += putFile8Bit(file,    level->creation_date.month);
6631   chunk_size += putFile8Bit(file,    level->creation_date.day);
6632
6633   return chunk_size;
6634 }
6635
6636 #if 0
6637 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
6638 {
6639   int i, x, y;
6640
6641   putFile8Bit(file, level->fieldx);
6642   putFile8Bit(file, level->fieldy);
6643
6644   putFile16BitBE(file, level->time);
6645   putFile16BitBE(file, level->gems_needed);
6646
6647   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
6648     putFile8Bit(file, level->name[i]);
6649
6650   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
6651     putFile8Bit(file, level->score[i]);
6652
6653   for (i = 0; i < STD_ELEMENT_CONTENTS; i++)
6654     for (y = 0; y < 3; y++)
6655       for (x = 0; x < 3; x++)
6656         putFile8Bit(file, (level->encoding_16bit_yamyam ? EL_EMPTY :
6657                            level->yamyam_content[i].e[x][y]));
6658   putFile8Bit(file, level->amoeba_speed);
6659   putFile8Bit(file, level->time_magic_wall);
6660   putFile8Bit(file, level->time_wheel);
6661   putFile8Bit(file, (level->encoding_16bit_amoeba ? EL_EMPTY :
6662                      level->amoeba_content));
6663   putFile8Bit(file, (level->initial_player_stepsize == STEPSIZE_FAST ? 1 : 0));
6664   putFile8Bit(file, (level->initial_gravity ? 1 : 0));
6665   putFile8Bit(file, (level->encoding_16bit_field ? 1 : 0));
6666   putFile8Bit(file, (level->em_slippery_gems ? 1 : 0));
6667
6668   putFile8Bit(file, (level->use_custom_template ? 1 : 0));
6669
6670   putFile8Bit(file, (level->block_last_field ? 1 : 0));
6671   putFile8Bit(file, (level->sp_block_last_field ? 1 : 0));
6672   putFile32BitBE(file, level->can_move_into_acid_bits);
6673   putFile8Bit(file, level->dont_collide_with_bits);
6674
6675   putFile8Bit(file, (level->use_spring_bug ? 1 : 0));
6676   putFile8Bit(file, (level->use_step_counter ? 1 : 0));
6677
6678   putFile8Bit(file, (level->instant_relocation ? 1 : 0));
6679   putFile8Bit(file, (level->can_pass_to_walkable ? 1 : 0));
6680   putFile8Bit(file, (level->grow_into_diggable ? 1 : 0));
6681
6682   putFile8Bit(file, level->game_engine_type);
6683
6684   WriteUnusedBytesToFile(file, LEVEL_CHUNK_HEAD_UNUSED);
6685 }
6686 #endif
6687
6688 static int SaveLevel_NAME(FILE *file, struct LevelInfo *level)
6689 {
6690   int chunk_size = 0;
6691   int i;
6692
6693   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
6694     chunk_size += putFile8Bit(file, level->name[i]);
6695
6696   return chunk_size;
6697 }
6698
6699 static int SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
6700 {
6701   int chunk_size = 0;
6702   int i;
6703
6704   for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
6705     chunk_size += putFile8Bit(file, level->author[i]);
6706
6707   return chunk_size;
6708 }
6709
6710 #if 0
6711 static int SaveLevel_BODY(FILE *file, struct LevelInfo *level)
6712 {
6713   int chunk_size = 0;
6714   int x, y;
6715
6716   for (y = 0; y < level->fieldy; y++) 
6717     for (x = 0; x < level->fieldx; x++) 
6718       if (level->encoding_16bit_field)
6719         chunk_size += putFile16BitBE(file, level->field[x][y]);
6720       else
6721         chunk_size += putFile8Bit(file, level->field[x][y]);
6722
6723   return chunk_size;
6724 }
6725 #endif
6726
6727 static int SaveLevel_BODY(FILE *file, struct LevelInfo *level)
6728 {
6729   int chunk_size = 0;
6730   int x, y;
6731
6732   for (y = 0; y < level->fieldy; y++) 
6733     for (x = 0; x < level->fieldx; x++) 
6734       chunk_size += putFile16BitBE(file, level->field[x][y]);
6735
6736   return chunk_size;
6737 }
6738
6739 #if 0
6740 static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
6741 {
6742   int i, x, y;
6743
6744   putFile8Bit(file, EL_YAMYAM);
6745   putFile8Bit(file, level->num_yamyam_contents);
6746   putFile8Bit(file, 0);
6747   putFile8Bit(file, 0);
6748
6749   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
6750     for (y = 0; y < 3; y++)
6751       for (x = 0; x < 3; x++)
6752         if (level->encoding_16bit_field)
6753           putFile16BitBE(file, level->yamyam_content[i].e[x][y]);
6754         else
6755           putFile8Bit(file, level->yamyam_content[i].e[x][y]);
6756 }
6757 #endif
6758
6759 #if 0
6760 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
6761 {
6762   int i, x, y;
6763   int num_contents, content_xsize, content_ysize;
6764   int content_array[MAX_ELEMENT_CONTENTS][3][3];
6765
6766   if (element == EL_YAMYAM)
6767   {
6768     num_contents = level->num_yamyam_contents;
6769     content_xsize = 3;
6770     content_ysize = 3;
6771
6772     for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
6773       for (y = 0; y < 3; y++)
6774         for (x = 0; x < 3; x++)
6775           content_array[i][x][y] = level->yamyam_content[i].e[x][y];
6776   }
6777   else if (element == EL_BD_AMOEBA)
6778   {
6779     num_contents = 1;
6780     content_xsize = 1;
6781     content_ysize = 1;
6782
6783     for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
6784       for (y = 0; y < 3; y++)
6785         for (x = 0; x < 3; x++)
6786           content_array[i][x][y] = EL_EMPTY;
6787     content_array[0][0][0] = level->amoeba_content;
6788   }
6789   else
6790   {
6791     /* chunk header already written -- write empty chunk data */
6792     WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_SIZE);
6793
6794     Error(ERR_WARN, "cannot save content for element '%d'", element);
6795     return;
6796   }
6797
6798   putFile16BitBE(file, element);
6799   putFile8Bit(file, num_contents);
6800   putFile8Bit(file, content_xsize);
6801   putFile8Bit(file, content_ysize);
6802
6803   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED);
6804
6805   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
6806     for (y = 0; y < 3; y++)
6807       for (x = 0; x < 3; x++)
6808         putFile16BitBE(file, content_array[i][x][y]);
6809 }
6810 #endif
6811
6812 #if 0
6813 static int SaveLevel_CNT3(FILE *file, struct LevelInfo *level, int element)
6814 {
6815   int envelope_nr = element - EL_ENVELOPE_1;
6816   int envelope_len = strlen(level->envelope_text[envelope_nr]) + 1;
6817   int chunk_size = 0;
6818   int i;
6819
6820   chunk_size += putFile16BitBE(file, element);
6821   chunk_size += putFile16BitBE(file, envelope_len);
6822   chunk_size += putFile8Bit(file, level->envelope_xsize[envelope_nr]);
6823   chunk_size += putFile8Bit(file, level->envelope_ysize[envelope_nr]);
6824
6825   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT3_UNUSED);
6826   chunk_size += LEVEL_CHUNK_CNT3_UNUSED;
6827
6828   for (i = 0; i < envelope_len; i++)
6829     chunk_size += putFile8Bit(file, level->envelope_text[envelope_nr][i]);
6830
6831   return chunk_size;
6832 }
6833 #endif
6834
6835 #if 0
6836 static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level,
6837                            int num_changed_custom_elements)
6838 {
6839   int i, check = 0;
6840
6841   putFile16BitBE(file, num_changed_custom_elements);
6842
6843   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6844   {
6845     int element = EL_CUSTOM_START + i;
6846
6847     struct ElementInfo *ei = &element_info[element];
6848
6849     if (ei->properties[EP_BITFIELD_BASE_NR] != EP_BITMASK_DEFAULT)
6850     {
6851       if (check < num_changed_custom_elements)
6852       {
6853         putFile16BitBE(file, element);
6854         putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
6855       }
6856
6857       check++;
6858     }
6859   }
6860
6861   if (check != num_changed_custom_elements)     /* should not happen */
6862     Error(ERR_WARN, "inconsistent number of custom element properties");
6863 }
6864 #endif
6865
6866 #if 0
6867 static void SaveLevel_CUS2(FILE *file, struct LevelInfo *level,
6868                            int num_changed_custom_elements)
6869 {
6870   int i, check = 0;
6871
6872   putFile16BitBE(file, num_changed_custom_elements);
6873
6874   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6875   {
6876     int element = EL_CUSTOM_START + i;
6877
6878     if (element_info[element].change->target_element != EL_EMPTY_SPACE)
6879     {
6880       if (check < num_changed_custom_elements)
6881       {
6882         putFile16BitBE(file, element);
6883         putFile16BitBE(file, element_info[element].change->target_element);
6884       }
6885
6886       check++;
6887     }
6888   }
6889
6890   if (check != num_changed_custom_elements)     /* should not happen */
6891     Error(ERR_WARN, "inconsistent number of custom target elements");
6892 }
6893 #endif
6894
6895 #if 0
6896 static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
6897                            int num_changed_custom_elements)
6898 {
6899   int i, j, x, y, check = 0;
6900
6901   putFile16BitBE(file, num_changed_custom_elements);
6902
6903   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6904   {
6905     int element = EL_CUSTOM_START + i;
6906     struct ElementInfo *ei = &element_info[element];
6907
6908     if (ei->modified_settings)
6909     {
6910       if (check < num_changed_custom_elements)
6911       {
6912         putFile16BitBE(file, element);
6913
6914         for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++)
6915           putFile8Bit(file, ei->description[j]);
6916
6917         putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
6918
6919         /* some free bytes for future properties and padding */
6920         WriteUnusedBytesToFile(file, 7);
6921
6922         putFile8Bit(file, ei->use_gfx_element);
6923         putFile16BitBE(file, ei->gfx_element_initial);
6924
6925         putFile8Bit(file, ei->collect_score_initial);
6926         putFile8Bit(file, ei->collect_count_initial);
6927
6928         putFile16BitBE(file, ei->push_delay_fixed);
6929         putFile16BitBE(file, ei->push_delay_random);
6930         putFile16BitBE(file, ei->move_delay_fixed);
6931         putFile16BitBE(file, ei->move_delay_random);
6932
6933         putFile16BitBE(file, ei->move_pattern);
6934         putFile8Bit(file, ei->move_direction_initial);
6935         putFile8Bit(file, ei->move_stepsize);
6936
6937         for (y = 0; y < 3; y++)
6938           for (x = 0; x < 3; x++)
6939             putFile16BitBE(file, ei->content.e[x][y]);
6940
6941         putFile32BitBE(file, ei->change->events);
6942
6943         putFile16BitBE(file, ei->change->target_element);
6944
6945         putFile16BitBE(file, ei->change->delay_fixed);
6946         putFile16BitBE(file, ei->change->delay_random);
6947         putFile16BitBE(file, ei->change->delay_frames);
6948
6949         putFile16BitBE(file, ei->change->initial_trigger_element);
6950
6951         putFile8Bit(file, ei->change->explode);
6952         putFile8Bit(file, ei->change->use_target_content);
6953         putFile8Bit(file, ei->change->only_if_complete);
6954         putFile8Bit(file, ei->change->use_random_replace);
6955
6956         putFile8Bit(file, ei->change->random_percentage);
6957         putFile8Bit(file, ei->change->replace_when);
6958
6959         for (y = 0; y < 3; y++)
6960           for (x = 0; x < 3; x++)
6961             putFile16BitBE(file, ei->change->content.e[x][y]);
6962
6963         putFile8Bit(file, ei->slippery_type);
6964
6965         /* some free bytes for future properties and padding */
6966         WriteUnusedBytesToFile(file, LEVEL_CPART_CUS3_UNUSED);
6967       }
6968
6969       check++;
6970     }
6971   }
6972
6973   if (check != num_changed_custom_elements)     /* should not happen */
6974     Error(ERR_WARN, "inconsistent number of custom element properties");
6975 }
6976 #endif
6977
6978 #if 0
6979 static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
6980 {
6981   struct ElementInfo *ei = &element_info[element];
6982   int i, j, x, y;
6983
6984   /* ---------- custom element base property values (96 bytes) ------------- */
6985
6986   putFile16BitBE(file, element);
6987
6988   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
6989     putFile8Bit(file, ei->description[i]);
6990
6991   putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
6992
6993   WriteUnusedBytesToFile(file, 4);      /* reserved for more base properties */
6994
6995   putFile8Bit(file, ei->num_change_pages);
6996
6997   putFile16BitBE(file, ei->ce_value_fixed_initial);
6998   putFile16BitBE(file, ei->ce_value_random_initial);
6999   putFile8Bit(file, ei->use_last_ce_value);
7000
7001   putFile8Bit(file, ei->use_gfx_element);
7002   putFile16BitBE(file, ei->gfx_element_initial);
7003
7004   putFile8Bit(file, ei->collect_score_initial);
7005   putFile8Bit(file, ei->collect_count_initial);
7006
7007   putFile8Bit(file, ei->drop_delay_fixed);
7008   putFile8Bit(file, ei->push_delay_fixed);
7009   putFile8Bit(file, ei->drop_delay_random);
7010   putFile8Bit(file, ei->push_delay_random);
7011   putFile16BitBE(file, ei->move_delay_fixed);
7012   putFile16BitBE(file, ei->move_delay_random);
7013
7014   /* bits 0 - 15 of "move_pattern" ... */
7015   putFile16BitBE(file, ei->move_pattern & 0xffff);
7016   putFile8Bit(file, ei->move_direction_initial);
7017   putFile8Bit(file, ei->move_stepsize);
7018
7019   putFile8Bit(file, ei->slippery_type);
7020
7021   for (y = 0; y < 3; y++)
7022     for (x = 0; x < 3; x++)
7023       putFile16BitBE(file, ei->content.e[x][y]);
7024
7025   putFile16BitBE(file, ei->move_enter_element);
7026   putFile16BitBE(file, ei->move_leave_element);
7027   putFile8Bit(file, ei->move_leave_type);
7028
7029   /* ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible) */
7030   putFile16BitBE(file, (ei->move_pattern >> 16) & 0xffff);
7031
7032   putFile8Bit(file, ei->access_direction);
7033
7034   putFile8Bit(file, ei->explosion_delay);
7035   putFile8Bit(file, ei->ignition_delay);
7036   putFile8Bit(file, ei->explosion_type);
7037
7038   /* some free bytes for future custom property values and padding */
7039   WriteUnusedBytesToFile(file, 1);
7040
7041   /* ---------- change page property values (48 bytes) --------------------- */
7042
7043   for (i = 0; i < ei->num_change_pages; i++)
7044   {
7045     struct ElementChangeInfo *change = &ei->change_page[i];
7046     unsigned int event_bits;
7047
7048     /* bits 0 - 31 of "has_event[]" ... */
7049     event_bits = 0;
7050     for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
7051       if (change->has_event[j])
7052         event_bits |= (1 << j);
7053     putFile32BitBE(file, event_bits);
7054
7055     putFile16BitBE(file, change->target_element);
7056
7057     putFile16BitBE(file, change->delay_fixed);
7058     putFile16BitBE(file, change->delay_random);
7059     putFile16BitBE(file, change->delay_frames);
7060
7061     putFile16BitBE(file, change->initial_trigger_element);
7062
7063     putFile8Bit(file, change->explode);
7064     putFile8Bit(file, change->use_target_content);
7065     putFile8Bit(file, change->only_if_complete);
7066     putFile8Bit(file, change->use_random_replace);
7067
7068     putFile8Bit(file, change->random_percentage);
7069     putFile8Bit(file, change->replace_when);
7070
7071     for (y = 0; y < 3; y++)
7072       for (x = 0; x < 3; x++)
7073         putFile16BitBE(file, change->target_content.e[x][y]);
7074
7075     putFile8Bit(file, change->can_change);
7076
7077     putFile8Bit(file, change->trigger_side);
7078
7079     putFile8Bit(file, change->trigger_player);
7080     putFile8Bit(file, (change->trigger_page == CH_PAGE_ANY ? CH_PAGE_ANY_FILE :
7081                        log_2(change->trigger_page)));
7082
7083     putFile8Bit(file, change->has_action);
7084     putFile8Bit(file, change->action_type);
7085     putFile8Bit(file, change->action_mode);
7086     putFile16BitBE(file, change->action_arg);
7087
7088     /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */
7089     event_bits = 0;
7090     for (j = 32; j < NUM_CHANGE_EVENTS; j++)
7091       if (change->has_event[j])
7092         event_bits |= (1 << (j - 32));
7093     putFile8Bit(file, event_bits);
7094   }
7095 }
7096 #endif
7097
7098 #if 0
7099 static void SaveLevel_GRP1(FILE *file, struct LevelInfo *level, int element)
7100 {
7101   struct ElementInfo *ei = &element_info[element];
7102   struct ElementGroupInfo *group = ei->group;
7103   int i;
7104
7105   putFile16BitBE(file, element);
7106
7107   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
7108     putFile8Bit(file, ei->description[i]);
7109
7110   putFile8Bit(file, group->num_elements);
7111
7112   putFile8Bit(file, ei->use_gfx_element);
7113   putFile16BitBE(file, ei->gfx_element_initial);
7114
7115   putFile8Bit(file, group->choice_mode);
7116
7117   /* some free bytes for future values and padding */
7118   WriteUnusedBytesToFile(file, 3);
7119
7120   for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
7121     putFile16BitBE(file, group->element[i]);
7122 }
7123 #endif
7124
7125 static int SaveLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *entry,
7126                                 boolean write_element)
7127 {
7128   int save_type = entry->save_type;
7129   int data_type = entry->data_type;
7130   int conf_type = entry->conf_type;
7131   int byte_mask = conf_type & CONF_MASK_BYTES;
7132   int element = entry->element;
7133   int default_value = entry->default_value;
7134   int num_bytes = 0;
7135   boolean modified = FALSE;
7136
7137   if (byte_mask != CONF_MASK_MULTI_BYTES)
7138   {
7139     void *value_ptr = entry->value;
7140     int value = (data_type == TYPE_BOOLEAN ? *(boolean *)value_ptr :
7141                  *(int *)value_ptr);
7142
7143     /* check if any settings have been modified before saving them */
7144     if (value != default_value)
7145       modified = TRUE;
7146
7147     /* do not save if explicitly told or if unmodified default settings */
7148     if ((save_type == SAVE_CONF_NEVER) ||
7149         (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
7150       return 0;
7151
7152     if (write_element)
7153       num_bytes += putFile16BitBE(file, element);
7154
7155     num_bytes += putFile8Bit(file, conf_type);
7156     num_bytes += (byte_mask == CONF_MASK_1_BYTE ? putFile8Bit   (file, value) :
7157                   byte_mask == CONF_MASK_2_BYTE ? putFile16BitBE(file, value) :
7158                   byte_mask == CONF_MASK_4_BYTE ? putFile32BitBE(file, value) :
7159                   0);
7160   }
7161   else if (data_type == TYPE_STRING)
7162   {
7163     char *default_string = entry->default_string;
7164     char *string = (char *)(entry->value);
7165     int string_length = strlen(string);
7166     int i;
7167
7168     /* check if any settings have been modified before saving them */
7169     if (!strEqual(string, default_string))
7170       modified = TRUE;
7171
7172     /* do not save if explicitly told or if unmodified default settings */
7173     if ((save_type == SAVE_CONF_NEVER) ||
7174         (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
7175       return 0;
7176
7177     if (write_element)
7178       num_bytes += putFile16BitBE(file, element);
7179
7180     num_bytes += putFile8Bit(file, conf_type);
7181     num_bytes += putFile16BitBE(file, string_length);
7182
7183     for (i = 0; i < string_length; i++)
7184       num_bytes += putFile8Bit(file, string[i]);
7185   }
7186   else if (data_type == TYPE_ELEMENT_LIST)
7187   {
7188     int *element_array = (int *)(entry->value);
7189     int num_elements = *(int *)(entry->num_entities);
7190     int i;
7191
7192     /* check if any settings have been modified before saving them */
7193     for (i = 0; i < num_elements; i++)
7194       if (element_array[i] != default_value)
7195         modified = TRUE;
7196
7197     /* do not save if explicitly told or if unmodified default settings */
7198     if ((save_type == SAVE_CONF_NEVER) ||
7199         (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
7200       return 0;
7201
7202     if (write_element)
7203       num_bytes += putFile16BitBE(file, element);
7204
7205     num_bytes += putFile8Bit(file, conf_type);
7206     num_bytes += putFile16BitBE(file, num_elements * CONF_ELEMENT_NUM_BYTES);
7207
7208     for (i = 0; i < num_elements; i++)
7209       num_bytes += putFile16BitBE(file, element_array[i]);
7210   }
7211   else if (data_type == TYPE_CONTENT_LIST)
7212   {
7213     struct Content *content = (struct Content *)(entry->value);
7214     int num_contents = *(int *)(entry->num_entities);
7215     int i, x, y;
7216
7217     /* check if any settings have been modified before saving them */
7218     for (i = 0; i < num_contents; i++)
7219       for (y = 0; y < 3; y++)
7220         for (x = 0; x < 3; x++)
7221           if (content[i].e[x][y] != default_value)
7222             modified = TRUE;
7223
7224     /* do not save if explicitly told or if unmodified default settings */
7225     if ((save_type == SAVE_CONF_NEVER) ||
7226         (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
7227       return 0;
7228
7229     if (write_element)
7230       num_bytes += putFile16BitBE(file, element);
7231
7232     num_bytes += putFile8Bit(file, conf_type);
7233     num_bytes += putFile16BitBE(file, num_contents * CONF_CONTENT_NUM_BYTES);
7234
7235     for (i = 0; i < num_contents; i++)
7236       for (y = 0; y < 3; y++)
7237         for (x = 0; x < 3; x++)
7238           num_bytes += putFile16BitBE(file, content[i].e[x][y]);
7239   }
7240
7241   return num_bytes;
7242 }
7243
7244 static int SaveLevel_INFO(FILE *file, struct LevelInfo *level)
7245 {
7246   int chunk_size = 0;
7247   int i;
7248
7249   li = *level;          /* copy level data into temporary buffer */
7250
7251   for (i = 0; chunk_config_INFO[i].data_type != -1; i++)
7252     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_INFO[i], FALSE);
7253
7254   return chunk_size;
7255 }
7256
7257 static int SaveLevel_ELEM(FILE *file, struct LevelInfo *level)
7258 {
7259   int chunk_size = 0;
7260   int i;
7261
7262   li = *level;          /* copy level data into temporary buffer */
7263
7264   for (i = 0; chunk_config_ELEM[i].data_type != -1; i++)
7265     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_ELEM[i], TRUE);
7266
7267   return chunk_size;
7268 }
7269
7270 static int SaveLevel_NOTE(FILE *file, struct LevelInfo *level, int element)
7271 {
7272   int envelope_nr = element - EL_ENVELOPE_1;
7273   int chunk_size = 0;
7274   int i;
7275
7276   chunk_size += putFile16BitBE(file, element);
7277
7278   /* copy envelope data into temporary buffer */
7279   xx_envelope = level->envelope[envelope_nr];
7280
7281   for (i = 0; chunk_config_NOTE[i].data_type != -1; i++)
7282     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_NOTE[i], FALSE);
7283
7284   return chunk_size;
7285 }
7286
7287 static int SaveLevel_CUSX(FILE *file, struct LevelInfo *level, int element)
7288 {
7289   struct ElementInfo *ei = &element_info[element];
7290   int chunk_size = 0;
7291   int i, j;
7292
7293   chunk_size += putFile16BitBE(file, element);
7294
7295   xx_ei = *ei;          /* copy element data into temporary buffer */
7296
7297   /* set default description string for this specific element */
7298   strcpy(xx_default_description, getDefaultElementDescription(ei));
7299
7300 #if 0
7301   /* set (fixed) number of content areas (may be wrong by broken level file) */
7302   /* (this is now directly corrected for broken level files after loading) */
7303   xx_num_contents = 1;
7304 #endif
7305
7306   for (i = 0; chunk_config_CUSX_base[i].data_type != -1; i++)
7307     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_CUSX_base[i], FALSE);
7308
7309   for (i = 0; i < ei->num_change_pages; i++)
7310   {
7311     struct ElementChangeInfo *change = &ei->change_page[i];
7312
7313     xx_current_change_page = i;
7314
7315     xx_change = *change;        /* copy change data into temporary buffer */
7316
7317     resetEventBits();
7318     setEventBitsFromEventFlags(change);
7319
7320     for (j = 0; chunk_config_CUSX_change[j].data_type != -1; j++)
7321       chunk_size += SaveLevel_MicroChunk(file, &chunk_config_CUSX_change[j],
7322                                          FALSE);
7323   }
7324
7325   return chunk_size;
7326 }
7327
7328 static int SaveLevel_GRPX(FILE *file, struct LevelInfo *level, int element)
7329 {
7330   struct ElementInfo *ei = &element_info[element];
7331   struct ElementGroupInfo *group = ei->group;
7332   int chunk_size = 0;
7333   int i;
7334
7335   chunk_size += putFile16BitBE(file, element);
7336
7337   xx_ei = *ei;          /* copy element data into temporary buffer */
7338   xx_group = *group;    /* copy group data into temporary buffer */
7339
7340   /* set default description string for this specific element */
7341   strcpy(xx_default_description, getDefaultElementDescription(ei));
7342
7343   for (i = 0; chunk_config_GRPX[i].data_type != -1; i++)
7344     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_GRPX[i], FALSE);
7345
7346   return chunk_size;
7347 }
7348
7349 static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
7350 {
7351   int chunk_size;
7352   int i;
7353   FILE *file;
7354
7355   if (!(file = fopen(filename, MODE_WRITE)))
7356   {
7357     Error(ERR_WARN, "cannot save level file '%s'", filename);
7358     return;
7359   }
7360
7361   level->file_version = FILE_VERSION_ACTUAL;
7362   level->game_version = GAME_VERSION_ACTUAL;
7363
7364   level->creation_date = getCurrentDate();
7365
7366   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
7367   putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
7368
7369   chunk_size = SaveLevel_VERS(NULL, level);
7370   putFileChunkBE(file, "VERS", chunk_size);
7371   SaveLevel_VERS(file, level);
7372
7373   chunk_size = SaveLevel_DATE(NULL, level);
7374   putFileChunkBE(file, "DATE", chunk_size);
7375   SaveLevel_DATE(file, level);
7376
7377   chunk_size = SaveLevel_NAME(NULL, level);
7378   putFileChunkBE(file, "NAME", chunk_size);
7379   SaveLevel_NAME(file, level);
7380
7381   chunk_size = SaveLevel_AUTH(NULL, level);
7382   putFileChunkBE(file, "AUTH", chunk_size);
7383   SaveLevel_AUTH(file, level);
7384
7385   chunk_size = SaveLevel_INFO(NULL, level);
7386   putFileChunkBE(file, "INFO", chunk_size);
7387   SaveLevel_INFO(file, level);
7388
7389   chunk_size = SaveLevel_BODY(NULL, level);
7390   putFileChunkBE(file, "BODY", chunk_size);
7391   SaveLevel_BODY(file, level);
7392
7393   chunk_size = SaveLevel_ELEM(NULL, level);
7394   if (chunk_size > LEVEL_CHUNK_ELEM_UNCHANGED)          /* save if changed */
7395   {
7396     putFileChunkBE(file, "ELEM", chunk_size);
7397     SaveLevel_ELEM(file, level);
7398   }
7399
7400   for (i = 0; i < NUM_ENVELOPES; i++)
7401   {
7402     int element = EL_ENVELOPE_1 + i;
7403
7404     chunk_size = SaveLevel_NOTE(NULL, level, element);
7405     if (chunk_size > LEVEL_CHUNK_NOTE_UNCHANGED)        /* save if changed */
7406     {
7407       putFileChunkBE(file, "NOTE", chunk_size);
7408       SaveLevel_NOTE(file, level, element);
7409     }
7410   }
7411
7412   /* if not using template level, check for non-default custom/group elements */
7413   if (!level->use_custom_template)
7414   {
7415     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
7416     {
7417       int element = EL_CUSTOM_START + i;
7418
7419       chunk_size = SaveLevel_CUSX(NULL, level, element);
7420       if (chunk_size > LEVEL_CHUNK_CUSX_UNCHANGED)      /* save if changed */
7421       {
7422         putFileChunkBE(file, "CUSX", chunk_size);
7423         SaveLevel_CUSX(file, level, element);
7424       }
7425     }
7426
7427     for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
7428     {
7429       int element = EL_GROUP_START + i;
7430
7431       chunk_size = SaveLevel_GRPX(NULL, level, element);
7432       if (chunk_size > LEVEL_CHUNK_GRPX_UNCHANGED)      /* save if changed */
7433       {
7434         putFileChunkBE(file, "GRPX", chunk_size);
7435         SaveLevel_GRPX(file, level, element);
7436       }
7437     }
7438   }
7439
7440   fclose(file);
7441
7442   SetFilePermissions(filename, PERMS_PRIVATE);
7443 }
7444
7445 void SaveLevel(int nr)
7446 {
7447   char *filename = getDefaultLevelFilename(nr);
7448
7449   SaveLevelFromFilename(&level, filename);
7450 }
7451
7452 void SaveLevelTemplate()
7453 {
7454   char *filename = getDefaultLevelFilename(-1);
7455
7456   SaveLevelFromFilename(&level, filename);
7457 }
7458
7459 boolean SaveLevelChecked(int nr)
7460 {
7461   char *filename = getDefaultLevelFilename(nr);
7462   boolean new_level = !fileExists(filename);
7463   boolean level_saved = FALSE;
7464
7465   if (new_level || Request("Save this level and kill the old ?", REQ_ASK))
7466   {
7467     SaveLevel(nr);
7468
7469     if (new_level)
7470       Request("Level saved !", REQ_CONFIRM);
7471
7472     level_saved = TRUE;
7473   }
7474
7475   return level_saved;
7476 }
7477
7478 void DumpLevel(struct LevelInfo *level)
7479 {
7480   if (level->no_valid_file)
7481   {
7482     Error(ERR_WARN, "cannot dump -- no valid level file found");
7483
7484     return;
7485   }
7486
7487   printf_line("-", 79);
7488   printf("Level xxx (file version %08d, game version %08d)\n",
7489          level->file_version, level->game_version);
7490   printf_line("-", 79);
7491
7492   printf("Level author: '%s'\n", level->author);
7493   printf("Level title:  '%s'\n", level->name);
7494   printf("\n");
7495   printf("Playfield size: %d x %d\n", level->fieldx, level->fieldy);
7496   printf("\n");
7497   printf("Level time:  %d seconds\n", level->time);
7498   printf("Gems needed: %d\n", level->gems_needed);
7499   printf("\n");
7500   printf("Time for magic wall: %d seconds\n", level->time_magic_wall);
7501   printf("Time for wheel:      %d seconds\n", level->time_wheel);
7502   printf("Time for light:      %d seconds\n", level->time_light);
7503   printf("Time for timegate:   %d seconds\n", level->time_timegate);
7504   printf("\n");
7505   printf("Amoeba speed: %d\n", level->amoeba_speed);
7506   printf("\n");
7507
7508   printf("EM style slippery gems:      %s\n", (level->em_slippery_gems ? "yes" : "no"));
7509   printf("Player blocks last field:    %s\n", (level->block_last_field ? "yes" : "no"));
7510   printf("SP player blocks last field: %s\n", (level->sp_block_last_field ? "yes" : "no"));
7511   printf("use spring bug: %s\n", (level->use_spring_bug ? "yes" : "no"));
7512   printf("use step counter: %s\n", (level->use_step_counter ? "yes" : "no"));
7513
7514   printf_line("-", 79);
7515 }
7516
7517
7518 /* ========================================================================= */
7519 /* tape file functions                                                       */
7520 /* ========================================================================= */
7521
7522 static void setTapeInfoToDefaults()
7523 {
7524   int i;
7525
7526   /* always start with reliable default values (empty tape) */
7527   TapeErase();
7528
7529   /* default values (also for pre-1.2 tapes) with only the first player */
7530   tape.player_participates[0] = TRUE;
7531   for (i = 1; i < MAX_PLAYERS; i++)
7532     tape.player_participates[i] = FALSE;
7533
7534   /* at least one (default: the first) player participates in every tape */
7535   tape.num_participating_players = 1;
7536
7537   tape.level_nr = level_nr;
7538   tape.counter = 0;
7539   tape.changed = FALSE;
7540
7541   tape.recording = FALSE;
7542   tape.playing = FALSE;
7543   tape.pausing = FALSE;
7544
7545   tape.no_valid_file = FALSE;
7546 }
7547
7548 static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
7549 {
7550   tape->file_version = getFileVersion(file);
7551   tape->game_version = getFileVersion(file);
7552
7553   return chunk_size;
7554 }
7555
7556 static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
7557 {
7558   int i;
7559
7560   tape->random_seed = getFile32BitBE(file);
7561   tape->date        = getFile32BitBE(file);
7562   tape->length      = getFile32BitBE(file);
7563
7564   /* read header fields that are new since version 1.2 */
7565   if (tape->file_version >= FILE_VERSION_1_2)
7566   {
7567     byte store_participating_players = getFile8Bit(file);
7568     int engine_version;
7569
7570     /* since version 1.2, tapes store which players participate in the tape */
7571     tape->num_participating_players = 0;
7572     for (i = 0; i < MAX_PLAYERS; i++)
7573     {
7574       tape->player_participates[i] = FALSE;
7575
7576       if (store_participating_players & (1 << i))
7577       {
7578         tape->player_participates[i] = TRUE;
7579         tape->num_participating_players++;
7580       }
7581     }
7582
7583     ReadUnusedBytesFromFile(file, TAPE_CHUNK_HEAD_UNUSED);
7584
7585     engine_version = getFileVersion(file);
7586     if (engine_version > 0)
7587       tape->engine_version = engine_version;
7588     else
7589       tape->engine_version = tape->game_version;
7590   }
7591
7592   return chunk_size;
7593 }
7594
7595 static int LoadTape_INFO(FILE *file, int chunk_size, struct TapeInfo *tape)
7596 {
7597   int level_identifier_size;
7598   int i;
7599
7600   level_identifier_size = getFile16BitBE(file);
7601
7602   tape->level_identifier =
7603     checked_realloc(tape->level_identifier, level_identifier_size);
7604
7605   for (i = 0; i < level_identifier_size; i++)
7606     tape->level_identifier[i] = getFile8Bit(file);
7607
7608   tape->level_nr = getFile16BitBE(file);
7609
7610   chunk_size = 2 + level_identifier_size + 2;
7611
7612   return chunk_size;
7613 }
7614
7615 static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
7616 {
7617   int i, j;
7618   int chunk_size_expected =
7619     (tape->num_participating_players + 1) * tape->length;
7620
7621   if (chunk_size_expected != chunk_size)
7622   {
7623     ReadUnusedBytesFromFile(file, chunk_size);
7624     return chunk_size_expected;
7625   }
7626
7627   for (i = 0; i < tape->length; i++)
7628   {
7629     if (i >= MAX_TAPE_LEN)
7630       break;
7631
7632     for (j = 0; j < MAX_PLAYERS; j++)
7633     {
7634       tape->pos[i].action[j] = MV_NONE;
7635
7636       if (tape->player_participates[j])
7637         tape->pos[i].action[j] = getFile8Bit(file);
7638     }
7639
7640     tape->pos[i].delay = getFile8Bit(file);
7641
7642     if (tape->file_version == FILE_VERSION_1_0)
7643     {
7644       /* eliminate possible diagonal moves in old tapes */
7645       /* this is only for backward compatibility */
7646
7647       byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
7648       byte action = tape->pos[i].action[0];
7649       int k, num_moves = 0;
7650
7651       for (k = 0; k<4; k++)
7652       {
7653         if (action & joy_dir[k])
7654         {
7655           tape->pos[i + num_moves].action[0] = joy_dir[k];
7656           if (num_moves > 0)
7657             tape->pos[i + num_moves].delay = 0;
7658           num_moves++;
7659         }
7660       }
7661
7662       if (num_moves > 1)
7663       {
7664         num_moves--;
7665         i += num_moves;
7666         tape->length += num_moves;
7667       }
7668     }
7669     else if (tape->file_version < FILE_VERSION_2_0)
7670     {
7671       /* convert pre-2.0 tapes to new tape format */
7672
7673       if (tape->pos[i].delay > 1)
7674       {
7675         /* action part */
7676         tape->pos[i + 1] = tape->pos[i];
7677         tape->pos[i + 1].delay = 1;
7678
7679         /* delay part */
7680         for (j = 0; j < MAX_PLAYERS; j++)
7681           tape->pos[i].action[j] = MV_NONE;
7682         tape->pos[i].delay--;
7683
7684         i++;
7685         tape->length++;
7686       }
7687     }
7688
7689     if (feof(file))
7690       break;
7691   }
7692
7693   if (i != tape->length)
7694     chunk_size = (tape->num_participating_players + 1) * i;
7695
7696   return chunk_size;
7697 }
7698
7699 void LoadTapeFromFilename(char *filename)
7700 {
7701   char cookie[MAX_LINE_LEN];
7702   char chunk_name[CHUNK_ID_LEN + 1];
7703   FILE *file;
7704   int chunk_size;
7705
7706   /* always start with reliable default values */
7707   setTapeInfoToDefaults();
7708
7709   if (!(file = fopen(filename, MODE_READ)))
7710   {
7711     tape.no_valid_file = TRUE;
7712
7713     return;
7714   }
7715
7716   getFileChunkBE(file, chunk_name, NULL);
7717   if (strEqual(chunk_name, "RND1"))
7718   {
7719     getFile32BitBE(file);               /* not used */
7720
7721     getFileChunkBE(file, chunk_name, NULL);
7722     if (!strEqual(chunk_name, "TAPE"))
7723     {
7724       tape.no_valid_file = TRUE;
7725
7726       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
7727       fclose(file);
7728       return;
7729     }
7730   }
7731   else  /* check for pre-2.0 file format with cookie string */
7732   {
7733     strcpy(cookie, chunk_name);
7734     fgets(&cookie[4], MAX_LINE_LEN - 4, file);
7735     if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
7736       cookie[strlen(cookie) - 1] = '\0';
7737
7738     if (!checkCookieString(cookie, TAPE_COOKIE_TMPL))
7739     {
7740       tape.no_valid_file = TRUE;
7741
7742       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
7743       fclose(file);
7744       return;
7745     }
7746
7747     if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1)
7748     {
7749       tape.no_valid_file = TRUE;
7750
7751       Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
7752       fclose(file);
7753       return;
7754     }
7755
7756     /* pre-2.0 tape files have no game version, so use file version here */
7757     tape.game_version = tape.file_version;
7758   }
7759
7760   if (tape.file_version < FILE_VERSION_1_2)
7761   {
7762     /* tape files from versions before 1.2.0 without chunk structure */
7763     LoadTape_HEAD(file, TAPE_CHUNK_HEAD_SIZE, &tape);
7764     LoadTape_BODY(file, 2 * tape.length,      &tape);
7765   }
7766   else
7767   {
7768     static struct
7769     {
7770       char *name;
7771       int size;
7772       int (*loader)(FILE *, int, struct TapeInfo *);
7773     }
7774     chunk_info[] =
7775     {
7776       { "VERS", TAPE_CHUNK_VERS_SIZE,   LoadTape_VERS },
7777       { "HEAD", TAPE_CHUNK_HEAD_SIZE,   LoadTape_HEAD },
7778       { "INFO", -1,                     LoadTape_INFO },
7779       { "BODY", -1,                     LoadTape_BODY },
7780       {  NULL,  0,                      NULL }
7781     };
7782
7783     while (getFileChunkBE(file, chunk_name, &chunk_size))
7784     {
7785       int i = 0;
7786
7787       while (chunk_info[i].name != NULL &&
7788              !strEqual(chunk_name, chunk_info[i].name))
7789         i++;
7790
7791       if (chunk_info[i].name == NULL)
7792       {
7793         Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'",
7794               chunk_name, filename);
7795         ReadUnusedBytesFromFile(file, chunk_size);
7796       }
7797       else if (chunk_info[i].size != -1 &&
7798                chunk_info[i].size != chunk_size)
7799       {
7800         Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
7801               chunk_size, chunk_name, filename);
7802         ReadUnusedBytesFromFile(file, chunk_size);
7803       }
7804       else
7805       {
7806         /* call function to load this tape chunk */
7807         int chunk_size_expected =
7808           (chunk_info[i].loader)(file, chunk_size, &tape);
7809
7810         /* the size of some chunks cannot be checked before reading other
7811            chunks first (like "HEAD" and "BODY") that contain some header
7812            information, so check them here */
7813         if (chunk_size_expected != chunk_size)
7814         {
7815           Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
7816                 chunk_size, chunk_name, filename);
7817         }
7818       }
7819     }
7820   }
7821
7822   fclose(file);
7823
7824   tape.length_seconds = GetTapeLength();
7825
7826 #if 0
7827   printf("::: tape file version: %d\n", tape.file_version);
7828   printf("::: tape game version: %d\n", tape.game_version);
7829   printf("::: tape engine version: %d\n", tape.engine_version);
7830 #endif
7831 }
7832
7833 void LoadTape(int nr)
7834 {
7835   char *filename = getTapeFilename(nr);
7836
7837   LoadTapeFromFilename(filename);
7838 }
7839
7840 void LoadSolutionTape(int nr)
7841 {
7842   char *filename = getSolutionTapeFilename(nr);
7843
7844   LoadTapeFromFilename(filename);
7845 }
7846
7847 static void SaveTape_VERS(FILE *file, struct TapeInfo *tape)
7848 {
7849   putFileVersion(file, tape->file_version);
7850   putFileVersion(file, tape->game_version);
7851 }
7852
7853 static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
7854 {
7855   int i;
7856   byte store_participating_players = 0;
7857
7858   /* set bits for participating players for compact storage */
7859   for (i = 0; i < MAX_PLAYERS; i++)
7860     if (tape->player_participates[i])
7861       store_participating_players |= (1 << i);
7862
7863   putFile32BitBE(file, tape->random_seed);
7864   putFile32BitBE(file, tape->date);
7865   putFile32BitBE(file, tape->length);
7866
7867   putFile8Bit(file, store_participating_players);
7868
7869   /* unused bytes not at the end here for 4-byte alignment of engine_version */
7870   WriteUnusedBytesToFile(file, TAPE_CHUNK_HEAD_UNUSED);
7871
7872   putFileVersion(file, tape->engine_version);
7873 }
7874
7875 static void SaveTape_INFO(FILE *file, struct TapeInfo *tape)
7876 {
7877   int level_identifier_size = strlen(tape->level_identifier) + 1;
7878   int i;
7879
7880   putFile16BitBE(file, level_identifier_size);
7881
7882   for (i = 0; i < level_identifier_size; i++)
7883     putFile8Bit(file, tape->level_identifier[i]);
7884
7885   putFile16BitBE(file, tape->level_nr);
7886 }
7887
7888 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
7889 {
7890   int i, j;
7891
7892   for (i = 0; i < tape->length; i++)
7893   {
7894     for (j = 0; j < MAX_PLAYERS; j++)
7895       if (tape->player_participates[j])
7896         putFile8Bit(file, tape->pos[i].action[j]);
7897
7898     putFile8Bit(file, tape->pos[i].delay);
7899   }
7900 }
7901
7902 void SaveTape(int nr)
7903 {
7904   char *filename = getTapeFilename(nr);
7905   FILE *file;
7906 #if 0
7907   boolean new_tape = TRUE;
7908 #endif
7909   int num_participating_players = 0;
7910   int info_chunk_size;
7911   int body_chunk_size;
7912   int i;
7913
7914   InitTapeDirectory(leveldir_current->subdir);
7915
7916 #if 0
7917   /* if a tape still exists, ask to overwrite it */
7918   if (fileExists(filename))
7919   {
7920     new_tape = FALSE;
7921     if (!Request("Replace old tape ?", REQ_ASK))
7922       return;
7923   }
7924 #endif
7925
7926   if (!(file = fopen(filename, MODE_WRITE)))
7927   {
7928     Error(ERR_WARN, "cannot save level recording file '%s'", filename);
7929     return;
7930   }
7931
7932   tape.file_version = FILE_VERSION_ACTUAL;
7933   tape.game_version = GAME_VERSION_ACTUAL;
7934
7935   /* count number of participating players  */
7936   for (i = 0; i < MAX_PLAYERS; i++)
7937     if (tape.player_participates[i])
7938       num_participating_players++;
7939
7940   info_chunk_size = 2 + (strlen(tape.level_identifier) + 1) + 2;
7941   body_chunk_size = (num_participating_players + 1) * tape.length;
7942
7943   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
7944   putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
7945
7946   putFileChunkBE(file, "VERS", TAPE_CHUNK_VERS_SIZE);
7947   SaveTape_VERS(file, &tape);
7948
7949   putFileChunkBE(file, "HEAD", TAPE_CHUNK_HEAD_SIZE);
7950   SaveTape_HEAD(file, &tape);
7951
7952   putFileChunkBE(file, "INFO", info_chunk_size);
7953   SaveTape_INFO(file, &tape);
7954
7955   putFileChunkBE(file, "BODY", body_chunk_size);
7956   SaveTape_BODY(file, &tape);
7957
7958   fclose(file);
7959
7960   SetFilePermissions(filename, PERMS_PRIVATE);
7961
7962   tape.changed = FALSE;
7963
7964 #if 0
7965   if (new_tape)
7966     Request("Tape saved !", REQ_CONFIRM);
7967 #endif
7968 }
7969
7970 boolean SaveTapeChecked(int nr)
7971 {
7972   char *filename = getTapeFilename(nr);
7973   boolean new_tape = !fileExists(filename);
7974   boolean tape_saved = FALSE;
7975
7976   if (new_tape || Request("Replace old tape ?", REQ_ASK))
7977   {
7978     SaveTape(nr);
7979
7980     if (new_tape)
7981       Request("Tape saved !", REQ_CONFIRM);
7982
7983     tape_saved = TRUE;
7984   }
7985
7986   return tape_saved;
7987 }
7988
7989 void DumpTape(struct TapeInfo *tape)
7990 {
7991   int tape_frame_counter;
7992   int i, j;
7993
7994   if (tape->no_valid_file)
7995   {
7996     Error(ERR_WARN, "cannot dump -- no valid tape file found");
7997
7998     return;
7999   }
8000
8001   printf_line("-", 79);
8002   printf("Tape of Level %03d (file version %08d, game version %08d)\n",
8003          tape->level_nr, tape->file_version, tape->game_version);
8004   printf("                  (effective engine version %08d)\n",
8005          tape->engine_version);
8006   printf("Level series identifier: '%s'\n", tape->level_identifier);
8007   printf_line("-", 79);
8008
8009   tape_frame_counter = 0;
8010
8011   for (i = 0; i < tape->length; i++)
8012   {
8013     if (i >= MAX_TAPE_LEN)
8014       break;
8015
8016     printf("%04d: ", i);
8017
8018     for (j = 0; j < MAX_PLAYERS; j++)
8019     {
8020       if (tape->player_participates[j])
8021       {
8022         int action = tape->pos[i].action[j];
8023
8024         printf("%d:%02x ", j, action);
8025         printf("[%c%c%c%c|%c%c] - ",
8026                (action & JOY_LEFT ? '<' : ' '),
8027                (action & JOY_RIGHT ? '>' : ' '),
8028                (action & JOY_UP ? '^' : ' '),
8029                (action & JOY_DOWN ? 'v' : ' '),
8030                (action & JOY_BUTTON_1 ? '1' : ' '),
8031                (action & JOY_BUTTON_2 ? '2' : ' '));
8032       }
8033     }
8034
8035     printf("(%03d) ", tape->pos[i].delay);
8036     printf("[%05d]\n", tape_frame_counter);
8037
8038     tape_frame_counter += tape->pos[i].delay;
8039   }
8040
8041   printf_line("-", 79);
8042 }
8043
8044
8045 /* ========================================================================= */
8046 /* score file functions                                                      */
8047 /* ========================================================================= */
8048
8049 void LoadScore(int nr)
8050 {
8051   int i;
8052   char *filename = getScoreFilename(nr);
8053   char cookie[MAX_LINE_LEN];
8054   char line[MAX_LINE_LEN];
8055   char *line_ptr;
8056   FILE *file;
8057
8058   /* always start with reliable default values */
8059   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
8060   {
8061     strcpy(highscore[i].Name, EMPTY_PLAYER_NAME);
8062     highscore[i].Score = 0;
8063   }
8064
8065   if (!(file = fopen(filename, MODE_READ)))
8066     return;
8067
8068   /* check file identifier */
8069   fgets(cookie, MAX_LINE_LEN, file);
8070   if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
8071     cookie[strlen(cookie) - 1] = '\0';
8072
8073   if (!checkCookieString(cookie, SCORE_COOKIE))
8074   {
8075     Error(ERR_WARN, "unknown format of score file '%s'", filename);
8076     fclose(file);
8077     return;
8078   }
8079
8080   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
8081   {
8082     fscanf(file, "%d", &highscore[i].Score);
8083     fgets(line, MAX_LINE_LEN, file);
8084
8085     if (line[strlen(line) - 1] == '\n')
8086       line[strlen(line) - 1] = '\0';
8087
8088     for (line_ptr = line; *line_ptr; line_ptr++)
8089     {
8090       if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
8091       {
8092         strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN);
8093         highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0';
8094         break;
8095       }
8096     }
8097   }
8098
8099   fclose(file);
8100 }
8101
8102 void SaveScore(int nr)
8103 {
8104   int i;
8105   char *filename = getScoreFilename(nr);
8106   FILE *file;
8107
8108   InitScoreDirectory(leveldir_current->subdir);
8109
8110   if (!(file = fopen(filename, MODE_WRITE)))
8111   {
8112     Error(ERR_WARN, "cannot save score for level %d", nr);
8113     return;
8114   }
8115
8116   fprintf(file, "%s\n\n", SCORE_COOKIE);
8117
8118   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
8119     fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name);
8120
8121   fclose(file);
8122
8123   SetFilePermissions(filename, PERMS_PUBLIC);
8124 }
8125
8126
8127 /* ========================================================================= */
8128 /* setup file functions                                                      */
8129 /* ========================================================================= */
8130
8131 #define TOKEN_STR_PLAYER_PREFIX                 "player_"
8132
8133 /* global setup */
8134 #define SETUP_TOKEN_PLAYER_NAME                 0
8135 #define SETUP_TOKEN_SOUND                       1
8136 #define SETUP_TOKEN_SOUND_LOOPS                 2
8137 #define SETUP_TOKEN_SOUND_MUSIC                 3
8138 #define SETUP_TOKEN_SOUND_SIMPLE                4
8139 #define SETUP_TOKEN_TOONS                       5
8140 #define SETUP_TOKEN_SCROLL_DELAY                6
8141 #define SETUP_TOKEN_SCROLL_DELAY_VALUE          7
8142 #define SETUP_TOKEN_SOFT_SCROLLING              8
8143 #define SETUP_TOKEN_FADE_SCREENS                9
8144 #define SETUP_TOKEN_AUTORECORD                  10
8145 #define SETUP_TOKEN_SHOW_TITLESCREEN            11
8146 #define SETUP_TOKEN_QUICK_DOORS                 12
8147 #define SETUP_TOKEN_TEAM_MODE                   13
8148 #define SETUP_TOKEN_HANDICAP                    14
8149 #define SETUP_TOKEN_SKIP_LEVELS                 15
8150 #define SETUP_TOKEN_TIME_LIMIT                  16
8151 #define SETUP_TOKEN_FULLSCREEN                  17
8152 #define SETUP_TOKEN_FULLSCREEN_MODE             18
8153 #define SETUP_TOKEN_ASK_ON_ESCAPE               19
8154 #define SETUP_TOKEN_ASK_ON_ESCAPE_EDITOR        20
8155 #define SETUP_TOKEN_QUICK_SWITCH                21
8156 #define SETUP_TOKEN_INPUT_ON_FOCUS              22
8157 #define SETUP_TOKEN_PREFER_AGA_GRAPHICS         23
8158 #define SETUP_TOKEN_GAME_FRAME_DELAY            24
8159 #define SETUP_TOKEN_GRAPHICS_SET                25
8160 #define SETUP_TOKEN_SOUNDS_SET                  26
8161 #define SETUP_TOKEN_MUSIC_SET                   27
8162 #define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS     28
8163 #define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS       29
8164 #define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC        30
8165
8166 #define NUM_GLOBAL_SETUP_TOKENS                 31
8167
8168 /* editor setup */
8169 #define SETUP_TOKEN_EDITOR_EL_BOULDERDASH       0
8170 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE      1
8171 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE_CLUB 2
8172 #define SETUP_TOKEN_EDITOR_EL_MORE              3
8173 #define SETUP_TOKEN_EDITOR_EL_SOKOBAN           4
8174 #define SETUP_TOKEN_EDITOR_EL_SUPAPLEX          5
8175 #define SETUP_TOKEN_EDITOR_EL_DIAMOND_CAVES     6
8176 #define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH    7
8177 #define SETUP_TOKEN_EDITOR_EL_CHARS             8
8178 #define SETUP_TOKEN_EDITOR_EL_STEEL_CHARS       9
8179 #define SETUP_TOKEN_EDITOR_EL_CUSTOM            10
8180 #define SETUP_TOKEN_EDITOR_EL_HEADLINES         11
8181 #define SETUP_TOKEN_EDITOR_EL_USER_DEFINED      12
8182 #define SETUP_TOKEN_EDITOR_EL_DYNAMIC           13
8183 #define SETUP_TOKEN_EDITOR_EL_BY_GAME           14
8184 #define SETUP_TOKEN_EDITOR_EL_BY_TYPE           15
8185 #define SETUP_TOKEN_EDITOR_SHOW_ELEMENT_TOKEN   16
8186
8187 #define NUM_EDITOR_SETUP_TOKENS                 17
8188
8189 /* editor cascade setup */
8190 #define SETUP_TOKEN_EDITOR_CASCADE_BD           0
8191 #define SETUP_TOKEN_EDITOR_CASCADE_EM           1
8192 #define SETUP_TOKEN_EDITOR_CASCADE_EMC          2
8193 #define SETUP_TOKEN_EDITOR_CASCADE_RND          3
8194 #define SETUP_TOKEN_EDITOR_CASCADE_SB           4
8195 #define SETUP_TOKEN_EDITOR_CASCADE_SP           5
8196 #define SETUP_TOKEN_EDITOR_CASCADE_DC           6
8197 #define SETUP_TOKEN_EDITOR_CASCADE_DX           7
8198 #define SETUP_TOKEN_EDITOR_CASCADE_TEXT         8
8199 #define SETUP_TOKEN_EDITOR_CASCADE_STEELTEXT    9
8200 #define SETUP_TOKEN_EDITOR_CASCADE_CE           10
8201 #define SETUP_TOKEN_EDITOR_CASCADE_GE           11
8202 #define SETUP_TOKEN_EDITOR_CASCADE_REF          12
8203 #define SETUP_TOKEN_EDITOR_CASCADE_USER         13
8204 #define SETUP_TOKEN_EDITOR_CASCADE_DYNAMIC      14
8205
8206 #define NUM_EDITOR_CASCADE_SETUP_TOKENS         15
8207
8208 /* shortcut setup */
8209 #define SETUP_TOKEN_SHORTCUT_SAVE_GAME          0
8210 #define SETUP_TOKEN_SHORTCUT_LOAD_GAME          1
8211 #define SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE       2
8212 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_1     3
8213 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_2     4
8214 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_3     5
8215 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_4     6
8216 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_ALL   7
8217
8218 #define NUM_SHORTCUT_SETUP_TOKENS               8
8219
8220 /* player setup */
8221 #define SETUP_TOKEN_PLAYER_USE_JOYSTICK         0
8222 #define SETUP_TOKEN_PLAYER_JOY_DEVICE_NAME      1
8223 #define SETUP_TOKEN_PLAYER_JOY_XLEFT            2
8224 #define SETUP_TOKEN_PLAYER_JOY_XMIDDLE          3
8225 #define SETUP_TOKEN_PLAYER_JOY_XRIGHT           4
8226 #define SETUP_TOKEN_PLAYER_JOY_YUPPER           5
8227 #define SETUP_TOKEN_PLAYER_JOY_YMIDDLE          6
8228 #define SETUP_TOKEN_PLAYER_JOY_YLOWER           7
8229 #define SETUP_TOKEN_PLAYER_JOY_SNAP             8
8230 #define SETUP_TOKEN_PLAYER_JOY_DROP             9
8231 #define SETUP_TOKEN_PLAYER_KEY_LEFT             10
8232 #define SETUP_TOKEN_PLAYER_KEY_RIGHT            11
8233 #define SETUP_TOKEN_PLAYER_KEY_UP               12
8234 #define SETUP_TOKEN_PLAYER_KEY_DOWN             13
8235 #define SETUP_TOKEN_PLAYER_KEY_SNAP             14
8236 #define SETUP_TOKEN_PLAYER_KEY_DROP             15
8237
8238 #define NUM_PLAYER_SETUP_TOKENS                 16
8239
8240 /* system setup */
8241 #define SETUP_TOKEN_SYSTEM_SDL_VIDEODRIVER      0
8242 #define SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER      1
8243 #define SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE  2
8244
8245 #define NUM_SYSTEM_SETUP_TOKENS                 3
8246
8247 /* options setup */
8248 #define SETUP_TOKEN_OPTIONS_VERBOSE             0
8249
8250 #define NUM_OPTIONS_SETUP_TOKENS                1
8251
8252
8253 static struct SetupInfo si;
8254 static struct SetupEditorInfo sei;
8255 static struct SetupEditorCascadeInfo seci;
8256 static struct SetupShortcutInfo ssi;
8257 static struct SetupInputInfo sii;
8258 static struct SetupSystemInfo syi;
8259 static struct OptionInfo soi;
8260
8261 static struct TokenInfo global_setup_tokens[] =
8262 {
8263   { TYPE_STRING, &si.player_name,       "player_name"                   },
8264   { TYPE_SWITCH, &si.sound,             "sound"                         },
8265   { TYPE_SWITCH, &si.sound_loops,       "repeating_sound_loops"         },
8266   { TYPE_SWITCH, &si.sound_music,       "background_music"              },
8267   { TYPE_SWITCH, &si.sound_simple,      "simple_sound_effects"          },
8268   { TYPE_SWITCH, &si.toons,             "toons"                         },
8269   { TYPE_SWITCH, &si.scroll_delay,      "scroll_delay"                  },
8270   { TYPE_INTEGER,&si.scroll_delay_value,"scroll_delay_value"            },
8271   { TYPE_SWITCH, &si.soft_scrolling,    "soft_scrolling"                },
8272   { TYPE_SWITCH, &si.fade_screens,      "fade_screens"                  },
8273   { TYPE_SWITCH, &si.autorecord,        "automatic_tape_recording"      },
8274   { TYPE_SWITCH, &si.show_titlescreen,  "show_titlescreen"              },
8275   { TYPE_SWITCH, &si.quick_doors,       "quick_doors"                   },
8276   { TYPE_SWITCH, &si.team_mode,         "team_mode"                     },
8277   { TYPE_SWITCH, &si.handicap,          "handicap"                      },
8278   { TYPE_SWITCH, &si.skip_levels,       "skip_levels"                   },
8279   { TYPE_SWITCH, &si.time_limit,        "time_limit"                    },
8280   { TYPE_SWITCH, &si.fullscreen,        "fullscreen"                    },
8281   { TYPE_STRING, &si.fullscreen_mode,   "fullscreen_mode"               },
8282   { TYPE_SWITCH, &si.ask_on_escape,     "ask_on_escape"                 },
8283   { TYPE_SWITCH, &si.ask_on_escape_editor, "ask_on_escape_editor"       },
8284   { TYPE_SWITCH, &si.quick_switch,      "quick_player_switch"           },
8285   { TYPE_SWITCH, &si.input_on_focus,    "input_on_focus"                },
8286   { TYPE_SWITCH, &si.prefer_aga_graphics, "prefer_aga_graphics"         },
8287   { TYPE_INTEGER,&si.game_frame_delay,  "game_frame_delay"              },
8288   { TYPE_STRING, &si.graphics_set,      "graphics_set"                  },
8289   { TYPE_STRING, &si.sounds_set,        "sounds_set"                    },
8290   { TYPE_STRING, &si.music_set,         "music_set"                     },
8291   { TYPE_SWITCH3,&si.override_level_graphics, "override_level_graphics" },
8292   { TYPE_SWITCH3,&si.override_level_sounds,   "override_level_sounds"   },
8293   { TYPE_SWITCH3,&si.override_level_music,    "override_level_music"    },
8294 };
8295
8296 static boolean not_used = FALSE;
8297 static struct TokenInfo editor_setup_tokens[] =
8298 {
8299 #if 1
8300   { TYPE_SWITCH, &not_used,             "editor.el_boulderdash"         },
8301   { TYPE_SWITCH, &not_used,             "editor.el_emerald_mine"        },
8302   { TYPE_SWITCH, &not_used,             "editor.el_emerald_mine_club"   },
8303   { TYPE_SWITCH, &not_used,             "editor.el_more"                },
8304   { TYPE_SWITCH, &not_used,             "editor.el_sokoban"             },
8305   { TYPE_SWITCH, &not_used,             "editor.el_supaplex"            },
8306   { TYPE_SWITCH, &not_used,             "editor.el_diamond_caves"       },
8307   { TYPE_SWITCH, &not_used,             "editor.el_dx_boulderdash"      },
8308 #else
8309   { TYPE_SWITCH, &sei.el_boulderdash,   "editor.el_boulderdash"         },
8310   { TYPE_SWITCH, &sei.el_emerald_mine,  "editor.el_emerald_mine"        },
8311   { TYPE_SWITCH, &sei.el_emerald_mine_club,"editor.el_emerald_mine_club"},
8312   { TYPE_SWITCH, &sei.el_more,          "editor.el_more"                },
8313   { TYPE_SWITCH, &sei.el_sokoban,       "editor.el_sokoban"             },
8314   { TYPE_SWITCH, &sei.el_supaplex,      "editor.el_supaplex"            },
8315   { TYPE_SWITCH, &sei.el_diamond_caves, "editor.el_diamond_caves"       },
8316   { TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash"      },
8317 #endif
8318   { TYPE_SWITCH, &sei.el_chars,         "editor.el_chars"               },
8319   { TYPE_SWITCH, &sei.el_steel_chars,   "editor.el_steel_chars"         },
8320   { TYPE_SWITCH, &sei.el_custom,        "editor.el_custom"              },
8321 #if 1
8322   { TYPE_SWITCH, &not_used,             "editor.el_headlines"           },
8323 #else
8324   { TYPE_SWITCH, &sei.el_headlines,     "editor.el_headlines"           },
8325 #endif
8326   { TYPE_SWITCH, &sei.el_user_defined,  "editor.el_user_defined"        },
8327   { TYPE_SWITCH, &sei.el_dynamic,       "editor.el_dynamic"             },
8328   { TYPE_SWITCH, &sei.el_by_game,       "editor.el_by_game"             },
8329   { TYPE_SWITCH, &sei.el_by_type,       "editor.el_by_type"             },
8330   { TYPE_SWITCH, &sei.show_element_token,"editor.show_element_token"    },
8331 };
8332
8333 static struct TokenInfo editor_cascade_setup_tokens[] =
8334 {
8335   { TYPE_SWITCH, &seci.el_bd,           "editor.cascade.el_bd"          },
8336   { TYPE_SWITCH, &seci.el_em,           "editor.cascade.el_em"          },
8337   { TYPE_SWITCH, &seci.el_emc,          "editor.cascade.el_emc"         },
8338   { TYPE_SWITCH, &seci.el_rnd,          "editor.cascade.el_rnd"         },
8339   { TYPE_SWITCH, &seci.el_sb,           "editor.cascade.el_sb"          },
8340   { TYPE_SWITCH, &seci.el_sp,           "editor.cascade.el_sp"          },
8341   { TYPE_SWITCH, &seci.el_dc,           "editor.cascade.el_dc"          },
8342   { TYPE_SWITCH, &seci.el_dx,           "editor.cascade.el_dx"          },
8343   { TYPE_SWITCH, &seci.el_chars,        "editor.cascade.el_chars"       },
8344   { TYPE_SWITCH, &seci.el_steel_chars,  "editor.cascade.el_steel_chars" },
8345   { TYPE_SWITCH, &seci.el_ce,           "editor.cascade.el_ce"          },
8346   { TYPE_SWITCH, &seci.el_ge,           "editor.cascade.el_ge"          },
8347   { TYPE_SWITCH, &seci.el_ref,          "editor.cascade.el_ref"         },
8348   { TYPE_SWITCH, &seci.el_user,         "editor.cascade.el_user"        },
8349   { TYPE_SWITCH, &seci.el_dynamic,      "editor.cascade.el_dynamic"     },
8350 };
8351
8352 static struct TokenInfo shortcut_setup_tokens[] =
8353 {
8354   { TYPE_KEY_X11, &ssi.save_game,       "shortcut.save_game"            },
8355   { TYPE_KEY_X11, &ssi.load_game,       "shortcut.load_game"            },
8356   { TYPE_KEY_X11, &ssi.toggle_pause,    "shortcut.toggle_pause"         },
8357   { TYPE_KEY_X11, &ssi.focus_player[0], "shortcut.focus_player_1"       },
8358   { TYPE_KEY_X11, &ssi.focus_player[1], "shortcut.focus_player_2"       },
8359   { TYPE_KEY_X11, &ssi.focus_player[2], "shortcut.focus_player_3"       },
8360   { TYPE_KEY_X11, &ssi.focus_player[3], "shortcut.focus_player_4"       },
8361   { TYPE_KEY_X11, &ssi.focus_player_all,"shortcut.focus_player_all"     },
8362 };
8363
8364 static struct TokenInfo player_setup_tokens[] =
8365 {
8366   { TYPE_BOOLEAN, &sii.use_joystick,    ".use_joystick"                 },
8367   { TYPE_STRING,  &sii.joy.device_name, ".joy.device_name"              },
8368   { TYPE_INTEGER, &sii.joy.xleft,       ".joy.xleft"                    },
8369   { TYPE_INTEGER, &sii.joy.xmiddle,     ".joy.xmiddle"                  },
8370   { TYPE_INTEGER, &sii.joy.xright,      ".joy.xright"                   },
8371   { TYPE_INTEGER, &sii.joy.yupper,      ".joy.yupper"                   },
8372   { TYPE_INTEGER, &sii.joy.ymiddle,     ".joy.ymiddle"                  },
8373   { TYPE_INTEGER, &sii.joy.ylower,      ".joy.ylower"                   },
8374   { TYPE_INTEGER, &sii.joy.snap,        ".joy.snap_field"               },
8375   { TYPE_INTEGER, &sii.joy.drop,        ".joy.place_bomb"               },
8376   { TYPE_KEY_X11, &sii.key.left,        ".key.move_left"                },
8377   { TYPE_KEY_X11, &sii.key.right,       ".key.move_right"               },
8378   { TYPE_KEY_X11, &sii.key.up,          ".key.move_up"                  },
8379   { TYPE_KEY_X11, &sii.key.down,        ".key.move_down"                },
8380   { TYPE_KEY_X11, &sii.key.snap,        ".key.snap_field"               },
8381   { TYPE_KEY_X11, &sii.key.drop,        ".key.place_bomb"               },
8382 };
8383
8384 static struct TokenInfo system_setup_tokens[] =
8385 {
8386   { TYPE_STRING,  &syi.sdl_videodriver, "system.sdl_videodriver"        },
8387   { TYPE_STRING,  &syi.sdl_audiodriver, "system.sdl_audiodriver"        },
8388   { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size" },
8389 };
8390
8391 static struct TokenInfo options_setup_tokens[] =
8392 {
8393   { TYPE_BOOLEAN, &soi.verbose,         "options.verbose"               },
8394 };
8395
8396 static char *get_corrected_login_name(char *login_name)
8397 {
8398   /* needed because player name must be a fixed length string */
8399   char *login_name_new = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
8400
8401   strncpy(login_name_new, login_name, MAX_PLAYER_NAME_LEN);
8402   login_name_new[MAX_PLAYER_NAME_LEN] = '\0';
8403
8404   if (strlen(login_name) > MAX_PLAYER_NAME_LEN)         /* name has been cut */
8405     if (strchr(login_name_new, ' '))
8406       *strchr(login_name_new, ' ') = '\0';
8407
8408   return login_name_new;
8409 }
8410
8411 static void setSetupInfoToDefaults(struct SetupInfo *si)
8412 {
8413   int i;
8414
8415   si->player_name = get_corrected_login_name(getLoginName());
8416
8417   si->sound = TRUE;
8418   si->sound_loops = TRUE;
8419   si->sound_music = TRUE;
8420   si->sound_simple = TRUE;
8421   si->toons = TRUE;
8422   si->scroll_delay = TRUE;
8423   si->scroll_delay_value = STD_SCROLL_DELAY;
8424   si->soft_scrolling = TRUE;
8425   si->fade_screens = TRUE;
8426   si->autorecord = TRUE;
8427   si->show_titlescreen = TRUE;
8428   si->quick_doors = FALSE;
8429   si->team_mode = FALSE;
8430   si->handicap = TRUE;
8431   si->skip_levels = TRUE;
8432   si->time_limit = TRUE;
8433   si->fullscreen = FALSE;
8434   si->fullscreen_mode = getStringCopy(DEFAULT_FULLSCREEN_MODE);
8435   si->ask_on_escape = TRUE;
8436   si->ask_on_escape_editor = TRUE;
8437   si->quick_switch = FALSE;
8438   si->input_on_focus = FALSE;
8439   si->prefer_aga_graphics = TRUE;
8440   si->game_frame_delay = GAME_FRAME_DELAY;
8441
8442   si->graphics_set = getStringCopy(GFX_DEFAULT_SUBDIR);
8443   si->sounds_set = getStringCopy(SND_DEFAULT_SUBDIR);
8444   si->music_set = getStringCopy(MUS_DEFAULT_SUBDIR);
8445   si->override_level_graphics = FALSE;
8446   si->override_level_sounds = FALSE;
8447   si->override_level_music = FALSE;
8448
8449   si->editor.el_boulderdash             = TRUE;
8450   si->editor.el_emerald_mine            = TRUE;
8451   si->editor.el_emerald_mine_club       = TRUE;
8452   si->editor.el_more                    = TRUE;
8453   si->editor.el_sokoban                 = TRUE;
8454   si->editor.el_supaplex                = TRUE;
8455   si->editor.el_diamond_caves           = TRUE;
8456   si->editor.el_dx_boulderdash          = TRUE;
8457   si->editor.el_chars                   = TRUE;
8458   si->editor.el_steel_chars             = TRUE;
8459   si->editor.el_custom                  = TRUE;
8460
8461   si->editor.el_headlines = TRUE;
8462   si->editor.el_user_defined = FALSE;
8463   si->editor.el_dynamic = TRUE;
8464
8465   si->editor.show_element_token = FALSE;
8466
8467   si->shortcut.save_game        = DEFAULT_KEY_SAVE_GAME;
8468   si->shortcut.load_game        = DEFAULT_KEY_LOAD_GAME;
8469   si->shortcut.toggle_pause     = DEFAULT_KEY_TOGGLE_PAUSE;
8470
8471   si->shortcut.focus_player[0]  = DEFAULT_KEY_FOCUS_PLAYER_1;
8472   si->shortcut.focus_player[1]  = DEFAULT_KEY_FOCUS_PLAYER_2;
8473   si->shortcut.focus_player[2]  = DEFAULT_KEY_FOCUS_PLAYER_3;
8474   si->shortcut.focus_player[3]  = DEFAULT_KEY_FOCUS_PLAYER_4;
8475   si->shortcut.focus_player_all = DEFAULT_KEY_FOCUS_PLAYER_ALL;
8476
8477   for (i = 0; i < MAX_PLAYERS; i++)
8478   {
8479     si->input[i].use_joystick = FALSE;
8480     si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
8481     si->input[i].joy.xleft   = JOYSTICK_XLEFT;
8482     si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
8483     si->input[i].joy.xright  = JOYSTICK_XRIGHT;
8484     si->input[i].joy.yupper  = JOYSTICK_YUPPER;
8485     si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
8486     si->input[i].joy.ylower  = JOYSTICK_YLOWER;
8487     si->input[i].joy.snap  = (i == 0 ? JOY_BUTTON_1 : 0);
8488     si->input[i].joy.drop  = (i == 0 ? JOY_BUTTON_2 : 0);
8489     si->input[i].key.left  = (i == 0 ? DEFAULT_KEY_LEFT  : KSYM_UNDEFINED);
8490     si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
8491     si->input[i].key.up    = (i == 0 ? DEFAULT_KEY_UP    : KSYM_UNDEFINED);
8492     si->input[i].key.down  = (i == 0 ? DEFAULT_KEY_DOWN  : KSYM_UNDEFINED);
8493     si->input[i].key.snap  = (i == 0 ? DEFAULT_KEY_SNAP  : KSYM_UNDEFINED);
8494     si->input[i].key.drop  = (i == 0 ? DEFAULT_KEY_DROP  : KSYM_UNDEFINED);
8495   }
8496
8497   si->system.sdl_videodriver = getStringCopy(ARG_DEFAULT);
8498   si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT);
8499   si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
8500
8501   si->options.verbose = FALSE;
8502
8503 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
8504   si->handicap = FALSE;
8505   si->fullscreen = TRUE;
8506   si->override_level_graphics = AUTO;
8507   si->override_level_sounds = AUTO;
8508   si->override_level_music = AUTO;
8509 #endif
8510 }
8511
8512 static void setSetupInfoToDefaults_EditorCascade(struct SetupInfo *si)
8513 {
8514   si->editor_cascade.el_bd              = TRUE;
8515   si->editor_cascade.el_em              = TRUE;
8516   si->editor_cascade.el_emc             = TRUE;
8517   si->editor_cascade.el_rnd             = TRUE;
8518   si->editor_cascade.el_sb              = TRUE;
8519   si->editor_cascade.el_sp              = TRUE;
8520   si->editor_cascade.el_dc              = TRUE;
8521   si->editor_cascade.el_dx              = TRUE;
8522
8523   si->editor_cascade.el_chars           = FALSE;
8524   si->editor_cascade.el_steel_chars     = FALSE;
8525   si->editor_cascade.el_ce              = FALSE;
8526   si->editor_cascade.el_ge              = FALSE;
8527   si->editor_cascade.el_ref             = FALSE;
8528   si->editor_cascade.el_user            = FALSE;
8529   si->editor_cascade.el_dynamic         = FALSE;
8530 }
8531
8532 static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
8533 {
8534   int i, pnr;
8535
8536   if (!setup_file_hash)
8537     return;
8538
8539   /* global setup */
8540   si = setup;
8541   for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
8542     setSetupInfo(global_setup_tokens, i,
8543                  getHashEntry(setup_file_hash, global_setup_tokens[i].text));
8544   setup = si;
8545
8546   /* editor setup */
8547   sei = setup.editor;
8548   for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
8549     setSetupInfo(editor_setup_tokens, i,
8550                  getHashEntry(setup_file_hash,editor_setup_tokens[i].text));
8551   setup.editor = sei;
8552
8553   /* shortcut setup */
8554   ssi = setup.shortcut;
8555   for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
8556     setSetupInfo(shortcut_setup_tokens, i,
8557                  getHashEntry(setup_file_hash,shortcut_setup_tokens[i].text));
8558   setup.shortcut = ssi;
8559
8560   /* player setup */
8561   for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
8562   {
8563     char prefix[30];
8564
8565     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
8566
8567     sii = setup.input[pnr];
8568     for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
8569     {
8570       char full_token[100];
8571
8572       sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
8573       setSetupInfo(player_setup_tokens, i,
8574                    getHashEntry(setup_file_hash, full_token));
8575     }
8576     setup.input[pnr] = sii;
8577   }
8578
8579   /* system setup */
8580   syi = setup.system;
8581   for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
8582     setSetupInfo(system_setup_tokens, i,
8583                  getHashEntry(setup_file_hash, system_setup_tokens[i].text));
8584   setup.system = syi;
8585
8586   /* options setup */
8587   soi = setup.options;
8588   for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
8589     setSetupInfo(options_setup_tokens, i,
8590                  getHashEntry(setup_file_hash, options_setup_tokens[i].text));
8591   setup.options = soi;
8592 }
8593
8594 static void decodeSetupFileHash_EditorCascade(SetupFileHash *setup_file_hash)
8595 {
8596   int i;
8597
8598   if (!setup_file_hash)
8599     return;
8600
8601   /* editor cascade setup */
8602   seci = setup.editor_cascade;
8603   for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
8604     setSetupInfo(editor_cascade_setup_tokens, i,
8605                  getHashEntry(setup_file_hash,
8606                               editor_cascade_setup_tokens[i].text));
8607   setup.editor_cascade = seci;
8608 }
8609
8610 void LoadSetup()
8611 {
8612   char *filename = getSetupFilename();
8613   SetupFileHash *setup_file_hash = NULL;
8614
8615   /* always start with reliable default values */
8616   setSetupInfoToDefaults(&setup);
8617
8618   setup_file_hash = loadSetupFileHash(filename);
8619
8620   if (setup_file_hash)
8621   {
8622     char *player_name_new;
8623
8624     checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP"));
8625     decodeSetupFileHash(setup_file_hash);
8626
8627     freeSetupFileHash(setup_file_hash);
8628
8629     /* needed to work around problems with fixed length strings */
8630     player_name_new = get_corrected_login_name(setup.player_name);
8631     free(setup.player_name);
8632     setup.player_name = player_name_new;
8633
8634     /* "scroll_delay: on(3) / off(0)" was replaced by scroll delay value */
8635     if (setup.scroll_delay == FALSE)
8636     {
8637       setup.scroll_delay_value = MIN_SCROLL_DELAY;
8638       setup.scroll_delay = TRUE;                        /* now always "on" */
8639     }
8640
8641     /* make sure that scroll delay value stays inside valid range */
8642     setup.scroll_delay_value =
8643       MIN(MAX(MIN_SCROLL_DELAY, setup.scroll_delay_value), MAX_SCROLL_DELAY);
8644   }
8645   else
8646     Error(ERR_WARN, "using default setup values");
8647 }
8648
8649 void LoadSetup_EditorCascade()
8650 {
8651   char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
8652   SetupFileHash *setup_file_hash = NULL;
8653
8654   /* always start with reliable default values */
8655   setSetupInfoToDefaults_EditorCascade(&setup);
8656
8657   setup_file_hash = loadSetupFileHash(filename);
8658
8659   if (setup_file_hash)
8660   {
8661     checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP"));
8662     decodeSetupFileHash_EditorCascade(setup_file_hash);
8663
8664     freeSetupFileHash(setup_file_hash);
8665   }
8666
8667   free(filename);
8668 }
8669
8670 void SaveSetup()
8671 {
8672   char *filename = getSetupFilename();
8673   FILE *file;
8674   int i, pnr;
8675
8676   InitUserDataDirectory();
8677
8678   if (!(file = fopen(filename, MODE_WRITE)))
8679   {
8680     Error(ERR_WARN, "cannot write setup file '%s'", filename);
8681     return;
8682   }
8683
8684   fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
8685                                                getCookie("SETUP")));
8686   fprintf(file, "\n");
8687
8688   /* global setup */
8689   si = setup;
8690   for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
8691   {
8692     /* just to make things nicer :) */
8693     if (i == SETUP_TOKEN_PLAYER_NAME + 1 ||
8694         i == SETUP_TOKEN_GRAPHICS_SET)
8695       fprintf(file, "\n");
8696
8697     fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
8698   }
8699
8700   /* editor setup */
8701   sei = setup.editor;
8702   fprintf(file, "\n");
8703   for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
8704     fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i));
8705
8706   /* shortcut setup */
8707   ssi = setup.shortcut;
8708   fprintf(file, "\n");
8709   for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
8710     fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
8711
8712   /* player setup */
8713   for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
8714   {
8715     char prefix[30];
8716
8717     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
8718     fprintf(file, "\n");
8719
8720     sii = setup.input[pnr];
8721     for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
8722       fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
8723   }
8724
8725   /* system setup */
8726   syi = setup.system;
8727   fprintf(file, "\n");
8728   for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
8729     fprintf(file, "%s\n", getSetupLine(system_setup_tokens, "", i));
8730
8731   /* options setup */
8732   soi = setup.options;
8733   fprintf(file, "\n");
8734   for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
8735     fprintf(file, "%s\n", getSetupLine(options_setup_tokens, "", i));
8736
8737   fclose(file);
8738
8739   SetFilePermissions(filename, PERMS_PRIVATE);
8740 }
8741
8742 void SaveSetup_EditorCascade()
8743 {
8744   char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
8745   FILE *file;
8746   int i;
8747
8748   InitUserDataDirectory();
8749
8750   if (!(file = fopen(filename, MODE_WRITE)))
8751   {
8752     Error(ERR_WARN, "cannot write editor cascade state file '%s'", filename);
8753     free(filename);
8754     return;
8755   }
8756
8757   fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
8758                                                getCookie("SETUP")));
8759   fprintf(file, "\n");
8760
8761   seci = setup.editor_cascade;
8762   fprintf(file, "\n");
8763   for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
8764     fprintf(file, "%s\n", getSetupLine(editor_cascade_setup_tokens, "", i));
8765
8766   fclose(file);
8767
8768   SetFilePermissions(filename, PERMS_PRIVATE);
8769
8770   free(filename);
8771 }
8772
8773 void LoadCustomElementDescriptions()
8774 {
8775   char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
8776   SetupFileHash *setup_file_hash;
8777   int i;
8778
8779   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
8780   {
8781     if (element_info[i].custom_description != NULL)
8782     {
8783       free(element_info[i].custom_description);
8784       element_info[i].custom_description = NULL;
8785     }
8786   }
8787
8788   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
8789     return;
8790
8791   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
8792   {
8793     char *token = getStringCat2(element_info[i].token_name, ".name");
8794     char *value = getHashEntry(setup_file_hash, token);
8795
8796     if (value != NULL)
8797       element_info[i].custom_description = getStringCopy(value);
8798
8799     free(token);
8800   }
8801
8802   freeSetupFileHash(setup_file_hash);
8803 }
8804
8805 static int getElementFromToken(char *token)
8806 {
8807 #if 1
8808   char *value = getHashEntry(element_token_hash, token);
8809
8810   if (value != NULL)
8811     return atoi(value);
8812 #else
8813   int i;
8814
8815   /* !!! OPTIMIZE THIS BY USING HASH !!! */
8816   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
8817     if (strEqual(token, element_info[i].token_name))
8818       return i;
8819 #endif
8820
8821   Error(ERR_WARN, "unknown element token '%s'", token);
8822
8823   return EL_UNDEFINED;
8824 }
8825
8826 static int get_token_parameter_value(char *token, char *value_raw)
8827 {
8828   char *suffix;
8829
8830   if (token == NULL || value_raw == NULL)
8831     return ARG_UNDEFINED_VALUE;
8832
8833   suffix = strrchr(token, '.');
8834   if (suffix == NULL)
8835     suffix = token;
8836
8837 #if 1
8838   if (strEqual(suffix, ".element"))
8839     return getElementFromToken(value_raw);
8840 #endif
8841
8842 #if 0
8843   if (strncmp(suffix, ".font", 5) == 0)
8844   {
8845     int i;
8846
8847     /* !!! OPTIMIZE THIS BY USING HASH !!! */
8848     for (i = 0; i < NUM_FONTS; i++)
8849       if (strEqual(value_raw, font_info[i].token_name))
8850         return i;
8851
8852     /* if font not found, use reliable default value */
8853     return FONT_INITIAL_1;
8854   }
8855 #endif
8856
8857   /* !!! USE CORRECT VALUE TYPE (currently works also for TYPE_BOOLEAN) !!! */
8858   return get_parameter_value(value_raw, suffix, TYPE_INTEGER);
8859 }
8860
8861 void InitMenuDesignSettings_Static()
8862 {
8863 #if 0
8864   static SetupFileHash *image_config_hash = NULL;
8865 #endif
8866   int i;
8867
8868 #if 0
8869   if (image_config_hash == NULL)
8870   {
8871     image_config_hash = newSetupFileHash();
8872
8873     for (i = 0; image_config[i].token != NULL; i++)
8874       setHashEntry(image_config_hash,
8875                    image_config[i].token,
8876                    image_config[i].value);
8877   }
8878 #endif
8879
8880 #if 1
8881   /* always start with reliable default values from static default config */
8882   for (i = 0; image_config_vars[i].token != NULL; i++)
8883   {
8884     char *value = getHashEntry(image_config_hash, image_config_vars[i].token);
8885
8886     if (value != NULL)
8887       *image_config_vars[i].value =
8888         get_token_parameter_value(image_config_vars[i].token, value);
8889   }
8890
8891 #else
8892
8893   int j;
8894
8895   /* always start with reliable default values from static default config */
8896   for (i = 0; image_config_vars[i].token != NULL; i++)
8897     for (j = 0; image_config[j].token != NULL; j++)
8898       if (strEqual(image_config_vars[i].token, image_config[j].token))
8899         *image_config_vars[i].value =
8900           get_token_parameter_value(image_config_vars[i].token,
8901                                     image_config[j].value);
8902 #endif
8903 }
8904
8905 static void InitMenuDesignSettings_SpecialPreProcessing()
8906 {
8907   int i;
8908
8909   /* the following initializes hierarchical values from static configuration */
8910
8911   /* special case: initialize "ARG_DEFAULT" values in static default config */
8912   /* (e.g., initialize "[titlemessage].fade_mode" from "[title].fade_mode") */
8913   titlemessage_initial_default.fade_mode  = title_initial_default.fade_mode;
8914   titlemessage_initial_default.fade_delay = title_initial_default.fade_delay;
8915   titlemessage_initial_default.post_delay = title_initial_default.post_delay;
8916   titlemessage_initial_default.auto_delay = title_initial_default.auto_delay;
8917   titlemessage_default.fade_mode  = title_default.fade_mode;
8918   titlemessage_default.fade_delay = title_default.fade_delay;
8919   titlemessage_default.post_delay = title_default.post_delay;
8920   titlemessage_default.auto_delay = title_default.auto_delay;
8921
8922   /* special case: initialize "ARG_DEFAULT" values in static default config */
8923   /* (e.g., init "titlemessage_1.fade_mode" from "[titlemessage].fade_mode") */
8924   for (i = 0; i < MAX_NUM_TITLE_MESSAGES; i++)
8925   {
8926     titlemessage_initial[i] = titlemessage_initial_default;
8927     titlemessage[i] = titlemessage_default;
8928   }
8929
8930   /* special case: initialize "ARG_DEFAULT" values in static default config */
8931   /* (eg, init "menu.enter_screen.SCORES.xyz" from "menu.enter_screen.xyz") */
8932   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
8933   {
8934     menu.enter_screen[i] = menu.enter_screen[GFX_SPECIAL_ARG_DEFAULT];
8935     menu.leave_screen[i] = menu.leave_screen[GFX_SPECIAL_ARG_DEFAULT];
8936   }
8937 }
8938
8939 static void InitMenuDesignSettings_SpecialPostProcessing()
8940 {
8941   /* special case: initialize later added SETUP list size from LEVELS value */
8942   if (menu.list_size[GAME_MODE_SETUP] == -1)
8943     menu.list_size[GAME_MODE_SETUP] = menu.list_size[GAME_MODE_LEVELS];
8944 }
8945
8946 static void LoadMenuDesignSettingsFromFilename(char *filename)
8947 {
8948   static struct TitleMessageInfo tmi;
8949   static struct TokenInfo titlemessage_tokens[] =
8950   {
8951     { TYPE_INTEGER,     &tmi.x,                 ".x"                    },
8952     { TYPE_INTEGER,     &tmi.y,                 ".y"                    },
8953     { TYPE_INTEGER,     &tmi.width,             ".width"                },
8954     { TYPE_INTEGER,     &tmi.height,            ".height"               },
8955     { TYPE_INTEGER,     &tmi.chars,             ".chars"                },
8956     { TYPE_INTEGER,     &tmi.lines,             ".lines"                },
8957     { TYPE_INTEGER,     &tmi.align,             ".align"                },
8958     { TYPE_INTEGER,     &tmi.valign,            ".valign"               },
8959     { TYPE_INTEGER,     &tmi.font,              ".font"                 },
8960     { TYPE_BOOLEAN,     &tmi.autowrap,          ".autowrap"             },
8961     { TYPE_BOOLEAN,     &tmi.centered,          ".centered"             },
8962     { TYPE_BOOLEAN,     &tmi.parse_comments,    ".parse_comments"       },
8963     { TYPE_INTEGER,     &tmi.sort_priority,     ".sort_priority"        },
8964     { TYPE_INTEGER,     &tmi.fade_mode,         ".fade_mode"            },
8965     { TYPE_INTEGER,     &tmi.fade_delay,        ".fade_delay"           },
8966     { TYPE_INTEGER,     &tmi.post_delay,        ".post_delay"           },
8967     { TYPE_INTEGER,     &tmi.auto_delay,        ".auto_delay"           },
8968
8969     { -1,               NULL,                   NULL                    }
8970   };
8971   static struct
8972   {
8973     struct TitleMessageInfo *array;
8974     char *text;
8975   }
8976   titlemessage_arrays[] =
8977   {
8978     { titlemessage_initial,             "[titlemessage_initial]"        },
8979     { titlemessage,                     "[titlemessage]"                },
8980
8981     { NULL,                             NULL                            }
8982   };
8983   SetupFileHash *setup_file_hash;
8984   int i, j, k;
8985
8986 #if 0
8987   printf("LoadMenuDesignSettings from file '%s' ...\n", filename);
8988 #endif
8989
8990   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
8991     return;
8992
8993   /* the following initializes hierarchical values from dynamic configuration */
8994
8995   /* special case: initialize with default values that may be overwritten */
8996   /* (e.g., init "menu.draw_xoffset.INFO" from "menu.draw_xoffset") */
8997   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
8998   {
8999     char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset");
9000     char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset");
9001     char *value_3 = getHashEntry(setup_file_hash, "menu.list_size");
9002
9003     if (value_1 != NULL)
9004       menu.draw_xoffset[i] = get_integer_from_string(value_1);
9005     if (value_2 != NULL)
9006       menu.draw_yoffset[i] = get_integer_from_string(value_2);
9007     if (value_3 != NULL)
9008       menu.list_size[i] = get_integer_from_string(value_3);
9009   }
9010
9011   /* special case: initialize with default values that may be overwritten */
9012   /* (eg, init "menu.draw_xoffset.INFO[XXX]" from "menu.draw_xoffset.INFO") */
9013   for (i = 0; i < NUM_SPECIAL_GFX_INFO_ARGS; i++)
9014   {
9015     char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset.INFO");
9016     char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset.INFO");
9017
9018     if (value_1 != NULL)
9019       menu.draw_xoffset_info[i] = get_integer_from_string(value_1);
9020     if (value_2 != NULL)
9021       menu.draw_yoffset_info[i] = get_integer_from_string(value_2);
9022   }
9023
9024   /* special case: initialize with default values that may be overwritten */
9025   /* (eg, init "menu.draw_xoffset.SETUP[XXX]" from "menu.draw_xoffset.SETUP") */
9026   for (i = 0; i < NUM_SPECIAL_GFX_SETUP_ARGS; i++)
9027   {
9028     char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset.SETUP");
9029     char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset.SETUP");
9030
9031     if (value_1 != NULL)
9032       menu.draw_xoffset_setup[i] = get_integer_from_string(value_1);
9033     if (value_2 != NULL)
9034       menu.draw_yoffset_setup[i] = get_integer_from_string(value_2);
9035   }
9036
9037   /* special case: initialize with default values that may be overwritten */
9038   /* (eg, init "menu.enter_screen.SCORES.xyz" from "menu.enter_screen.xyz") */
9039   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
9040   {
9041     char *token_1 = "menu.enter_screen.fade_mode";
9042     char *token_2 = "menu.enter_screen.fade_delay";
9043     char *token_3 = "menu.enter_screen.post_delay";
9044     char *token_4 = "menu.leave_screen.fade_mode";
9045     char *token_5 = "menu.leave_screen.fade_delay";
9046     char *token_6 = "menu.leave_screen.post_delay";
9047     char *value_1 = getHashEntry(setup_file_hash, token_1);
9048     char *value_2 = getHashEntry(setup_file_hash, token_2);
9049     char *value_3 = getHashEntry(setup_file_hash, token_3);
9050     char *value_4 = getHashEntry(setup_file_hash, token_4);
9051     char *value_5 = getHashEntry(setup_file_hash, token_5);
9052     char *value_6 = getHashEntry(setup_file_hash, token_6);
9053
9054     if (value_1 != NULL)
9055       menu.enter_screen[i].fade_mode = get_token_parameter_value(token_1,
9056                                                                  value_1);
9057     if (value_2 != NULL)
9058       menu.enter_screen[i].fade_delay = get_token_parameter_value(token_2,
9059                                                                   value_2);
9060     if (value_3 != NULL)
9061       menu.enter_screen[i].post_delay = get_token_parameter_value(token_3,
9062                                                                   value_3);
9063     if (value_4 != NULL)
9064       menu.leave_screen[i].fade_mode = get_token_parameter_value(token_4,
9065                                                                  value_4);
9066     if (value_5 != NULL)
9067       menu.leave_screen[i].fade_delay = get_token_parameter_value(token_5,
9068                                                                   value_5);
9069     if (value_6 != NULL)
9070       menu.leave_screen[i].post_delay = get_token_parameter_value(token_6,
9071                                                                   value_6);
9072   }
9073
9074   /* special case: initialize with default values that may be overwritten */
9075   /* (e.g., init "titlemessage_1.fade_mode" from "[titlemessage].fade_mode") */
9076   for (i = 0; titlemessage_arrays[i].array != NULL; i++)
9077   {
9078     struct TitleMessageInfo *array = titlemessage_arrays[i].array;
9079     char *base_token = titlemessage_arrays[i].text;
9080
9081     for (j = 0; titlemessage_tokens[j].type != -1; j++)
9082     {
9083       char *token = getStringCat2(base_token, titlemessage_tokens[j].text);
9084       char *value = getHashEntry(setup_file_hash, token);
9085
9086       if (value != NULL)
9087       {
9088         int parameter_value = get_token_parameter_value(token, value);
9089
9090         for (k = 0; k < MAX_NUM_TITLE_MESSAGES; k++)
9091         {
9092           tmi = array[k];
9093
9094           if (titlemessage_tokens[j].type == TYPE_INTEGER)
9095             *(boolean *)titlemessage_tokens[j].value = (boolean)parameter_value;
9096           else
9097             *(int     *)titlemessage_tokens[j].value = (int)parameter_value;
9098
9099           array[k] = tmi;
9100         }
9101       }
9102
9103       free(token);
9104     }
9105   }
9106
9107   /* read (and overwrite with) values that may be specified in config file */
9108   for (i = 0; image_config_vars[i].token != NULL; i++)
9109   {
9110     char *value = getHashEntry(setup_file_hash, image_config_vars[i].token);
9111
9112     /* (ignore definitions set to "[DEFAULT]" which are already initialized) */
9113     if (value != NULL && !strEqual(value, ARG_DEFAULT))
9114       *image_config_vars[i].value =
9115         get_token_parameter_value(image_config_vars[i].token, value);
9116   }
9117
9118   freeSetupFileHash(setup_file_hash);
9119 }
9120
9121 void LoadMenuDesignSettings()
9122 {
9123   char *filename_base = UNDEFINED_FILENAME, *filename_local;
9124
9125   InitMenuDesignSettings_Static();
9126   InitMenuDesignSettings_SpecialPreProcessing();
9127
9128 #if 1
9129   if (!GFX_OVERRIDE_ARTWORK(ARTWORK_TYPE_GRAPHICS))
9130 #else
9131   if (!SETUP_OVERRIDE_ARTWORK(setup, ARTWORK_TYPE_GRAPHICS))
9132 #endif
9133   {
9134     /* first look for special settings configured in level series config */
9135     filename_base = getCustomArtworkLevelConfigFilename(ARTWORK_TYPE_GRAPHICS);
9136
9137     if (fileExists(filename_base))
9138       LoadMenuDesignSettingsFromFilename(filename_base);
9139   }
9140
9141   filename_local = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
9142
9143   if (filename_local != NULL && !strEqual(filename_base, filename_local))
9144     LoadMenuDesignSettingsFromFilename(filename_local);
9145
9146   InitMenuDesignSettings_SpecialPostProcessing();
9147 }
9148
9149 void LoadUserDefinedEditorElementList(int **elements, int *num_elements)
9150 {
9151   char *filename = getEditorSetupFilename();
9152   SetupFileList *setup_file_list, *list;
9153   SetupFileHash *element_hash;
9154   int num_unknown_tokens = 0;
9155   int i;
9156
9157   if ((setup_file_list = loadSetupFileList(filename)) == NULL)
9158     return;
9159
9160   element_hash = newSetupFileHash();
9161
9162   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9163     setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
9164
9165   /* determined size may be larger than needed (due to unknown elements) */
9166   *num_elements = 0;
9167   for (list = setup_file_list; list != NULL; list = list->next)
9168     (*num_elements)++;
9169
9170   /* add space for up to 3 more elements for padding that may be needed */
9171   *num_elements += 3;
9172
9173   /* free memory for old list of elements, if needed */
9174   checked_free(*elements);
9175
9176   /* allocate memory for new list of elements */
9177   *elements = checked_malloc(*num_elements * sizeof(int));
9178
9179   *num_elements = 0;
9180   for (list = setup_file_list; list != NULL; list = list->next)
9181   {
9182     char *value = getHashEntry(element_hash, list->token);
9183
9184     if (value == NULL)          /* try to find obsolete token mapping */
9185     {
9186       char *mapped_token = get_mapped_token(list->token);
9187
9188       if (mapped_token != NULL)
9189       {
9190         value = getHashEntry(element_hash, mapped_token);
9191
9192         free(mapped_token);
9193       }
9194     }
9195
9196     if (value != NULL)
9197     {
9198       (*elements)[(*num_elements)++] = atoi(value);
9199     }
9200     else
9201     {
9202       if (num_unknown_tokens == 0)
9203       {
9204         Error(ERR_INFO_LINE, "-");
9205         Error(ERR_INFO, "warning: unknown token(s) found in config file:");
9206         Error(ERR_INFO, "- config file: '%s'", filename);
9207
9208         num_unknown_tokens++;
9209       }
9210
9211       Error(ERR_INFO, "- token: '%s'", list->token);
9212     }
9213   }
9214
9215   if (num_unknown_tokens > 0)
9216     Error(ERR_INFO_LINE, "-");
9217
9218   while (*num_elements % 4)     /* pad with empty elements, if needed */
9219     (*elements)[(*num_elements)++] = EL_EMPTY;
9220
9221   freeSetupFileList(setup_file_list);
9222   freeSetupFileHash(element_hash);
9223
9224 #if 0
9225   for (i = 0; i < *num_elements; i++)
9226     printf("editor: element '%s' [%d]\n",
9227            element_info[(*elements)[i]].token_name, (*elements)[i]);
9228 #endif
9229 }
9230
9231 static struct MusicFileInfo *get_music_file_info_ext(char *basename, int music,
9232                                                      boolean is_sound)
9233 {
9234   SetupFileHash *setup_file_hash = NULL;
9235   struct MusicFileInfo tmp_music_file_info, *new_music_file_info;
9236   char *filename_music, *filename_prefix, *filename_info;
9237   struct
9238   {
9239     char *token;
9240     char **value_ptr;
9241   }
9242   token_to_value_ptr[] =
9243   {
9244     { "title_header",   &tmp_music_file_info.title_header       },
9245     { "artist_header",  &tmp_music_file_info.artist_header      },
9246     { "album_header",   &tmp_music_file_info.album_header       },
9247     { "year_header",    &tmp_music_file_info.year_header        },
9248
9249     { "title",          &tmp_music_file_info.title              },
9250     { "artist",         &tmp_music_file_info.artist             },
9251     { "album",          &tmp_music_file_info.album              },
9252     { "year",           &tmp_music_file_info.year               },
9253
9254     { NULL,             NULL                                    },
9255   };
9256   int i;
9257
9258   filename_music = (is_sound ? getCustomSoundFilename(basename) :
9259                     getCustomMusicFilename(basename));
9260
9261   if (filename_music == NULL)
9262     return NULL;
9263
9264   /* ---------- try to replace file extension ---------- */
9265
9266   filename_prefix = getStringCopy(filename_music);
9267   if (strrchr(filename_prefix, '.') != NULL)
9268     *strrchr(filename_prefix, '.') = '\0';
9269   filename_info = getStringCat2(filename_prefix, ".txt");
9270
9271 #if 0
9272   printf("trying to load file '%s'...\n", filename_info);
9273 #endif
9274
9275   if (fileExists(filename_info))
9276     setup_file_hash = loadSetupFileHash(filename_info);
9277
9278   free(filename_prefix);
9279   free(filename_info);
9280
9281   if (setup_file_hash == NULL)
9282   {
9283     /* ---------- try to add file extension ---------- */
9284
9285     filename_prefix = getStringCopy(filename_music);
9286     filename_info = getStringCat2(filename_prefix, ".txt");
9287
9288 #if 0
9289     printf("trying to load file '%s'...\n", filename_info);
9290 #endif
9291
9292     if (fileExists(filename_info))
9293       setup_file_hash = loadSetupFileHash(filename_info);
9294
9295     free(filename_prefix);
9296     free(filename_info);
9297   }
9298
9299   if (setup_file_hash == NULL)
9300     return NULL;
9301
9302   /* ---------- music file info found ---------- */
9303
9304   clear_mem(&tmp_music_file_info, sizeof(struct MusicFileInfo));
9305
9306   for (i = 0; token_to_value_ptr[i].token != NULL; i++)
9307   {
9308     char *value = getHashEntry(setup_file_hash, token_to_value_ptr[i].token);
9309
9310     *token_to_value_ptr[i].value_ptr =
9311       getStringCopy(value != NULL && *value != '\0' ? value : UNKNOWN_NAME);
9312   }
9313
9314   tmp_music_file_info.basename = getStringCopy(basename);
9315   tmp_music_file_info.music = music;
9316   tmp_music_file_info.is_sound = is_sound;
9317
9318   new_music_file_info = checked_malloc(sizeof(struct MusicFileInfo));
9319   *new_music_file_info = tmp_music_file_info;
9320
9321   return new_music_file_info;
9322 }
9323
9324 static struct MusicFileInfo *get_music_file_info(char *basename, int music)
9325 {
9326   return get_music_file_info_ext(basename, music, FALSE);
9327 }
9328
9329 static struct MusicFileInfo *get_sound_file_info(char *basename, int sound)
9330 {
9331   return get_music_file_info_ext(basename, sound, TRUE);
9332 }
9333
9334 static boolean music_info_listed_ext(struct MusicFileInfo *list,
9335                                      char *basename, boolean is_sound)
9336 {
9337   for (; list != NULL; list = list->next)
9338     if (list->is_sound == is_sound && strEqual(list->basename, basename))
9339       return TRUE;
9340
9341   return FALSE;
9342 }
9343
9344 static boolean music_info_listed(struct MusicFileInfo *list, char *basename)
9345 {
9346   return music_info_listed_ext(list, basename, FALSE);
9347 }
9348
9349 static boolean sound_info_listed(struct MusicFileInfo *list, char *basename)
9350 {
9351   return music_info_listed_ext(list, basename, TRUE);
9352 }
9353
9354 void LoadMusicInfo()
9355 {
9356   char *music_directory = getCustomMusicDirectory();
9357   int num_music = getMusicListSize();
9358   int num_music_noconf = 0;
9359   int num_sounds = getSoundListSize();
9360   DIR *dir;
9361   struct dirent *dir_entry;
9362   struct FileInfo *music, *sound;
9363   struct MusicFileInfo *next, **new;
9364   int i;
9365
9366   while (music_file_info != NULL)
9367   {
9368     next = music_file_info->next;
9369
9370     checked_free(music_file_info->basename);
9371
9372     checked_free(music_file_info->title_header);
9373     checked_free(music_file_info->artist_header);
9374     checked_free(music_file_info->album_header);
9375     checked_free(music_file_info->year_header);
9376
9377     checked_free(music_file_info->title);
9378     checked_free(music_file_info->artist);
9379     checked_free(music_file_info->album);
9380     checked_free(music_file_info->year);
9381
9382     free(music_file_info);
9383
9384     music_file_info = next;
9385   }
9386
9387   new = &music_file_info;
9388
9389   for (i = 0; i < num_music; i++)
9390   {
9391     music = getMusicListEntry(i);
9392
9393     if (music->filename == NULL)
9394       continue;
9395
9396     if (strEqual(music->filename, UNDEFINED_FILENAME))
9397       continue;
9398
9399     /* a configured file may be not recognized as music */
9400     if (!FileIsMusic(music->filename))
9401       continue;
9402
9403 #if 0
9404     printf("::: -> '%s' (configured)\n", music->filename);
9405 #endif
9406
9407     if (!music_info_listed(music_file_info, music->filename))
9408     {
9409       *new = get_music_file_info(music->filename, i);
9410       if (*new != NULL)
9411         new = &(*new)->next;
9412     }
9413   }
9414
9415   if ((dir = opendir(music_directory)) == NULL)
9416   {
9417     Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
9418     return;
9419   }
9420
9421   while ((dir_entry = readdir(dir)) != NULL)    /* loop until last dir entry */
9422   {
9423     char *basename = dir_entry->d_name;
9424     boolean music_already_used = FALSE;
9425     int i;
9426
9427     /* skip all music files that are configured in music config file */
9428     for (i = 0; i < num_music; i++)
9429     {
9430       music = getMusicListEntry(i);
9431
9432       if (music->filename == NULL)
9433         continue;
9434
9435       if (strEqual(basename, music->filename))
9436       {
9437         music_already_used = TRUE;
9438         break;
9439       }
9440     }
9441
9442     if (music_already_used)
9443       continue;
9444
9445     if (!FileIsMusic(basename))
9446       continue;
9447
9448 #if 0
9449     printf("::: -> '%s' (found in directory)\n", basename);
9450 #endif
9451
9452     if (!music_info_listed(music_file_info, basename))
9453     {
9454       *new = get_music_file_info(basename, MAP_NOCONF_MUSIC(num_music_noconf));
9455       if (*new != NULL)
9456         new = &(*new)->next;
9457     }
9458
9459     num_music_noconf++;
9460   }
9461
9462   closedir(dir);
9463
9464   for (i = 0; i < num_sounds; i++)
9465   {
9466     sound = getSoundListEntry(i);
9467
9468     if (sound->filename == NULL)
9469       continue;
9470
9471     if (strEqual(sound->filename, UNDEFINED_FILENAME))
9472       continue;
9473
9474     /* a configured file may be not recognized as sound */
9475     if (!FileIsSound(sound->filename))
9476       continue;
9477
9478 #if 0
9479     printf("::: -> '%s' (configured)\n", sound->filename);
9480 #endif
9481
9482     if (!sound_info_listed(music_file_info, sound->filename))
9483     {
9484       *new = get_sound_file_info(sound->filename, i);
9485       if (*new != NULL)
9486         new = &(*new)->next;
9487     }
9488   }
9489
9490 #if 0
9491   for (next = music_file_info; next != NULL; next = next->next)
9492     printf("::: title == '%s'\n", next->title);
9493 #endif
9494 }
9495
9496 void add_helpanim_entry(int element, int action, int direction, int delay,
9497                         int *num_list_entries)
9498 {
9499   struct HelpAnimInfo *new_list_entry;
9500   (*num_list_entries)++;
9501
9502   helpanim_info =
9503     checked_realloc(helpanim_info,
9504                     *num_list_entries * sizeof(struct HelpAnimInfo));
9505   new_list_entry = &helpanim_info[*num_list_entries - 1];
9506
9507   new_list_entry->element = element;
9508   new_list_entry->action = action;
9509   new_list_entry->direction = direction;
9510   new_list_entry->delay = delay;
9511 }
9512
9513 void print_unknown_token(char *filename, char *token, int token_nr)
9514 {
9515   if (token_nr == 0)
9516   {
9517     Error(ERR_INFO_LINE, "-");
9518     Error(ERR_INFO, "warning: unknown token(s) found in config file:");
9519     Error(ERR_INFO, "- config file: '%s'", filename);
9520   }
9521
9522   Error(ERR_INFO, "- token: '%s'", token);
9523 }
9524
9525 void print_unknown_token_end(int token_nr)
9526 {
9527   if (token_nr > 0)
9528     Error(ERR_INFO_LINE, "-");
9529 }
9530
9531 void LoadHelpAnimInfo()
9532 {
9533   char *filename = getHelpAnimFilename();
9534   SetupFileList *setup_file_list = NULL, *list;
9535   SetupFileHash *element_hash, *action_hash, *direction_hash;
9536   int num_list_entries = 0;
9537   int num_unknown_tokens = 0;
9538   int i;
9539
9540   if (fileExists(filename))
9541     setup_file_list = loadSetupFileList(filename);
9542
9543   if (setup_file_list == NULL)
9544   {
9545     /* use reliable default values from static configuration */
9546     SetupFileList *insert_ptr;
9547
9548     insert_ptr = setup_file_list =
9549       newSetupFileList(helpanim_config[0].token,
9550                        helpanim_config[0].value);
9551
9552     for (i = 1; helpanim_config[i].token; i++)
9553       insert_ptr = addListEntry(insert_ptr,
9554                                 helpanim_config[i].token,
9555                                 helpanim_config[i].value);
9556   }
9557
9558   element_hash   = newSetupFileHash();
9559   action_hash    = newSetupFileHash();
9560   direction_hash = newSetupFileHash();
9561
9562   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
9563     setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
9564
9565   for (i = 0; i < NUM_ACTIONS; i++)
9566     setHashEntry(action_hash, element_action_info[i].suffix,
9567                  i_to_a(element_action_info[i].value));
9568
9569   /* do not store direction index (bit) here, but direction value! */
9570   for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
9571     setHashEntry(direction_hash, element_direction_info[i].suffix,
9572                  i_to_a(1 << element_direction_info[i].value));
9573
9574   for (list = setup_file_list; list != NULL; list = list->next)
9575   {
9576     char *element_token, *action_token, *direction_token;
9577     char *element_value, *action_value, *direction_value;
9578     int delay = atoi(list->value);
9579
9580     if (strEqual(list->token, "end"))
9581     {
9582       add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
9583
9584       continue;
9585     }
9586
9587     /* first try to break element into element/action/direction parts;
9588        if this does not work, also accept combined "element[.act][.dir]"
9589        elements (like "dynamite.active"), which are unique elements */
9590
9591     if (strchr(list->token, '.') == NULL)       /* token contains no '.' */
9592     {
9593       element_value = getHashEntry(element_hash, list->token);
9594       if (element_value != NULL)        /* element found */
9595         add_helpanim_entry(atoi(element_value), -1, -1, delay,
9596                            &num_list_entries);
9597       else
9598       {
9599         /* no further suffixes found -- this is not an element */
9600         print_unknown_token(filename, list->token, num_unknown_tokens++);
9601       }
9602
9603       continue;
9604     }
9605
9606     /* token has format "<prefix>.<something>" */
9607
9608     action_token = strchr(list->token, '.');    /* suffix may be action ... */
9609     direction_token = action_token;             /* ... or direction */
9610
9611     element_token = getStringCopy(list->token);
9612     *strchr(element_token, '.') = '\0';
9613
9614     element_value = getHashEntry(element_hash, element_token);
9615
9616     if (element_value == NULL)          /* this is no element */
9617     {
9618       element_value = getHashEntry(element_hash, list->token);
9619       if (element_value != NULL)        /* combined element found */
9620         add_helpanim_entry(atoi(element_value), -1, -1, delay,
9621                            &num_list_entries);
9622       else
9623         print_unknown_token(filename, list->token, num_unknown_tokens++);
9624
9625       free(element_token);
9626
9627       continue;
9628     }
9629
9630     action_value = getHashEntry(action_hash, action_token);
9631
9632     if (action_value != NULL)           /* action found */
9633     {
9634       add_helpanim_entry(atoi(element_value), atoi(action_value), -1, delay,
9635                     &num_list_entries);
9636
9637       free(element_token);
9638
9639       continue;
9640     }
9641
9642     direction_value = getHashEntry(direction_hash, direction_token);
9643
9644     if (direction_value != NULL)        /* direction found */
9645     {
9646       add_helpanim_entry(atoi(element_value), -1, atoi(direction_value), delay,
9647                          &num_list_entries);
9648
9649       free(element_token);
9650
9651       continue;
9652     }
9653
9654     if (strchr(action_token + 1, '.') == NULL)
9655     {
9656       /* no further suffixes found -- this is not an action nor direction */
9657
9658       element_value = getHashEntry(element_hash, list->token);
9659       if (element_value != NULL)        /* combined element found */
9660         add_helpanim_entry(atoi(element_value), -1, -1, delay,
9661                            &num_list_entries);
9662       else
9663         print_unknown_token(filename, list->token, num_unknown_tokens++);
9664
9665       free(element_token);
9666
9667       continue;
9668     }
9669
9670     /* token has format "<prefix>.<suffix>.<something>" */
9671
9672     direction_token = strchr(action_token + 1, '.');
9673
9674     action_token = getStringCopy(action_token);
9675     *strchr(action_token + 1, '.') = '\0';
9676
9677     action_value = getHashEntry(action_hash, action_token);
9678
9679     if (action_value == NULL)           /* this is no action */
9680     {
9681       element_value = getHashEntry(element_hash, list->token);
9682       if (element_value != NULL)        /* combined element found */
9683         add_helpanim_entry(atoi(element_value), -1, -1, delay,
9684                            &num_list_entries);
9685       else
9686         print_unknown_token(filename, list->token, num_unknown_tokens++);
9687
9688       free(element_token);
9689       free(action_token);
9690
9691       continue;
9692     }
9693
9694     direction_value = getHashEntry(direction_hash, direction_token);
9695
9696     if (direction_value != NULL)        /* direction found */
9697     {
9698       add_helpanim_entry(atoi(element_value), atoi(action_value),
9699                          atoi(direction_value), delay, &num_list_entries);
9700
9701       free(element_token);
9702       free(action_token);
9703
9704       continue;
9705     }
9706
9707     /* this is no direction */
9708
9709     element_value = getHashEntry(element_hash, list->token);
9710     if (element_value != NULL)          /* combined element found */
9711       add_helpanim_entry(atoi(element_value), -1, -1, delay,
9712                          &num_list_entries);
9713     else
9714       print_unknown_token(filename, list->token, num_unknown_tokens++);
9715
9716     free(element_token);
9717     free(action_token);
9718   }
9719
9720   print_unknown_token_end(num_unknown_tokens);
9721
9722   add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
9723   add_helpanim_entry(HELPANIM_LIST_END,  -1, -1, -1, &num_list_entries);
9724
9725   freeSetupFileList(setup_file_list);
9726   freeSetupFileHash(element_hash);
9727   freeSetupFileHash(action_hash);
9728   freeSetupFileHash(direction_hash);
9729
9730 #if 0
9731   for (i = 0; i < num_list_entries; i++)
9732     printf("::: '%s': %d, %d, %d => %d\n",
9733            EL_NAME(helpanim_info[i].element),
9734            helpanim_info[i].element,
9735            helpanim_info[i].action,
9736            helpanim_info[i].direction,
9737            helpanim_info[i].delay);
9738 #endif
9739 }
9740
9741 void LoadHelpTextInfo()
9742 {
9743   char *filename = getHelpTextFilename();
9744   int i;
9745
9746   if (helptext_info != NULL)
9747   {
9748     freeSetupFileHash(helptext_info);
9749     helptext_info = NULL;
9750   }
9751
9752   if (fileExists(filename))
9753     helptext_info = loadSetupFileHash(filename);
9754
9755   if (helptext_info == NULL)
9756   {
9757     /* use reliable default values from static configuration */
9758     helptext_info = newSetupFileHash();
9759
9760     for (i = 0; helptext_config[i].token; i++)
9761       setHashEntry(helptext_info,
9762                    helptext_config[i].token,
9763                    helptext_config[i].value);
9764   }
9765
9766 #if 0
9767   BEGIN_HASH_ITERATION(helptext_info, itr)
9768   {
9769     printf("::: '%s' => '%s'\n",
9770            HASH_ITERATION_TOKEN(itr), HASH_ITERATION_VALUE(itr));
9771   }
9772   END_HASH_ITERATION(hash, itr)
9773 #endif
9774 }
9775
9776
9777 /* ------------------------------------------------------------------------- */
9778 /* convert levels                                                            */
9779 /* ------------------------------------------------------------------------- */
9780
9781 #define MAX_NUM_CONVERT_LEVELS          1000
9782
9783 void ConvertLevels()
9784 {
9785   static LevelDirTree *convert_leveldir = NULL;
9786   static int convert_level_nr = -1;
9787   static int num_levels_handled = 0;
9788   static int num_levels_converted = 0;
9789   static boolean levels_failed[MAX_NUM_CONVERT_LEVELS];
9790   int i;
9791
9792   convert_leveldir = getTreeInfoFromIdentifier(leveldir_first,
9793                                                global.convert_leveldir);
9794
9795   if (convert_leveldir == NULL)
9796     Error(ERR_EXIT, "no such level identifier: '%s'",
9797           global.convert_leveldir);
9798
9799   leveldir_current = convert_leveldir;
9800
9801   if (global.convert_level_nr != -1)
9802   {
9803     convert_leveldir->first_level = global.convert_level_nr;
9804     convert_leveldir->last_level  = global.convert_level_nr;
9805   }
9806
9807   convert_level_nr = convert_leveldir->first_level;
9808
9809   printf_line("=", 79);
9810   printf("Converting levels\n");
9811   printf_line("-", 79);
9812   printf("Level series identifier: '%s'\n", convert_leveldir->identifier);
9813   printf("Level series name:       '%s'\n", convert_leveldir->name);
9814   printf("Level series author:     '%s'\n", convert_leveldir->author);
9815   printf("Number of levels:        %d\n",   convert_leveldir->levels);
9816   printf_line("=", 79);
9817   printf("\n");
9818
9819   for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++)
9820     levels_failed[i] = FALSE;
9821
9822   while (convert_level_nr <= convert_leveldir->last_level)
9823   {
9824     char *level_filename;
9825     boolean new_level;
9826
9827     level_nr = convert_level_nr++;
9828
9829     printf("Level %03d: ", level_nr);
9830
9831     LoadLevel(level_nr);
9832     if (level.no_valid_file)
9833     {
9834       printf("(no level)\n");
9835       continue;
9836     }
9837
9838     printf("converting level ... ");
9839
9840     level_filename = getDefaultLevelFilename(level_nr);
9841     new_level = !fileExists(level_filename);
9842
9843     if (new_level)
9844     {
9845       SaveLevel(level_nr);
9846
9847       num_levels_converted++;
9848
9849       printf("converted.\n");
9850     }
9851     else
9852     {
9853       if (level_nr >= 0 && level_nr < MAX_NUM_CONVERT_LEVELS)
9854         levels_failed[level_nr] = TRUE;
9855
9856       printf("NOT CONVERTED -- LEVEL ALREADY EXISTS.\n");
9857     }
9858
9859     num_levels_handled++;
9860   }
9861
9862   printf("\n");
9863   printf_line("=", 79);
9864   printf("Number of levels handled: %d\n", num_levels_handled);
9865   printf("Number of levels converted: %d (%d%%)\n", num_levels_converted,
9866          (num_levels_handled ?
9867           num_levels_converted * 100 / num_levels_handled : 0));
9868   printf_line("-", 79);
9869   printf("Summary (for automatic parsing by scripts):\n");
9870   printf("LEVELDIR '%s', CONVERTED %d/%d (%d%%)",
9871          convert_leveldir->identifier, num_levels_converted,
9872          num_levels_handled,
9873          (num_levels_handled ?
9874           num_levels_converted * 100 / num_levels_handled : 0));
9875
9876   if (num_levels_handled != num_levels_converted)
9877   {
9878     printf(", FAILED:");
9879     for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++)
9880       if (levels_failed[i])
9881         printf(" %03d", i);
9882   }
9883
9884   printf("\n");
9885   printf_line("=", 79);
9886
9887   CloseAllAndExit(0);
9888 }
9889
9890
9891 /* ------------------------------------------------------------------------- */
9892 /* create and save images for use in level sketches (raw BMP format)         */
9893 /* ------------------------------------------------------------------------- */
9894
9895 void CreateLevelSketchImages()
9896 {
9897 #if defined(TARGET_SDL)
9898   Bitmap *bitmap1;
9899   Bitmap *bitmap2;
9900   int i;
9901
9902   InitElementPropertiesGfxElement();
9903
9904   bitmap1 = CreateBitmap(TILEX, TILEY, DEFAULT_DEPTH);
9905   bitmap2 = CreateBitmap(MINI_TILEX, MINI_TILEY, DEFAULT_DEPTH);
9906
9907   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9908   {
9909     Bitmap *src_bitmap;
9910     int src_x, src_y;
9911     int element = getMappedElement(i);
9912     int graphic = el2edimg(element);
9913     char basename1[16];
9914     char basename2[16];
9915     char *filename1;
9916     char *filename2;
9917
9918     sprintf(basename1, "%03d.bmp", i);
9919     sprintf(basename2, "%03ds.bmp", i);
9920
9921     filename1 = getPath2(global.create_images_dir, basename1);
9922     filename2 = getPath2(global.create_images_dir, basename2);
9923
9924     getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
9925     BlitBitmap(src_bitmap, bitmap1, src_x, src_y, TILEX, TILEY, 0, 0);
9926
9927     if (SDL_SaveBMP(bitmap1->surface, filename1) != 0)
9928       Error(ERR_EXIT, "cannot save level sketch image file '%s'", filename1);
9929
9930     getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
9931     BlitBitmap(src_bitmap, bitmap2, src_x, src_y, MINI_TILEX, MINI_TILEY, 0, 0);
9932
9933     if (SDL_SaveBMP(bitmap2->surface, filename2) != 0)
9934       Error(ERR_EXIT, "cannot save level sketch image file '%s'", filename2);
9935
9936     free(filename1);
9937     free(filename2);
9938
9939     if (options.debug)
9940       printf("%03d `%03d%c", i, i, (i % 10 < 9 ? ' ' : '\n'));
9941   }
9942
9943   FreeBitmap(bitmap1);
9944   FreeBitmap(bitmap2);
9945
9946   if (options.debug)
9947     printf("\n");
9948
9949   Error(ERR_INFO, "%d normal and small images created", NUM_FILE_ELEMENTS);
9950
9951   CloseAllAndExit(0);
9952 #endif
9953 }
9954
9955
9956 /* ------------------------------------------------------------------------- */
9957 /* create and save images for custom and group elements (raw BMP format)     */
9958 /* ------------------------------------------------------------------------- */
9959
9960 void CreateCustomElementImages()
9961 {
9962 #if defined(TARGET_SDL)
9963   char *filename = "graphics.classic/RocksCE.bmp";
9964   Bitmap *bitmap;
9965   Bitmap *src_bitmap;
9966   int dummy_graphic = IMG_CUSTOM_99;
9967   int yoffset_ce = 0;
9968   int yoffset_ge = (TILEY * NUM_CUSTOM_ELEMENTS / 16);
9969   int src_x, src_y;
9970   int i;
9971
9972   bitmap = CreateBitmap(TILEX * 16 * 2,
9973                         TILEY * (NUM_CUSTOM_ELEMENTS + NUM_GROUP_ELEMENTS) / 16,
9974                         DEFAULT_DEPTH);
9975
9976   getGraphicSource(dummy_graphic, 0, &src_bitmap, &src_x, &src_y);
9977
9978   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
9979   {
9980     int x = i % 16;
9981     int y = i / 16;
9982     int ii = i + 1;
9983     int j;
9984
9985     BlitBitmap(src_bitmap, bitmap, 0, 0, TILEX, TILEY,
9986                TILEX * x, TILEY * y + yoffset_ce);
9987
9988     BlitBitmap(src_bitmap, bitmap, 0, TILEY, TILEX, TILEY,
9989                TILEX * x + TILEX * 16, TILEY * y + yoffset_ce);
9990
9991     for (j = 2; j >= 0; j--)
9992     {
9993       int c = ii % 10;
9994
9995       BlitBitmap(src_bitmap, bitmap, TILEX + c * 7, 0, 6, 10,
9996                  TILEX * x + 6 + j * 7,
9997                  TILEY * y + 11 + yoffset_ce);
9998
9999       BlitBitmap(src_bitmap, bitmap, TILEX + c * 8, TILEY, 6, 10,
10000                  TILEX * 16 + TILEX * x + 6 + j * 8,
10001                  TILEY * y + 10 + yoffset_ce);
10002
10003       ii /= 10;
10004     }
10005   }
10006
10007   for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
10008   {
10009     int x = i % 16;
10010     int y = i / 16;
10011     int ii = i + 1;
10012     int j;
10013
10014     BlitBitmap(src_bitmap, bitmap, 0, 0, TILEX, TILEY,
10015                TILEX * x, TILEY * y + yoffset_ge);
10016
10017     BlitBitmap(src_bitmap, bitmap, 0, TILEY, TILEX, TILEY,
10018                TILEX * x + TILEX * 16, TILEY * y + yoffset_ge);
10019
10020     for (j = 1; j >= 0; j--)
10021     {
10022       int c = ii % 10;
10023
10024       BlitBitmap(src_bitmap, bitmap, TILEX + c * 10, 11, 10, 10,
10025                  TILEX * x + 6 + j * 10,
10026                  TILEY * y + 11 + yoffset_ge);
10027
10028       BlitBitmap(src_bitmap, bitmap, TILEX + c * 8, TILEY + 12, 6, 10,
10029                  TILEX * 16 + TILEX * x + 10 + j * 8,
10030                  TILEY * y + 10 + yoffset_ge);
10031
10032       ii /= 10;
10033     }
10034   }
10035
10036   if (SDL_SaveBMP(bitmap->surface, filename) != 0)
10037     Error(ERR_EXIT, "cannot save CE graphics file '%s'", filename);
10038
10039   FreeBitmap(bitmap);
10040
10041   CloseAllAndExit(0);
10042 #endif
10043 }
10044
10045 #if 0
10046 void CreateLevelSketchImages_TEST()
10047 {
10048   void CreateCustomElementImages()
10049 }
10050 #endif