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