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