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