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