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