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