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