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