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