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