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