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