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