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