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