rnd-20091211-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 #if 1
6335
6336 static boolean check_special_flags(char *flag)
6337 {
6338 #if 0
6339   printf("::: '%s', '%s', '%s'\n",
6340          flag,
6341          options.special_flags,
6342          leveldir_current->special_flags);
6343 #endif
6344
6345   if (strEqual(options.special_flags, flag) ||
6346       strEqual(leveldir_current->special_flags, flag))
6347     return TRUE;
6348
6349   return FALSE;
6350 }
6351
6352 #else
6353
6354 #define SPECIAL_FLAG_LOAD_XSB_TO_CES    (1 << 0)
6355
6356 static unsigned long get_special_flags(char *flags_string)
6357 {
6358   unsigned long flags_value = 0;
6359
6360   if (strEqual(flags_string, "load_xsb_to_ces"))
6361     flags_value = SPECIAL_FLAG_LOAD_XSB_TO_CES;
6362
6363   return flags_value;
6364 }
6365
6366 #endif
6367
6368 int getMappedElement_SB(int element_ascii, boolean use_ces)
6369 {
6370   static struct
6371   {
6372     int ascii;
6373     int sb;
6374     int ce;
6375   }
6376   sb_element_mapping[] =
6377   {
6378     { ' ', EL_EMPTY,                EL_CUSTOM_1 },  /* floor (space) */
6379     { '#', EL_STEELWALL,            EL_CUSTOM_2 },  /* wall */
6380     { '@', EL_PLAYER_1,             EL_CUSTOM_3 },  /* player */
6381     { '$', EL_SOKOBAN_OBJECT,       EL_CUSTOM_4 },  /* box */
6382     { '.', EL_SOKOBAN_FIELD_EMPTY,  EL_CUSTOM_5 },  /* goal square */
6383     { '*', EL_SOKOBAN_FIELD_FULL,   EL_CUSTOM_6 },  /* box on goal square */
6384     { '+', EL_SOKOBAN_FIELD_PLAYER, EL_CUSTOM_7 },  /* player on goal square */
6385     { '_', EL_INVISIBLE_STEELWALL,  EL_CUSTOM_8 },  /* floor beyond border */
6386
6387     { 0,   -1,                      -1          },
6388   };
6389
6390   int i;
6391
6392   for (i = 0; sb_element_mapping[i].ascii != 0; i++)
6393     if (element_ascii == sb_element_mapping[i].ascii)
6394       return (use_ces ? sb_element_mapping[i].ce : sb_element_mapping[i].sb);
6395
6396   return EL_UNDEFINED;
6397 }
6398
6399 static void LoadLevelFromFileInfo_SB(struct LevelInfo *level,
6400                                      struct LevelFileInfo *level_file_info)
6401 {
6402   char *filename = level_file_info->filename;
6403   char line[MAX_LINE_LEN], line_raw[MAX_LINE_LEN], previous_line[MAX_LINE_LEN];
6404   char last_comment[MAX_LINE_LEN];
6405   char level_name[MAX_LINE_LEN];
6406   char *line_ptr;
6407   FILE *file;
6408   int num_levels_to_skip = level_file_info->nr - leveldir_current->first_level;
6409   boolean read_continued_line = FALSE;
6410   boolean reading_playfield = FALSE;
6411   boolean got_valid_playfield_line = FALSE;
6412   boolean invalid_playfield_char = FALSE;
6413 #if 1
6414   boolean load_xsb_to_ces = check_special_flags("load_xsb_to_ces");
6415 #else
6416   boolean load_xsb_to_ces = options.special_flags & SPECIAL_FLAG_LOAD_XSB_TO_CES;
6417 #endif
6418   int file_level_nr = 0;
6419   int line_nr = 0;
6420   int x, y;
6421
6422 #if 0
6423   printf("::: looking for level number %d [%d]\n",
6424          level_file_info->nr, num_levels_to_skip);
6425 #endif
6426
6427   last_comment[0] = '\0';
6428   level_name[0] = '\0';
6429
6430   if (!(file = fopen(filename, MODE_READ)))
6431   {
6432     level->no_valid_file = TRUE;
6433
6434     Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
6435
6436     return;
6437   }
6438
6439   while (!feof(file))
6440   {
6441     /* level successfully read, but next level may follow here */
6442     if (!got_valid_playfield_line && reading_playfield)
6443     {
6444 #if 0
6445       printf("::: read complete playfield\n");
6446 #endif
6447
6448       /* read playfield from single level file -- skip remaining file */
6449       if (!level_file_info->packed)
6450         break;
6451
6452       if (file_level_nr >= num_levels_to_skip)
6453         break;
6454
6455       file_level_nr++;
6456
6457       last_comment[0] = '\0';
6458       level_name[0] = '\0';
6459
6460       reading_playfield = FALSE;
6461     }
6462
6463     got_valid_playfield_line = FALSE;
6464
6465     /* read next line of input file */
6466     if (!fgets(line, MAX_LINE_LEN, file))
6467       break;
6468
6469     /* check if line was completely read and is terminated by line break */
6470     if (strlen(line) > 0 && line[strlen(line) - 1] == '\n')
6471       line_nr++;
6472
6473     /* cut trailing line break (this can be newline and/or carriage return) */
6474     for (line_ptr = &line[strlen(line)]; line_ptr >= line; line_ptr--)
6475       if ((*line_ptr == '\n' || *line_ptr == '\r') && *(line_ptr + 1) == '\0')
6476         *line_ptr = '\0';
6477
6478     /* copy raw input line for later use (mainly debugging output) */
6479     strcpy(line_raw, line);
6480
6481     if (read_continued_line)
6482     {
6483       /* append new line to existing line, if there is enough space */
6484       if (strlen(previous_line) + strlen(line_ptr) < MAX_LINE_LEN)
6485         strcat(previous_line, line_ptr);
6486
6487       strcpy(line, previous_line);      /* copy storage buffer to line */
6488
6489       read_continued_line = FALSE;
6490     }
6491
6492     /* if the last character is '\', continue at next line */
6493     if (strlen(line) > 0 && line[strlen(line) - 1] == '\\')
6494     {
6495       line[strlen(line) - 1] = '\0';    /* cut off trailing backslash */
6496       strcpy(previous_line, line);      /* copy line to storage buffer */
6497
6498       read_continued_line = TRUE;
6499
6500       continue;
6501     }
6502
6503     /* skip empty lines */
6504     if (line[0] == '\0')
6505       continue;
6506
6507     /* extract comment text from comment line */
6508     if (line[0] == ';')
6509     {
6510       for (line_ptr = line; *line_ptr; line_ptr++)
6511         if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != ';')
6512           break;
6513
6514       strcpy(last_comment, line_ptr);
6515
6516 #if 0
6517       printf("::: found comment '%s' in line %d\n", last_comment, line_nr);
6518 #endif
6519
6520       continue;
6521     }
6522
6523     /* extract level title text from line containing level title */
6524     if (line[0] == '\'')
6525     {
6526       strcpy(level_name, &line[1]);
6527
6528       if (strlen(level_name) > 0 && level_name[strlen(level_name) - 1] == '\'')
6529         level_name[strlen(level_name) - 1] = '\0';
6530
6531 #if 0
6532       printf("::: found level name '%s' in line %d\n", level_name, line_nr);
6533 #endif
6534
6535       continue;
6536     }
6537
6538     /* skip lines containing only spaces (or empty lines) */
6539     for (line_ptr = line; *line_ptr; line_ptr++)
6540       if (*line_ptr != ' ')
6541         break;
6542     if (*line_ptr == '\0')
6543       continue;
6544
6545     /* at this point, we have found a line containing part of a playfield */
6546
6547 #if 0
6548     printf("::: found playfield row in line %d\n", line_nr);
6549 #endif
6550
6551     got_valid_playfield_line = TRUE;
6552
6553     if (!reading_playfield)
6554     {
6555       reading_playfield = TRUE;
6556       invalid_playfield_char = FALSE;
6557
6558       for (x = 0; x < MAX_LEV_FIELDX; x++)
6559         for (y = 0; y < MAX_LEV_FIELDY; y++)
6560           level->field[x][y] = getMappedElement_SB(' ', load_xsb_to_ces);
6561
6562       level->fieldx = 0;
6563       level->fieldy = 0;
6564
6565       /* start with topmost tile row */
6566       y = 0;
6567     }
6568
6569     /* skip playfield line if larger row than allowed */
6570     if (y >= MAX_LEV_FIELDY)
6571       continue;
6572
6573     /* start with leftmost tile column */
6574     x = 0;
6575
6576     /* read playfield elements from line */
6577     for (line_ptr = line; *line_ptr; line_ptr++)
6578     {
6579       int mapped_sb_element = getMappedElement_SB(*line_ptr, load_xsb_to_ces);
6580
6581       /* stop parsing playfield line if larger column than allowed */
6582       if (x >= MAX_LEV_FIELDX)
6583         break;
6584
6585       if (mapped_sb_element == EL_UNDEFINED)
6586       {
6587         invalid_playfield_char = TRUE;
6588
6589         break;
6590       }
6591
6592       level->field[x][y] = mapped_sb_element;
6593
6594       /* continue with next tile column */
6595       x++;
6596
6597       level->fieldx = MAX(x, level->fieldx);
6598     }
6599
6600     if (invalid_playfield_char)
6601     {
6602       /* if first playfield line, treat invalid lines as comment lines */
6603       if (y == 0)
6604         reading_playfield = FALSE;
6605
6606       continue;
6607     }
6608
6609     /* continue with next tile row */
6610     y++;
6611   }
6612
6613   fclose(file);
6614
6615   level->fieldy = y;
6616
6617   level->fieldx = MIN(MAX(MIN_LEV_FIELDX, level->fieldx), MAX_LEV_FIELDX);
6618   level->fieldy = MIN(MAX(MIN_LEV_FIELDY, level->fieldy), MAX_LEV_FIELDY);
6619
6620   if (!reading_playfield)
6621   {
6622     level->no_valid_file = TRUE;
6623
6624     Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
6625
6626     return;
6627   }
6628
6629   if (*level_name != '\0')
6630   {
6631     strncpy(level->name, level_name, MAX_LEVEL_NAME_LEN);
6632     level->name[MAX_LEVEL_NAME_LEN] = '\0';
6633
6634 #if 0
6635     printf(":1: level name: '%s'\n", level->name);
6636 #endif
6637   }
6638   else if (*last_comment != '\0')
6639   {
6640     strncpy(level->name, last_comment, MAX_LEVEL_NAME_LEN);
6641     level->name[MAX_LEVEL_NAME_LEN] = '\0';
6642
6643 #if 0
6644     printf(":2: level name: '%s'\n", level->name);
6645 #endif
6646   }
6647   else
6648   {
6649     sprintf(level->name, "--> Level %d <--", level_file_info->nr);
6650   }
6651
6652   /* set all empty fields beyond the border walls to invisible steel wall */
6653   for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
6654   {
6655     if ((x == 0 || x == level->fieldx - 1 ||
6656          y == 0 || y == level->fieldy - 1) &&
6657         level->field[x][y] == getMappedElement_SB(' ', load_xsb_to_ces))
6658       FloodFillLevel(x, y, getMappedElement_SB('_', load_xsb_to_ces),
6659                      level->field, level->fieldx, level->fieldy);
6660   }
6661
6662   if (load_xsb_to_ces)
6663   {
6664     level->time = 0;
6665     level->use_step_counter = TRUE;
6666
6667     level->initial_player_stepsize[0] = STEPSIZE_SLOW;
6668
6669     level->use_custom_template = TRUE;
6670   }
6671 }
6672
6673
6674 /* ------------------------------------------------------------------------- */
6675 /* functions for handling native levels                                      */
6676 /* ------------------------------------------------------------------------- */
6677
6678 static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,
6679                                      struct LevelFileInfo *level_file_info)
6680 {
6681   if (!LoadNativeLevel_EM(level_file_info->filename))
6682     level->no_valid_file = TRUE;
6683 }
6684
6685 static void LoadLevelFromFileInfo_SP(struct LevelInfo *level,
6686                                      struct LevelFileInfo *level_file_info)
6687 {
6688   int pos = 0;
6689
6690   /* determine position of requested level inside level package */
6691   if (level_file_info->packed)
6692     pos = level_file_info->nr - leveldir_current->first_level;
6693
6694   if (!LoadNativeLevel_SP(level_file_info->filename, pos))
6695     level->no_valid_file = TRUE;
6696 }
6697
6698 void CopyNativeLevel_RND_to_Native(struct LevelInfo *level)
6699 {
6700   if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
6701     CopyNativeLevel_RND_to_EM(level);
6702   else if (level->game_engine_type == GAME_ENGINE_TYPE_SP)
6703     CopyNativeLevel_RND_to_SP(level);
6704 }
6705
6706 void CopyNativeLevel_Native_to_RND(struct LevelInfo *level)
6707 {
6708   if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
6709     CopyNativeLevel_EM_to_RND(level);
6710   else if (level->game_engine_type == GAME_ENGINE_TYPE_SP)
6711     CopyNativeLevel_SP_to_RND(level);
6712 }
6713
6714
6715 /* ------------------------------------------------------------------------- */
6716 /* functions for loading generic level                                       */
6717 /* ------------------------------------------------------------------------- */
6718
6719 void LoadLevelFromFileInfo(struct LevelInfo *level,
6720                            struct LevelFileInfo *level_file_info)
6721 {
6722   /* always start with reliable default values */
6723   setLevelInfoToDefaults(level);
6724
6725   switch (level_file_info->type)
6726   {
6727     case LEVEL_FILE_TYPE_RND:
6728       LoadLevelFromFileInfo_RND(level, level_file_info);
6729       break;
6730
6731     case LEVEL_FILE_TYPE_EM:
6732       LoadLevelFromFileInfo_EM(level, level_file_info);
6733       level->game_engine_type = GAME_ENGINE_TYPE_EM;
6734       break;
6735
6736     case LEVEL_FILE_TYPE_SP:
6737       LoadLevelFromFileInfo_SP(level, level_file_info);
6738       level->game_engine_type = GAME_ENGINE_TYPE_SP;
6739       break;
6740
6741     case LEVEL_FILE_TYPE_DC:
6742       LoadLevelFromFileInfo_DC(level, level_file_info);
6743       break;
6744
6745     case LEVEL_FILE_TYPE_SB:
6746       LoadLevelFromFileInfo_SB(level, level_file_info);
6747       break;
6748
6749     default:
6750       LoadLevelFromFileInfo_RND(level, level_file_info);
6751       break;
6752   }
6753
6754   /* if level file is invalid, restore level structure to default values */
6755   if (level->no_valid_file)
6756     setLevelInfoToDefaults(level);
6757
6758   if (level->game_engine_type == GAME_ENGINE_TYPE_UNKNOWN)
6759     level->game_engine_type = GAME_ENGINE_TYPE_RND;
6760
6761   if (level_file_info->type != LEVEL_FILE_TYPE_RND)
6762     CopyNativeLevel_Native_to_RND(level);
6763 }
6764
6765 void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
6766 {
6767   static struct LevelFileInfo level_file_info;
6768
6769   /* always start with reliable default values */
6770   setFileInfoToDefaults(&level_file_info);
6771
6772   level_file_info.nr = 0;                       /* unknown level number */
6773   level_file_info.type = LEVEL_FILE_TYPE_RND;   /* no others supported yet */
6774   level_file_info.filename = filename;
6775
6776   LoadLevelFromFileInfo(level, &level_file_info);
6777 }
6778
6779 static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
6780 {
6781   int i, j;
6782
6783   if (leveldir_current == NULL)         /* only when dumping level */
6784     return;
6785
6786   /* all engine modifications also valid for levels which use latest engine */
6787   if (level->game_version < VERSION_IDENT(3,2,0,5))
6788   {
6789     /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */
6790     level->score[SC_TIME_BONUS] /= 10;
6791   }
6792
6793 #if 0
6794   leveldir_current->latest_engine = TRUE;       /* !!! TEST ONLY !!! */
6795 #endif
6796
6797   if (leveldir_current->latest_engine)
6798   {
6799     /* ---------- use latest game engine ----------------------------------- */
6800
6801     /* For all levels which are forced to use the latest game engine version
6802        (normally all but user contributed, private and undefined levels), set
6803        the game engine version to the actual version; this allows for actual
6804        corrections in the game engine to take effect for existing, converted
6805        levels (from "classic" or other existing games) to make the emulation
6806        of the corresponding game more accurate, while (hopefully) not breaking
6807        existing levels created from other players. */
6808
6809     level->game_version = GAME_VERSION_ACTUAL;
6810
6811     /* Set special EM style gems behaviour: EM style gems slip down from
6812        normal, steel and growing wall. As this is a more fundamental change,
6813        it seems better to set the default behaviour to "off" (as it is more
6814        natural) and make it configurable in the level editor (as a property
6815        of gem style elements). Already existing converted levels (neither
6816        private nor contributed levels) are changed to the new behaviour. */
6817
6818     if (level->file_version < FILE_VERSION_2_0)
6819       level->em_slippery_gems = TRUE;
6820
6821     return;
6822   }
6823
6824   /* ---------- use game engine the level was created with ----------------- */
6825
6826   /* For all levels which are not forced to use the latest game engine
6827      version (normally user contributed, private and undefined levels),
6828      use the version of the game engine the levels were created for.
6829
6830      Since 2.0.1, the game engine version is now directly stored
6831      in the level file (chunk "VERS"), so there is no need anymore
6832      to set the game version from the file version (except for old,
6833      pre-2.0 levels, where the game version is still taken from the
6834      file format version used to store the level -- see above). */
6835
6836   /* player was faster than enemies in 1.0.0 and before */
6837   if (level->file_version == FILE_VERSION_1_0)
6838     for (i = 0; i < MAX_PLAYERS; i++)
6839       level->initial_player_stepsize[i] = STEPSIZE_FAST;
6840
6841   /* default behaviour for EM style gems was "slippery" only in 2.0.1 */
6842   if (level->game_version == VERSION_IDENT(2,0,1,0))
6843     level->em_slippery_gems = TRUE;
6844
6845   /* springs could be pushed over pits before (pre-release version) 2.2.0 */
6846   if (level->game_version < VERSION_IDENT(2,2,0,0))
6847     level->use_spring_bug = TRUE;
6848
6849   if (level->game_version < VERSION_IDENT(3,2,0,5))
6850   {
6851     /* time orb caused limited time in endless time levels before 3.2.0-5 */
6852     level->use_time_orb_bug = TRUE;
6853
6854     /* default behaviour for snapping was "no snap delay" before 3.2.0-5 */
6855     level->block_snap_field = FALSE;
6856
6857     /* extra time score was same value as time left score before 3.2.0-5 */
6858     level->extra_time_score = level->score[SC_TIME_BONUS];
6859
6860 #if 0
6861     /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */
6862     level->score[SC_TIME_BONUS] /= 10;
6863 #endif
6864   }
6865
6866   if (level->game_version < VERSION_IDENT(3,2,0,7))
6867   {
6868     /* default behaviour for snapping was "not continuous" before 3.2.0-7 */
6869     level->continuous_snapping = FALSE;
6870   }
6871
6872   /* only few elements were able to actively move into acid before 3.1.0 */
6873   /* trigger settings did not exist before 3.1.0; set to default "any" */
6874   if (level->game_version < VERSION_IDENT(3,1,0,0))
6875   {
6876     /* correct "can move into acid" settings (all zero in old levels) */
6877
6878     level->can_move_into_acid_bits = 0; /* nothing can move into acid */
6879     level->dont_collide_with_bits = 0; /* nothing is deadly when colliding */
6880
6881     setMoveIntoAcidProperty(level, EL_ROBOT,     TRUE);
6882     setMoveIntoAcidProperty(level, EL_SATELLITE, TRUE);
6883     setMoveIntoAcidProperty(level, EL_PENGUIN,   TRUE);
6884     setMoveIntoAcidProperty(level, EL_BALLOON,   TRUE);
6885
6886     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6887       SET_PROPERTY(EL_CUSTOM_START + i, EP_CAN_MOVE_INTO_ACID, TRUE);
6888
6889     /* correct trigger settings (stored as zero == "none" in old levels) */
6890
6891     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6892     {
6893       int element = EL_CUSTOM_START + i;
6894       struct ElementInfo *ei = &element_info[element];
6895
6896       for (j = 0; j < ei->num_change_pages; j++)
6897       {
6898         struct ElementChangeInfo *change = &ei->change_page[j];
6899
6900         change->trigger_player = CH_PLAYER_ANY;
6901         change->trigger_page = CH_PAGE_ANY;
6902       }
6903     }
6904   }
6905
6906   /* try to detect and fix "Snake Bite" levels, which are broken with 3.2.0 */
6907   {
6908     int element = EL_CUSTOM_256;
6909     struct ElementInfo *ei = &element_info[element];
6910     struct ElementChangeInfo *change = &ei->change_page[0];
6911
6912     /* This is needed to fix a problem that was caused by a bugfix in function
6913        game.c/CreateFieldExt() introduced with 3.2.0 that corrects the behaviour
6914        when a custom element changes to EL_SOKOBAN_FIELD_PLAYER (before, it did
6915        not replace walkable elements, but instead just placed the player on it,
6916        without placing the Sokoban field under the player). Unfortunately, this
6917        breaks "Snake Bite" style levels when the snake is halfway through a door
6918        that just closes (the snake head is still alive and can be moved in this
6919        case). This can be fixed by replacing the EL_SOKOBAN_FIELD_PLAYER by the
6920        player (without Sokoban element) which then gets killed as designed). */
6921
6922     if ((strncmp(leveldir_current->identifier, "snake_bite", 10) == 0 ||
6923          strncmp(ei->description, "pause b4 death", 14) == 0) &&
6924         change->target_element == EL_SOKOBAN_FIELD_PLAYER)
6925       change->target_element = EL_PLAYER_1;
6926   }
6927
6928 #if 1
6929   /* try to detect and fix "Zelda" style levels, which are broken with 3.2.5 */
6930   if (level->game_version < VERSION_IDENT(3,2,5,0))
6931   {
6932     /* This is needed to fix a problem that was caused by a bugfix in function
6933        game.c/CheckTriggeredElementChangeExt() introduced with 3.2.5 that
6934        corrects the behaviour when a custom element changes to another custom
6935        element with a higher element number that has change actions defined.
6936        Normally, only one change per frame is allowed for custom elements.
6937        Therefore, it is checked if a custom element already changed in the
6938        current frame; if it did, subsequent changes are suppressed.
6939        Unfortunately, this is only checked for element changes, but not for
6940        change actions, which are still executed. As the function above loops
6941        through all custom elements from lower to higher, an element change
6942        resulting in a lower CE number won't be checked again, while a target
6943        element with a higher number will also be checked, and potential change
6944        actions will get executed for this CE, too (which is wrong), while
6945        further changes are ignored (which is correct). As this bugfix breaks
6946        Zelda II (and introduces graphical bugs to Zelda I, and also breaks a
6947        few other levels like Alan Bond's "FMV"), allow the previous, incorrect
6948        behaviour for existing levels and tapes that make use of this bug */
6949
6950     level->use_action_after_change_bug = TRUE;
6951   }
6952 #else
6953   /* !!! THIS DOES NOT FIX "Zelda I" (GRAPHICALLY) AND "Alan's FMV" LEVELS */
6954   /* try to detect and fix "Zelda II" levels, which are broken with 3.2.5 */
6955   {
6956     int element = EL_CUSTOM_16;
6957     struct ElementInfo *ei = &element_info[element];
6958
6959     /* This is needed to fix a problem that was caused by a bugfix in function
6960        game.c/CheckTriggeredElementChangeExt() introduced with 3.2.5 that
6961        corrects the behaviour when a custom element changes to another custom
6962        element with a higher element number that has change actions defined.
6963        Normally, only one change per frame is allowed for custom elements.
6964        Therefore, it is checked if a custom element already changed in the
6965        current frame; if it did, subsequent changes are suppressed.
6966        Unfortunately, this is only checked for element changes, but not for
6967        change actions, which are still executed. As the function above loops
6968        through all custom elements from lower to higher, an element change
6969        resulting in a lower CE number won't be checked again, while a target
6970        element with a higher number will also be checked, and potential change
6971        actions will get executed for this CE, too (which is wrong), while
6972        further changes are ignored (which is correct). As this bugfix breaks
6973        Zelda II (but no other levels), allow the previous, incorrect behaviour
6974        for this outstanding level set to not break the game or existing tapes */
6975
6976     if (strncmp(leveldir_current->identifier, "zelda2", 6) == 0 ||
6977         strncmp(ei->description, "scanline - row 1", 16) == 0)
6978       level->use_action_after_change_bug = TRUE;
6979   }
6980 #endif
6981
6982   /* not centering level after relocating player was default only in 3.2.3 */
6983   if (level->game_version == VERSION_IDENT(3,2,3,0))    /* (no pre-releases) */
6984     level->shifted_relocation = TRUE;
6985
6986   /* EM style elements always chain-exploded in R'n'D engine before 3.2.6 */
6987   if (level->game_version < VERSION_IDENT(3,2,6,0))
6988     level->em_explodes_by_fire = TRUE;
6989 }
6990
6991 static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
6992 {
6993   int i, j, x, y;
6994
6995   /* map custom element change events that have changed in newer versions
6996      (these following values were accidentally changed in version 3.0.1)
6997      (this seems to be needed only for 'ab_levelset3' and 'ab_levelset4') */
6998   if (level->game_version <= VERSION_IDENT(3,0,0,0))
6999   {
7000     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
7001     {
7002       int element = EL_CUSTOM_START + i;
7003
7004       /* order of checking and copying events to be mapped is important */
7005       /* (do not change the start and end value -- they are constant) */
7006       for (j = CE_BY_OTHER_ACTION; j >= CE_VALUE_GETS_ZERO; j--)
7007       {
7008         if (HAS_CHANGE_EVENT(element, j - 2))
7009         {
7010           SET_CHANGE_EVENT(element, j - 2, FALSE);
7011           SET_CHANGE_EVENT(element, j, TRUE);
7012         }
7013       }
7014
7015       /* order of checking and copying events to be mapped is important */
7016       /* (do not change the start and end value -- they are constant) */
7017       for (j = CE_PLAYER_COLLECTS_X; j >= CE_HITTING_SOMETHING; j--)
7018       {
7019         if (HAS_CHANGE_EVENT(element, j - 1))
7020         {
7021           SET_CHANGE_EVENT(element, j - 1, FALSE);
7022           SET_CHANGE_EVENT(element, j, TRUE);
7023         }
7024       }
7025     }
7026   }
7027
7028   /* initialize "can_change" field for old levels with only one change page */
7029   if (level->game_version <= VERSION_IDENT(3,0,2,0))
7030   {
7031     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
7032     {
7033       int element = EL_CUSTOM_START + i;
7034
7035       if (CAN_CHANGE(element))
7036         element_info[element].change->can_change = TRUE;
7037     }
7038   }
7039
7040   /* correct custom element values (for old levels without these options) */
7041   if (level->game_version < VERSION_IDENT(3,1,1,0))
7042   {
7043     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
7044     {
7045       int element = EL_CUSTOM_START + i;
7046       struct ElementInfo *ei = &element_info[element];
7047
7048       if (ei->access_direction == MV_NO_DIRECTION)
7049         ei->access_direction = MV_ALL_DIRECTIONS;
7050     }
7051   }
7052
7053   /* correct custom element values (fix invalid values for all versions) */
7054   if (1)
7055   {
7056     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
7057     {
7058       int element = EL_CUSTOM_START + i;
7059       struct ElementInfo *ei = &element_info[element];
7060
7061       for (j = 0; j < ei->num_change_pages; j++)
7062       {
7063         struct ElementChangeInfo *change = &ei->change_page[j];
7064
7065         if (change->trigger_player == CH_PLAYER_NONE)
7066           change->trigger_player = CH_PLAYER_ANY;
7067
7068         if (change->trigger_side == CH_SIDE_NONE)
7069           change->trigger_side = CH_SIDE_ANY;
7070       }
7071     }
7072   }
7073
7074   /* initialize "can_explode" field for old levels which did not store this */
7075   /* !!! CHECK THIS -- "<= 3,1,0,0" IS PROBABLY WRONG !!! */
7076   if (level->game_version <= VERSION_IDENT(3,1,0,0))
7077   {
7078     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
7079     {
7080       int element = EL_CUSTOM_START + i;
7081
7082       if (EXPLODES_1X1_OLD(element))
7083         element_info[element].explosion_type = EXPLODES_1X1;
7084
7085       SET_PROPERTY(element, EP_CAN_EXPLODE, (EXPLODES_BY_FIRE(element) ||
7086                                              EXPLODES_SMASHED(element) ||
7087                                              EXPLODES_IMPACT(element)));
7088     }
7089   }
7090
7091   /* correct previously hard-coded move delay values for maze runner style */
7092   if (level->game_version < VERSION_IDENT(3,1,1,0))
7093   {
7094     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
7095     {
7096       int element = EL_CUSTOM_START + i;
7097
7098       if (element_info[element].move_pattern & MV_MAZE_RUNNER_STYLE)
7099       {
7100         /* previously hard-coded and therefore ignored */
7101         element_info[element].move_delay_fixed = 9;
7102         element_info[element].move_delay_random = 0;
7103       }
7104     }
7105   }
7106
7107   /* map elements that have changed in newer versions */
7108   level->amoeba_content = getMappedElementByVersion(level->amoeba_content,
7109                                                     level->game_version);
7110   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
7111     for (x = 0; x < 3; x++)
7112       for (y = 0; y < 3; y++)
7113         level->yamyam_content[i].e[x][y] =
7114           getMappedElementByVersion(level->yamyam_content[i].e[x][y],
7115                                     level->game_version);
7116
7117   /* initialize element properties for level editor etc. */
7118   InitElementPropertiesEngine(level->game_version);
7119   InitElementPropertiesAfterLoading(level->game_version);
7120   InitElementPropertiesGfxElement();
7121 }
7122
7123 static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
7124 {
7125   int x, y;
7126
7127   /* map elements that have changed in newer versions */
7128   for (y = 0; y < level->fieldy; y++)
7129     for (x = 0; x < level->fieldx; x++)
7130       level->field[x][y] = getMappedElementByVersion(level->field[x][y],
7131                                                      level->game_version);
7132
7133   /* copy elements to runtime playfield array */
7134   for (x = 0; x < MAX_LEV_FIELDX; x++)
7135     for (y = 0; y < MAX_LEV_FIELDY; y++)
7136       Feld[x][y] = level->field[x][y];
7137
7138   /* initialize level size variables for faster access */
7139   lev_fieldx = level->fieldx;
7140   lev_fieldy = level->fieldy;
7141
7142   /* determine border element for this level */
7143   if (level->file_info.type == LEVEL_FILE_TYPE_DC)
7144     BorderElement = EL_EMPTY;   /* (in editor, SetBorderElement() is used) */
7145   else
7146     SetBorderElement();
7147 }
7148
7149 static void LoadLevel_InitNativeEngines(struct LevelInfo *level,char *filename)
7150 {
7151   struct LevelFileInfo *level_file_info = &level->file_info;
7152
7153   if (level_file_info->type == LEVEL_FILE_TYPE_RND)
7154     CopyNativeLevel_RND_to_Native(level);
7155 }
7156
7157 void LoadLevelTemplate(int nr)
7158 {
7159   char *filename;
7160
7161   setLevelFileInfo(&level_template.file_info, nr);
7162   filename = level_template.file_info.filename;
7163
7164   LoadLevelFromFileInfo(&level_template, &level_template.file_info);
7165
7166   LoadLevel_InitVersion(&level_template, filename);
7167   LoadLevel_InitElements(&level_template, filename);
7168
7169   ActivateLevelTemplate();
7170 }
7171
7172 void LoadLevel(int nr)
7173 {
7174   char *filename;
7175
7176   setLevelFileInfo(&level.file_info, nr);
7177   filename = level.file_info.filename;
7178
7179   LoadLevelFromFileInfo(&level, &level.file_info);
7180
7181   if (level.use_custom_template)
7182     LoadLevelTemplate(-1);
7183
7184   LoadLevel_InitVersion(&level, filename);
7185   LoadLevel_InitElements(&level, filename);
7186   LoadLevel_InitPlayfield(&level, filename);
7187
7188   LoadLevel_InitNativeEngines(&level, filename);
7189 }
7190
7191 static int SaveLevel_VERS(FILE *file, struct LevelInfo *level)
7192 {
7193   int chunk_size = 0;
7194
7195   chunk_size += putFileVersion(file, level->file_version);
7196   chunk_size += putFileVersion(file, level->game_version);
7197
7198   return chunk_size;
7199 }
7200
7201 static int SaveLevel_DATE(FILE *file, struct LevelInfo *level)
7202 {
7203   int chunk_size = 0;
7204
7205   chunk_size += putFile16BitBE(file, level->creation_date.year);
7206   chunk_size += putFile8Bit(file,    level->creation_date.month);
7207   chunk_size += putFile8Bit(file,    level->creation_date.day);
7208
7209   return chunk_size;
7210 }
7211
7212 #if 0
7213 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
7214 {
7215   int i, x, y;
7216
7217   putFile8Bit(file, level->fieldx);
7218   putFile8Bit(file, level->fieldy);
7219
7220   putFile16BitBE(file, level->time);
7221   putFile16BitBE(file, level->gems_needed);
7222
7223   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
7224     putFile8Bit(file, level->name[i]);
7225
7226   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
7227     putFile8Bit(file, level->score[i]);
7228
7229   for (i = 0; i < STD_ELEMENT_CONTENTS; i++)
7230     for (y = 0; y < 3; y++)
7231       for (x = 0; x < 3; x++)
7232         putFile8Bit(file, (level->encoding_16bit_yamyam ? EL_EMPTY :
7233                            level->yamyam_content[i].e[x][y]));
7234   putFile8Bit(file, level->amoeba_speed);
7235   putFile8Bit(file, level->time_magic_wall);
7236   putFile8Bit(file, level->time_wheel);
7237   putFile8Bit(file, (level->encoding_16bit_amoeba ? EL_EMPTY :
7238                      level->amoeba_content));
7239   putFile8Bit(file, (level->initial_player_stepsize == STEPSIZE_FAST ? 1 : 0));
7240   putFile8Bit(file, (level->initial_gravity ? 1 : 0));
7241   putFile8Bit(file, (level->encoding_16bit_field ? 1 : 0));
7242   putFile8Bit(file, (level->em_slippery_gems ? 1 : 0));
7243
7244   putFile8Bit(file, (level->use_custom_template ? 1 : 0));
7245
7246   putFile8Bit(file, (level->block_last_field ? 1 : 0));
7247   putFile8Bit(file, (level->sp_block_last_field ? 1 : 0));
7248   putFile32BitBE(file, level->can_move_into_acid_bits);
7249   putFile8Bit(file, level->dont_collide_with_bits);
7250
7251   putFile8Bit(file, (level->use_spring_bug ? 1 : 0));
7252   putFile8Bit(file, (level->use_step_counter ? 1 : 0));
7253
7254   putFile8Bit(file, (level->instant_relocation ? 1 : 0));
7255   putFile8Bit(file, (level->can_pass_to_walkable ? 1 : 0));
7256   putFile8Bit(file, (level->grow_into_diggable ? 1 : 0));
7257
7258   putFile8Bit(file, level->game_engine_type);
7259
7260   WriteUnusedBytesToFile(file, LEVEL_CHUNK_HEAD_UNUSED);
7261 }
7262 #endif
7263
7264 static int SaveLevel_NAME(FILE *file, struct LevelInfo *level)
7265 {
7266   int chunk_size = 0;
7267   int i;
7268
7269   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
7270     chunk_size += putFile8Bit(file, level->name[i]);
7271
7272   return chunk_size;
7273 }
7274
7275 static int SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
7276 {
7277   int chunk_size = 0;
7278   int i;
7279
7280   for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
7281     chunk_size += putFile8Bit(file, level->author[i]);
7282
7283   return chunk_size;
7284 }
7285
7286 #if 0
7287 static int SaveLevel_BODY(FILE *file, struct LevelInfo *level)
7288 {
7289   int chunk_size = 0;
7290   int x, y;
7291
7292   for (y = 0; y < level->fieldy; y++) 
7293     for (x = 0; x < level->fieldx; x++) 
7294       if (level->encoding_16bit_field)
7295         chunk_size += putFile16BitBE(file, level->field[x][y]);
7296       else
7297         chunk_size += putFile8Bit(file, level->field[x][y]);
7298
7299   return chunk_size;
7300 }
7301 #endif
7302
7303 static int SaveLevel_BODY(FILE *file, struct LevelInfo *level)
7304 {
7305   int chunk_size = 0;
7306   int x, y;
7307
7308   for (y = 0; y < level->fieldy; y++) 
7309     for (x = 0; x < level->fieldx; x++) 
7310       chunk_size += putFile16BitBE(file, level->field[x][y]);
7311
7312   return chunk_size;
7313 }
7314
7315 #if 0
7316 static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
7317 {
7318   int i, x, y;
7319
7320   putFile8Bit(file, EL_YAMYAM);
7321   putFile8Bit(file, level->num_yamyam_contents);
7322   putFile8Bit(file, 0);
7323   putFile8Bit(file, 0);
7324
7325   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
7326     for (y = 0; y < 3; y++)
7327       for (x = 0; x < 3; x++)
7328         if (level->encoding_16bit_field)
7329           putFile16BitBE(file, level->yamyam_content[i].e[x][y]);
7330         else
7331           putFile8Bit(file, level->yamyam_content[i].e[x][y]);
7332 }
7333 #endif
7334
7335 #if 0
7336 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
7337 {
7338   int i, x, y;
7339   int num_contents, content_xsize, content_ysize;
7340   int content_array[MAX_ELEMENT_CONTENTS][3][3];
7341
7342   if (element == EL_YAMYAM)
7343   {
7344     num_contents = level->num_yamyam_contents;
7345     content_xsize = 3;
7346     content_ysize = 3;
7347
7348     for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
7349       for (y = 0; y < 3; y++)
7350         for (x = 0; x < 3; x++)
7351           content_array[i][x][y] = level->yamyam_content[i].e[x][y];
7352   }
7353   else if (element == EL_BD_AMOEBA)
7354   {
7355     num_contents = 1;
7356     content_xsize = 1;
7357     content_ysize = 1;
7358
7359     for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
7360       for (y = 0; y < 3; y++)
7361         for (x = 0; x < 3; x++)
7362           content_array[i][x][y] = EL_EMPTY;
7363     content_array[0][0][0] = level->amoeba_content;
7364   }
7365   else
7366   {
7367     /* chunk header already written -- write empty chunk data */
7368     WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_SIZE);
7369
7370     Error(ERR_WARN, "cannot save content for element '%d'", element);
7371     return;
7372   }
7373
7374   putFile16BitBE(file, element);
7375   putFile8Bit(file, num_contents);
7376   putFile8Bit(file, content_xsize);
7377   putFile8Bit(file, content_ysize);
7378
7379   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED);
7380
7381   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
7382     for (y = 0; y < 3; y++)
7383       for (x = 0; x < 3; x++)
7384         putFile16BitBE(file, content_array[i][x][y]);
7385 }
7386 #endif
7387
7388 #if 0
7389 static int SaveLevel_CNT3(FILE *file, struct LevelInfo *level, int element)
7390 {
7391   int envelope_nr = element - EL_ENVELOPE_1;
7392   int envelope_len = strlen(level->envelope_text[envelope_nr]) + 1;
7393   int chunk_size = 0;
7394   int i;
7395
7396   chunk_size += putFile16BitBE(file, element);
7397   chunk_size += putFile16BitBE(file, envelope_len);
7398   chunk_size += putFile8Bit(file, level->envelope_xsize[envelope_nr]);
7399   chunk_size += putFile8Bit(file, level->envelope_ysize[envelope_nr]);
7400
7401   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT3_UNUSED);
7402   chunk_size += LEVEL_CHUNK_CNT3_UNUSED;
7403
7404   for (i = 0; i < envelope_len; i++)
7405     chunk_size += putFile8Bit(file, level->envelope_text[envelope_nr][i]);
7406
7407   return chunk_size;
7408 }
7409 #endif
7410
7411 #if 0
7412 static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level,
7413                            int num_changed_custom_elements)
7414 {
7415   int i, check = 0;
7416
7417   putFile16BitBE(file, num_changed_custom_elements);
7418
7419   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
7420   {
7421     int element = EL_CUSTOM_START + i;
7422
7423     struct ElementInfo *ei = &element_info[element];
7424
7425     if (ei->properties[EP_BITFIELD_BASE_NR] != EP_BITMASK_DEFAULT)
7426     {
7427       if (check < num_changed_custom_elements)
7428       {
7429         putFile16BitBE(file, element);
7430         putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
7431       }
7432
7433       check++;
7434     }
7435   }
7436
7437   if (check != num_changed_custom_elements)     /* should not happen */
7438     Error(ERR_WARN, "inconsistent number of custom element properties");
7439 }
7440 #endif
7441
7442 #if 0
7443 static void SaveLevel_CUS2(FILE *file, struct LevelInfo *level,
7444                            int num_changed_custom_elements)
7445 {
7446   int i, check = 0;
7447
7448   putFile16BitBE(file, num_changed_custom_elements);
7449
7450   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
7451   {
7452     int element = EL_CUSTOM_START + i;
7453
7454     if (element_info[element].change->target_element != EL_EMPTY_SPACE)
7455     {
7456       if (check < num_changed_custom_elements)
7457       {
7458         putFile16BitBE(file, element);
7459         putFile16BitBE(file, element_info[element].change->target_element);
7460       }
7461
7462       check++;
7463     }
7464   }
7465
7466   if (check != num_changed_custom_elements)     /* should not happen */
7467     Error(ERR_WARN, "inconsistent number of custom target elements");
7468 }
7469 #endif
7470
7471 #if 0
7472 static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
7473                            int num_changed_custom_elements)
7474 {
7475   int i, j, x, y, check = 0;
7476
7477   putFile16BitBE(file, num_changed_custom_elements);
7478
7479   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
7480   {
7481     int element = EL_CUSTOM_START + i;
7482     struct ElementInfo *ei = &element_info[element];
7483
7484     if (ei->modified_settings)
7485     {
7486       if (check < num_changed_custom_elements)
7487       {
7488         putFile16BitBE(file, element);
7489
7490         for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++)
7491           putFile8Bit(file, ei->description[j]);
7492
7493         putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
7494
7495         /* some free bytes for future properties and padding */
7496         WriteUnusedBytesToFile(file, 7);
7497
7498         putFile8Bit(file, ei->use_gfx_element);
7499         putFile16BitBE(file, ei->gfx_element_initial);
7500
7501         putFile8Bit(file, ei->collect_score_initial);
7502         putFile8Bit(file, ei->collect_count_initial);
7503
7504         putFile16BitBE(file, ei->push_delay_fixed);
7505         putFile16BitBE(file, ei->push_delay_random);
7506         putFile16BitBE(file, ei->move_delay_fixed);
7507         putFile16BitBE(file, ei->move_delay_random);
7508
7509         putFile16BitBE(file, ei->move_pattern);
7510         putFile8Bit(file, ei->move_direction_initial);
7511         putFile8Bit(file, ei->move_stepsize);
7512
7513         for (y = 0; y < 3; y++)
7514           for (x = 0; x < 3; x++)
7515             putFile16BitBE(file, ei->content.e[x][y]);
7516
7517         putFile32BitBE(file, ei->change->events);
7518
7519         putFile16BitBE(file, ei->change->target_element);
7520
7521         putFile16BitBE(file, ei->change->delay_fixed);
7522         putFile16BitBE(file, ei->change->delay_random);
7523         putFile16BitBE(file, ei->change->delay_frames);
7524
7525         putFile16BitBE(file, ei->change->initial_trigger_element);
7526
7527         putFile8Bit(file, ei->change->explode);
7528         putFile8Bit(file, ei->change->use_target_content);
7529         putFile8Bit(file, ei->change->only_if_complete);
7530         putFile8Bit(file, ei->change->use_random_replace);
7531
7532         putFile8Bit(file, ei->change->random_percentage);
7533         putFile8Bit(file, ei->change->replace_when);
7534
7535         for (y = 0; y < 3; y++)
7536           for (x = 0; x < 3; x++)
7537             putFile16BitBE(file, ei->change->content.e[x][y]);
7538
7539         putFile8Bit(file, ei->slippery_type);
7540
7541         /* some free bytes for future properties and padding */
7542         WriteUnusedBytesToFile(file, LEVEL_CPART_CUS3_UNUSED);
7543       }
7544
7545       check++;
7546     }
7547   }
7548
7549   if (check != num_changed_custom_elements)     /* should not happen */
7550     Error(ERR_WARN, "inconsistent number of custom element properties");
7551 }
7552 #endif
7553
7554 #if 0
7555 static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
7556 {
7557   struct ElementInfo *ei = &element_info[element];
7558   int i, j, x, y;
7559
7560   /* ---------- custom element base property values (96 bytes) ------------- */
7561
7562   putFile16BitBE(file, element);
7563
7564   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
7565     putFile8Bit(file, ei->description[i]);
7566
7567   putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
7568
7569   WriteUnusedBytesToFile(file, 4);      /* reserved for more base properties */
7570
7571   putFile8Bit(file, ei->num_change_pages);
7572
7573   putFile16BitBE(file, ei->ce_value_fixed_initial);
7574   putFile16BitBE(file, ei->ce_value_random_initial);
7575   putFile8Bit(file, ei->use_last_ce_value);
7576
7577   putFile8Bit(file, ei->use_gfx_element);
7578   putFile16BitBE(file, ei->gfx_element_initial);
7579
7580   putFile8Bit(file, ei->collect_score_initial);
7581   putFile8Bit(file, ei->collect_count_initial);
7582
7583   putFile8Bit(file, ei->drop_delay_fixed);
7584   putFile8Bit(file, ei->push_delay_fixed);
7585   putFile8Bit(file, ei->drop_delay_random);
7586   putFile8Bit(file, ei->push_delay_random);
7587   putFile16BitBE(file, ei->move_delay_fixed);
7588   putFile16BitBE(file, ei->move_delay_random);
7589
7590   /* bits 0 - 15 of "move_pattern" ... */
7591   putFile16BitBE(file, ei->move_pattern & 0xffff);
7592   putFile8Bit(file, ei->move_direction_initial);
7593   putFile8Bit(file, ei->move_stepsize);
7594
7595   putFile8Bit(file, ei->slippery_type);
7596
7597   for (y = 0; y < 3; y++)
7598     for (x = 0; x < 3; x++)
7599       putFile16BitBE(file, ei->content.e[x][y]);
7600
7601   putFile16BitBE(file, ei->move_enter_element);
7602   putFile16BitBE(file, ei->move_leave_element);
7603   putFile8Bit(file, ei->move_leave_type);
7604
7605   /* ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible) */
7606   putFile16BitBE(file, (ei->move_pattern >> 16) & 0xffff);
7607
7608   putFile8Bit(file, ei->access_direction);
7609
7610   putFile8Bit(file, ei->explosion_delay);
7611   putFile8Bit(file, ei->ignition_delay);
7612   putFile8Bit(file, ei->explosion_type);
7613
7614   /* some free bytes for future custom property values and padding */
7615   WriteUnusedBytesToFile(file, 1);
7616
7617   /* ---------- change page property values (48 bytes) --------------------- */
7618
7619   for (i = 0; i < ei->num_change_pages; i++)
7620   {
7621     struct ElementChangeInfo *change = &ei->change_page[i];
7622     unsigned int event_bits;
7623
7624     /* bits 0 - 31 of "has_event[]" ... */
7625     event_bits = 0;
7626     for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
7627       if (change->has_event[j])
7628         event_bits |= (1 << j);
7629     putFile32BitBE(file, event_bits);
7630
7631     putFile16BitBE(file, change->target_element);
7632
7633     putFile16BitBE(file, change->delay_fixed);
7634     putFile16BitBE(file, change->delay_random);
7635     putFile16BitBE(file, change->delay_frames);
7636
7637     putFile16BitBE(file, change->initial_trigger_element);
7638
7639     putFile8Bit(file, change->explode);
7640     putFile8Bit(file, change->use_target_content);
7641     putFile8Bit(file, change->only_if_complete);
7642     putFile8Bit(file, change->use_random_replace);
7643
7644     putFile8Bit(file, change->random_percentage);
7645     putFile8Bit(file, change->replace_when);
7646
7647     for (y = 0; y < 3; y++)
7648       for (x = 0; x < 3; x++)
7649         putFile16BitBE(file, change->target_content.e[x][y]);
7650
7651     putFile8Bit(file, change->can_change);
7652
7653     putFile8Bit(file, change->trigger_side);
7654
7655     putFile8Bit(file, change->trigger_player);
7656     putFile8Bit(file, (change->trigger_page == CH_PAGE_ANY ? CH_PAGE_ANY_FILE :
7657                        log_2(change->trigger_page)));
7658
7659     putFile8Bit(file, change->has_action);
7660     putFile8Bit(file, change->action_type);
7661     putFile8Bit(file, change->action_mode);
7662     putFile16BitBE(file, change->action_arg);
7663
7664     /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */
7665     event_bits = 0;
7666     for (j = 32; j < NUM_CHANGE_EVENTS; j++)
7667       if (change->has_event[j])
7668         event_bits |= (1 << (j - 32));
7669     putFile8Bit(file, event_bits);
7670   }
7671 }
7672 #endif
7673
7674 #if 0
7675 static void SaveLevel_GRP1(FILE *file, struct LevelInfo *level, int element)
7676 {
7677   struct ElementInfo *ei = &element_info[element];
7678   struct ElementGroupInfo *group = ei->group;
7679   int i;
7680
7681   putFile16BitBE(file, element);
7682
7683   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
7684     putFile8Bit(file, ei->description[i]);
7685
7686   putFile8Bit(file, group->num_elements);
7687
7688   putFile8Bit(file, ei->use_gfx_element);
7689   putFile16BitBE(file, ei->gfx_element_initial);
7690
7691   putFile8Bit(file, group->choice_mode);
7692
7693   /* some free bytes for future values and padding */
7694   WriteUnusedBytesToFile(file, 3);
7695
7696   for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
7697     putFile16BitBE(file, group->element[i]);
7698 }
7699 #endif
7700
7701 static int SaveLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *entry,
7702                                 boolean write_element)
7703 {
7704   int save_type = entry->save_type;
7705   int data_type = entry->data_type;
7706   int conf_type = entry->conf_type;
7707   int byte_mask = conf_type & CONF_MASK_BYTES;
7708   int element = entry->element;
7709   int default_value = entry->default_value;
7710   int num_bytes = 0;
7711   boolean modified = FALSE;
7712
7713   if (byte_mask != CONF_MASK_MULTI_BYTES)
7714   {
7715     void *value_ptr = entry->value;
7716     int value = (data_type == TYPE_BOOLEAN ? *(boolean *)value_ptr :
7717                  *(int *)value_ptr);
7718
7719     /* check if any settings have been modified before saving them */
7720     if (value != default_value)
7721       modified = TRUE;
7722
7723     /* do not save if explicitly told or if unmodified default settings */
7724     if ((save_type == SAVE_CONF_NEVER) ||
7725         (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
7726       return 0;
7727
7728     if (write_element)
7729       num_bytes += putFile16BitBE(file, element);
7730
7731     num_bytes += putFile8Bit(file, conf_type);
7732     num_bytes += (byte_mask == CONF_MASK_1_BYTE ? putFile8Bit   (file, value) :
7733                   byte_mask == CONF_MASK_2_BYTE ? putFile16BitBE(file, value) :
7734                   byte_mask == CONF_MASK_4_BYTE ? putFile32BitBE(file, value) :
7735                   0);
7736   }
7737   else if (data_type == TYPE_STRING)
7738   {
7739     char *default_string = entry->default_string;
7740     char *string = (char *)(entry->value);
7741     int string_length = strlen(string);
7742     int i;
7743
7744     /* check if any settings have been modified before saving them */
7745     if (!strEqual(string, default_string))
7746       modified = TRUE;
7747
7748     /* do not save if explicitly told or if unmodified default settings */
7749     if ((save_type == SAVE_CONF_NEVER) ||
7750         (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
7751       return 0;
7752
7753     if (write_element)
7754       num_bytes += putFile16BitBE(file, element);
7755
7756     num_bytes += putFile8Bit(file, conf_type);
7757     num_bytes += putFile16BitBE(file, string_length);
7758
7759     for (i = 0; i < string_length; i++)
7760       num_bytes += putFile8Bit(file, string[i]);
7761   }
7762   else if (data_type == TYPE_ELEMENT_LIST)
7763   {
7764     int *element_array = (int *)(entry->value);
7765     int num_elements = *(int *)(entry->num_entities);
7766     int i;
7767
7768     /* check if any settings have been modified before saving them */
7769     for (i = 0; i < num_elements; i++)
7770       if (element_array[i] != default_value)
7771         modified = TRUE;
7772
7773     /* do not save if explicitly told or if unmodified default settings */
7774     if ((save_type == SAVE_CONF_NEVER) ||
7775         (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
7776       return 0;
7777
7778     if (write_element)
7779       num_bytes += putFile16BitBE(file, element);
7780
7781     num_bytes += putFile8Bit(file, conf_type);
7782     num_bytes += putFile16BitBE(file, num_elements * CONF_ELEMENT_NUM_BYTES);
7783
7784     for (i = 0; i < num_elements; i++)
7785       num_bytes += putFile16BitBE(file, element_array[i]);
7786   }
7787   else if (data_type == TYPE_CONTENT_LIST)
7788   {
7789     struct Content *content = (struct Content *)(entry->value);
7790     int num_contents = *(int *)(entry->num_entities);
7791     int i, x, y;
7792
7793     /* check if any settings have been modified before saving them */
7794     for (i = 0; i < num_contents; i++)
7795       for (y = 0; y < 3; y++)
7796         for (x = 0; x < 3; x++)
7797           if (content[i].e[x][y] != default_value)
7798             modified = TRUE;
7799
7800     /* do not save if explicitly told or if unmodified default settings */
7801     if ((save_type == SAVE_CONF_NEVER) ||
7802         (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
7803       return 0;
7804
7805     if (write_element)
7806       num_bytes += putFile16BitBE(file, element);
7807
7808     num_bytes += putFile8Bit(file, conf_type);
7809     num_bytes += putFile16BitBE(file, num_contents * CONF_CONTENT_NUM_BYTES);
7810
7811     for (i = 0; i < num_contents; i++)
7812       for (y = 0; y < 3; y++)
7813         for (x = 0; x < 3; x++)
7814           num_bytes += putFile16BitBE(file, content[i].e[x][y]);
7815   }
7816
7817   return num_bytes;
7818 }
7819
7820 static int SaveLevel_INFO(FILE *file, struct LevelInfo *level)
7821 {
7822   int chunk_size = 0;
7823   int i;
7824
7825   li = *level;          /* copy level data into temporary buffer */
7826
7827   for (i = 0; chunk_config_INFO[i].data_type != -1; i++)
7828     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_INFO[i], FALSE);
7829
7830   return chunk_size;
7831 }
7832
7833 static int SaveLevel_ELEM(FILE *file, struct LevelInfo *level)
7834 {
7835   int chunk_size = 0;
7836   int i;
7837
7838   li = *level;          /* copy level data into temporary buffer */
7839
7840   for (i = 0; chunk_config_ELEM[i].data_type != -1; i++)
7841     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_ELEM[i], TRUE);
7842
7843   return chunk_size;
7844 }
7845
7846 static int SaveLevel_NOTE(FILE *file, struct LevelInfo *level, int element)
7847 {
7848   int envelope_nr = element - EL_ENVELOPE_1;
7849   int chunk_size = 0;
7850   int i;
7851
7852   chunk_size += putFile16BitBE(file, element);
7853
7854   /* copy envelope data into temporary buffer */
7855   xx_envelope = level->envelope[envelope_nr];
7856
7857   for (i = 0; chunk_config_NOTE[i].data_type != -1; i++)
7858     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_NOTE[i], FALSE);
7859
7860   return chunk_size;
7861 }
7862
7863 static int SaveLevel_CUSX(FILE *file, struct LevelInfo *level, int element)
7864 {
7865   struct ElementInfo *ei = &element_info[element];
7866   int chunk_size = 0;
7867   int i, j;
7868
7869   chunk_size += putFile16BitBE(file, element);
7870
7871   xx_ei = *ei;          /* copy element data into temporary buffer */
7872
7873   /* set default description string for this specific element */
7874   strcpy(xx_default_description, getDefaultElementDescription(ei));
7875
7876 #if 0
7877   /* set (fixed) number of content areas (may be wrong by broken level file) */
7878   /* (this is now directly corrected for broken level files after loading) */
7879   xx_num_contents = 1;
7880 #endif
7881
7882   for (i = 0; chunk_config_CUSX_base[i].data_type != -1; i++)
7883     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_CUSX_base[i], FALSE);
7884
7885   for (i = 0; i < ei->num_change_pages; i++)
7886   {
7887     struct ElementChangeInfo *change = &ei->change_page[i];
7888
7889     xx_current_change_page = i;
7890
7891     xx_change = *change;        /* copy change data into temporary buffer */
7892
7893     resetEventBits();
7894     setEventBitsFromEventFlags(change);
7895
7896     for (j = 0; chunk_config_CUSX_change[j].data_type != -1; j++)
7897       chunk_size += SaveLevel_MicroChunk(file, &chunk_config_CUSX_change[j],
7898                                          FALSE);
7899   }
7900
7901   return chunk_size;
7902 }
7903
7904 static int SaveLevel_GRPX(FILE *file, struct LevelInfo *level, int element)
7905 {
7906   struct ElementInfo *ei = &element_info[element];
7907   struct ElementGroupInfo *group = ei->group;
7908   int chunk_size = 0;
7909   int i;
7910
7911   chunk_size += putFile16BitBE(file, element);
7912
7913   xx_ei = *ei;          /* copy element data into temporary buffer */
7914   xx_group = *group;    /* copy group data into temporary buffer */
7915
7916   /* set default description string for this specific element */
7917   strcpy(xx_default_description, getDefaultElementDescription(ei));
7918
7919   for (i = 0; chunk_config_GRPX[i].data_type != -1; i++)
7920     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_GRPX[i], FALSE);
7921
7922   return chunk_size;
7923 }
7924
7925 static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
7926 {
7927   int chunk_size;
7928   int i;
7929   FILE *file;
7930
7931   if (!(file = fopen(filename, MODE_WRITE)))
7932   {
7933     Error(ERR_WARN, "cannot save level file '%s'", filename);
7934     return;
7935   }
7936
7937   level->file_version = FILE_VERSION_ACTUAL;
7938   level->game_version = GAME_VERSION_ACTUAL;
7939
7940   level->creation_date = getCurrentDate();
7941
7942   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
7943   putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
7944
7945   chunk_size = SaveLevel_VERS(NULL, level);
7946   putFileChunkBE(file, "VERS", chunk_size);
7947   SaveLevel_VERS(file, level);
7948
7949   chunk_size = SaveLevel_DATE(NULL, level);
7950   putFileChunkBE(file, "DATE", chunk_size);
7951   SaveLevel_DATE(file, level);
7952
7953   chunk_size = SaveLevel_NAME(NULL, level);
7954   putFileChunkBE(file, "NAME", chunk_size);
7955   SaveLevel_NAME(file, level);
7956
7957   chunk_size = SaveLevel_AUTH(NULL, level);
7958   putFileChunkBE(file, "AUTH", chunk_size);
7959   SaveLevel_AUTH(file, level);
7960
7961   chunk_size = SaveLevel_INFO(NULL, level);
7962   putFileChunkBE(file, "INFO", chunk_size);
7963   SaveLevel_INFO(file, level);
7964
7965   chunk_size = SaveLevel_BODY(NULL, level);
7966   putFileChunkBE(file, "BODY", chunk_size);
7967   SaveLevel_BODY(file, level);
7968
7969   chunk_size = SaveLevel_ELEM(NULL, level);
7970   if (chunk_size > LEVEL_CHUNK_ELEM_UNCHANGED)          /* save if changed */
7971   {
7972     putFileChunkBE(file, "ELEM", chunk_size);
7973     SaveLevel_ELEM(file, level);
7974   }
7975
7976   for (i = 0; i < NUM_ENVELOPES; i++)
7977   {
7978     int element = EL_ENVELOPE_1 + i;
7979
7980     chunk_size = SaveLevel_NOTE(NULL, level, element);
7981     if (chunk_size > LEVEL_CHUNK_NOTE_UNCHANGED)        /* save if changed */
7982     {
7983       putFileChunkBE(file, "NOTE", chunk_size);
7984       SaveLevel_NOTE(file, level, element);
7985     }
7986   }
7987
7988   /* if not using template level, check for non-default custom/group elements */
7989   if (!level->use_custom_template)
7990   {
7991     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
7992     {
7993       int element = EL_CUSTOM_START + i;
7994
7995       chunk_size = SaveLevel_CUSX(NULL, level, element);
7996       if (chunk_size > LEVEL_CHUNK_CUSX_UNCHANGED)      /* save if changed */
7997       {
7998         putFileChunkBE(file, "CUSX", chunk_size);
7999         SaveLevel_CUSX(file, level, element);
8000       }
8001     }
8002
8003     for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
8004     {
8005       int element = EL_GROUP_START + i;
8006
8007       chunk_size = SaveLevel_GRPX(NULL, level, element);
8008       if (chunk_size > LEVEL_CHUNK_GRPX_UNCHANGED)      /* save if changed */
8009       {
8010         putFileChunkBE(file, "GRPX", chunk_size);
8011         SaveLevel_GRPX(file, level, element);
8012       }
8013     }
8014   }
8015
8016   fclose(file);
8017
8018   SetFilePermissions(filename, PERMS_PRIVATE);
8019 }
8020
8021 void SaveLevel(int nr)
8022 {
8023   char *filename = getDefaultLevelFilename(nr);
8024
8025   SaveLevelFromFilename(&level, filename);
8026 }
8027
8028 void SaveLevelTemplate()
8029 {
8030   char *filename = getDefaultLevelFilename(-1);
8031
8032   SaveLevelFromFilename(&level, filename);
8033 }
8034
8035 boolean SaveLevelChecked(int nr)
8036 {
8037   char *filename = getDefaultLevelFilename(nr);
8038   boolean new_level = !fileExists(filename);
8039   boolean level_saved = FALSE;
8040
8041   if (new_level || Request("Save this level and kill the old ?", REQ_ASK))
8042   {
8043     SaveLevel(nr);
8044
8045     if (new_level)
8046       Request("Level saved !", REQ_CONFIRM);
8047
8048     level_saved = TRUE;
8049   }
8050
8051   return level_saved;
8052 }
8053
8054 void DumpLevel(struct LevelInfo *level)
8055 {
8056   if (level->no_valid_file)
8057   {
8058     Error(ERR_WARN, "cannot dump -- no valid level file found");
8059
8060     return;
8061   }
8062
8063   printf_line("-", 79);
8064   printf("Level xxx (file version %08d, game version %08d)\n",
8065          level->file_version, level->game_version);
8066   printf_line("-", 79);
8067
8068   printf("Level author: '%s'\n", level->author);
8069   printf("Level title:  '%s'\n", level->name);
8070   printf("\n");
8071   printf("Playfield size: %d x %d\n", level->fieldx, level->fieldy);
8072   printf("\n");
8073   printf("Level time:  %d seconds\n", level->time);
8074   printf("Gems needed: %d\n", level->gems_needed);
8075   printf("\n");
8076   printf("Time for magic wall: %d seconds\n", level->time_magic_wall);
8077   printf("Time for wheel:      %d seconds\n", level->time_wheel);
8078   printf("Time for light:      %d seconds\n", level->time_light);
8079   printf("Time for timegate:   %d seconds\n", level->time_timegate);
8080   printf("\n");
8081   printf("Amoeba speed: %d\n", level->amoeba_speed);
8082   printf("\n");
8083
8084   printf("EM style slippery gems:      %s\n", (level->em_slippery_gems ? "yes" : "no"));
8085   printf("Player blocks last field:    %s\n", (level->block_last_field ? "yes" : "no"));
8086   printf("SP player blocks last field: %s\n", (level->sp_block_last_field ? "yes" : "no"));
8087   printf("use spring bug: %s\n", (level->use_spring_bug ? "yes" : "no"));
8088   printf("use step counter: %s\n", (level->use_step_counter ? "yes" : "no"));
8089
8090   printf_line("-", 79);
8091 }
8092
8093
8094 /* ========================================================================= */
8095 /* tape file functions                                                       */
8096 /* ========================================================================= */
8097
8098 static void setTapeInfoToDefaults()
8099 {
8100   int i;
8101
8102   /* always start with reliable default values (empty tape) */
8103   TapeErase();
8104
8105   /* default values (also for pre-1.2 tapes) with only the first player */
8106   tape.player_participates[0] = TRUE;
8107   for (i = 1; i < MAX_PLAYERS; i++)
8108     tape.player_participates[i] = FALSE;
8109
8110   /* at least one (default: the first) player participates in every tape */
8111   tape.num_participating_players = 1;
8112
8113   tape.level_nr = level_nr;
8114   tape.counter = 0;
8115   tape.changed = FALSE;
8116
8117   tape.recording = FALSE;
8118   tape.playing = FALSE;
8119   tape.pausing = FALSE;
8120
8121   tape.no_valid_file = FALSE;
8122 }
8123
8124 static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
8125 {
8126   tape->file_version = getFileVersion(file);
8127   tape->game_version = getFileVersion(file);
8128
8129   return chunk_size;
8130 }
8131
8132 static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
8133 {
8134   int i;
8135
8136   tape->random_seed = getFile32BitBE(file);
8137   tape->date        = getFile32BitBE(file);
8138   tape->length      = getFile32BitBE(file);
8139
8140   /* read header fields that are new since version 1.2 */
8141   if (tape->file_version >= FILE_VERSION_1_2)
8142   {
8143     byte store_participating_players = getFile8Bit(file);
8144     int engine_version;
8145
8146     /* since version 1.2, tapes store which players participate in the tape */
8147     tape->num_participating_players = 0;
8148     for (i = 0; i < MAX_PLAYERS; i++)
8149     {
8150       tape->player_participates[i] = FALSE;
8151
8152       if (store_participating_players & (1 << i))
8153       {
8154         tape->player_participates[i] = TRUE;
8155         tape->num_participating_players++;
8156       }
8157     }
8158
8159     ReadUnusedBytesFromFile(file, TAPE_CHUNK_HEAD_UNUSED);
8160
8161     engine_version = getFileVersion(file);
8162     if (engine_version > 0)
8163       tape->engine_version = engine_version;
8164     else
8165       tape->engine_version = tape->game_version;
8166   }
8167
8168   return chunk_size;
8169 }
8170
8171 static int LoadTape_INFO(FILE *file, int chunk_size, struct TapeInfo *tape)
8172 {
8173   int level_identifier_size;
8174   int i;
8175
8176   level_identifier_size = getFile16BitBE(file);
8177
8178   tape->level_identifier =
8179     checked_realloc(tape->level_identifier, level_identifier_size);
8180
8181   for (i = 0; i < level_identifier_size; i++)
8182     tape->level_identifier[i] = getFile8Bit(file);
8183
8184   tape->level_nr = getFile16BitBE(file);
8185
8186   chunk_size = 2 + level_identifier_size + 2;
8187
8188   return chunk_size;
8189 }
8190
8191 static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
8192 {
8193   int i, j;
8194   int chunk_size_expected =
8195     (tape->num_participating_players + 1) * tape->length;
8196
8197   if (chunk_size_expected != chunk_size)
8198   {
8199     ReadUnusedBytesFromFile(file, chunk_size);
8200     return chunk_size_expected;
8201   }
8202
8203   for (i = 0; i < tape->length; i++)
8204   {
8205     if (i >= MAX_TAPE_LEN)
8206       break;
8207
8208     for (j = 0; j < MAX_PLAYERS; j++)
8209     {
8210       tape->pos[i].action[j] = MV_NONE;
8211
8212       if (tape->player_participates[j])
8213         tape->pos[i].action[j] = getFile8Bit(file);
8214     }
8215
8216     tape->pos[i].delay = getFile8Bit(file);
8217
8218     if (tape->file_version == FILE_VERSION_1_0)
8219     {
8220       /* eliminate possible diagonal moves in old tapes */
8221       /* this is only for backward compatibility */
8222
8223       byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
8224       byte action = tape->pos[i].action[0];
8225       int k, num_moves = 0;
8226
8227       for (k = 0; k<4; k++)
8228       {
8229         if (action & joy_dir[k])
8230         {
8231           tape->pos[i + num_moves].action[0] = joy_dir[k];
8232           if (num_moves > 0)
8233             tape->pos[i + num_moves].delay = 0;
8234           num_moves++;
8235         }
8236       }
8237
8238       if (num_moves > 1)
8239       {
8240         num_moves--;
8241         i += num_moves;
8242         tape->length += num_moves;
8243       }
8244     }
8245     else if (tape->file_version < FILE_VERSION_2_0)
8246     {
8247       /* convert pre-2.0 tapes to new tape format */
8248
8249       if (tape->pos[i].delay > 1)
8250       {
8251         /* action part */
8252         tape->pos[i + 1] = tape->pos[i];
8253         tape->pos[i + 1].delay = 1;
8254
8255         /* delay part */
8256         for (j = 0; j < MAX_PLAYERS; j++)
8257           tape->pos[i].action[j] = MV_NONE;
8258         tape->pos[i].delay--;
8259
8260         i++;
8261         tape->length++;
8262       }
8263     }
8264
8265     if (feof(file))
8266       break;
8267   }
8268
8269   if (i != tape->length)
8270     chunk_size = (tape->num_participating_players + 1) * i;
8271
8272   return chunk_size;
8273 }
8274
8275 void LoadTapeFromFilename(char *filename)
8276 {
8277   char cookie[MAX_LINE_LEN];
8278   char chunk_name[CHUNK_ID_LEN + 1];
8279   FILE *file;
8280   int chunk_size;
8281
8282   /* always start with reliable default values */
8283   setTapeInfoToDefaults();
8284
8285   if (!(file = fopen(filename, MODE_READ)))
8286   {
8287     tape.no_valid_file = TRUE;
8288
8289     return;
8290   }
8291
8292   getFileChunkBE(file, chunk_name, NULL);
8293   if (strEqual(chunk_name, "RND1"))
8294   {
8295     getFile32BitBE(file);               /* not used */
8296
8297     getFileChunkBE(file, chunk_name, NULL);
8298     if (!strEqual(chunk_name, "TAPE"))
8299     {
8300       tape.no_valid_file = TRUE;
8301
8302       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
8303       fclose(file);
8304       return;
8305     }
8306   }
8307   else  /* check for pre-2.0 file format with cookie string */
8308   {
8309     strcpy(cookie, chunk_name);
8310     fgets(&cookie[4], MAX_LINE_LEN - 4, file);
8311     if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
8312       cookie[strlen(cookie) - 1] = '\0';
8313
8314     if (!checkCookieString(cookie, TAPE_COOKIE_TMPL))
8315     {
8316       tape.no_valid_file = TRUE;
8317
8318       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
8319       fclose(file);
8320       return;
8321     }
8322
8323     if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1)
8324     {
8325       tape.no_valid_file = TRUE;
8326
8327       Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
8328       fclose(file);
8329       return;
8330     }
8331
8332     /* pre-2.0 tape files have no game version, so use file version here */
8333     tape.game_version = tape.file_version;
8334   }
8335
8336   if (tape.file_version < FILE_VERSION_1_2)
8337   {
8338     /* tape files from versions before 1.2.0 without chunk structure */
8339     LoadTape_HEAD(file, TAPE_CHUNK_HEAD_SIZE, &tape);
8340     LoadTape_BODY(file, 2 * tape.length,      &tape);
8341   }
8342   else
8343   {
8344     static struct
8345     {
8346       char *name;
8347       int size;
8348       int (*loader)(FILE *, int, struct TapeInfo *);
8349     }
8350     chunk_info[] =
8351     {
8352       { "VERS", TAPE_CHUNK_VERS_SIZE,   LoadTape_VERS },
8353       { "HEAD", TAPE_CHUNK_HEAD_SIZE,   LoadTape_HEAD },
8354       { "INFO", -1,                     LoadTape_INFO },
8355       { "BODY", -1,                     LoadTape_BODY },
8356       {  NULL,  0,                      NULL }
8357     };
8358
8359     while (getFileChunkBE(file, chunk_name, &chunk_size))
8360     {
8361       int i = 0;
8362
8363       while (chunk_info[i].name != NULL &&
8364              !strEqual(chunk_name, chunk_info[i].name))
8365         i++;
8366
8367       if (chunk_info[i].name == NULL)
8368       {
8369         Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'",
8370               chunk_name, filename);
8371         ReadUnusedBytesFromFile(file, chunk_size);
8372       }
8373       else if (chunk_info[i].size != -1 &&
8374                chunk_info[i].size != chunk_size)
8375       {
8376         Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
8377               chunk_size, chunk_name, filename);
8378         ReadUnusedBytesFromFile(file, chunk_size);
8379       }
8380       else
8381       {
8382         /* call function to load this tape chunk */
8383         int chunk_size_expected =
8384           (chunk_info[i].loader)(file, chunk_size, &tape);
8385
8386         /* the size of some chunks cannot be checked before reading other
8387            chunks first (like "HEAD" and "BODY") that contain some header
8388            information, so check them here */
8389         if (chunk_size_expected != chunk_size)
8390         {
8391           Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
8392                 chunk_size, chunk_name, filename);
8393         }
8394       }
8395     }
8396   }
8397
8398   fclose(file);
8399
8400   tape.length_seconds = GetTapeLength();
8401
8402 #if 0
8403   printf("::: tape file version: %d\n", tape.file_version);
8404   printf("::: tape game version: %d\n", tape.game_version);
8405   printf("::: tape engine version: %d\n", tape.engine_version);
8406 #endif
8407 }
8408
8409 void LoadTape(int nr)
8410 {
8411   char *filename = getTapeFilename(nr);
8412
8413   LoadTapeFromFilename(filename);
8414 }
8415
8416 void LoadSolutionTape(int nr)
8417 {
8418   char *filename = getSolutionTapeFilename(nr);
8419
8420   LoadTapeFromFilename(filename);
8421
8422 #if 1
8423   if (TAPE_IS_EMPTY(tape) &&
8424       level.game_engine_type == GAME_ENGINE_TYPE_SP &&
8425       level.native_sp_level->demo.is_available)
8426     CopyNativeTape_SP_to_RND(&level);
8427 #endif
8428 }
8429
8430 static void SaveTape_VERS(FILE *file, struct TapeInfo *tape)
8431 {
8432   putFileVersion(file, tape->file_version);
8433   putFileVersion(file, tape->game_version);
8434 }
8435
8436 static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
8437 {
8438   int i;
8439   byte store_participating_players = 0;
8440
8441   /* set bits for participating players for compact storage */
8442   for (i = 0; i < MAX_PLAYERS; i++)
8443     if (tape->player_participates[i])
8444       store_participating_players |= (1 << i);
8445
8446   putFile32BitBE(file, tape->random_seed);
8447   putFile32BitBE(file, tape->date);
8448   putFile32BitBE(file, tape->length);
8449
8450   putFile8Bit(file, store_participating_players);
8451
8452   /* unused bytes not at the end here for 4-byte alignment of engine_version */
8453   WriteUnusedBytesToFile(file, TAPE_CHUNK_HEAD_UNUSED);
8454
8455   putFileVersion(file, tape->engine_version);
8456 }
8457
8458 static void SaveTape_INFO(FILE *file, struct TapeInfo *tape)
8459 {
8460   int level_identifier_size = strlen(tape->level_identifier) + 1;
8461   int i;
8462
8463   putFile16BitBE(file, level_identifier_size);
8464
8465   for (i = 0; i < level_identifier_size; i++)
8466     putFile8Bit(file, tape->level_identifier[i]);
8467
8468   putFile16BitBE(file, tape->level_nr);
8469 }
8470
8471 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
8472 {
8473   int i, j;
8474
8475   for (i = 0; i < tape->length; i++)
8476   {
8477     for (j = 0; j < MAX_PLAYERS; j++)
8478       if (tape->player_participates[j])
8479         putFile8Bit(file, tape->pos[i].action[j]);
8480
8481     putFile8Bit(file, tape->pos[i].delay);
8482   }
8483 }
8484
8485 void SaveTape(int nr)
8486 {
8487   char *filename = getTapeFilename(nr);
8488   FILE *file;
8489 #if 0
8490   boolean new_tape = TRUE;
8491 #endif
8492   int num_participating_players = 0;
8493   int info_chunk_size;
8494   int body_chunk_size;
8495   int i;
8496
8497   InitTapeDirectory(leveldir_current->subdir);
8498
8499 #if 0
8500   /* if a tape still exists, ask to overwrite it */
8501   if (fileExists(filename))
8502   {
8503     new_tape = FALSE;
8504     if (!Request("Replace old tape ?", REQ_ASK))
8505       return;
8506   }
8507 #endif
8508
8509   if (!(file = fopen(filename, MODE_WRITE)))
8510   {
8511     Error(ERR_WARN, "cannot save level recording file '%s'", filename);
8512     return;
8513   }
8514
8515   tape.file_version = FILE_VERSION_ACTUAL;
8516   tape.game_version = GAME_VERSION_ACTUAL;
8517
8518   /* count number of participating players  */
8519   for (i = 0; i < MAX_PLAYERS; i++)
8520     if (tape.player_participates[i])
8521       num_participating_players++;
8522
8523   info_chunk_size = 2 + (strlen(tape.level_identifier) + 1) + 2;
8524   body_chunk_size = (num_participating_players + 1) * tape.length;
8525
8526   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
8527   putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
8528
8529   putFileChunkBE(file, "VERS", TAPE_CHUNK_VERS_SIZE);
8530   SaveTape_VERS(file, &tape);
8531
8532   putFileChunkBE(file, "HEAD", TAPE_CHUNK_HEAD_SIZE);
8533   SaveTape_HEAD(file, &tape);
8534
8535   putFileChunkBE(file, "INFO", info_chunk_size);
8536   SaveTape_INFO(file, &tape);
8537
8538   putFileChunkBE(file, "BODY", body_chunk_size);
8539   SaveTape_BODY(file, &tape);
8540
8541   fclose(file);
8542
8543   SetFilePermissions(filename, PERMS_PRIVATE);
8544
8545   tape.changed = FALSE;
8546
8547 #if 0
8548   if (new_tape)
8549     Request("Tape saved !", REQ_CONFIRM);
8550 #endif
8551 }
8552
8553 boolean SaveTapeChecked(int nr)
8554 {
8555   char *filename = getTapeFilename(nr);
8556   boolean new_tape = !fileExists(filename);
8557   boolean tape_saved = FALSE;
8558
8559   if (new_tape || Request("Replace old tape ?", REQ_ASK))
8560   {
8561     SaveTape(nr);
8562
8563     if (new_tape)
8564       Request("Tape saved !", REQ_CONFIRM);
8565
8566     tape_saved = TRUE;
8567   }
8568
8569   return tape_saved;
8570 }
8571
8572 void DumpTape(struct TapeInfo *tape)
8573 {
8574   int tape_frame_counter;
8575   int i, j;
8576
8577   if (tape->no_valid_file)
8578   {
8579     Error(ERR_WARN, "cannot dump -- no valid tape file found");
8580
8581     return;
8582   }
8583
8584   printf_line("-", 79);
8585   printf("Tape of Level %03d (file version %08d, game version %08d)\n",
8586          tape->level_nr, tape->file_version, tape->game_version);
8587   printf("                  (effective engine version %08d)\n",
8588          tape->engine_version);
8589   printf("Level series identifier: '%s'\n", tape->level_identifier);
8590   printf_line("-", 79);
8591
8592   tape_frame_counter = 0;
8593
8594   for (i = 0; i < tape->length; i++)
8595   {
8596     if (i >= MAX_TAPE_LEN)
8597       break;
8598
8599     printf("%04d: ", i);
8600
8601     for (j = 0; j < MAX_PLAYERS; j++)
8602     {
8603       if (tape->player_participates[j])
8604       {
8605         int action = tape->pos[i].action[j];
8606
8607         printf("%d:%02x ", j, action);
8608         printf("[%c%c%c%c|%c%c] - ",
8609                (action & JOY_LEFT ? '<' : ' '),
8610                (action & JOY_RIGHT ? '>' : ' '),
8611                (action & JOY_UP ? '^' : ' '),
8612                (action & JOY_DOWN ? 'v' : ' '),
8613                (action & JOY_BUTTON_1 ? '1' : ' '),
8614                (action & JOY_BUTTON_2 ? '2' : ' '));
8615       }
8616     }
8617
8618     printf("(%03d) ", tape->pos[i].delay);
8619     printf("[%05d]\n", tape_frame_counter);
8620
8621     tape_frame_counter += tape->pos[i].delay;
8622   }
8623
8624   printf_line("-", 79);
8625 }
8626
8627
8628 /* ========================================================================= */
8629 /* score file functions                                                      */
8630 /* ========================================================================= */
8631
8632 void LoadScore(int nr)
8633 {
8634   int i;
8635   char *filename = getScoreFilename(nr);
8636   char cookie[MAX_LINE_LEN];
8637   char line[MAX_LINE_LEN];
8638   char *line_ptr;
8639   FILE *file;
8640
8641   /* always start with reliable default values */
8642   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
8643   {
8644     strcpy(highscore[i].Name, EMPTY_PLAYER_NAME);
8645     highscore[i].Score = 0;
8646   }
8647
8648   if (!(file = fopen(filename, MODE_READ)))
8649     return;
8650
8651   /* check file identifier */
8652   fgets(cookie, MAX_LINE_LEN, file);
8653   if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
8654     cookie[strlen(cookie) - 1] = '\0';
8655
8656   if (!checkCookieString(cookie, SCORE_COOKIE))
8657   {
8658     Error(ERR_WARN, "unknown format of score file '%s'", filename);
8659     fclose(file);
8660     return;
8661   }
8662
8663   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
8664   {
8665     fscanf(file, "%d", &highscore[i].Score);
8666     fgets(line, MAX_LINE_LEN, file);
8667
8668     if (line[strlen(line) - 1] == '\n')
8669       line[strlen(line) - 1] = '\0';
8670
8671     for (line_ptr = line; *line_ptr; line_ptr++)
8672     {
8673       if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
8674       {
8675         strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN);
8676         highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0';
8677         break;
8678       }
8679     }
8680   }
8681
8682   fclose(file);
8683 }
8684
8685 void SaveScore(int nr)
8686 {
8687   int i;
8688   char *filename = getScoreFilename(nr);
8689   FILE *file;
8690
8691   InitScoreDirectory(leveldir_current->subdir);
8692
8693   if (!(file = fopen(filename, MODE_WRITE)))
8694   {
8695     Error(ERR_WARN, "cannot save score for level %d", nr);
8696     return;
8697   }
8698
8699   fprintf(file, "%s\n\n", SCORE_COOKIE);
8700
8701   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
8702     fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name);
8703
8704   fclose(file);
8705
8706   SetFilePermissions(filename, PERMS_PUBLIC);
8707 }
8708
8709
8710 /* ========================================================================= */
8711 /* setup file functions                                                      */
8712 /* ========================================================================= */
8713
8714 #define TOKEN_STR_PLAYER_PREFIX                 "player_"
8715
8716 /* global setup */
8717 #define SETUP_TOKEN_PLAYER_NAME                 0
8718 #define SETUP_TOKEN_SOUND                       1
8719 #define SETUP_TOKEN_SOUND_LOOPS                 2
8720 #define SETUP_TOKEN_SOUND_MUSIC                 3
8721 #define SETUP_TOKEN_SOUND_SIMPLE                4
8722 #define SETUP_TOKEN_TOONS                       5
8723 #define SETUP_TOKEN_SCROLL_DELAY                6
8724 #define SETUP_TOKEN_SCROLL_DELAY_VALUE          7
8725 #define SETUP_TOKEN_SOFT_SCROLLING              8
8726 #define SETUP_TOKEN_FADE_SCREENS                9
8727 #define SETUP_TOKEN_AUTORECORD                  10
8728 #define SETUP_TOKEN_SHOW_TITLESCREEN            11
8729 #define SETUP_TOKEN_QUICK_DOORS                 12
8730 #define SETUP_TOKEN_TEAM_MODE                   13
8731 #define SETUP_TOKEN_HANDICAP                    14
8732 #define SETUP_TOKEN_SKIP_LEVELS                 15
8733 #define SETUP_TOKEN_TIME_LIMIT                  16
8734 #define SETUP_TOKEN_FULLSCREEN                  17
8735 #define SETUP_TOKEN_FULLSCREEN_MODE             18
8736 #define SETUP_TOKEN_ASK_ON_ESCAPE               19
8737 #define SETUP_TOKEN_ASK_ON_ESCAPE_EDITOR        20
8738 #define SETUP_TOKEN_QUICK_SWITCH                21
8739 #define SETUP_TOKEN_INPUT_ON_FOCUS              22
8740 #define SETUP_TOKEN_PREFER_AGA_GRAPHICS         23
8741 #define SETUP_TOKEN_GAME_FRAME_DELAY            24
8742 #define SETUP_TOKEN_SP_SHOW_BORDER_ELEMENTS     25
8743 #define SETUP_TOKEN_GRAPHICS_SET                26
8744 #define SETUP_TOKEN_SOUNDS_SET                  27
8745 #define SETUP_TOKEN_MUSIC_SET                   28
8746 #define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS     29
8747 #define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS       30
8748 #define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC        31
8749
8750 #define NUM_GLOBAL_SETUP_TOKENS                 32
8751
8752 /* editor setup */
8753 #define SETUP_TOKEN_EDITOR_EL_BOULDERDASH       0
8754 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE      1
8755 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE_CLUB 2
8756 #define SETUP_TOKEN_EDITOR_EL_MORE              3
8757 #define SETUP_TOKEN_EDITOR_EL_SOKOBAN           4
8758 #define SETUP_TOKEN_EDITOR_EL_SUPAPLEX          5
8759 #define SETUP_TOKEN_EDITOR_EL_DIAMOND_CAVES     6
8760 #define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH    7
8761 #define SETUP_TOKEN_EDITOR_EL_CHARS             8
8762 #define SETUP_TOKEN_EDITOR_EL_STEEL_CHARS       9
8763 #define SETUP_TOKEN_EDITOR_EL_CUSTOM            10
8764 #define SETUP_TOKEN_EDITOR_EL_HEADLINES         11
8765 #define SETUP_TOKEN_EDITOR_EL_USER_DEFINED      12
8766 #define SETUP_TOKEN_EDITOR_EL_DYNAMIC           13
8767 #define SETUP_TOKEN_EDITOR_EL_BY_GAME           14
8768 #define SETUP_TOKEN_EDITOR_EL_BY_TYPE           15
8769 #define SETUP_TOKEN_EDITOR_SHOW_ELEMENT_TOKEN   16
8770
8771 #define NUM_EDITOR_SETUP_TOKENS                 17
8772
8773 /* editor cascade setup */
8774 #define SETUP_TOKEN_EDITOR_CASCADE_BD           0
8775 #define SETUP_TOKEN_EDITOR_CASCADE_EM           1
8776 #define SETUP_TOKEN_EDITOR_CASCADE_EMC          2
8777 #define SETUP_TOKEN_EDITOR_CASCADE_RND          3
8778 #define SETUP_TOKEN_EDITOR_CASCADE_SB           4
8779 #define SETUP_TOKEN_EDITOR_CASCADE_SP           5
8780 #define SETUP_TOKEN_EDITOR_CASCADE_DC           6
8781 #define SETUP_TOKEN_EDITOR_CASCADE_DX           7
8782 #define SETUP_TOKEN_EDITOR_CASCADE_TEXT         8
8783 #define SETUP_TOKEN_EDITOR_CASCADE_STEELTEXT    9
8784 #define SETUP_TOKEN_EDITOR_CASCADE_CE           10
8785 #define SETUP_TOKEN_EDITOR_CASCADE_GE           11
8786 #define SETUP_TOKEN_EDITOR_CASCADE_REF          12
8787 #define SETUP_TOKEN_EDITOR_CASCADE_USER         13
8788 #define SETUP_TOKEN_EDITOR_CASCADE_DYNAMIC      14
8789
8790 #define NUM_EDITOR_CASCADE_SETUP_TOKENS         15
8791
8792 /* shortcut setup */
8793 #define SETUP_TOKEN_SHORTCUT_SAVE_GAME          0
8794 #define SETUP_TOKEN_SHORTCUT_LOAD_GAME          1
8795 #define SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE       2
8796 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_1     3
8797 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_2     4
8798 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_3     5
8799 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_4     6
8800 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_ALL   7
8801
8802 #define NUM_SHORTCUT_SETUP_TOKENS               8
8803
8804 /* player setup */
8805 #define SETUP_TOKEN_PLAYER_USE_JOYSTICK         0
8806 #define SETUP_TOKEN_PLAYER_JOY_DEVICE_NAME      1
8807 #define SETUP_TOKEN_PLAYER_JOY_XLEFT            2
8808 #define SETUP_TOKEN_PLAYER_JOY_XMIDDLE          3
8809 #define SETUP_TOKEN_PLAYER_JOY_XRIGHT           4
8810 #define SETUP_TOKEN_PLAYER_JOY_YUPPER           5
8811 #define SETUP_TOKEN_PLAYER_JOY_YMIDDLE          6
8812 #define SETUP_TOKEN_PLAYER_JOY_YLOWER           7
8813 #define SETUP_TOKEN_PLAYER_JOY_SNAP             8
8814 #define SETUP_TOKEN_PLAYER_JOY_DROP             9
8815 #define SETUP_TOKEN_PLAYER_KEY_LEFT             10
8816 #define SETUP_TOKEN_PLAYER_KEY_RIGHT            11
8817 #define SETUP_TOKEN_PLAYER_KEY_UP               12
8818 #define SETUP_TOKEN_PLAYER_KEY_DOWN             13
8819 #define SETUP_TOKEN_PLAYER_KEY_SNAP             14
8820 #define SETUP_TOKEN_PLAYER_KEY_DROP             15
8821
8822 #define NUM_PLAYER_SETUP_TOKENS                 16
8823
8824 /* system setup */
8825 #define SETUP_TOKEN_SYSTEM_SDL_VIDEODRIVER      0
8826 #define SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER      1
8827 #define SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE  2
8828
8829 #define NUM_SYSTEM_SETUP_TOKENS                 3
8830
8831 /* options setup */
8832 #define SETUP_TOKEN_OPTIONS_VERBOSE             0
8833
8834 #define NUM_OPTIONS_SETUP_TOKENS                1
8835
8836
8837 static struct SetupInfo si;
8838 static struct SetupEditorInfo sei;
8839 static struct SetupEditorCascadeInfo seci;
8840 static struct SetupShortcutInfo ssi;
8841 static struct SetupInputInfo sii;
8842 static struct SetupSystemInfo syi;
8843 static struct OptionInfo soi;
8844
8845 static struct TokenInfo global_setup_tokens[] =
8846 {
8847   { TYPE_STRING, &si.player_name,             "player_name"             },
8848   { TYPE_SWITCH, &si.sound,                   "sound"                   },
8849   { TYPE_SWITCH, &si.sound_loops,             "repeating_sound_loops"   },
8850   { TYPE_SWITCH, &si.sound_music,             "background_music"        },
8851   { TYPE_SWITCH, &si.sound_simple,            "simple_sound_effects"    },
8852   { TYPE_SWITCH, &si.toons,                   "toons"                   },
8853   { TYPE_SWITCH, &si.scroll_delay,            "scroll_delay"            },
8854   { TYPE_INTEGER,&si.scroll_delay_value,      "scroll_delay_value"      },
8855   { TYPE_SWITCH, &si.soft_scrolling,          "soft_scrolling"          },
8856   { TYPE_SWITCH, &si.fade_screens,            "fade_screens"            },
8857   { TYPE_SWITCH, &si.autorecord,              "automatic_tape_recording"},
8858   { TYPE_SWITCH, &si.show_titlescreen,        "show_titlescreen"        },
8859   { TYPE_SWITCH, &si.quick_doors,             "quick_doors"             },
8860   { TYPE_SWITCH, &si.team_mode,               "team_mode"               },
8861   { TYPE_SWITCH, &si.handicap,                "handicap"                },
8862   { TYPE_SWITCH, &si.skip_levels,             "skip_levels"             },
8863   { TYPE_SWITCH, &si.time_limit,              "time_limit"              },
8864   { TYPE_SWITCH, &si.fullscreen,              "fullscreen"              },
8865   { TYPE_STRING, &si.fullscreen_mode,         "fullscreen_mode"         },
8866   { TYPE_SWITCH, &si.ask_on_escape,           "ask_on_escape"           },
8867   { TYPE_SWITCH, &si.ask_on_escape_editor,    "ask_on_escape_editor"    },
8868   { TYPE_SWITCH, &si.quick_switch,            "quick_player_switch"     },
8869   { TYPE_SWITCH, &si.input_on_focus,          "input_on_focus"          },
8870   { TYPE_SWITCH, &si.prefer_aga_graphics,     "prefer_aga_graphics"     },
8871   { TYPE_INTEGER,&si.game_frame_delay,        "game_frame_delay"        },
8872   { TYPE_SWITCH, &si.sp_show_border_elements, "sp_show_border_elements" },
8873   { TYPE_STRING, &si.graphics_set,            "graphics_set"            },
8874   { TYPE_STRING, &si.sounds_set,              "sounds_set"              },
8875   { TYPE_STRING, &si.music_set,               "music_set"               },
8876   { TYPE_SWITCH3,&si.override_level_graphics, "override_level_graphics" },
8877   { TYPE_SWITCH3,&si.override_level_sounds,   "override_level_sounds"   },
8878   { TYPE_SWITCH3,&si.override_level_music,    "override_level_music"    },
8879 };
8880
8881 static boolean not_used = FALSE;
8882 static struct TokenInfo editor_setup_tokens[] =
8883 {
8884 #if 1
8885   { TYPE_SWITCH, &not_used,             "editor.el_boulderdash"         },
8886   { TYPE_SWITCH, &not_used,             "editor.el_emerald_mine"        },
8887   { TYPE_SWITCH, &not_used,             "editor.el_emerald_mine_club"   },
8888   { TYPE_SWITCH, &not_used,             "editor.el_more"                },
8889   { TYPE_SWITCH, &not_used,             "editor.el_sokoban"             },
8890   { TYPE_SWITCH, &not_used,             "editor.el_supaplex"            },
8891   { TYPE_SWITCH, &not_used,             "editor.el_diamond_caves"       },
8892   { TYPE_SWITCH, &not_used,             "editor.el_dx_boulderdash"      },
8893 #else
8894   { TYPE_SWITCH, &sei.el_boulderdash,   "editor.el_boulderdash"         },
8895   { TYPE_SWITCH, &sei.el_emerald_mine,  "editor.el_emerald_mine"        },
8896   { TYPE_SWITCH, &sei.el_emerald_mine_club,"editor.el_emerald_mine_club"},
8897   { TYPE_SWITCH, &sei.el_more,          "editor.el_more"                },
8898   { TYPE_SWITCH, &sei.el_sokoban,       "editor.el_sokoban"             },
8899   { TYPE_SWITCH, &sei.el_supaplex,      "editor.el_supaplex"            },
8900   { TYPE_SWITCH, &sei.el_diamond_caves, "editor.el_diamond_caves"       },
8901   { TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash"      },
8902 #endif
8903   { TYPE_SWITCH, &sei.el_chars,         "editor.el_chars"               },
8904   { TYPE_SWITCH, &sei.el_steel_chars,   "editor.el_steel_chars"         },
8905   { TYPE_SWITCH, &sei.el_custom,        "editor.el_custom"              },
8906 #if 1
8907   { TYPE_SWITCH, &not_used,             "editor.el_headlines"           },
8908 #else
8909   { TYPE_SWITCH, &sei.el_headlines,     "editor.el_headlines"           },
8910 #endif
8911   { TYPE_SWITCH, &sei.el_user_defined,  "editor.el_user_defined"        },
8912   { TYPE_SWITCH, &sei.el_dynamic,       "editor.el_dynamic"             },
8913   { TYPE_SWITCH, &sei.el_by_game,       "editor.el_by_game"             },
8914   { TYPE_SWITCH, &sei.el_by_type,       "editor.el_by_type"             },
8915   { TYPE_SWITCH, &sei.show_element_token,"editor.show_element_token"    },
8916 };
8917
8918 static struct TokenInfo editor_cascade_setup_tokens[] =
8919 {
8920   { TYPE_SWITCH, &seci.el_bd,           "editor.cascade.el_bd"          },
8921   { TYPE_SWITCH, &seci.el_em,           "editor.cascade.el_em"          },
8922   { TYPE_SWITCH, &seci.el_emc,          "editor.cascade.el_emc"         },
8923   { TYPE_SWITCH, &seci.el_rnd,          "editor.cascade.el_rnd"         },
8924   { TYPE_SWITCH, &seci.el_sb,           "editor.cascade.el_sb"          },
8925   { TYPE_SWITCH, &seci.el_sp,           "editor.cascade.el_sp"          },
8926   { TYPE_SWITCH, &seci.el_dc,           "editor.cascade.el_dc"          },
8927   { TYPE_SWITCH, &seci.el_dx,           "editor.cascade.el_dx"          },
8928   { TYPE_SWITCH, &seci.el_chars,        "editor.cascade.el_chars"       },
8929   { TYPE_SWITCH, &seci.el_steel_chars,  "editor.cascade.el_steel_chars" },
8930   { TYPE_SWITCH, &seci.el_ce,           "editor.cascade.el_ce"          },
8931   { TYPE_SWITCH, &seci.el_ge,           "editor.cascade.el_ge"          },
8932   { TYPE_SWITCH, &seci.el_ref,          "editor.cascade.el_ref"         },
8933   { TYPE_SWITCH, &seci.el_user,         "editor.cascade.el_user"        },
8934   { TYPE_SWITCH, &seci.el_dynamic,      "editor.cascade.el_dynamic"     },
8935 };
8936
8937 static struct TokenInfo shortcut_setup_tokens[] =
8938 {
8939   { TYPE_KEY_X11, &ssi.save_game,       "shortcut.save_game"            },
8940   { TYPE_KEY_X11, &ssi.load_game,       "shortcut.load_game"            },
8941   { TYPE_KEY_X11, &ssi.toggle_pause,    "shortcut.toggle_pause"         },
8942   { TYPE_KEY_X11, &ssi.focus_player[0], "shortcut.focus_player_1"       },
8943   { TYPE_KEY_X11, &ssi.focus_player[1], "shortcut.focus_player_2"       },
8944   { TYPE_KEY_X11, &ssi.focus_player[2], "shortcut.focus_player_3"       },
8945   { TYPE_KEY_X11, &ssi.focus_player[3], "shortcut.focus_player_4"       },
8946   { TYPE_KEY_X11, &ssi.focus_player_all,"shortcut.focus_player_all"     },
8947 };
8948
8949 static struct TokenInfo player_setup_tokens[] =
8950 {
8951   { TYPE_BOOLEAN, &sii.use_joystick,    ".use_joystick"                 },
8952   { TYPE_STRING,  &sii.joy.device_name, ".joy.device_name"              },
8953   { TYPE_INTEGER, &sii.joy.xleft,       ".joy.xleft"                    },
8954   { TYPE_INTEGER, &sii.joy.xmiddle,     ".joy.xmiddle"                  },
8955   { TYPE_INTEGER, &sii.joy.xright,      ".joy.xright"                   },
8956   { TYPE_INTEGER, &sii.joy.yupper,      ".joy.yupper"                   },
8957   { TYPE_INTEGER, &sii.joy.ymiddle,     ".joy.ymiddle"                  },
8958   { TYPE_INTEGER, &sii.joy.ylower,      ".joy.ylower"                   },
8959   { TYPE_INTEGER, &sii.joy.snap,        ".joy.snap_field"               },
8960   { TYPE_INTEGER, &sii.joy.drop,        ".joy.place_bomb"               },
8961   { TYPE_KEY_X11, &sii.key.left,        ".key.move_left"                },
8962   { TYPE_KEY_X11, &sii.key.right,       ".key.move_right"               },
8963   { TYPE_KEY_X11, &sii.key.up,          ".key.move_up"                  },
8964   { TYPE_KEY_X11, &sii.key.down,        ".key.move_down"                },
8965   { TYPE_KEY_X11, &sii.key.snap,        ".key.snap_field"               },
8966   { TYPE_KEY_X11, &sii.key.drop,        ".key.place_bomb"               },
8967 };
8968
8969 static struct TokenInfo system_setup_tokens[] =
8970 {
8971   { TYPE_STRING,  &syi.sdl_videodriver, "system.sdl_videodriver"        },
8972   { TYPE_STRING,  &syi.sdl_audiodriver, "system.sdl_audiodriver"        },
8973   { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size" },
8974 };
8975
8976 static struct TokenInfo options_setup_tokens[] =
8977 {
8978   { TYPE_BOOLEAN, &soi.verbose,         "options.verbose"               },
8979 };
8980
8981 static char *get_corrected_login_name(char *login_name)
8982 {
8983   /* needed because player name must be a fixed length string */
8984   char *login_name_new = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
8985
8986   strncpy(login_name_new, login_name, MAX_PLAYER_NAME_LEN);
8987   login_name_new[MAX_PLAYER_NAME_LEN] = '\0';
8988
8989   if (strlen(login_name) > MAX_PLAYER_NAME_LEN)         /* name has been cut */
8990     if (strchr(login_name_new, ' '))
8991       *strchr(login_name_new, ' ') = '\0';
8992
8993   return login_name_new;
8994 }
8995
8996 static void setSetupInfoToDefaults(struct SetupInfo *si)
8997 {
8998   int i;
8999
9000   si->player_name = get_corrected_login_name(getLoginName());
9001
9002   si->sound = TRUE;
9003   si->sound_loops = TRUE;
9004   si->sound_music = TRUE;
9005   si->sound_simple = TRUE;
9006   si->toons = TRUE;
9007   si->scroll_delay = TRUE;
9008   si->scroll_delay_value = STD_SCROLL_DELAY;
9009   si->soft_scrolling = TRUE;
9010   si->fade_screens = TRUE;
9011   si->autorecord = TRUE;
9012   si->show_titlescreen = TRUE;
9013   si->quick_doors = FALSE;
9014   si->team_mode = FALSE;
9015   si->handicap = TRUE;
9016   si->skip_levels = TRUE;
9017   si->time_limit = TRUE;
9018   si->fullscreen = FALSE;
9019   si->fullscreen_mode = getStringCopy(DEFAULT_FULLSCREEN_MODE);
9020   si->ask_on_escape = TRUE;
9021   si->ask_on_escape_editor = TRUE;
9022   si->quick_switch = FALSE;
9023   si->input_on_focus = FALSE;
9024   si->prefer_aga_graphics = TRUE;
9025   si->game_frame_delay = GAME_FRAME_DELAY;
9026   si->sp_show_border_elements = FALSE;
9027
9028   si->graphics_set = getStringCopy(GFX_DEFAULT_SUBDIR);
9029   si->sounds_set = getStringCopy(SND_DEFAULT_SUBDIR);
9030   si->music_set = getStringCopy(MUS_DEFAULT_SUBDIR);
9031   si->override_level_graphics = FALSE;
9032   si->override_level_sounds = FALSE;
9033   si->override_level_music = FALSE;
9034
9035   si->editor.el_boulderdash             = TRUE;
9036   si->editor.el_emerald_mine            = TRUE;
9037   si->editor.el_emerald_mine_club       = TRUE;
9038   si->editor.el_more                    = TRUE;
9039   si->editor.el_sokoban                 = TRUE;
9040   si->editor.el_supaplex                = TRUE;
9041   si->editor.el_diamond_caves           = TRUE;
9042   si->editor.el_dx_boulderdash          = TRUE;
9043   si->editor.el_chars                   = TRUE;
9044   si->editor.el_steel_chars             = TRUE;
9045   si->editor.el_custom                  = TRUE;
9046
9047   si->editor.el_headlines = TRUE;
9048   si->editor.el_user_defined = FALSE;
9049   si->editor.el_dynamic = TRUE;
9050
9051   si->editor.show_element_token = FALSE;
9052
9053   si->shortcut.save_game        = DEFAULT_KEY_SAVE_GAME;
9054   si->shortcut.load_game        = DEFAULT_KEY_LOAD_GAME;
9055   si->shortcut.toggle_pause     = DEFAULT_KEY_TOGGLE_PAUSE;
9056
9057   si->shortcut.focus_player[0]  = DEFAULT_KEY_FOCUS_PLAYER_1;
9058   si->shortcut.focus_player[1]  = DEFAULT_KEY_FOCUS_PLAYER_2;
9059   si->shortcut.focus_player[2]  = DEFAULT_KEY_FOCUS_PLAYER_3;
9060   si->shortcut.focus_player[3]  = DEFAULT_KEY_FOCUS_PLAYER_4;
9061   si->shortcut.focus_player_all = DEFAULT_KEY_FOCUS_PLAYER_ALL;
9062
9063   for (i = 0; i < MAX_PLAYERS; i++)
9064   {
9065     si->input[i].use_joystick = FALSE;
9066     si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
9067     si->input[i].joy.xleft   = JOYSTICK_XLEFT;
9068     si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
9069     si->input[i].joy.xright  = JOYSTICK_XRIGHT;
9070     si->input[i].joy.yupper  = JOYSTICK_YUPPER;
9071     si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
9072     si->input[i].joy.ylower  = JOYSTICK_YLOWER;
9073     si->input[i].joy.snap  = (i == 0 ? JOY_BUTTON_1 : 0);
9074     si->input[i].joy.drop  = (i == 0 ? JOY_BUTTON_2 : 0);
9075     si->input[i].key.left  = (i == 0 ? DEFAULT_KEY_LEFT  : KSYM_UNDEFINED);
9076     si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
9077     si->input[i].key.up    = (i == 0 ? DEFAULT_KEY_UP    : KSYM_UNDEFINED);
9078     si->input[i].key.down  = (i == 0 ? DEFAULT_KEY_DOWN  : KSYM_UNDEFINED);
9079     si->input[i].key.snap  = (i == 0 ? DEFAULT_KEY_SNAP  : KSYM_UNDEFINED);
9080     si->input[i].key.drop  = (i == 0 ? DEFAULT_KEY_DROP  : KSYM_UNDEFINED);
9081   }
9082
9083   si->system.sdl_videodriver = getStringCopy(ARG_DEFAULT);
9084   si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT);
9085   si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
9086
9087   si->options.verbose = FALSE;
9088
9089 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
9090   si->handicap = FALSE;
9091   si->fullscreen = TRUE;
9092   si->override_level_graphics = AUTO;
9093   si->override_level_sounds = AUTO;
9094   si->override_level_music = AUTO;
9095 #endif
9096 }
9097
9098 static void setSetupInfoToDefaults_EditorCascade(struct SetupInfo *si)
9099 {
9100   si->editor_cascade.el_bd              = TRUE;
9101   si->editor_cascade.el_em              = TRUE;
9102   si->editor_cascade.el_emc             = TRUE;
9103   si->editor_cascade.el_rnd             = TRUE;
9104   si->editor_cascade.el_sb              = TRUE;
9105   si->editor_cascade.el_sp              = TRUE;
9106   si->editor_cascade.el_dc              = TRUE;
9107   si->editor_cascade.el_dx              = TRUE;
9108
9109   si->editor_cascade.el_chars           = FALSE;
9110   si->editor_cascade.el_steel_chars     = FALSE;
9111   si->editor_cascade.el_ce              = FALSE;
9112   si->editor_cascade.el_ge              = FALSE;
9113   si->editor_cascade.el_ref             = FALSE;
9114   si->editor_cascade.el_user            = FALSE;
9115   si->editor_cascade.el_dynamic         = FALSE;
9116 }
9117
9118 static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
9119 {
9120   int i, pnr;
9121
9122   if (!setup_file_hash)
9123     return;
9124
9125   /* global setup */
9126   si = setup;
9127   for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
9128     setSetupInfo(global_setup_tokens, i,
9129                  getHashEntry(setup_file_hash, global_setup_tokens[i].text));
9130   setup = si;
9131
9132   /* editor setup */
9133   sei = setup.editor;
9134   for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
9135     setSetupInfo(editor_setup_tokens, i,
9136                  getHashEntry(setup_file_hash,editor_setup_tokens[i].text));
9137   setup.editor = sei;
9138
9139   /* shortcut setup */
9140   ssi = setup.shortcut;
9141   for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
9142     setSetupInfo(shortcut_setup_tokens, i,
9143                  getHashEntry(setup_file_hash,shortcut_setup_tokens[i].text));
9144   setup.shortcut = ssi;
9145
9146   /* player setup */
9147   for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
9148   {
9149     char prefix[30];
9150
9151     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
9152
9153     sii = setup.input[pnr];
9154     for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
9155     {
9156       char full_token[100];
9157
9158       sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
9159       setSetupInfo(player_setup_tokens, i,
9160                    getHashEntry(setup_file_hash, full_token));
9161     }
9162     setup.input[pnr] = sii;
9163   }
9164
9165   /* system setup */
9166   syi = setup.system;
9167   for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
9168     setSetupInfo(system_setup_tokens, i,
9169                  getHashEntry(setup_file_hash, system_setup_tokens[i].text));
9170   setup.system = syi;
9171
9172   /* options setup */
9173   soi = setup.options;
9174   for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
9175     setSetupInfo(options_setup_tokens, i,
9176                  getHashEntry(setup_file_hash, options_setup_tokens[i].text));
9177   setup.options = soi;
9178 }
9179
9180 static void decodeSetupFileHash_EditorCascade(SetupFileHash *setup_file_hash)
9181 {
9182   int i;
9183
9184   if (!setup_file_hash)
9185     return;
9186
9187   /* editor cascade setup */
9188   seci = setup.editor_cascade;
9189   for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
9190     setSetupInfo(editor_cascade_setup_tokens, i,
9191                  getHashEntry(setup_file_hash,
9192                               editor_cascade_setup_tokens[i].text));
9193   setup.editor_cascade = seci;
9194 }
9195
9196 void LoadSetup()
9197 {
9198   char *filename = getSetupFilename();
9199   SetupFileHash *setup_file_hash = NULL;
9200
9201   /* always start with reliable default values */
9202   setSetupInfoToDefaults(&setup);
9203
9204   setup_file_hash = loadSetupFileHash(filename);
9205
9206   if (setup_file_hash)
9207   {
9208     char *player_name_new;
9209
9210     checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP"));
9211     decodeSetupFileHash(setup_file_hash);
9212
9213     freeSetupFileHash(setup_file_hash);
9214
9215     /* needed to work around problems with fixed length strings */
9216     player_name_new = get_corrected_login_name(setup.player_name);
9217     free(setup.player_name);
9218     setup.player_name = player_name_new;
9219
9220     /* "scroll_delay: on(3) / off(0)" was replaced by scroll delay value */
9221     if (setup.scroll_delay == FALSE)
9222     {
9223       setup.scroll_delay_value = MIN_SCROLL_DELAY;
9224       setup.scroll_delay = TRUE;                        /* now always "on" */
9225     }
9226
9227     /* make sure that scroll delay value stays inside valid range */
9228     setup.scroll_delay_value =
9229       MIN(MAX(MIN_SCROLL_DELAY, setup.scroll_delay_value), MAX_SCROLL_DELAY);
9230   }
9231   else
9232     Error(ERR_WARN, "using default setup values");
9233 }
9234
9235 void LoadSetup_EditorCascade()
9236 {
9237   char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
9238   SetupFileHash *setup_file_hash = NULL;
9239
9240   /* always start with reliable default values */
9241   setSetupInfoToDefaults_EditorCascade(&setup);
9242
9243   setup_file_hash = loadSetupFileHash(filename);
9244
9245   if (setup_file_hash)
9246   {
9247     checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP"));
9248     decodeSetupFileHash_EditorCascade(setup_file_hash);
9249
9250     freeSetupFileHash(setup_file_hash);
9251   }
9252
9253   free(filename);
9254 }
9255
9256 void SaveSetup()
9257 {
9258   char *filename = getSetupFilename();
9259   FILE *file;
9260   int i, pnr;
9261
9262   InitUserDataDirectory();
9263
9264   if (!(file = fopen(filename, MODE_WRITE)))
9265   {
9266     Error(ERR_WARN, "cannot write setup file '%s'", filename);
9267     return;
9268   }
9269
9270   fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
9271                                                getCookie("SETUP")));
9272   fprintf(file, "\n");
9273
9274   /* global setup */
9275   si = setup;
9276   for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
9277   {
9278     /* just to make things nicer :) */
9279     if (i == SETUP_TOKEN_PLAYER_NAME + 1 ||
9280         i == SETUP_TOKEN_GRAPHICS_SET)
9281       fprintf(file, "\n");
9282
9283     fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
9284   }
9285
9286   /* editor setup */
9287   sei = setup.editor;
9288   fprintf(file, "\n");
9289   for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
9290     fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i));
9291
9292   /* shortcut setup */
9293   ssi = setup.shortcut;
9294   fprintf(file, "\n");
9295   for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
9296     fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
9297
9298   /* player setup */
9299   for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
9300   {
9301     char prefix[30];
9302
9303     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
9304     fprintf(file, "\n");
9305
9306     sii = setup.input[pnr];
9307     for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
9308       fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
9309   }
9310
9311   /* system setup */
9312   syi = setup.system;
9313   fprintf(file, "\n");
9314   for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
9315     fprintf(file, "%s\n", getSetupLine(system_setup_tokens, "", i));
9316
9317   /* options setup */
9318   soi = setup.options;
9319   fprintf(file, "\n");
9320   for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
9321     fprintf(file, "%s\n", getSetupLine(options_setup_tokens, "", i));
9322
9323   fclose(file);
9324
9325   SetFilePermissions(filename, PERMS_PRIVATE);
9326 }
9327
9328 void SaveSetup_EditorCascade()
9329 {
9330   char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
9331   FILE *file;
9332   int i;
9333
9334   InitUserDataDirectory();
9335
9336   if (!(file = fopen(filename, MODE_WRITE)))
9337   {
9338     Error(ERR_WARN, "cannot write editor cascade state file '%s'", filename);
9339     free(filename);
9340     return;
9341   }
9342
9343   fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
9344                                                getCookie("SETUP")));
9345   fprintf(file, "\n");
9346
9347   seci = setup.editor_cascade;
9348   fprintf(file, "\n");
9349   for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
9350     fprintf(file, "%s\n", getSetupLine(editor_cascade_setup_tokens, "", i));
9351
9352   fclose(file);
9353
9354   SetFilePermissions(filename, PERMS_PRIVATE);
9355
9356   free(filename);
9357 }
9358
9359 void LoadCustomElementDescriptions()
9360 {
9361   char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
9362   SetupFileHash *setup_file_hash;
9363   int i;
9364
9365   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9366   {
9367     if (element_info[i].custom_description != NULL)
9368     {
9369       free(element_info[i].custom_description);
9370       element_info[i].custom_description = NULL;
9371     }
9372   }
9373
9374   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
9375     return;
9376
9377   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9378   {
9379     char *token = getStringCat2(element_info[i].token_name, ".name");
9380     char *value = getHashEntry(setup_file_hash, token);
9381
9382     if (value != NULL)
9383       element_info[i].custom_description = getStringCopy(value);
9384
9385     free(token);
9386   }
9387
9388   freeSetupFileHash(setup_file_hash);
9389 }
9390
9391 static int getElementFromToken(char *token)
9392 {
9393 #if 1
9394   char *value = getHashEntry(element_token_hash, token);
9395
9396   if (value != NULL)
9397     return atoi(value);
9398 #else
9399   int i;
9400
9401   /* !!! OPTIMIZE THIS BY USING HASH !!! */
9402   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
9403     if (strEqual(token, element_info[i].token_name))
9404       return i;
9405 #endif
9406
9407   Error(ERR_WARN, "unknown element token '%s'", token);
9408
9409   return EL_UNDEFINED;
9410 }
9411
9412 static int get_token_parameter_value(char *token, char *value_raw)
9413 {
9414   char *suffix;
9415
9416   if (token == NULL || value_raw == NULL)
9417     return ARG_UNDEFINED_VALUE;
9418
9419   suffix = strrchr(token, '.');
9420   if (suffix == NULL)
9421     suffix = token;
9422
9423 #if 1
9424   if (strEqual(suffix, ".element"))
9425     return getElementFromToken(value_raw);
9426 #endif
9427
9428 #if 0
9429   if (strncmp(suffix, ".font", 5) == 0)
9430   {
9431     int i;
9432
9433     /* !!! OPTIMIZE THIS BY USING HASH !!! */
9434     for (i = 0; i < NUM_FONTS; i++)
9435       if (strEqual(value_raw, font_info[i].token_name))
9436         return i;
9437
9438     /* if font not found, use reliable default value */
9439     return FONT_INITIAL_1;
9440   }
9441 #endif
9442
9443   /* !!! USE CORRECT VALUE TYPE (currently works also for TYPE_BOOLEAN) !!! */
9444   return get_parameter_value(value_raw, suffix, TYPE_INTEGER);
9445 }
9446
9447 void InitMenuDesignSettings_Static()
9448 {
9449 #if 0
9450   static SetupFileHash *image_config_hash = NULL;
9451 #endif
9452   int i;
9453
9454 #if 0
9455   if (image_config_hash == NULL)
9456   {
9457     image_config_hash = newSetupFileHash();
9458
9459     for (i = 0; image_config[i].token != NULL; i++)
9460       setHashEntry(image_config_hash,
9461                    image_config[i].token,
9462                    image_config[i].value);
9463   }
9464 #endif
9465
9466 #if 1
9467   /* always start with reliable default values from static default config */
9468   for (i = 0; image_config_vars[i].token != NULL; i++)
9469   {
9470     char *value = getHashEntry(image_config_hash, image_config_vars[i].token);
9471
9472     if (value != NULL)
9473       *image_config_vars[i].value =
9474         get_token_parameter_value(image_config_vars[i].token, value);
9475   }
9476
9477 #else
9478
9479   int j;
9480
9481   /* always start with reliable default values from static default config */
9482   for (i = 0; image_config_vars[i].token != NULL; i++)
9483     for (j = 0; image_config[j].token != NULL; j++)
9484       if (strEqual(image_config_vars[i].token, image_config[j].token))
9485         *image_config_vars[i].value =
9486           get_token_parameter_value(image_config_vars[i].token,
9487                                     image_config[j].value);
9488 #endif
9489 }
9490
9491 static void InitMenuDesignSettings_SpecialPreProcessing()
9492 {
9493   int i;
9494
9495   /* the following initializes hierarchical values from static configuration */
9496
9497   /* special case: initialize "ARG_DEFAULT" values in static default config */
9498   /* (e.g., initialize "[titlemessage].fade_mode" from "[title].fade_mode") */
9499   titlemessage_initial_default.fade_mode  = title_initial_default.fade_mode;
9500   titlemessage_initial_default.fade_delay = title_initial_default.fade_delay;
9501   titlemessage_initial_default.post_delay = title_initial_default.post_delay;
9502   titlemessage_initial_default.auto_delay = title_initial_default.auto_delay;
9503   titlemessage_default.fade_mode  = title_default.fade_mode;
9504   titlemessage_default.fade_delay = title_default.fade_delay;
9505   titlemessage_default.post_delay = title_default.post_delay;
9506   titlemessage_default.auto_delay = title_default.auto_delay;
9507
9508   /* special case: initialize "ARG_DEFAULT" values in static default config */
9509   /* (e.g., init "titlemessage_1.fade_mode" from "[titlemessage].fade_mode") */
9510   for (i = 0; i < MAX_NUM_TITLE_MESSAGES; i++)
9511   {
9512     titlemessage_initial[i] = titlemessage_initial_default;
9513     titlemessage[i] = titlemessage_default;
9514   }
9515
9516   /* special case: initialize "ARG_DEFAULT" values in static default config */
9517   /* (eg, init "menu.enter_screen.SCORES.xyz" from "menu.enter_screen.xyz") */
9518   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
9519   {
9520     menu.enter_screen[i] = menu.enter_screen[GFX_SPECIAL_ARG_DEFAULT];
9521     menu.leave_screen[i] = menu.leave_screen[GFX_SPECIAL_ARG_DEFAULT];
9522   }
9523 }
9524
9525 static void InitMenuDesignSettings_SpecialPostProcessing()
9526 {
9527   /* special case: initialize later added SETUP list size from LEVELS value */
9528   if (menu.list_size[GAME_MODE_SETUP] == -1)
9529     menu.list_size[GAME_MODE_SETUP] = menu.list_size[GAME_MODE_LEVELS];
9530 }
9531
9532 static void LoadMenuDesignSettingsFromFilename(char *filename)
9533 {
9534   static struct TitleMessageInfo tmi;
9535   static struct TokenInfo titlemessage_tokens[] =
9536   {
9537     { TYPE_INTEGER,     &tmi.x,                 ".x"                    },
9538     { TYPE_INTEGER,     &tmi.y,                 ".y"                    },
9539     { TYPE_INTEGER,     &tmi.width,             ".width"                },
9540     { TYPE_INTEGER,     &tmi.height,            ".height"               },
9541     { TYPE_INTEGER,     &tmi.chars,             ".chars"                },
9542     { TYPE_INTEGER,     &tmi.lines,             ".lines"                },
9543     { TYPE_INTEGER,     &tmi.align,             ".align"                },
9544     { TYPE_INTEGER,     &tmi.valign,            ".valign"               },
9545     { TYPE_INTEGER,     &tmi.font,              ".font"                 },
9546     { TYPE_BOOLEAN,     &tmi.autowrap,          ".autowrap"             },
9547     { TYPE_BOOLEAN,     &tmi.centered,          ".centered"             },
9548     { TYPE_BOOLEAN,     &tmi.parse_comments,    ".parse_comments"       },
9549     { TYPE_INTEGER,     &tmi.sort_priority,     ".sort_priority"        },
9550     { TYPE_INTEGER,     &tmi.fade_mode,         ".fade_mode"            },
9551     { TYPE_INTEGER,     &tmi.fade_delay,        ".fade_delay"           },
9552     { TYPE_INTEGER,     &tmi.post_delay,        ".post_delay"           },
9553     { TYPE_INTEGER,     &tmi.auto_delay,        ".auto_delay"           },
9554
9555     { -1,               NULL,                   NULL                    }
9556   };
9557   static struct
9558   {
9559     struct TitleMessageInfo *array;
9560     char *text;
9561   }
9562   titlemessage_arrays[] =
9563   {
9564     { titlemessage_initial,             "[titlemessage_initial]"        },
9565     { titlemessage,                     "[titlemessage]"                },
9566
9567     { NULL,                             NULL                            }
9568   };
9569   SetupFileHash *setup_file_hash;
9570   int i, j, k;
9571
9572 #if 0
9573   printf("LoadMenuDesignSettings from file '%s' ...\n", filename);
9574 #endif
9575
9576   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
9577     return;
9578
9579   /* the following initializes hierarchical values from dynamic configuration */
9580
9581   /* special case: initialize with default values that may be overwritten */
9582   /* (e.g., init "menu.draw_xoffset.INFO" from "menu.draw_xoffset") */
9583   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
9584   {
9585     char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset");
9586     char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset");
9587     char *value_3 = getHashEntry(setup_file_hash, "menu.list_size");
9588
9589     if (value_1 != NULL)
9590       menu.draw_xoffset[i] = get_integer_from_string(value_1);
9591     if (value_2 != NULL)
9592       menu.draw_yoffset[i] = get_integer_from_string(value_2);
9593     if (value_3 != NULL)
9594       menu.list_size[i] = get_integer_from_string(value_3);
9595   }
9596
9597   /* special case: initialize with default values that may be overwritten */
9598   /* (eg, init "menu.draw_xoffset.INFO[XXX]" from "menu.draw_xoffset.INFO") */
9599   for (i = 0; i < NUM_SPECIAL_GFX_INFO_ARGS; i++)
9600   {
9601     char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset.INFO");
9602     char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset.INFO");
9603
9604     if (value_1 != NULL)
9605       menu.draw_xoffset_info[i] = get_integer_from_string(value_1);
9606     if (value_2 != NULL)
9607       menu.draw_yoffset_info[i] = get_integer_from_string(value_2);
9608   }
9609
9610   /* special case: initialize with default values that may be overwritten */
9611   /* (eg, init "menu.draw_xoffset.SETUP[XXX]" from "menu.draw_xoffset.SETUP") */
9612   for (i = 0; i < NUM_SPECIAL_GFX_SETUP_ARGS; i++)
9613   {
9614     char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset.SETUP");
9615     char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset.SETUP");
9616
9617     if (value_1 != NULL)
9618       menu.draw_xoffset_setup[i] = get_integer_from_string(value_1);
9619     if (value_2 != NULL)
9620       menu.draw_yoffset_setup[i] = get_integer_from_string(value_2);
9621   }
9622
9623   /* special case: initialize with default values that may be overwritten */
9624   /* (eg, init "menu.enter_screen.SCORES.xyz" from "menu.enter_screen.xyz") */
9625   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
9626   {
9627     char *token_1 = "menu.enter_screen.fade_mode";
9628     char *token_2 = "menu.enter_screen.fade_delay";
9629     char *token_3 = "menu.enter_screen.post_delay";
9630     char *token_4 = "menu.leave_screen.fade_mode";
9631     char *token_5 = "menu.leave_screen.fade_delay";
9632     char *token_6 = "menu.leave_screen.post_delay";
9633     char *value_1 = getHashEntry(setup_file_hash, token_1);
9634     char *value_2 = getHashEntry(setup_file_hash, token_2);
9635     char *value_3 = getHashEntry(setup_file_hash, token_3);
9636     char *value_4 = getHashEntry(setup_file_hash, token_4);
9637     char *value_5 = getHashEntry(setup_file_hash, token_5);
9638     char *value_6 = getHashEntry(setup_file_hash, token_6);
9639
9640     if (value_1 != NULL)
9641       menu.enter_screen[i].fade_mode = get_token_parameter_value(token_1,
9642                                                                  value_1);
9643     if (value_2 != NULL)
9644       menu.enter_screen[i].fade_delay = get_token_parameter_value(token_2,
9645                                                                   value_2);
9646     if (value_3 != NULL)
9647       menu.enter_screen[i].post_delay = get_token_parameter_value(token_3,
9648                                                                   value_3);
9649     if (value_4 != NULL)
9650       menu.leave_screen[i].fade_mode = get_token_parameter_value(token_4,
9651                                                                  value_4);
9652     if (value_5 != NULL)
9653       menu.leave_screen[i].fade_delay = get_token_parameter_value(token_5,
9654                                                                   value_5);
9655     if (value_6 != NULL)
9656       menu.leave_screen[i].post_delay = get_token_parameter_value(token_6,
9657                                                                   value_6);
9658   }
9659
9660   /* special case: initialize with default values that may be overwritten */
9661   /* (e.g., init "titlemessage_1.fade_mode" from "[titlemessage].fade_mode") */
9662   for (i = 0; titlemessage_arrays[i].array != NULL; i++)
9663   {
9664     struct TitleMessageInfo *array = titlemessage_arrays[i].array;
9665     char *base_token = titlemessage_arrays[i].text;
9666
9667     for (j = 0; titlemessage_tokens[j].type != -1; j++)
9668     {
9669       char *token = getStringCat2(base_token, titlemessage_tokens[j].text);
9670       char *value = getHashEntry(setup_file_hash, token);
9671
9672       if (value != NULL)
9673       {
9674         int parameter_value = get_token_parameter_value(token, value);
9675
9676         for (k = 0; k < MAX_NUM_TITLE_MESSAGES; k++)
9677         {
9678           tmi = array[k];
9679
9680           if (titlemessage_tokens[j].type == TYPE_INTEGER)
9681             *(boolean *)titlemessage_tokens[j].value = (boolean)parameter_value;
9682           else
9683             *(int     *)titlemessage_tokens[j].value = (int)parameter_value;
9684
9685           array[k] = tmi;
9686         }
9687       }
9688
9689       free(token);
9690     }
9691   }
9692
9693   /* read (and overwrite with) values that may be specified in config file */
9694   for (i = 0; image_config_vars[i].token != NULL; i++)
9695   {
9696     char *value = getHashEntry(setup_file_hash, image_config_vars[i].token);
9697
9698     /* (ignore definitions set to "[DEFAULT]" which are already initialized) */
9699     if (value != NULL && !strEqual(value, ARG_DEFAULT))
9700       *image_config_vars[i].value =
9701         get_token_parameter_value(image_config_vars[i].token, value);
9702   }
9703
9704   freeSetupFileHash(setup_file_hash);
9705 }
9706
9707 void LoadMenuDesignSettings()
9708 {
9709   char *filename_base = UNDEFINED_FILENAME, *filename_local;
9710
9711   InitMenuDesignSettings_Static();
9712   InitMenuDesignSettings_SpecialPreProcessing();
9713
9714 #if 1
9715   if (!GFX_OVERRIDE_ARTWORK(ARTWORK_TYPE_GRAPHICS))
9716 #else
9717   if (!SETUP_OVERRIDE_ARTWORK(setup, ARTWORK_TYPE_GRAPHICS))
9718 #endif
9719   {
9720     /* first look for special settings configured in level series config */
9721     filename_base = getCustomArtworkLevelConfigFilename(ARTWORK_TYPE_GRAPHICS);
9722
9723     if (fileExists(filename_base))
9724       LoadMenuDesignSettingsFromFilename(filename_base);
9725   }
9726
9727   filename_local = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
9728
9729   if (filename_local != NULL && !strEqual(filename_base, filename_local))
9730     LoadMenuDesignSettingsFromFilename(filename_local);
9731
9732   InitMenuDesignSettings_SpecialPostProcessing();
9733 }
9734
9735 void LoadUserDefinedEditorElementList(int **elements, int *num_elements)
9736 {
9737   char *filename = getEditorSetupFilename();
9738   SetupFileList *setup_file_list, *list;
9739   SetupFileHash *element_hash;
9740   int num_unknown_tokens = 0;
9741   int i;
9742
9743   if ((setup_file_list = loadSetupFileList(filename)) == NULL)
9744     return;
9745
9746   element_hash = newSetupFileHash();
9747
9748   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9749     setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
9750
9751   /* determined size may be larger than needed (due to unknown elements) */
9752   *num_elements = 0;
9753   for (list = setup_file_list; list != NULL; list = list->next)
9754     (*num_elements)++;
9755
9756   /* add space for up to 3 more elements for padding that may be needed */
9757   *num_elements += 3;
9758
9759   /* free memory for old list of elements, if needed */
9760   checked_free(*elements);
9761
9762   /* allocate memory for new list of elements */
9763   *elements = checked_malloc(*num_elements * sizeof(int));
9764
9765   *num_elements = 0;
9766   for (list = setup_file_list; list != NULL; list = list->next)
9767   {
9768     char *value = getHashEntry(element_hash, list->token);
9769
9770     if (value == NULL)          /* try to find obsolete token mapping */
9771     {
9772       char *mapped_token = get_mapped_token(list->token);
9773
9774       if (mapped_token != NULL)
9775       {
9776         value = getHashEntry(element_hash, mapped_token);
9777
9778         free(mapped_token);
9779       }
9780     }
9781
9782     if (value != NULL)
9783     {
9784       (*elements)[(*num_elements)++] = atoi(value);
9785     }
9786     else
9787     {
9788       if (num_unknown_tokens == 0)
9789       {
9790         Error(ERR_INFO_LINE, "-");
9791         Error(ERR_INFO, "warning: unknown token(s) found in config file:");
9792         Error(ERR_INFO, "- config file: '%s'", filename);
9793
9794         num_unknown_tokens++;
9795       }
9796
9797       Error(ERR_INFO, "- token: '%s'", list->token);
9798     }
9799   }
9800
9801   if (num_unknown_tokens > 0)
9802     Error(ERR_INFO_LINE, "-");
9803
9804   while (*num_elements % 4)     /* pad with empty elements, if needed */
9805     (*elements)[(*num_elements)++] = EL_EMPTY;
9806
9807   freeSetupFileList(setup_file_list);
9808   freeSetupFileHash(element_hash);
9809
9810 #if 0
9811   for (i = 0; i < *num_elements; i++)
9812     printf("editor: element '%s' [%d]\n",
9813            element_info[(*elements)[i]].token_name, (*elements)[i]);
9814 #endif
9815 }
9816
9817 static struct MusicFileInfo *get_music_file_info_ext(char *basename, int music,
9818                                                      boolean is_sound)
9819 {
9820   SetupFileHash *setup_file_hash = NULL;
9821   struct MusicFileInfo tmp_music_file_info, *new_music_file_info;
9822   char *filename_music, *filename_prefix, *filename_info;
9823   struct
9824   {
9825     char *token;
9826     char **value_ptr;
9827   }
9828   token_to_value_ptr[] =
9829   {
9830     { "title_header",   &tmp_music_file_info.title_header       },
9831     { "artist_header",  &tmp_music_file_info.artist_header      },
9832     { "album_header",   &tmp_music_file_info.album_header       },
9833     { "year_header",    &tmp_music_file_info.year_header        },
9834
9835     { "title",          &tmp_music_file_info.title              },
9836     { "artist",         &tmp_music_file_info.artist             },
9837     { "album",          &tmp_music_file_info.album              },
9838     { "year",           &tmp_music_file_info.year               },
9839
9840     { NULL,             NULL                                    },
9841   };
9842   int i;
9843
9844   filename_music = (is_sound ? getCustomSoundFilename(basename) :
9845                     getCustomMusicFilename(basename));
9846
9847   if (filename_music == NULL)
9848     return NULL;
9849
9850   /* ---------- try to replace file extension ---------- */
9851
9852   filename_prefix = getStringCopy(filename_music);
9853   if (strrchr(filename_prefix, '.') != NULL)
9854     *strrchr(filename_prefix, '.') = '\0';
9855   filename_info = getStringCat2(filename_prefix, ".txt");
9856
9857 #if 0
9858   printf("trying to load file '%s'...\n", filename_info);
9859 #endif
9860
9861   if (fileExists(filename_info))
9862     setup_file_hash = loadSetupFileHash(filename_info);
9863
9864   free(filename_prefix);
9865   free(filename_info);
9866
9867   if (setup_file_hash == NULL)
9868   {
9869     /* ---------- try to add file extension ---------- */
9870
9871     filename_prefix = getStringCopy(filename_music);
9872     filename_info = getStringCat2(filename_prefix, ".txt");
9873
9874 #if 0
9875     printf("trying to load file '%s'...\n", filename_info);
9876 #endif
9877
9878     if (fileExists(filename_info))
9879       setup_file_hash = loadSetupFileHash(filename_info);
9880
9881     free(filename_prefix);
9882     free(filename_info);
9883   }
9884
9885   if (setup_file_hash == NULL)
9886     return NULL;
9887
9888   /* ---------- music file info found ---------- */
9889
9890   clear_mem(&tmp_music_file_info, sizeof(struct MusicFileInfo));
9891
9892   for (i = 0; token_to_value_ptr[i].token != NULL; i++)
9893   {
9894     char *value = getHashEntry(setup_file_hash, token_to_value_ptr[i].token);
9895
9896     *token_to_value_ptr[i].value_ptr =
9897       getStringCopy(value != NULL && *value != '\0' ? value : UNKNOWN_NAME);
9898   }
9899
9900   tmp_music_file_info.basename = getStringCopy(basename);
9901   tmp_music_file_info.music = music;
9902   tmp_music_file_info.is_sound = is_sound;
9903
9904   new_music_file_info = checked_malloc(sizeof(struct MusicFileInfo));
9905   *new_music_file_info = tmp_music_file_info;
9906
9907   return new_music_file_info;
9908 }
9909
9910 static struct MusicFileInfo *get_music_file_info(char *basename, int music)
9911 {
9912   return get_music_file_info_ext(basename, music, FALSE);
9913 }
9914
9915 static struct MusicFileInfo *get_sound_file_info(char *basename, int sound)
9916 {
9917   return get_music_file_info_ext(basename, sound, TRUE);
9918 }
9919
9920 static boolean music_info_listed_ext(struct MusicFileInfo *list,
9921                                      char *basename, boolean is_sound)
9922 {
9923   for (; list != NULL; list = list->next)
9924     if (list->is_sound == is_sound && strEqual(list->basename, basename))
9925       return TRUE;
9926
9927   return FALSE;
9928 }
9929
9930 static boolean music_info_listed(struct MusicFileInfo *list, char *basename)
9931 {
9932   return music_info_listed_ext(list, basename, FALSE);
9933 }
9934
9935 static boolean sound_info_listed(struct MusicFileInfo *list, char *basename)
9936 {
9937   return music_info_listed_ext(list, basename, TRUE);
9938 }
9939
9940 void LoadMusicInfo()
9941 {
9942   char *music_directory = getCustomMusicDirectory();
9943   int num_music = getMusicListSize();
9944   int num_music_noconf = 0;
9945   int num_sounds = getSoundListSize();
9946   DIR *dir;
9947   struct dirent *dir_entry;
9948   struct FileInfo *music, *sound;
9949   struct MusicFileInfo *next, **new;
9950   int i;
9951
9952   while (music_file_info != NULL)
9953   {
9954     next = music_file_info->next;
9955
9956     checked_free(music_file_info->basename);
9957
9958     checked_free(music_file_info->title_header);
9959     checked_free(music_file_info->artist_header);
9960     checked_free(music_file_info->album_header);
9961     checked_free(music_file_info->year_header);
9962
9963     checked_free(music_file_info->title);
9964     checked_free(music_file_info->artist);
9965     checked_free(music_file_info->album);
9966     checked_free(music_file_info->year);
9967
9968     free(music_file_info);
9969
9970     music_file_info = next;
9971   }
9972
9973   new = &music_file_info;
9974
9975   for (i = 0; i < num_music; i++)
9976   {
9977     music = getMusicListEntry(i);
9978
9979     if (music->filename == NULL)
9980       continue;
9981
9982     if (strEqual(music->filename, UNDEFINED_FILENAME))
9983       continue;
9984
9985     /* a configured file may be not recognized as music */
9986     if (!FileIsMusic(music->filename))
9987       continue;
9988
9989 #if 0
9990     printf("::: -> '%s' (configured)\n", music->filename);
9991 #endif
9992
9993     if (!music_info_listed(music_file_info, music->filename))
9994     {
9995       *new = get_music_file_info(music->filename, i);
9996       if (*new != NULL)
9997         new = &(*new)->next;
9998     }
9999   }
10000
10001   if ((dir = opendir(music_directory)) == NULL)
10002   {
10003     Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
10004     return;
10005   }
10006
10007   while ((dir_entry = readdir(dir)) != NULL)    /* loop until last dir entry */
10008   {
10009     char *basename = dir_entry->d_name;
10010     boolean music_already_used = FALSE;
10011     int i;
10012
10013     /* skip all music files that are configured in music config file */
10014     for (i = 0; i < num_music; i++)
10015     {
10016       music = getMusicListEntry(i);
10017
10018       if (music->filename == NULL)
10019         continue;
10020
10021       if (strEqual(basename, music->filename))
10022       {
10023         music_already_used = TRUE;
10024         break;
10025       }
10026     }
10027
10028     if (music_already_used)
10029       continue;
10030
10031     if (!FileIsMusic(basename))
10032       continue;
10033
10034 #if 0
10035     printf("::: -> '%s' (found in directory)\n", basename);
10036 #endif
10037
10038     if (!music_info_listed(music_file_info, basename))
10039     {
10040       *new = get_music_file_info(basename, MAP_NOCONF_MUSIC(num_music_noconf));
10041       if (*new != NULL)
10042         new = &(*new)->next;
10043     }
10044
10045     num_music_noconf++;
10046   }
10047
10048   closedir(dir);
10049
10050   for (i = 0; i < num_sounds; i++)
10051   {
10052     sound = getSoundListEntry(i);
10053
10054     if (sound->filename == NULL)
10055       continue;
10056
10057     if (strEqual(sound->filename, UNDEFINED_FILENAME))
10058       continue;
10059
10060     /* a configured file may be not recognized as sound */
10061     if (!FileIsSound(sound->filename))
10062       continue;
10063
10064 #if 0
10065     printf("::: -> '%s' (configured)\n", sound->filename);
10066 #endif
10067
10068     if (!sound_info_listed(music_file_info, sound->filename))
10069     {
10070       *new = get_sound_file_info(sound->filename, i);
10071       if (*new != NULL)
10072         new = &(*new)->next;
10073     }
10074   }
10075
10076 #if 0
10077   for (next = music_file_info; next != NULL; next = next->next)
10078     printf("::: title == '%s'\n", next->title);
10079 #endif
10080 }
10081
10082 void add_helpanim_entry(int element, int action, int direction, int delay,
10083                         int *num_list_entries)
10084 {
10085   struct HelpAnimInfo *new_list_entry;
10086   (*num_list_entries)++;
10087
10088   helpanim_info =
10089     checked_realloc(helpanim_info,
10090                     *num_list_entries * sizeof(struct HelpAnimInfo));
10091   new_list_entry = &helpanim_info[*num_list_entries - 1];
10092
10093   new_list_entry->element = element;
10094   new_list_entry->action = action;
10095   new_list_entry->direction = direction;
10096   new_list_entry->delay = delay;
10097 }
10098
10099 void print_unknown_token(char *filename, char *token, int token_nr)
10100 {
10101   if (token_nr == 0)
10102   {
10103     Error(ERR_INFO_LINE, "-");
10104     Error(ERR_INFO, "warning: unknown token(s) found in config file:");
10105     Error(ERR_INFO, "- config file: '%s'", filename);
10106   }
10107
10108   Error(ERR_INFO, "- token: '%s'", token);
10109 }
10110
10111 void print_unknown_token_end(int token_nr)
10112 {
10113   if (token_nr > 0)
10114     Error(ERR_INFO_LINE, "-");
10115 }
10116
10117 void LoadHelpAnimInfo()
10118 {
10119   char *filename = getHelpAnimFilename();
10120   SetupFileList *setup_file_list = NULL, *list;
10121   SetupFileHash *element_hash, *action_hash, *direction_hash;
10122   int num_list_entries = 0;
10123   int num_unknown_tokens = 0;
10124   int i;
10125
10126   if (fileExists(filename))
10127     setup_file_list = loadSetupFileList(filename);
10128
10129   if (setup_file_list == NULL)
10130   {
10131     /* use reliable default values from static configuration */
10132     SetupFileList *insert_ptr;
10133
10134     insert_ptr = setup_file_list =
10135       newSetupFileList(helpanim_config[0].token,
10136                        helpanim_config[0].value);
10137
10138     for (i = 1; helpanim_config[i].token; i++)
10139       insert_ptr = addListEntry(insert_ptr,
10140                                 helpanim_config[i].token,
10141                                 helpanim_config[i].value);
10142   }
10143
10144   element_hash   = newSetupFileHash();
10145   action_hash    = newSetupFileHash();
10146   direction_hash = newSetupFileHash();
10147
10148   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
10149     setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
10150
10151   for (i = 0; i < NUM_ACTIONS; i++)
10152     setHashEntry(action_hash, element_action_info[i].suffix,
10153                  i_to_a(element_action_info[i].value));
10154
10155   /* do not store direction index (bit) here, but direction value! */
10156   for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
10157     setHashEntry(direction_hash, element_direction_info[i].suffix,
10158                  i_to_a(1 << element_direction_info[i].value));
10159
10160   for (list = setup_file_list; list != NULL; list = list->next)
10161   {
10162     char *element_token, *action_token, *direction_token;
10163     char *element_value, *action_value, *direction_value;
10164     int delay = atoi(list->value);
10165
10166     if (strEqual(list->token, "end"))
10167     {
10168       add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
10169
10170       continue;
10171     }
10172
10173     /* first try to break element into element/action/direction parts;
10174        if this does not work, also accept combined "element[.act][.dir]"
10175        elements (like "dynamite.active"), which are unique elements */
10176
10177     if (strchr(list->token, '.') == NULL)       /* token contains no '.' */
10178     {
10179       element_value = getHashEntry(element_hash, list->token);
10180       if (element_value != NULL)        /* element found */
10181         add_helpanim_entry(atoi(element_value), -1, -1, delay,
10182                            &num_list_entries);
10183       else
10184       {
10185         /* no further suffixes found -- this is not an element */
10186         print_unknown_token(filename, list->token, num_unknown_tokens++);
10187       }
10188
10189       continue;
10190     }
10191
10192     /* token has format "<prefix>.<something>" */
10193
10194     action_token = strchr(list->token, '.');    /* suffix may be action ... */
10195     direction_token = action_token;             /* ... or direction */
10196
10197     element_token = getStringCopy(list->token);
10198     *strchr(element_token, '.') = '\0';
10199
10200     element_value = getHashEntry(element_hash, element_token);
10201
10202     if (element_value == NULL)          /* this is no element */
10203     {
10204       element_value = getHashEntry(element_hash, list->token);
10205       if (element_value != NULL)        /* combined element found */
10206         add_helpanim_entry(atoi(element_value), -1, -1, delay,
10207                            &num_list_entries);
10208       else
10209         print_unknown_token(filename, list->token, num_unknown_tokens++);
10210
10211       free(element_token);
10212
10213       continue;
10214     }
10215
10216     action_value = getHashEntry(action_hash, action_token);
10217
10218     if (action_value != NULL)           /* action found */
10219     {
10220       add_helpanim_entry(atoi(element_value), atoi(action_value), -1, delay,
10221                     &num_list_entries);
10222
10223       free(element_token);
10224
10225       continue;
10226     }
10227
10228     direction_value = getHashEntry(direction_hash, direction_token);
10229
10230     if (direction_value != NULL)        /* direction found */
10231     {
10232       add_helpanim_entry(atoi(element_value), -1, atoi(direction_value), delay,
10233                          &num_list_entries);
10234
10235       free(element_token);
10236
10237       continue;
10238     }
10239
10240     if (strchr(action_token + 1, '.') == NULL)
10241     {
10242       /* no further suffixes found -- this is not an action nor direction */
10243
10244       element_value = getHashEntry(element_hash, list->token);
10245       if (element_value != NULL)        /* combined element found */
10246         add_helpanim_entry(atoi(element_value), -1, -1, delay,
10247                            &num_list_entries);
10248       else
10249         print_unknown_token(filename, list->token, num_unknown_tokens++);
10250
10251       free(element_token);
10252
10253       continue;
10254     }
10255
10256     /* token has format "<prefix>.<suffix>.<something>" */
10257
10258     direction_token = strchr(action_token + 1, '.');
10259
10260     action_token = getStringCopy(action_token);
10261     *strchr(action_token + 1, '.') = '\0';
10262
10263     action_value = getHashEntry(action_hash, action_token);
10264
10265     if (action_value == NULL)           /* this is no action */
10266     {
10267       element_value = getHashEntry(element_hash, list->token);
10268       if (element_value != NULL)        /* combined element found */
10269         add_helpanim_entry(atoi(element_value), -1, -1, delay,
10270                            &num_list_entries);
10271       else
10272         print_unknown_token(filename, list->token, num_unknown_tokens++);
10273
10274       free(element_token);
10275       free(action_token);
10276
10277       continue;
10278     }
10279
10280     direction_value = getHashEntry(direction_hash, direction_token);
10281
10282     if (direction_value != NULL)        /* direction found */
10283     {
10284       add_helpanim_entry(atoi(element_value), atoi(action_value),
10285                          atoi(direction_value), delay, &num_list_entries);
10286
10287       free(element_token);
10288       free(action_token);
10289
10290       continue;
10291     }
10292
10293     /* this is no direction */
10294
10295     element_value = getHashEntry(element_hash, list->token);
10296     if (element_value != NULL)          /* combined element found */
10297       add_helpanim_entry(atoi(element_value), -1, -1, delay,
10298                          &num_list_entries);
10299     else
10300       print_unknown_token(filename, list->token, num_unknown_tokens++);
10301
10302     free(element_token);
10303     free(action_token);
10304   }
10305
10306   print_unknown_token_end(num_unknown_tokens);
10307
10308   add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
10309   add_helpanim_entry(HELPANIM_LIST_END,  -1, -1, -1, &num_list_entries);
10310
10311   freeSetupFileList(setup_file_list);
10312   freeSetupFileHash(element_hash);
10313   freeSetupFileHash(action_hash);
10314   freeSetupFileHash(direction_hash);
10315
10316 #if 0
10317   for (i = 0; i < num_list_entries; i++)
10318     printf("::: '%s': %d, %d, %d => %d\n",
10319            EL_NAME(helpanim_info[i].element),
10320            helpanim_info[i].element,
10321            helpanim_info[i].action,
10322            helpanim_info[i].direction,
10323            helpanim_info[i].delay);
10324 #endif
10325 }
10326
10327 void LoadHelpTextInfo()
10328 {
10329   char *filename = getHelpTextFilename();
10330   int i;
10331
10332   if (helptext_info != NULL)
10333   {
10334     freeSetupFileHash(helptext_info);
10335     helptext_info = NULL;
10336   }
10337
10338   if (fileExists(filename))
10339     helptext_info = loadSetupFileHash(filename);
10340
10341   if (helptext_info == NULL)
10342   {
10343     /* use reliable default values from static configuration */
10344     helptext_info = newSetupFileHash();
10345
10346     for (i = 0; helptext_config[i].token; i++)
10347       setHashEntry(helptext_info,
10348                    helptext_config[i].token,
10349                    helptext_config[i].value);
10350   }
10351
10352 #if 0
10353   BEGIN_HASH_ITERATION(helptext_info, itr)
10354   {
10355     printf("::: '%s' => '%s'\n",
10356            HASH_ITERATION_TOKEN(itr), HASH_ITERATION_VALUE(itr));
10357   }
10358   END_HASH_ITERATION(hash, itr)
10359 #endif
10360 }
10361
10362
10363 /* ------------------------------------------------------------------------- */
10364 /* convert levels                                                            */
10365 /* ------------------------------------------------------------------------- */
10366
10367 #define MAX_NUM_CONVERT_LEVELS          1000
10368
10369 void ConvertLevels()
10370 {
10371   static LevelDirTree *convert_leveldir = NULL;
10372   static int convert_level_nr = -1;
10373   static int num_levels_handled = 0;
10374   static int num_levels_converted = 0;
10375   static boolean levels_failed[MAX_NUM_CONVERT_LEVELS];
10376   int i;
10377
10378   convert_leveldir = getTreeInfoFromIdentifier(leveldir_first,
10379                                                global.convert_leveldir);
10380
10381   if (convert_leveldir == NULL)
10382     Error(ERR_EXIT, "no such level identifier: '%s'",
10383           global.convert_leveldir);
10384
10385   leveldir_current = convert_leveldir;
10386
10387   if (global.convert_level_nr != -1)
10388   {
10389     convert_leveldir->first_level = global.convert_level_nr;
10390     convert_leveldir->last_level  = global.convert_level_nr;
10391   }
10392
10393   convert_level_nr = convert_leveldir->first_level;
10394
10395   printf_line("=", 79);
10396   printf("Converting levels\n");
10397   printf_line("-", 79);
10398   printf("Level series identifier: '%s'\n", convert_leveldir->identifier);
10399   printf("Level series name:       '%s'\n", convert_leveldir->name);
10400   printf("Level series author:     '%s'\n", convert_leveldir->author);
10401   printf("Number of levels:        %d\n",   convert_leveldir->levels);
10402   printf_line("=", 79);
10403   printf("\n");
10404
10405   for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++)
10406     levels_failed[i] = FALSE;
10407
10408   while (convert_level_nr <= convert_leveldir->last_level)
10409   {
10410     char *level_filename;
10411     boolean new_level;
10412
10413     level_nr = convert_level_nr++;
10414
10415     printf("Level %03d: ", level_nr);
10416
10417     LoadLevel(level_nr);
10418     if (level.no_valid_file)
10419     {
10420       printf("(no level)\n");
10421       continue;
10422     }
10423
10424     printf("converting level ... ");
10425
10426     level_filename = getDefaultLevelFilename(level_nr);
10427     new_level = !fileExists(level_filename);
10428
10429     if (new_level)
10430     {
10431       SaveLevel(level_nr);
10432
10433       num_levels_converted++;
10434
10435       printf("converted.\n");
10436     }
10437     else
10438     {
10439       if (level_nr >= 0 && level_nr < MAX_NUM_CONVERT_LEVELS)
10440         levels_failed[level_nr] = TRUE;
10441
10442       printf("NOT CONVERTED -- LEVEL ALREADY EXISTS.\n");
10443     }
10444
10445     num_levels_handled++;
10446   }
10447
10448   printf("\n");
10449   printf_line("=", 79);
10450   printf("Number of levels handled: %d\n", num_levels_handled);
10451   printf("Number of levels converted: %d (%d%%)\n", num_levels_converted,
10452          (num_levels_handled ?
10453           num_levels_converted * 100 / num_levels_handled : 0));
10454   printf_line("-", 79);
10455   printf("Summary (for automatic parsing by scripts):\n");
10456   printf("LEVELDIR '%s', CONVERTED %d/%d (%d%%)",
10457          convert_leveldir->identifier, num_levels_converted,
10458          num_levels_handled,
10459          (num_levels_handled ?
10460           num_levels_converted * 100 / num_levels_handled : 0));
10461
10462   if (num_levels_handled != num_levels_converted)
10463   {
10464     printf(", FAILED:");
10465     for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++)
10466       if (levels_failed[i])
10467         printf(" %03d", i);
10468   }
10469
10470   printf("\n");
10471   printf_line("=", 79);
10472
10473   CloseAllAndExit(0);
10474 }
10475
10476
10477 /* ------------------------------------------------------------------------- */
10478 /* create and save images for use in level sketches (raw BMP format)         */
10479 /* ------------------------------------------------------------------------- */
10480
10481 void CreateLevelSketchImages()
10482 {
10483 #if defined(TARGET_SDL)
10484   Bitmap *bitmap1;
10485   Bitmap *bitmap2;
10486   int i;
10487
10488   InitElementPropertiesGfxElement();
10489
10490   bitmap1 = CreateBitmap(TILEX, TILEY, DEFAULT_DEPTH);
10491   bitmap2 = CreateBitmap(MINI_TILEX, MINI_TILEY, DEFAULT_DEPTH);
10492
10493   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
10494   {
10495     Bitmap *src_bitmap;
10496     int src_x, src_y;
10497     int element = getMappedElement(i);
10498     int graphic = el2edimg(element);
10499     char basename1[16];
10500     char basename2[16];
10501     char *filename1;
10502     char *filename2;
10503
10504     sprintf(basename1, "%03d.bmp", i);
10505     sprintf(basename2, "%03ds.bmp", i);
10506
10507     filename1 = getPath2(global.create_images_dir, basename1);
10508     filename2 = getPath2(global.create_images_dir, basename2);
10509
10510     getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
10511     BlitBitmap(src_bitmap, bitmap1, src_x, src_y, TILEX, TILEY, 0, 0);
10512
10513     if (SDL_SaveBMP(bitmap1->surface, filename1) != 0)
10514       Error(ERR_EXIT, "cannot save level sketch image file '%s'", filename1);
10515
10516     getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
10517     BlitBitmap(src_bitmap, bitmap2, src_x, src_y, MINI_TILEX, MINI_TILEY, 0, 0);
10518
10519     if (SDL_SaveBMP(bitmap2->surface, filename2) != 0)
10520       Error(ERR_EXIT, "cannot save level sketch image file '%s'", filename2);
10521
10522     free(filename1);
10523     free(filename2);
10524
10525     if (options.debug)
10526       printf("%03d `%03d%c", i, i, (i % 10 < 9 ? ' ' : '\n'));
10527   }
10528
10529   FreeBitmap(bitmap1);
10530   FreeBitmap(bitmap2);
10531
10532   if (options.debug)
10533     printf("\n");
10534
10535   Error(ERR_INFO, "%d normal and small images created", NUM_FILE_ELEMENTS);
10536
10537   CloseAllAndExit(0);
10538 #endif
10539 }
10540
10541
10542 /* ------------------------------------------------------------------------- */
10543 /* create and save images for custom and group elements (raw BMP format)     */
10544 /* ------------------------------------------------------------------------- */
10545
10546 void CreateCustomElementImages()
10547 {
10548 #if defined(TARGET_SDL)
10549   char *filename = "graphics.classic/RocksCE.bmp";
10550   Bitmap *bitmap;
10551   Bitmap *src_bitmap;
10552   int dummy_graphic = IMG_CUSTOM_99;
10553   int yoffset_ce = 0;
10554   int yoffset_ge = (TILEY * NUM_CUSTOM_ELEMENTS / 16);
10555   int src_x, src_y;
10556   int i;
10557
10558   bitmap = CreateBitmap(TILEX * 16 * 2,
10559                         TILEY * (NUM_CUSTOM_ELEMENTS + NUM_GROUP_ELEMENTS) / 16,
10560                         DEFAULT_DEPTH);
10561
10562   getGraphicSource(dummy_graphic, 0, &src_bitmap, &src_x, &src_y);
10563
10564   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
10565   {
10566     int x = i % 16;
10567     int y = i / 16;
10568     int ii = i + 1;
10569     int j;
10570
10571     BlitBitmap(src_bitmap, bitmap, 0, 0, TILEX, TILEY,
10572                TILEX * x, TILEY * y + yoffset_ce);
10573
10574     BlitBitmap(src_bitmap, bitmap, 0, TILEY, TILEX, TILEY,
10575                TILEX * x + TILEX * 16, TILEY * y + yoffset_ce);
10576
10577     for (j = 2; j >= 0; j--)
10578     {
10579       int c = ii % 10;
10580
10581       BlitBitmap(src_bitmap, bitmap, TILEX + c * 7, 0, 6, 10,
10582                  TILEX * x + 6 + j * 7,
10583                  TILEY * y + 11 + yoffset_ce);
10584
10585       BlitBitmap(src_bitmap, bitmap, TILEX + c * 8, TILEY, 6, 10,
10586                  TILEX * 16 + TILEX * x + 6 + j * 8,
10587                  TILEY * y + 10 + yoffset_ce);
10588
10589       ii /= 10;
10590     }
10591   }
10592
10593   for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
10594   {
10595     int x = i % 16;
10596     int y = i / 16;
10597     int ii = i + 1;
10598     int j;
10599
10600     BlitBitmap(src_bitmap, bitmap, 0, 0, TILEX, TILEY,
10601                TILEX * x, TILEY * y + yoffset_ge);
10602
10603     BlitBitmap(src_bitmap, bitmap, 0, TILEY, TILEX, TILEY,
10604                TILEX * x + TILEX * 16, TILEY * y + yoffset_ge);
10605
10606     for (j = 1; j >= 0; j--)
10607     {
10608       int c = ii % 10;
10609
10610       BlitBitmap(src_bitmap, bitmap, TILEX + c * 10, 11, 10, 10,
10611                  TILEX * x + 6 + j * 10,
10612                  TILEY * y + 11 + yoffset_ge);
10613
10614       BlitBitmap(src_bitmap, bitmap, TILEX + c * 8, TILEY + 12, 6, 10,
10615                  TILEX * 16 + TILEX * x + 10 + j * 8,
10616                  TILEY * y + 10 + yoffset_ge);
10617
10618       ii /= 10;
10619     }
10620   }
10621
10622   if (SDL_SaveBMP(bitmap->surface, filename) != 0)
10623     Error(ERR_EXIT, "cannot save CE graphics file '%s'", filename);
10624
10625   FreeBitmap(bitmap);
10626
10627   CloseAllAndExit(0);
10628 #endif
10629 }
10630
10631 #if 0
10632 void CreateLevelSketchImages_TEST()
10633 {
10634   void CreateCustomElementImages()
10635 }
10636 #endif