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