rnd-20060805-5-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 #if 1
4874   /* try to detect and fix "Snake Bite" levels, which are broken with 3.2.0 */
4875   {
4876     int element = EL_CUSTOM_START + 255;
4877     struct ElementInfo *ei = &element_info[element];
4878     struct ElementChangeInfo *change = &ei->change_page[0];
4879
4880     /* This is needed to fix a problem that was caused by a bugfix in function
4881        game.c/CreateFieldExt() introduced with 3.2.0 that corrects the behaviour
4882        when a custom element changes to EL_SOKOBAN_FIELD_PLAYER (before, it did
4883        not replace walkable elements, but instead just placed the player on it,
4884        without placing the Sokoban field under the player). Unfortunately, this
4885        breaks "Snake Bite" style levels when the snake is halfway through a door
4886        that just closes (the snake head is still alive and can be moved in this
4887        case). This can be fixed by replacing the EL_SOKOBAN_FIELD_PLAYER by the
4888        player (without Sokoban element) which then gets killed as designed). */
4889
4890     if ((strncmp(leveldir_current->identifier, "snake_bite", 10) == 0 ||
4891          strncmp(ei->description, "pause b4 death", 14) == 0) &&
4892         change->target_element == EL_SOKOBAN_FIELD_PLAYER)
4893       change->target_element = EL_PLAYER_1;
4894   }
4895 #endif
4896 }
4897
4898 static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
4899 {
4900   int i, j, x, y;
4901
4902   /* map custom element change events that have changed in newer versions
4903      (these following values were accidentally changed in version 3.0.1)
4904      (this seems to be needed only for 'ab_levelset3' and 'ab_levelset4') */
4905   if (level->game_version <= VERSION_IDENT(3,0,0,0))
4906   {
4907     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4908     {
4909       int element = EL_CUSTOM_START + i;
4910
4911       /* order of checking and copying events to be mapped is important */
4912       /* (do not change the start and end value -- they are constant) */
4913       for (j = CE_BY_OTHER_ACTION; j >= CE_VALUE_GETS_ZERO; j--)
4914       {
4915         if (HAS_CHANGE_EVENT(element, j - 2))
4916         {
4917           SET_CHANGE_EVENT(element, j - 2, FALSE);
4918           SET_CHANGE_EVENT(element, j, TRUE);
4919         }
4920       }
4921
4922       /* order of checking and copying events to be mapped is important */
4923       /* (do not change the start and end value -- they are constant) */
4924       for (j = CE_PLAYER_COLLECTS_X; j >= CE_HITTING_SOMETHING; j--)
4925       {
4926         if (HAS_CHANGE_EVENT(element, j - 1))
4927         {
4928           SET_CHANGE_EVENT(element, j - 1, FALSE);
4929           SET_CHANGE_EVENT(element, j, TRUE);
4930         }
4931       }
4932     }
4933   }
4934
4935   /* initialize "can_change" field for old levels with only one change page */
4936   if (level->game_version <= VERSION_IDENT(3,0,2,0))
4937   {
4938     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4939     {
4940       int element = EL_CUSTOM_START + i;
4941
4942       if (CAN_CHANGE(element))
4943         element_info[element].change->can_change = TRUE;
4944     }
4945   }
4946
4947   /* correct custom element values (for old levels without these options) */
4948   if (level->game_version < VERSION_IDENT(3,1,1,0))
4949   {
4950     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4951     {
4952       int element = EL_CUSTOM_START + i;
4953       struct ElementInfo *ei = &element_info[element];
4954
4955       if (ei->access_direction == MV_NO_DIRECTION)
4956         ei->access_direction = MV_ALL_DIRECTIONS;
4957
4958 #if 0
4959       for (j = 0; j < ei->num_change_pages; j++)
4960       {
4961         struct ElementChangeInfo *change = &ei->change_page[j];
4962
4963         if (change->trigger_side == CH_SIDE_NONE)
4964           change->trigger_side = CH_SIDE_ANY;
4965       }
4966 #endif
4967     }
4968   }
4969
4970 #if 1
4971   /* correct custom element values (fix invalid values for all versions) */
4972   if (1)
4973   {
4974     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4975     {
4976       int element = EL_CUSTOM_START + i;
4977       struct ElementInfo *ei = &element_info[element];
4978
4979       for (j = 0; j < ei->num_change_pages; j++)
4980       {
4981         struct ElementChangeInfo *change = &ei->change_page[j];
4982
4983         if (change->trigger_player == CH_PLAYER_NONE)
4984           change->trigger_player = CH_PLAYER_ANY;
4985
4986         if (change->trigger_side == CH_SIDE_NONE)
4987           change->trigger_side = CH_SIDE_ANY;
4988       }
4989     }
4990   }
4991 #endif
4992
4993   /* initialize "can_explode" field for old levels which did not store this */
4994   /* !!! CHECK THIS -- "<= 3,1,0,0" IS PROBABLY WRONG !!! */
4995   if (level->game_version <= VERSION_IDENT(3,1,0,0))
4996   {
4997     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4998     {
4999       int element = EL_CUSTOM_START + i;
5000
5001       if (EXPLODES_1X1_OLD(element))
5002         element_info[element].explosion_type = EXPLODES_1X1;
5003
5004       SET_PROPERTY(element, EP_CAN_EXPLODE, (EXPLODES_BY_FIRE(element) ||
5005                                              EXPLODES_SMASHED(element) ||
5006                                              EXPLODES_IMPACT(element)));
5007     }
5008   }
5009
5010   /* correct previously hard-coded move delay values for maze runner style */
5011   if (level->game_version < VERSION_IDENT(3,1,1,0))
5012   {
5013     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
5014     {
5015       int element = EL_CUSTOM_START + i;
5016
5017       if (element_info[element].move_pattern & MV_MAZE_RUNNER_STYLE)
5018       {
5019         /* previously hard-coded and therefore ignored */
5020         element_info[element].move_delay_fixed = 9;
5021         element_info[element].move_delay_random = 0;
5022       }
5023     }
5024   }
5025
5026   /* map elements that have changed in newer versions */
5027   level->amoeba_content = getMappedElementByVersion(level->amoeba_content,
5028                                                     level->game_version);
5029   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
5030     for (x = 0; x < 3; x++)
5031       for (y = 0; y < 3; y++)
5032         level->yamyam_content[i].e[x][y] =
5033           getMappedElementByVersion(level->yamyam_content[i].e[x][y],
5034                                     level->game_version);
5035
5036   /* initialize element properties for level editor etc. */
5037   InitElementPropertiesEngine(level->game_version);
5038   InitElementPropertiesAfterLoading(level->game_version);
5039 }
5040
5041 static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
5042 {
5043   int x, y;
5044
5045   /* map elements that have changed in newer versions */
5046   for (y = 0; y < level->fieldy; y++)
5047     for (x = 0; x < level->fieldx; x++)
5048       level->field[x][y] = getMappedElementByVersion(level->field[x][y],
5049                                                      level->game_version);
5050
5051   /* copy elements to runtime playfield array */
5052   for (x = 0; x < MAX_LEV_FIELDX; x++)
5053     for (y = 0; y < MAX_LEV_FIELDY; y++)
5054       Feld[x][y] = level->field[x][y];
5055
5056   /* initialize level size variables for faster access */
5057   lev_fieldx = level->fieldx;
5058   lev_fieldy = level->fieldy;
5059
5060   /* determine border element for this level */
5061   SetBorderElement();
5062 }
5063
5064 static void LoadLevel_InitNativeEngines(struct LevelInfo *level,char *filename)
5065 {
5066   struct LevelFileInfo *level_file_info = &level->file_info;
5067
5068 #if 1
5069   if (level_file_info->type == LEVEL_FILE_TYPE_RND)
5070     CopyNativeLevel_RND_to_Native(level);
5071 #else
5072   if (level_file_info->type == LEVEL_FILE_TYPE_RND)
5073     CopyNativeLevel_RND_to_Native(level);
5074   else
5075     CopyNativeLevel_Native_to_RND(level);
5076 #endif
5077 }
5078
5079 void LoadLevelTemplate(int nr)
5080 {
5081   char *filename;
5082
5083   setLevelFileInfo(&level_template.file_info, nr);
5084   filename = level_template.file_info.filename;
5085
5086   LoadLevelFromFileInfo(&level_template, &level_template.file_info);
5087
5088   LoadLevel_InitVersion(&level_template, filename);
5089   LoadLevel_InitElements(&level_template, filename);
5090
5091   ActivateLevelTemplate();
5092 }
5093
5094 void LoadLevel(int nr)
5095 {
5096   char *filename;
5097
5098   setLevelFileInfo(&level.file_info, nr);
5099   filename = level.file_info.filename;
5100
5101   LoadLevelFromFileInfo(&level, &level.file_info);
5102
5103   if (level.use_custom_template)
5104     LoadLevelTemplate(-1);
5105
5106   LoadLevel_InitVersion(&level, filename);
5107   LoadLevel_InitElements(&level, filename);
5108   LoadLevel_InitPlayfield(&level, filename);
5109
5110   LoadLevel_InitNativeEngines(&level, filename);
5111 }
5112
5113 static int SaveLevel_VERS(FILE *file, struct LevelInfo *level)
5114 {
5115   int chunk_size = 0;
5116
5117   chunk_size += putFileVersion(file, level->file_version);
5118   chunk_size += putFileVersion(file, level->game_version);
5119
5120   return chunk_size;
5121 }
5122
5123 static int SaveLevel_DATE(FILE *file, struct LevelInfo *level)
5124 {
5125   int chunk_size = 0;
5126
5127   chunk_size += putFile16BitBE(file, level->creation_date.year);
5128   chunk_size += putFile8Bit(file,    level->creation_date.month);
5129   chunk_size += putFile8Bit(file,    level->creation_date.day);
5130
5131   return chunk_size;
5132 }
5133
5134 #if 0
5135 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
5136 {
5137   int i, x, y;
5138
5139   putFile8Bit(file, level->fieldx);
5140   putFile8Bit(file, level->fieldy);
5141
5142   putFile16BitBE(file, level->time);
5143   putFile16BitBE(file, level->gems_needed);
5144
5145   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
5146     putFile8Bit(file, level->name[i]);
5147
5148   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
5149     putFile8Bit(file, level->score[i]);
5150
5151   for (i = 0; i < STD_ELEMENT_CONTENTS; i++)
5152     for (y = 0; y < 3; y++)
5153       for (x = 0; x < 3; x++)
5154         putFile8Bit(file, (level->encoding_16bit_yamyam ? EL_EMPTY :
5155                            level->yamyam_content[i].e[x][y]));
5156   putFile8Bit(file, level->amoeba_speed);
5157   putFile8Bit(file, level->time_magic_wall);
5158   putFile8Bit(file, level->time_wheel);
5159   putFile8Bit(file, (level->encoding_16bit_amoeba ? EL_EMPTY :
5160                      level->amoeba_content));
5161   putFile8Bit(file, (level->initial_player_stepsize == STEPSIZE_FAST ? 1 : 0));
5162   putFile8Bit(file, (level->initial_gravity ? 1 : 0));
5163   putFile8Bit(file, (level->encoding_16bit_field ? 1 : 0));
5164   putFile8Bit(file, (level->em_slippery_gems ? 1 : 0));
5165
5166   putFile8Bit(file, (level->use_custom_template ? 1 : 0));
5167
5168   putFile8Bit(file, (level->block_last_field ? 1 : 0));
5169   putFile8Bit(file, (level->sp_block_last_field ? 1 : 0));
5170   putFile32BitBE(file, level->can_move_into_acid_bits);
5171   putFile8Bit(file, level->dont_collide_with_bits);
5172
5173   putFile8Bit(file, (level->use_spring_bug ? 1 : 0));
5174   putFile8Bit(file, (level->use_step_counter ? 1 : 0));
5175
5176   putFile8Bit(file, (level->instant_relocation ? 1 : 0));
5177   putFile8Bit(file, (level->can_pass_to_walkable ? 1 : 0));
5178   putFile8Bit(file, (level->grow_into_diggable ? 1 : 0));
5179
5180   putFile8Bit(file, level->game_engine_type);
5181
5182   WriteUnusedBytesToFile(file, LEVEL_CHUNK_HEAD_UNUSED);
5183 }
5184 #endif
5185
5186 static int SaveLevel_NAME(FILE *file, struct LevelInfo *level)
5187 {
5188   int chunk_size = 0;
5189   int i;
5190
5191   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
5192     chunk_size += putFile8Bit(file, level->name[i]);
5193
5194   return chunk_size;
5195 }
5196
5197 static int SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
5198 {
5199   int chunk_size = 0;
5200   int i;
5201
5202   for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
5203     chunk_size += putFile8Bit(file, level->author[i]);
5204
5205   return chunk_size;
5206 }
5207
5208 #if 0
5209 static int SaveLevel_BODY(FILE *file, struct LevelInfo *level)
5210 {
5211   int chunk_size = 0;
5212   int x, y;
5213
5214   for (y = 0; y < level->fieldy; y++) 
5215     for (x = 0; x < level->fieldx; x++) 
5216       if (level->encoding_16bit_field)
5217         chunk_size += putFile16BitBE(file, level->field[x][y]);
5218       else
5219         chunk_size += putFile8Bit(file, level->field[x][y]);
5220
5221   return chunk_size;
5222 }
5223 #endif
5224
5225 static int SaveLevel_BODY(FILE *file, struct LevelInfo *level)
5226 {
5227   int chunk_size = 0;
5228   int x, y;
5229
5230   for (y = 0; y < level->fieldy; y++) 
5231     for (x = 0; x < level->fieldx; x++) 
5232       chunk_size += putFile16BitBE(file, level->field[x][y]);
5233
5234   return chunk_size;
5235 }
5236
5237 #if 0
5238 static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
5239 {
5240   int i, x, y;
5241
5242   putFile8Bit(file, EL_YAMYAM);
5243   putFile8Bit(file, level->num_yamyam_contents);
5244   putFile8Bit(file, 0);
5245   putFile8Bit(file, 0);
5246
5247   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
5248     for (y = 0; y < 3; y++)
5249       for (x = 0; x < 3; x++)
5250         if (level->encoding_16bit_field)
5251           putFile16BitBE(file, level->yamyam_content[i].e[x][y]);
5252         else
5253           putFile8Bit(file, level->yamyam_content[i].e[x][y]);
5254 }
5255 #endif
5256
5257 #if 0
5258 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
5259 {
5260   int i, x, y;
5261   int num_contents, content_xsize, content_ysize;
5262   int content_array[MAX_ELEMENT_CONTENTS][3][3];
5263
5264   if (element == EL_YAMYAM)
5265   {
5266     num_contents = level->num_yamyam_contents;
5267     content_xsize = 3;
5268     content_ysize = 3;
5269
5270     for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
5271       for (y = 0; y < 3; y++)
5272         for (x = 0; x < 3; x++)
5273           content_array[i][x][y] = level->yamyam_content[i].e[x][y];
5274   }
5275   else if (element == EL_BD_AMOEBA)
5276   {
5277     num_contents = 1;
5278     content_xsize = 1;
5279     content_ysize = 1;
5280
5281     for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
5282       for (y = 0; y < 3; y++)
5283         for (x = 0; x < 3; x++)
5284           content_array[i][x][y] = EL_EMPTY;
5285     content_array[0][0][0] = level->amoeba_content;
5286   }
5287   else
5288   {
5289     /* chunk header already written -- write empty chunk data */
5290     WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_SIZE);
5291
5292     Error(ERR_WARN, "cannot save content for element '%d'", element);
5293     return;
5294   }
5295
5296   putFile16BitBE(file, element);
5297   putFile8Bit(file, num_contents);
5298   putFile8Bit(file, content_xsize);
5299   putFile8Bit(file, content_ysize);
5300
5301   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED);
5302
5303   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
5304     for (y = 0; y < 3; y++)
5305       for (x = 0; x < 3; x++)
5306         putFile16BitBE(file, content_array[i][x][y]);
5307 }
5308 #endif
5309
5310 #if 0
5311 static int SaveLevel_CNT3(FILE *file, struct LevelInfo *level, int element)
5312 {
5313   int envelope_nr = element - EL_ENVELOPE_1;
5314   int envelope_len = strlen(level->envelope_text[envelope_nr]) + 1;
5315   int chunk_size = 0;
5316   int i;
5317
5318   chunk_size += putFile16BitBE(file, element);
5319   chunk_size += putFile16BitBE(file, envelope_len);
5320   chunk_size += putFile8Bit(file, level->envelope_xsize[envelope_nr]);
5321   chunk_size += putFile8Bit(file, level->envelope_ysize[envelope_nr]);
5322
5323   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT3_UNUSED);
5324   chunk_size += LEVEL_CHUNK_CNT3_UNUSED;
5325
5326   for (i = 0; i < envelope_len; i++)
5327     chunk_size += putFile8Bit(file, level->envelope_text[envelope_nr][i]);
5328
5329   return chunk_size;
5330 }
5331 #endif
5332
5333 #if 0
5334 static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level,
5335                            int num_changed_custom_elements)
5336 {
5337   int i, check = 0;
5338
5339   putFile16BitBE(file, num_changed_custom_elements);
5340
5341   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
5342   {
5343     int element = EL_CUSTOM_START + i;
5344
5345 #if 1
5346     struct ElementInfo *ei = &element_info[element];
5347
5348     if (ei->properties[EP_BITFIELD_BASE_NR] != EP_BITMASK_DEFAULT)
5349     {
5350       if (check < num_changed_custom_elements)
5351       {
5352         putFile16BitBE(file, element);
5353         putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
5354       }
5355
5356       check++;
5357     }
5358 #else
5359     if (Properties[element][EP_BITFIELD_BASE_NR] != EP_BITMASK_DEFAULT)
5360     {
5361       if (check < num_changed_custom_elements)
5362       {
5363         putFile16BitBE(file, element);
5364         putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE_NR]);
5365       }
5366
5367       check++;
5368     }
5369 #endif
5370   }
5371
5372   if (check != num_changed_custom_elements)     /* should not happen */
5373     Error(ERR_WARN, "inconsistent number of custom element properties");
5374 }
5375 #endif
5376
5377 #if 0
5378 static void SaveLevel_CUS2(FILE *file, struct LevelInfo *level,
5379                            int num_changed_custom_elements)
5380 {
5381   int i, check = 0;
5382
5383   putFile16BitBE(file, num_changed_custom_elements);
5384
5385   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
5386   {
5387     int element = EL_CUSTOM_START + i;
5388
5389     if (element_info[element].change->target_element != EL_EMPTY_SPACE)
5390     {
5391       if (check < num_changed_custom_elements)
5392       {
5393         putFile16BitBE(file, element);
5394         putFile16BitBE(file, element_info[element].change->target_element);
5395       }
5396
5397       check++;
5398     }
5399   }
5400
5401   if (check != num_changed_custom_elements)     /* should not happen */
5402     Error(ERR_WARN, "inconsistent number of custom target elements");
5403 }
5404 #endif
5405
5406 #if 0
5407 static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
5408                            int num_changed_custom_elements)
5409 {
5410   int i, j, x, y, check = 0;
5411
5412   putFile16BitBE(file, num_changed_custom_elements);
5413
5414   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
5415   {
5416     int element = EL_CUSTOM_START + i;
5417     struct ElementInfo *ei = &element_info[element];
5418
5419     if (ei->modified_settings)
5420     {
5421       if (check < num_changed_custom_elements)
5422       {
5423         putFile16BitBE(file, element);
5424
5425         for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++)
5426           putFile8Bit(file, ei->description[j]);
5427
5428 #if 1
5429         putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
5430 #else
5431         putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE_NR]);
5432 #endif
5433
5434         /* some free bytes for future properties and padding */
5435         WriteUnusedBytesToFile(file, 7);
5436
5437         putFile8Bit(file, ei->use_gfx_element);
5438         putFile16BitBE(file, ei->gfx_element);
5439
5440         putFile8Bit(file, ei->collect_score_initial);
5441         putFile8Bit(file, ei->collect_count_initial);
5442
5443         putFile16BitBE(file, ei->push_delay_fixed);
5444         putFile16BitBE(file, ei->push_delay_random);
5445         putFile16BitBE(file, ei->move_delay_fixed);
5446         putFile16BitBE(file, ei->move_delay_random);
5447
5448         putFile16BitBE(file, ei->move_pattern);
5449         putFile8Bit(file, ei->move_direction_initial);
5450         putFile8Bit(file, ei->move_stepsize);
5451
5452         for (y = 0; y < 3; y++)
5453           for (x = 0; x < 3; x++)
5454             putFile16BitBE(file, ei->content.e[x][y]);
5455
5456         putFile32BitBE(file, ei->change->events);
5457
5458         putFile16BitBE(file, ei->change->target_element);
5459
5460         putFile16BitBE(file, ei->change->delay_fixed);
5461         putFile16BitBE(file, ei->change->delay_random);
5462         putFile16BitBE(file, ei->change->delay_frames);
5463
5464         putFile16BitBE(file, ei->change->trigger_element);
5465
5466         putFile8Bit(file, ei->change->explode);
5467         putFile8Bit(file, ei->change->use_target_content);
5468         putFile8Bit(file, ei->change->only_if_complete);
5469         putFile8Bit(file, ei->change->use_random_replace);
5470
5471         putFile8Bit(file, ei->change->random_percentage);
5472         putFile8Bit(file, ei->change->replace_when);
5473
5474         for (y = 0; y < 3; y++)
5475           for (x = 0; x < 3; x++)
5476             putFile16BitBE(file, ei->change->content.e[x][y]);
5477
5478         putFile8Bit(file, ei->slippery_type);
5479
5480         /* some free bytes for future properties and padding */
5481         WriteUnusedBytesToFile(file, LEVEL_CPART_CUS3_UNUSED);
5482       }
5483
5484       check++;
5485     }
5486   }
5487
5488   if (check != num_changed_custom_elements)     /* should not happen */
5489     Error(ERR_WARN, "inconsistent number of custom element properties");
5490 }
5491 #endif
5492
5493 #if 0
5494 static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
5495 {
5496   struct ElementInfo *ei = &element_info[element];
5497   int i, j, x, y;
5498
5499   /* ---------- custom element base property values (96 bytes) ------------- */
5500
5501   putFile16BitBE(file, element);
5502
5503   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
5504     putFile8Bit(file, ei->description[i]);
5505
5506 #if 1
5507   putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
5508 #else
5509   putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE_NR]);
5510 #endif
5511   WriteUnusedBytesToFile(file, 4);      /* reserved for more base properties */
5512
5513   putFile8Bit(file, ei->num_change_pages);
5514
5515   putFile16BitBE(file, ei->ce_value_fixed_initial);
5516   putFile16BitBE(file, ei->ce_value_random_initial);
5517   putFile8Bit(file, ei->use_last_ce_value);
5518
5519   putFile8Bit(file, ei->use_gfx_element);
5520   putFile16BitBE(file, ei->gfx_element);
5521
5522   putFile8Bit(file, ei->collect_score_initial);
5523   putFile8Bit(file, ei->collect_count_initial);
5524
5525   putFile8Bit(file, ei->drop_delay_fixed);
5526   putFile8Bit(file, ei->push_delay_fixed);
5527   putFile8Bit(file, ei->drop_delay_random);
5528   putFile8Bit(file, ei->push_delay_random);
5529   putFile16BitBE(file, ei->move_delay_fixed);
5530   putFile16BitBE(file, ei->move_delay_random);
5531
5532   /* bits 0 - 15 of "move_pattern" ... */
5533   putFile16BitBE(file, ei->move_pattern & 0xffff);
5534   putFile8Bit(file, ei->move_direction_initial);
5535   putFile8Bit(file, ei->move_stepsize);
5536
5537   putFile8Bit(file, ei->slippery_type);
5538
5539   for (y = 0; y < 3; y++)
5540     for (x = 0; x < 3; x++)
5541       putFile16BitBE(file, ei->content.e[x][y]);
5542
5543   putFile16BitBE(file, ei->move_enter_element);
5544   putFile16BitBE(file, ei->move_leave_element);
5545   putFile8Bit(file, ei->move_leave_type);
5546
5547   /* ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible) */
5548   putFile16BitBE(file, (ei->move_pattern >> 16) & 0xffff);
5549
5550   putFile8Bit(file, ei->access_direction);
5551
5552   putFile8Bit(file, ei->explosion_delay);
5553   putFile8Bit(file, ei->ignition_delay);
5554   putFile8Bit(file, ei->explosion_type);
5555
5556   /* some free bytes for future custom property values and padding */
5557   WriteUnusedBytesToFile(file, 1);
5558
5559   /* ---------- change page property values (48 bytes) --------------------- */
5560
5561   for (i = 0; i < ei->num_change_pages; i++)
5562   {
5563     struct ElementChangeInfo *change = &ei->change_page[i];
5564     unsigned int event_bits;
5565
5566     /* bits 0 - 31 of "has_event[]" ... */
5567     event_bits = 0;
5568     for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
5569       if (change->has_event[j])
5570         event_bits |= (1 << j);
5571     putFile32BitBE(file, event_bits);
5572
5573     putFile16BitBE(file, change->target_element);
5574
5575     putFile16BitBE(file, change->delay_fixed);
5576     putFile16BitBE(file, change->delay_random);
5577     putFile16BitBE(file, change->delay_frames);
5578
5579     putFile16BitBE(file, change->trigger_element);
5580
5581     putFile8Bit(file, change->explode);
5582     putFile8Bit(file, change->use_target_content);
5583     putFile8Bit(file, change->only_if_complete);
5584     putFile8Bit(file, change->use_random_replace);
5585
5586     putFile8Bit(file, change->random_percentage);
5587     putFile8Bit(file, change->replace_when);
5588
5589     for (y = 0; y < 3; y++)
5590       for (x = 0; x < 3; x++)
5591         putFile16BitBE(file, change->target_content.e[x][y]);
5592
5593     putFile8Bit(file, change->can_change);
5594
5595     putFile8Bit(file, change->trigger_side);
5596
5597     putFile8Bit(file, change->trigger_player);
5598     putFile8Bit(file, (change->trigger_page == CH_PAGE_ANY ? CH_PAGE_ANY_FILE :
5599                        log_2(change->trigger_page)));
5600
5601     putFile8Bit(file, change->has_action);
5602     putFile8Bit(file, change->action_type);
5603     putFile8Bit(file, change->action_mode);
5604     putFile16BitBE(file, change->action_arg);
5605
5606     /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */
5607     event_bits = 0;
5608     for (j = 32; j < NUM_CHANGE_EVENTS; j++)
5609       if (change->has_event[j])
5610         event_bits |= (1 << (j - 32));
5611     putFile8Bit(file, event_bits);
5612   }
5613 }
5614 #endif
5615
5616 #if 0
5617 static void SaveLevel_GRP1(FILE *file, struct LevelInfo *level, int element)
5618 {
5619   struct ElementInfo *ei = &element_info[element];
5620   struct ElementGroupInfo *group = ei->group;
5621   int i;
5622
5623   putFile16BitBE(file, element);
5624
5625   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
5626     putFile8Bit(file, ei->description[i]);
5627
5628   putFile8Bit(file, group->num_elements);
5629
5630   putFile8Bit(file, ei->use_gfx_element);
5631   putFile16BitBE(file, ei->gfx_element);
5632
5633   putFile8Bit(file, group->choice_mode);
5634
5635   /* some free bytes for future values and padding */
5636   WriteUnusedBytesToFile(file, 3);
5637
5638   for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
5639     putFile16BitBE(file, group->element[i]);
5640 }
5641 #endif
5642
5643 static int SaveLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *entry,
5644                                 boolean write_element)
5645 {
5646   int save_type = entry->save_type;
5647   int data_type = entry->data_type;
5648   int conf_type = entry->conf_type;
5649   int byte_mask = conf_type & CONF_MASK_BYTES;
5650   int element = entry->element;
5651   int default_value = entry->default_value;
5652   int num_bytes = 0;
5653   boolean modified = FALSE;
5654
5655   if (byte_mask != CONF_MASK_MULTI_BYTES)
5656   {
5657     void *value_ptr = entry->value;
5658     int value = (data_type == TYPE_BOOLEAN ? *(boolean *)value_ptr :
5659                  *(int *)value_ptr);
5660
5661     /* check if any settings have been modified before saving them */
5662     if (value != default_value)
5663       modified = TRUE;
5664
5665     /* do not save if explicitly told or if unmodified default settings */
5666     if ((save_type == SAVE_CONF_NEVER) ||
5667         (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
5668       return 0;
5669
5670     if (write_element)
5671       num_bytes += putFile16BitBE(file, element);
5672
5673     num_bytes += putFile8Bit(file, conf_type);
5674     num_bytes += (byte_mask == CONF_MASK_1_BYTE ? putFile8Bit   (file, value) :
5675                   byte_mask == CONF_MASK_2_BYTE ? putFile16BitBE(file, value) :
5676                   byte_mask == CONF_MASK_4_BYTE ? putFile32BitBE(file, value) :
5677                   0);
5678   }
5679   else if (data_type == TYPE_STRING)
5680   {
5681     char *default_string = entry->default_string;
5682     char *string = (char *)(entry->value);
5683     int string_length = strlen(string);
5684     int i;
5685
5686     /* check if any settings have been modified before saving them */
5687     if (!strEqual(string, default_string))
5688       modified = TRUE;
5689
5690     /* do not save if explicitly told or if unmodified default settings */
5691     if ((save_type == SAVE_CONF_NEVER) ||
5692         (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
5693       return 0;
5694
5695     if (write_element)
5696       num_bytes += putFile16BitBE(file, element);
5697
5698     num_bytes += putFile8Bit(file, conf_type);
5699     num_bytes += putFile16BitBE(file, string_length);
5700
5701     for (i = 0; i < string_length; i++)
5702       num_bytes += putFile8Bit(file, string[i]);
5703   }
5704   else if (data_type == TYPE_ELEMENT_LIST)
5705   {
5706     int *element_array = (int *)(entry->value);
5707     int num_elements = *(int *)(entry->num_entities);
5708     int i;
5709
5710     /* check if any settings have been modified before saving them */
5711     for (i = 0; i < num_elements; i++)
5712       if (element_array[i] != default_value)
5713         modified = TRUE;
5714
5715     /* do not save if explicitly told or if unmodified default settings */
5716     if ((save_type == SAVE_CONF_NEVER) ||
5717         (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
5718       return 0;
5719
5720     if (write_element)
5721       num_bytes += putFile16BitBE(file, element);
5722
5723     num_bytes += putFile8Bit(file, conf_type);
5724     num_bytes += putFile16BitBE(file, num_elements * CONF_ELEMENT_NUM_BYTES);
5725
5726     for (i = 0; i < num_elements; i++)
5727       num_bytes += putFile16BitBE(file, element_array[i]);
5728   }
5729   else if (data_type == TYPE_CONTENT_LIST)
5730   {
5731     struct Content *content = (struct Content *)(entry->value);
5732     int num_contents = *(int *)(entry->num_entities);
5733     int i, x, y;
5734
5735     /* check if any settings have been modified before saving them */
5736     for (i = 0; i < num_contents; i++)
5737       for (y = 0; y < 3; y++)
5738         for (x = 0; x < 3; x++)
5739           if (content[i].e[x][y] != default_value)
5740             modified = TRUE;
5741
5742     /* do not save if explicitly told or if unmodified default settings */
5743     if ((save_type == SAVE_CONF_NEVER) ||
5744         (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
5745       return 0;
5746
5747     if (write_element)
5748       num_bytes += putFile16BitBE(file, element);
5749
5750     num_bytes += putFile8Bit(file, conf_type);
5751     num_bytes += putFile16BitBE(file, num_contents * CONF_CONTENT_NUM_BYTES);
5752
5753     for (i = 0; i < num_contents; i++)
5754       for (y = 0; y < 3; y++)
5755         for (x = 0; x < 3; x++)
5756           num_bytes += putFile16BitBE(file, content[i].e[x][y]);
5757   }
5758
5759   return num_bytes;
5760 }
5761
5762 #if 0
5763
5764 static int SaveLevel_MicroChunk_SingleValue(FILE *file,
5765                                             struct LevelFileConfigInfo *entry)
5766 {
5767   int default_value = entry->default_value;
5768   int element = entry->element;
5769   int data_type = entry->data_type;
5770   int conf_type = entry->conf_type;
5771   int byte_mask = conf_type & CONF_MASK_BYTES;
5772   void *value_ptr = entry->value;
5773   int value = (data_type == TYPE_BOOLEAN ? *(boolean *)value_ptr :
5774                *(int *)value_ptr);
5775   int num_bytes = 0;
5776   boolean modified = FALSE;
5777
5778   /* check if any settings have been modified before saving them */
5779   if (value != default_value)
5780     modified = TRUE;
5781
5782   if (!modified)                /* do not save unmodified default settings */
5783     return 0;
5784
5785 #if 0
5786   printf("::: %02x, %d: %d != %d\n",
5787          byte_mask, conf_type & CONF_MASK_TOKEN,
5788          value, default_value);
5789 #endif
5790
5791   if (element != -1)
5792     num_bytes += putFile16BitBE(file, element);
5793
5794   num_bytes += putFile8Bit(file, conf_type);
5795   num_bytes += (byte_mask == CONF_MASK_1_BYTE ? putFile8Bit   (file, value) :
5796                 byte_mask == CONF_MASK_2_BYTE ? putFile16BitBE(file, value) :
5797                 byte_mask == CONF_MASK_4_BYTE ? putFile32BitBE(file, value) :0);
5798
5799   return num_bytes;
5800 }
5801
5802 static int SaveLevel_MicroChunk_ElementList(FILE *file,
5803                                             struct LevelFileConfigInfo *entry)
5804 {
5805   int *element_array = (int *)(entry->value);
5806   int num_elements = *(int *)(entry->num_entities);
5807   int default_value = entry->default_value;
5808   int element = entry->element;
5809   int conf_type = entry->conf_type;
5810   int num_bytes = 0;
5811   boolean modified = FALSE;
5812   int i;
5813
5814   /* check if any settings have been modified before saving them */
5815   for (i = 0; i < num_elements; i++)
5816     if (element_array[i] != default_value)
5817       modified = TRUE;
5818
5819   if (!modified)                /* do not save unmodified default settings */
5820     return 0;
5821
5822   if (element != -1)
5823     num_bytes += putFile16BitBE(file, element);
5824
5825   num_bytes += putFile8Bit(file, conf_type);
5826   num_bytes += putFile16BitBE(file, num_elements * CONF_ELEMENT_NUM_BYTES);
5827
5828   for (i = 0; i < num_elements; i++)
5829     num_bytes += putFile16BitBE(file, element_array[i]);
5830
5831   return num_bytes;
5832 }
5833
5834 static int SaveLevel_MicroChunk_ContentList(FILE *file,
5835                                             struct LevelFileConfigInfo *entry)
5836 {
5837   struct Content *content = (struct Content *)(entry->value);
5838   int num_contents = *(int *)(entry->num_entities);
5839   int default_value = entry->default_value;
5840   int element = entry->element;
5841   int conf_type = entry->conf_type;
5842   int num_bytes = 0;
5843   boolean modified = FALSE;
5844   int i, x, y;
5845
5846   /* check if any settings have been modified before saving them */
5847   for (i = 0; i < num_contents; i++)
5848     for (y = 0; y < 3; y++)
5849       for (x = 0; x < 3; x++)
5850         if (content[i].e[x][y] != default_value)
5851           modified = TRUE;
5852
5853   if (!modified)                /* do not save unmodified default settings */
5854     return 0;
5855
5856   if (element != -1)
5857     num_bytes += putFile16BitBE(file, element);
5858
5859   num_bytes += putFile8Bit(file, conf_type);
5860   num_bytes += putFile16BitBE(file, num_contents * CONF_CONTENT_NUM_BYTES);
5861
5862   for (i = 0; i < num_contents; i++)
5863     for (y = 0; y < 3; y++)
5864       for (x = 0; x < 3; x++)
5865         num_bytes += putFile16BitBE(file, content[i].e[x][y]);
5866
5867   return num_bytes;
5868 }
5869
5870 #endif
5871
5872 static int SaveLevel_INFO(FILE *file, struct LevelInfo *level)
5873 {
5874   int chunk_size = 0;
5875   int i;
5876
5877   li = *level;          /* copy level data into temporary buffer */
5878
5879   for (i = 0; chunk_config_INFO[i].data_type != -1; i++)
5880     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_INFO[i], FALSE);
5881
5882   return chunk_size;
5883 }
5884
5885 static int SaveLevel_ELEM(FILE *file, struct LevelInfo *level)
5886 {
5887   int chunk_size = 0;
5888   int i;
5889
5890   li = *level;          /* copy level data into temporary buffer */
5891
5892   for (i = 0; chunk_config_ELEM[i].data_type != -1; i++)
5893   {
5894 #if 1
5895     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_ELEM[i], TRUE);
5896 #else
5897     struct LevelFileConfigInfo *conf = &chunk_config_ELEM[i];
5898     int data_type = conf->data_type;
5899     int conf_type = conf->conf_type;
5900     int byte_mask = conf_type & CONF_MASK_BYTES;
5901
5902     if (byte_mask != CONF_MASK_MULTI_BYTES)
5903       chunk_size += SaveLevel_MicroChunk_SingleValue(file, conf);
5904     else if (data_type == TYPE_ELEMENT_LIST)
5905       chunk_size += SaveLevel_MicroChunk_ElementList(file, conf);
5906     else if (data_type == TYPE_CONTENT_LIST)
5907       chunk_size += SaveLevel_MicroChunk_ContentList(file, conf);
5908 #endif
5909   }
5910
5911   return chunk_size;
5912 }
5913
5914 static int SaveLevel_NOTE(FILE *file, struct LevelInfo *level, int element)
5915 {
5916   int envelope_nr = element - EL_ENVELOPE_1;
5917   int chunk_size = 0;
5918   int i;
5919
5920   chunk_size += putFile16BitBE(file, element);
5921
5922   /* copy envelope data into temporary buffer */
5923   xx_envelope = level->envelope[envelope_nr];
5924
5925   for (i = 0; chunk_config_NOTE[i].data_type != -1; i++)
5926     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_NOTE[i], FALSE);
5927
5928   return chunk_size;
5929 }
5930
5931 static int SaveLevel_CUSX(FILE *file, struct LevelInfo *level, int element)
5932 {
5933   struct ElementInfo *ei = &element_info[element];
5934   int chunk_size = 0;
5935   int i, j;
5936
5937   chunk_size += putFile16BitBE(file, element);
5938
5939   xx_ei = *ei;          /* copy element data into temporary buffer */
5940
5941   /* set default description string for this specific element */
5942   strcpy(xx_default_description, getDefaultElementDescription(ei));
5943
5944   /* set (fixed) number of content areas (may have been overwritten earlier) */
5945   xx_num_contents = 1;
5946
5947 #if 0
5948   printf("::: - element config\n");
5949 #endif
5950
5951   for (i = 0; chunk_config_CUSX_base[i].data_type != -1; i++)
5952     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_CUSX_base[i], FALSE);
5953
5954 #if 0
5955   printf("::: - change pages\n");
5956 #endif
5957
5958   for (i = 0; i < ei->num_change_pages; i++)
5959   {
5960     struct ElementChangeInfo *change = &ei->change_page[i];
5961
5962     xx_current_change_page = i;
5963
5964     xx_change = *change;        /* copy change data into temporary buffer */
5965
5966 #if 0
5967     printf(":::   %d: xx_change.action_mode == %d\n",
5968            i, xx_change.action_mode);
5969     printf(":::   %d: xx_change.action_arg == %d\n",
5970            i, xx_change.action_arg);
5971 #endif
5972
5973     resetEventBits();
5974     setEventBitsFromEventFlags(change);
5975
5976     for (j = 0; chunk_config_CUSX_change[j].data_type != -1; j++)
5977       chunk_size += SaveLevel_MicroChunk(file, &chunk_config_CUSX_change[j],
5978                                          FALSE);
5979
5980 #if 0
5981     if (element == EL_CUSTOM_START)
5982       printf("::: - saving change page %d / %d (%d bytes)\n",
5983              i, ei->num_change_pages, chunk_size);
5984 #endif
5985   }
5986
5987   return chunk_size;
5988 }
5989
5990 static int SaveLevel_GRPX(FILE *file, struct LevelInfo *level, int element)
5991 {
5992   struct ElementInfo *ei = &element_info[element];
5993   struct ElementGroupInfo *group = ei->group;
5994   int chunk_size = 0;
5995   int i;
5996
5997   chunk_size += putFile16BitBE(file, element);
5998
5999   xx_ei = *ei;          /* copy element data into temporary buffer */
6000   xx_group = *group;    /* copy group data into temporary buffer */
6001
6002   /* set default description string for this specific element */
6003   strcpy(xx_default_description, getDefaultElementDescription(ei));
6004
6005   for (i = 0; chunk_config_GRPX[i].data_type != -1; i++)
6006     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_GRPX[i], FALSE);
6007
6008   return chunk_size;
6009 }
6010
6011 static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
6012 {
6013   int chunk_size;
6014 #if 1
6015   int i;
6016 #else
6017   int i, x, y;
6018 #endif
6019   FILE *file;
6020
6021   if (!(file = fopen(filename, MODE_WRITE)))
6022   {
6023     Error(ERR_WARN, "cannot save level file '%s'", filename);
6024     return;
6025   }
6026
6027   level->file_version = FILE_VERSION_ACTUAL;
6028   level->game_version = GAME_VERSION_ACTUAL;
6029
6030   level->creation_date = getCurrentDate();
6031
6032 #if 0
6033   /* check level field for 16-bit elements */
6034   level->encoding_16bit_field = FALSE;
6035   for (y = 0; y < level->fieldy; y++) 
6036     for (x = 0; x < level->fieldx; x++) 
6037       if (level->field[x][y] > 255)
6038         level->encoding_16bit_field = TRUE;
6039 #endif
6040
6041 #if 0
6042   /* check yamyam content for 16-bit elements */
6043   level->encoding_16bit_yamyam = FALSE;
6044   for (i = 0; i < level->num_yamyam_contents; i++)
6045     for (y = 0; y < 3; y++)
6046       for (x = 0; x < 3; x++)
6047         if (level->yamyam_content[i].e[x][y] > 255)
6048           level->encoding_16bit_yamyam = TRUE;
6049 #endif
6050
6051 #if 0
6052   /* check amoeba content for 16-bit elements */
6053   level->encoding_16bit_amoeba = FALSE;
6054   if (level->amoeba_content > 255)
6055     level->encoding_16bit_amoeba = TRUE;
6056 #endif
6057
6058 #if 0
6059   /* calculate size of "BODY" chunk */
6060   body_chunk_size =
6061     level->fieldx * level->fieldy * (level->encoding_16bit_field ? 2 : 1);
6062 #endif
6063
6064   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
6065   putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
6066
6067   chunk_size = SaveLevel_VERS(NULL, level);
6068   putFileChunkBE(file, "VERS", chunk_size);
6069   SaveLevel_VERS(file, level);
6070
6071   chunk_size = SaveLevel_DATE(NULL, level);
6072   putFileChunkBE(file, "DATE", chunk_size);
6073   SaveLevel_DATE(file, level);
6074
6075 #if 0
6076   putFileChunkBE(file, "HEAD", LEVEL_CHUNK_HEAD_SIZE);
6077   SaveLevel_HEAD(file, level);
6078 #endif
6079
6080   chunk_size = SaveLevel_NAME(NULL, level);
6081   putFileChunkBE(file, "NAME", chunk_size);
6082   SaveLevel_NAME(file, level);
6083
6084   chunk_size = SaveLevel_AUTH(NULL, level);
6085   putFileChunkBE(file, "AUTH", chunk_size);
6086   SaveLevel_AUTH(file, level);
6087
6088   chunk_size = SaveLevel_INFO(NULL, level);
6089   putFileChunkBE(file, "INFO", chunk_size);
6090   SaveLevel_INFO(file, level);
6091
6092   chunk_size = SaveLevel_BODY(NULL, level);
6093   putFileChunkBE(file, "BODY", chunk_size);
6094   SaveLevel_BODY(file, level);
6095
6096 #if 0
6097   if (level->encoding_16bit_yamyam ||
6098       level->num_yamyam_contents != STD_ELEMENT_CONTENTS)
6099   {
6100     putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
6101     SaveLevel_CNT2(file, level, EL_YAMYAM);
6102   }
6103
6104   if (level->encoding_16bit_amoeba)
6105   {
6106     putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
6107     SaveLevel_CNT2(file, level, EL_BD_AMOEBA);
6108   }
6109 #endif
6110
6111 #if 0
6112   /* check for envelope content */
6113   for (i = 0; i < 4; i++)
6114   {
6115     if (strlen(level->envelope_text[i]) > 0)
6116     {
6117       int envelope_len = strlen(level->envelope_text[i]) + 1;
6118
6119       putFileChunkBE(file, "CNT3", LEVEL_CHUNK_CNT3_SIZE(envelope_len));
6120       SaveLevel_CNT3(file, level, EL_ENVELOPE_1 + i);
6121     }
6122   }
6123 #endif
6124
6125 #if 0
6126   /* if not using template level, check for non-default custom/group elements */
6127   if (!level->use_custom_template)
6128   {
6129     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6130     {
6131       int element = EL_CUSTOM_START + i;
6132
6133       if (element_info[element].modified_settings)
6134       {
6135         int num_change_pages = element_info[element].num_change_pages;
6136
6137         putFileChunkBE(file, "CUS4", LEVEL_CHUNK_CUS4_SIZE(num_change_pages));
6138         SaveLevel_CUS4(file, level, element);
6139       }
6140     }
6141
6142     for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
6143     {
6144       int element = EL_GROUP_START + i;
6145
6146       if (element_info[element].modified_settings)
6147       {
6148         putFileChunkBE(file, "GRP1", LEVEL_CHUNK_GRP1_SIZE);
6149         SaveLevel_GRP1(file, level, element);
6150       }
6151     }
6152   }
6153 #endif
6154
6155   chunk_size = SaveLevel_ELEM(NULL, level);
6156   if (chunk_size > LEVEL_CHUNK_ELEM_UNCHANGED)          /* save if changed */
6157   {
6158     putFileChunkBE(file, "ELEM", chunk_size);
6159     SaveLevel_ELEM(file, level);
6160   }
6161
6162 #if 1
6163   for (i = 0; i < NUM_ENVELOPES; i++)
6164   {
6165     int element = EL_ENVELOPE_1 + i;
6166
6167     chunk_size = SaveLevel_NOTE(NULL, level, element);
6168     if (chunk_size > LEVEL_CHUNK_NOTE_UNCHANGED)        /* save if changed */
6169     {
6170       putFileChunkBE(file, "NOTE", chunk_size);
6171       SaveLevel_NOTE(file, level, element);
6172     }
6173   }
6174 #endif
6175
6176 #if 1
6177   /* if not using template level, check for non-default custom/group elements */
6178   if (!level->use_custom_template)
6179   {
6180     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6181     {
6182       int element = EL_CUSTOM_START + i;
6183
6184       chunk_size = SaveLevel_CUSX(NULL, level, element);
6185       if (chunk_size > LEVEL_CHUNK_CUSX_UNCHANGED)      /* save if changed */
6186       {
6187         putFileChunkBE(file, "CUSX", chunk_size);
6188         SaveLevel_CUSX(file, level, element);
6189       }
6190     }
6191
6192     for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
6193     {
6194       int element = EL_GROUP_START + i;
6195
6196       chunk_size = SaveLevel_GRPX(NULL, level, element);
6197       if (chunk_size > LEVEL_CHUNK_GRPX_UNCHANGED)      /* save if changed */
6198       {
6199         putFileChunkBE(file, "GRPX", chunk_size);
6200         SaveLevel_GRPX(file, level, element);
6201       }
6202     }
6203   }
6204 #endif
6205
6206   fclose(file);
6207
6208   SetFilePermissions(filename, PERMS_PRIVATE);
6209 }
6210
6211 void SaveLevel(int nr)
6212 {
6213   char *filename = getDefaultLevelFilename(nr);
6214
6215   SaveLevelFromFilename(&level, filename);
6216 }
6217
6218 void SaveLevelTemplate()
6219 {
6220   char *filename = getDefaultLevelFilename(-1);
6221
6222   SaveLevelFromFilename(&level, filename);
6223 }
6224
6225 void DumpLevel(struct LevelInfo *level)
6226 {
6227   if (level->no_valid_file)
6228   {
6229     Error(ERR_WARN, "cannot dump -- no valid level file found");
6230
6231     return;
6232   }
6233
6234   printf_line("-", 79);
6235   printf("Level xxx (file version %08d, game version %08d)\n",
6236          level->file_version, level->game_version);
6237   printf_line("-", 79);
6238
6239   printf("Level author: '%s'\n", level->author);
6240   printf("Level title:  '%s'\n", level->name);
6241   printf("\n");
6242   printf("Playfield size: %d x %d\n", level->fieldx, level->fieldy);
6243   printf("\n");
6244   printf("Level time:  %d seconds\n", level->time);
6245   printf("Gems needed: %d\n", level->gems_needed);
6246   printf("\n");
6247   printf("Time for magic wall: %d seconds\n", level->time_magic_wall);
6248   printf("Time for wheel:      %d seconds\n", level->time_wheel);
6249   printf("Time for light:      %d seconds\n", level->time_light);
6250   printf("Time for timegate:   %d seconds\n", level->time_timegate);
6251   printf("\n");
6252   printf("Amoeba speed: %d\n", level->amoeba_speed);
6253   printf("\n");
6254
6255 #if 0
6256   printf("Initial gravity:             %s\n", (level->initial_gravity ? "yes" : "no"));
6257   printf("Initial player stepsize:     %d\n", level->initial_player_stepsize);
6258 #endif
6259
6260   printf("EM style slippery gems:      %s\n", (level->em_slippery_gems ? "yes" : "no"));
6261   printf("Player blocks last field:    %s\n", (level->block_last_field ? "yes" : "no"));
6262   printf("SP player blocks last field: %s\n", (level->sp_block_last_field ? "yes" : "no"));
6263   printf("use spring bug: %s\n", (level->use_spring_bug ? "yes" : "no"));
6264   printf("use step counter: %s\n", (level->use_step_counter ? "yes" : "no"));
6265
6266   printf_line("-", 79);
6267 }
6268
6269
6270 /* ========================================================================= */
6271 /* tape file functions                                                       */
6272 /* ========================================================================= */
6273
6274 static void setTapeInfoToDefaults()
6275 {
6276   int i;
6277
6278   /* always start with reliable default values (empty tape) */
6279   TapeErase();
6280
6281   /* default values (also for pre-1.2 tapes) with only the first player */
6282   tape.player_participates[0] = TRUE;
6283   for (i = 1; i < MAX_PLAYERS; i++)
6284     tape.player_participates[i] = FALSE;
6285
6286   /* at least one (default: the first) player participates in every tape */
6287   tape.num_participating_players = 1;
6288
6289   tape.level_nr = level_nr;
6290   tape.counter = 0;
6291   tape.changed = FALSE;
6292
6293   tape.recording = FALSE;
6294   tape.playing = FALSE;
6295   tape.pausing = FALSE;
6296
6297   tape.no_valid_file = FALSE;
6298 }
6299
6300 static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
6301 {
6302   tape->file_version = getFileVersion(file);
6303   tape->game_version = getFileVersion(file);
6304
6305   return chunk_size;
6306 }
6307
6308 static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
6309 {
6310   int i;
6311
6312   tape->random_seed = getFile32BitBE(file);
6313   tape->date        = getFile32BitBE(file);
6314   tape->length      = getFile32BitBE(file);
6315
6316   /* read header fields that are new since version 1.2 */
6317   if (tape->file_version >= FILE_VERSION_1_2)
6318   {
6319     byte store_participating_players = getFile8Bit(file);
6320     int engine_version;
6321
6322     /* since version 1.2, tapes store which players participate in the tape */
6323     tape->num_participating_players = 0;
6324     for (i = 0; i < MAX_PLAYERS; i++)
6325     {
6326       tape->player_participates[i] = FALSE;
6327
6328       if (store_participating_players & (1 << i))
6329       {
6330         tape->player_participates[i] = TRUE;
6331         tape->num_participating_players++;
6332       }
6333     }
6334
6335     ReadUnusedBytesFromFile(file, TAPE_CHUNK_HEAD_UNUSED);
6336
6337     engine_version = getFileVersion(file);
6338     if (engine_version > 0)
6339       tape->engine_version = engine_version;
6340     else
6341       tape->engine_version = tape->game_version;
6342   }
6343
6344   return chunk_size;
6345 }
6346
6347 static int LoadTape_INFO(FILE *file, int chunk_size, struct TapeInfo *tape)
6348 {
6349   int level_identifier_size;
6350   int i;
6351
6352   level_identifier_size = getFile16BitBE(file);
6353
6354   tape->level_identifier =
6355     checked_realloc(tape->level_identifier, level_identifier_size);
6356
6357   for (i = 0; i < level_identifier_size; i++)
6358     tape->level_identifier[i] = getFile8Bit(file);
6359
6360   tape->level_nr = getFile16BitBE(file);
6361
6362   chunk_size = 2 + level_identifier_size + 2;
6363
6364   return chunk_size;
6365 }
6366
6367 static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
6368 {
6369   int i, j;
6370   int chunk_size_expected =
6371     (tape->num_participating_players + 1) * tape->length;
6372
6373   if (chunk_size_expected != chunk_size)
6374   {
6375     ReadUnusedBytesFromFile(file, chunk_size);
6376     return chunk_size_expected;
6377   }
6378
6379   for (i = 0; i < tape->length; i++)
6380   {
6381     if (i >= MAX_TAPE_LEN)
6382       break;
6383
6384     for (j = 0; j < MAX_PLAYERS; j++)
6385     {
6386       tape->pos[i].action[j] = MV_NONE;
6387
6388       if (tape->player_participates[j])
6389         tape->pos[i].action[j] = getFile8Bit(file);
6390     }
6391
6392     tape->pos[i].delay = getFile8Bit(file);
6393
6394     if (tape->file_version == FILE_VERSION_1_0)
6395     {
6396       /* eliminate possible diagonal moves in old tapes */
6397       /* this is only for backward compatibility */
6398
6399       byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
6400       byte action = tape->pos[i].action[0];
6401       int k, num_moves = 0;
6402
6403       for (k = 0; k<4; k++)
6404       {
6405         if (action & joy_dir[k])
6406         {
6407           tape->pos[i + num_moves].action[0] = joy_dir[k];
6408           if (num_moves > 0)
6409             tape->pos[i + num_moves].delay = 0;
6410           num_moves++;
6411         }
6412       }
6413
6414       if (num_moves > 1)
6415       {
6416         num_moves--;
6417         i += num_moves;
6418         tape->length += num_moves;
6419       }
6420     }
6421     else if (tape->file_version < FILE_VERSION_2_0)
6422     {
6423       /* convert pre-2.0 tapes to new tape format */
6424
6425       if (tape->pos[i].delay > 1)
6426       {
6427         /* action part */
6428         tape->pos[i + 1] = tape->pos[i];
6429         tape->pos[i + 1].delay = 1;
6430
6431         /* delay part */
6432         for (j = 0; j < MAX_PLAYERS; j++)
6433           tape->pos[i].action[j] = MV_NONE;
6434         tape->pos[i].delay--;
6435
6436         i++;
6437         tape->length++;
6438       }
6439     }
6440
6441     if (feof(file))
6442       break;
6443   }
6444
6445   if (i != tape->length)
6446     chunk_size = (tape->num_participating_players + 1) * i;
6447
6448   return chunk_size;
6449 }
6450
6451 void LoadTapeFromFilename(char *filename)
6452 {
6453   char cookie[MAX_LINE_LEN];
6454   char chunk_name[CHUNK_ID_LEN + 1];
6455   FILE *file;
6456   int chunk_size;
6457
6458   /* always start with reliable default values */
6459   setTapeInfoToDefaults();
6460
6461   if (!(file = fopen(filename, MODE_READ)))
6462   {
6463     tape.no_valid_file = TRUE;
6464
6465     return;
6466   }
6467
6468   getFileChunkBE(file, chunk_name, NULL);
6469   if (strEqual(chunk_name, "RND1"))
6470   {
6471     getFile32BitBE(file);               /* not used */
6472
6473     getFileChunkBE(file, chunk_name, NULL);
6474     if (!strEqual(chunk_name, "TAPE"))
6475     {
6476       tape.no_valid_file = TRUE;
6477
6478       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
6479       fclose(file);
6480       return;
6481     }
6482   }
6483   else  /* check for pre-2.0 file format with cookie string */
6484   {
6485     strcpy(cookie, chunk_name);
6486     fgets(&cookie[4], MAX_LINE_LEN - 4, file);
6487     if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
6488       cookie[strlen(cookie) - 1] = '\0';
6489
6490     if (!checkCookieString(cookie, TAPE_COOKIE_TMPL))
6491     {
6492       tape.no_valid_file = TRUE;
6493
6494       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
6495       fclose(file);
6496       return;
6497     }
6498
6499     if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1)
6500     {
6501       tape.no_valid_file = TRUE;
6502
6503       Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
6504       fclose(file);
6505       return;
6506     }
6507
6508     /* pre-2.0 tape files have no game version, so use file version here */
6509     tape.game_version = tape.file_version;
6510   }
6511
6512   if (tape.file_version < FILE_VERSION_1_2)
6513   {
6514     /* tape files from versions before 1.2.0 without chunk structure */
6515     LoadTape_HEAD(file, TAPE_CHUNK_HEAD_SIZE, &tape);
6516     LoadTape_BODY(file, 2 * tape.length,      &tape);
6517   }
6518   else
6519   {
6520     static struct
6521     {
6522       char *name;
6523       int size;
6524       int (*loader)(FILE *, int, struct TapeInfo *);
6525     }
6526     chunk_info[] =
6527     {
6528       { "VERS", TAPE_CHUNK_VERS_SIZE,   LoadTape_VERS },
6529       { "HEAD", TAPE_CHUNK_HEAD_SIZE,   LoadTape_HEAD },
6530       { "INFO", -1,                     LoadTape_INFO },
6531       { "BODY", -1,                     LoadTape_BODY },
6532       {  NULL,  0,                      NULL }
6533     };
6534
6535     while (getFileChunkBE(file, chunk_name, &chunk_size))
6536     {
6537       int i = 0;
6538
6539       while (chunk_info[i].name != NULL &&
6540              !strEqual(chunk_name, chunk_info[i].name))
6541         i++;
6542
6543       if (chunk_info[i].name == NULL)
6544       {
6545         Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'",
6546               chunk_name, filename);
6547         ReadUnusedBytesFromFile(file, chunk_size);
6548       }
6549       else if (chunk_info[i].size != -1 &&
6550                chunk_info[i].size != chunk_size)
6551       {
6552         Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
6553               chunk_size, chunk_name, filename);
6554         ReadUnusedBytesFromFile(file, chunk_size);
6555       }
6556       else
6557       {
6558         /* call function to load this tape chunk */
6559         int chunk_size_expected =
6560           (chunk_info[i].loader)(file, chunk_size, &tape);
6561
6562         /* the size of some chunks cannot be checked before reading other
6563            chunks first (like "HEAD" and "BODY") that contain some header
6564            information, so check them here */
6565         if (chunk_size_expected != chunk_size)
6566         {
6567           Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
6568                 chunk_size, chunk_name, filename);
6569         }
6570       }
6571     }
6572   }
6573
6574   fclose(file);
6575
6576   tape.length_seconds = GetTapeLength();
6577
6578 #if 0
6579   printf("::: tape file version: %d\n", tape.file_version);
6580   printf("::: tape game version: %d\n", tape.game_version);
6581   printf("::: tape engine version: %d\n", tape.engine_version);
6582 #endif
6583 }
6584
6585 void LoadTape(int nr)
6586 {
6587   char *filename = getTapeFilename(nr);
6588
6589   LoadTapeFromFilename(filename);
6590 }
6591
6592 void LoadSolutionTape(int nr)
6593 {
6594   char *filename = getSolutionTapeFilename(nr);
6595
6596   LoadTapeFromFilename(filename);
6597 }
6598
6599 static void SaveTape_VERS(FILE *file, struct TapeInfo *tape)
6600 {
6601   putFileVersion(file, tape->file_version);
6602   putFileVersion(file, tape->game_version);
6603 }
6604
6605 static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
6606 {
6607   int i;
6608   byte store_participating_players = 0;
6609
6610   /* set bits for participating players for compact storage */
6611   for (i = 0; i < MAX_PLAYERS; i++)
6612     if (tape->player_participates[i])
6613       store_participating_players |= (1 << i);
6614
6615   putFile32BitBE(file, tape->random_seed);
6616   putFile32BitBE(file, tape->date);
6617   putFile32BitBE(file, tape->length);
6618
6619   putFile8Bit(file, store_participating_players);
6620
6621   /* unused bytes not at the end here for 4-byte alignment of engine_version */
6622   WriteUnusedBytesToFile(file, TAPE_CHUNK_HEAD_UNUSED);
6623
6624   putFileVersion(file, tape->engine_version);
6625 }
6626
6627 static void SaveTape_INFO(FILE *file, struct TapeInfo *tape)
6628 {
6629   int level_identifier_size = strlen(tape->level_identifier) + 1;
6630   int i;
6631
6632   putFile16BitBE(file, level_identifier_size);
6633
6634   for (i = 0; i < level_identifier_size; i++)
6635     putFile8Bit(file, tape->level_identifier[i]);
6636
6637   putFile16BitBE(file, tape->level_nr);
6638 }
6639
6640 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
6641 {
6642   int i, j;
6643
6644   for (i = 0; i < tape->length; i++)
6645   {
6646     for (j = 0; j < MAX_PLAYERS; j++)
6647       if (tape->player_participates[j])
6648         putFile8Bit(file, tape->pos[i].action[j]);
6649
6650     putFile8Bit(file, tape->pos[i].delay);
6651   }
6652 }
6653
6654 void SaveTape(int nr)
6655 {
6656   char *filename = getTapeFilename(nr);
6657   FILE *file;
6658   boolean new_tape = TRUE;
6659   int num_participating_players = 0;
6660   int info_chunk_size;
6661   int body_chunk_size;
6662   int i;
6663
6664   InitTapeDirectory(leveldir_current->subdir);
6665
6666   /* if a tape still exists, ask to overwrite it */
6667   if (fileExists(filename))
6668   {
6669     new_tape = FALSE;
6670     if (!Request("Replace old tape ?", REQ_ASK))
6671       return;
6672   }
6673
6674   if (!(file = fopen(filename, MODE_WRITE)))
6675   {
6676     Error(ERR_WARN, "cannot save level recording file '%s'", filename);
6677     return;
6678   }
6679
6680   tape.file_version = FILE_VERSION_ACTUAL;
6681   tape.game_version = GAME_VERSION_ACTUAL;
6682
6683   /* count number of participating players  */
6684   for (i = 0; i < MAX_PLAYERS; i++)
6685     if (tape.player_participates[i])
6686       num_participating_players++;
6687
6688   info_chunk_size = 2 + (strlen(tape.level_identifier) + 1) + 2;
6689   body_chunk_size = (num_participating_players + 1) * tape.length;
6690
6691   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
6692   putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
6693
6694   putFileChunkBE(file, "VERS", TAPE_CHUNK_VERS_SIZE);
6695   SaveTape_VERS(file, &tape);
6696
6697   putFileChunkBE(file, "HEAD", TAPE_CHUNK_HEAD_SIZE);
6698   SaveTape_HEAD(file, &tape);
6699
6700   putFileChunkBE(file, "INFO", info_chunk_size);
6701   SaveTape_INFO(file, &tape);
6702
6703   putFileChunkBE(file, "BODY", body_chunk_size);
6704   SaveTape_BODY(file, &tape);
6705
6706   fclose(file);
6707
6708   SetFilePermissions(filename, PERMS_PRIVATE);
6709
6710   tape.changed = FALSE;
6711
6712   if (new_tape)
6713     Request("Tape saved !", REQ_CONFIRM);
6714 }
6715
6716 void DumpTape(struct TapeInfo *tape)
6717 {
6718   int tape_frame_counter;
6719   int i, j;
6720
6721   if (tape->no_valid_file)
6722   {
6723     Error(ERR_WARN, "cannot dump -- no valid tape file found");
6724
6725     return;
6726   }
6727
6728   printf_line("-", 79);
6729   printf("Tape of Level %03d (file version %08d, game version %08d)\n",
6730          tape->level_nr, tape->file_version, tape->game_version);
6731   printf("                  (effective engine version %08d)\n",
6732          tape->engine_version);
6733   printf("Level series identifier: '%s'\n", tape->level_identifier);
6734   printf_line("-", 79);
6735
6736   tape_frame_counter = 0;
6737
6738   for (i = 0; i < tape->length; i++)
6739   {
6740     if (i >= MAX_TAPE_LEN)
6741       break;
6742
6743     printf("%04d: ", i);
6744
6745     for (j = 0; j < MAX_PLAYERS; j++)
6746     {
6747       if (tape->player_participates[j])
6748       {
6749         int action = tape->pos[i].action[j];
6750
6751         printf("%d:%02x ", j, action);
6752         printf("[%c%c%c%c|%c%c] - ",
6753                (action & JOY_LEFT ? '<' : ' '),
6754                (action & JOY_RIGHT ? '>' : ' '),
6755                (action & JOY_UP ? '^' : ' '),
6756                (action & JOY_DOWN ? 'v' : ' '),
6757                (action & JOY_BUTTON_1 ? '1' : ' '),
6758                (action & JOY_BUTTON_2 ? '2' : ' '));
6759       }
6760     }
6761
6762     printf("(%03d) ", tape->pos[i].delay);
6763     printf("[%05d]\n", tape_frame_counter);
6764
6765     tape_frame_counter += tape->pos[i].delay;
6766   }
6767
6768   printf_line("-", 79);
6769 }
6770
6771
6772 /* ========================================================================= */
6773 /* score file functions                                                      */
6774 /* ========================================================================= */
6775
6776 void LoadScore(int nr)
6777 {
6778   int i;
6779   char *filename = getScoreFilename(nr);
6780   char cookie[MAX_LINE_LEN];
6781   char line[MAX_LINE_LEN];
6782   char *line_ptr;
6783   FILE *file;
6784
6785   /* always start with reliable default values */
6786   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
6787   {
6788     strcpy(highscore[i].Name, EMPTY_PLAYER_NAME);
6789     highscore[i].Score = 0;
6790   }
6791
6792   if (!(file = fopen(filename, MODE_READ)))
6793     return;
6794
6795   /* check file identifier */
6796   fgets(cookie, MAX_LINE_LEN, file);
6797   if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
6798     cookie[strlen(cookie) - 1] = '\0';
6799
6800   if (!checkCookieString(cookie, SCORE_COOKIE))
6801   {
6802     Error(ERR_WARN, "unknown format of score file '%s'", filename);
6803     fclose(file);
6804     return;
6805   }
6806
6807   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
6808   {
6809     fscanf(file, "%d", &highscore[i].Score);
6810     fgets(line, MAX_LINE_LEN, file);
6811
6812     if (line[strlen(line) - 1] == '\n')
6813       line[strlen(line) - 1] = '\0';
6814
6815     for (line_ptr = line; *line_ptr; line_ptr++)
6816     {
6817       if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
6818       {
6819         strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN);
6820         highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0';
6821         break;
6822       }
6823     }
6824   }
6825
6826   fclose(file);
6827 }
6828
6829 void SaveScore(int nr)
6830 {
6831   int i;
6832   char *filename = getScoreFilename(nr);
6833   FILE *file;
6834
6835   InitScoreDirectory(leveldir_current->subdir);
6836
6837   if (!(file = fopen(filename, MODE_WRITE)))
6838   {
6839     Error(ERR_WARN, "cannot save score for level %d", nr);
6840     return;
6841   }
6842
6843   fprintf(file, "%s\n\n", SCORE_COOKIE);
6844
6845   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
6846     fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name);
6847
6848   fclose(file);
6849
6850   SetFilePermissions(filename, PERMS_PUBLIC);
6851 }
6852
6853
6854 /* ========================================================================= */
6855 /* setup file functions                                                      */
6856 /* ========================================================================= */
6857
6858 #define TOKEN_STR_PLAYER_PREFIX                 "player_"
6859
6860 /* global setup */
6861 #define SETUP_TOKEN_PLAYER_NAME                 0
6862 #define SETUP_TOKEN_SOUND                       1
6863 #define SETUP_TOKEN_SOUND_LOOPS                 2
6864 #define SETUP_TOKEN_SOUND_MUSIC                 3
6865 #define SETUP_TOKEN_SOUND_SIMPLE                4
6866 #define SETUP_TOKEN_TOONS                       5
6867 #define SETUP_TOKEN_SCROLL_DELAY                6
6868 #define SETUP_TOKEN_SOFT_SCROLLING              7
6869 #define SETUP_TOKEN_FADING                      8
6870 #define SETUP_TOKEN_AUTORECORD                  9
6871 #define SETUP_TOKEN_SHOW_TITLESCREEN            10
6872 #define SETUP_TOKEN_QUICK_DOORS                 11
6873 #define SETUP_TOKEN_TEAM_MODE                   12
6874 #define SETUP_TOKEN_HANDICAP                    13
6875 #define SETUP_TOKEN_SKIP_LEVELS                 14
6876 #define SETUP_TOKEN_TIME_LIMIT                  15
6877 #define SETUP_TOKEN_FULLSCREEN                  16
6878 #define SETUP_TOKEN_FULLSCREEN_MODE             17
6879 #define SETUP_TOKEN_ASK_ON_ESCAPE               18
6880 #define SETUP_TOKEN_ASK_ON_ESCAPE_EDITOR        19
6881 #define SETUP_TOKEN_QUICK_SWITCH                20
6882 #define SETUP_TOKEN_INPUT_ON_FOCUS              21
6883 #define SETUP_TOKEN_PREFER_AGA_GRAPHICS         22
6884 #define SETUP_TOKEN_GRAPHICS_SET                23
6885 #define SETUP_TOKEN_SOUNDS_SET                  24
6886 #define SETUP_TOKEN_MUSIC_SET                   25
6887 #define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS     26
6888 #define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS       27
6889 #define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC        28
6890
6891 #define NUM_GLOBAL_SETUP_TOKENS                 29
6892
6893 /* editor setup */
6894 #define SETUP_TOKEN_EDITOR_EL_BOULDERDASH       0
6895 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE      1
6896 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE_CLUB 2
6897 #define SETUP_TOKEN_EDITOR_EL_MORE              3
6898 #define SETUP_TOKEN_EDITOR_EL_SOKOBAN           4
6899 #define SETUP_TOKEN_EDITOR_EL_SUPAPLEX          5
6900 #define SETUP_TOKEN_EDITOR_EL_DIAMOND_CAVES     6
6901 #define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH    7
6902 #define SETUP_TOKEN_EDITOR_EL_CHARS             8
6903 #define SETUP_TOKEN_EDITOR_EL_CUSTOM            9
6904 #define SETUP_TOKEN_EDITOR_EL_HEADLINES         10
6905 #define SETUP_TOKEN_EDITOR_EL_USER_DEFINED      11
6906 #define SETUP_TOKEN_EDITOR_EL_DYNAMIC           12
6907 #define SETUP_TOKEN_EDITOR_EL_BY_GAME           13
6908 #define SETUP_TOKEN_EDITOR_EL_BY_TYPE           14
6909 #define SETUP_TOKEN_EDITOR_SHOW_ELEMENT_TOKEN   15
6910
6911 #define NUM_EDITOR_SETUP_TOKENS                 16
6912
6913 /* editor cascade setup */
6914 #define SETUP_TOKEN_EDITOR_CASCADE_BD           0
6915 #define SETUP_TOKEN_EDITOR_CASCADE_EM           1
6916 #define SETUP_TOKEN_EDITOR_CASCADE_EMC          2
6917 #define SETUP_TOKEN_EDITOR_CASCADE_RND          3
6918 #define SETUP_TOKEN_EDITOR_CASCADE_SB           4
6919 #define SETUP_TOKEN_EDITOR_CASCADE_SP           5
6920 #define SETUP_TOKEN_EDITOR_CASCADE_DC           6
6921 #define SETUP_TOKEN_EDITOR_CASCADE_DX           7
6922 #define SETUP_TOKEN_EDITOR_CASCADE_TEXT         8
6923 #define SETUP_TOKEN_EDITOR_CASCADE_CE           9
6924 #define SETUP_TOKEN_EDITOR_CASCADE_GE           10
6925 #define SETUP_TOKEN_EDITOR_CASCADE_REF          11
6926 #define SETUP_TOKEN_EDITOR_CASCADE_USER         12
6927 #define SETUP_TOKEN_EDITOR_CASCADE_DYNAMIC      13
6928
6929 #define NUM_EDITOR_CASCADE_SETUP_TOKENS         14
6930
6931 /* shortcut setup */
6932 #define SETUP_TOKEN_SHORTCUT_SAVE_GAME          0
6933 #define SETUP_TOKEN_SHORTCUT_LOAD_GAME          1
6934 #define SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE       2
6935 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_1     3
6936 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_2     4
6937 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_3     5
6938 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_4     6
6939 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_ALL   7
6940
6941 #define NUM_SHORTCUT_SETUP_TOKENS               8
6942
6943 /* player setup */
6944 #define SETUP_TOKEN_PLAYER_USE_JOYSTICK         0
6945 #define SETUP_TOKEN_PLAYER_JOY_DEVICE_NAME      1
6946 #define SETUP_TOKEN_PLAYER_JOY_XLEFT            2
6947 #define SETUP_TOKEN_PLAYER_JOY_XMIDDLE          3
6948 #define SETUP_TOKEN_PLAYER_JOY_XRIGHT           4
6949 #define SETUP_TOKEN_PLAYER_JOY_YUPPER           5
6950 #define SETUP_TOKEN_PLAYER_JOY_YMIDDLE          6
6951 #define SETUP_TOKEN_PLAYER_JOY_YLOWER           7
6952 #define SETUP_TOKEN_PLAYER_JOY_SNAP             8
6953 #define SETUP_TOKEN_PLAYER_JOY_DROP             9
6954 #define SETUP_TOKEN_PLAYER_KEY_LEFT             10
6955 #define SETUP_TOKEN_PLAYER_KEY_RIGHT            11
6956 #define SETUP_TOKEN_PLAYER_KEY_UP               12
6957 #define SETUP_TOKEN_PLAYER_KEY_DOWN             13
6958 #define SETUP_TOKEN_PLAYER_KEY_SNAP             14
6959 #define SETUP_TOKEN_PLAYER_KEY_DROP             15
6960
6961 #define NUM_PLAYER_SETUP_TOKENS                 16
6962
6963 /* system setup */
6964 #define SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER      0
6965 #define SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE  1
6966
6967 #define NUM_SYSTEM_SETUP_TOKENS                 2
6968
6969 /* options setup */
6970 #define SETUP_TOKEN_OPTIONS_VERBOSE             0
6971
6972 #define NUM_OPTIONS_SETUP_TOKENS                1
6973
6974
6975 static struct SetupInfo si;
6976 static struct SetupEditorInfo sei;
6977 static struct SetupEditorCascadeInfo seci;
6978 static struct SetupShortcutInfo ssi;
6979 static struct SetupInputInfo sii;
6980 static struct SetupSystemInfo syi;
6981 static struct OptionInfo soi;
6982
6983 static struct TokenInfo global_setup_tokens[] =
6984 {
6985   { TYPE_STRING, &si.player_name,       "player_name"                   },
6986   { TYPE_SWITCH, &si.sound,             "sound"                         },
6987   { TYPE_SWITCH, &si.sound_loops,       "repeating_sound_loops"         },
6988   { TYPE_SWITCH, &si.sound_music,       "background_music"              },
6989   { TYPE_SWITCH, &si.sound_simple,      "simple_sound_effects"          },
6990   { TYPE_SWITCH, &si.toons,             "toons"                         },
6991   { TYPE_SWITCH, &si.scroll_delay,      "scroll_delay"                  },
6992   { TYPE_SWITCH, &si.soft_scrolling,    "soft_scrolling"                },
6993   { TYPE_SWITCH, &si.fading,            "screen_fading"                 },
6994   { TYPE_SWITCH, &si.autorecord,        "automatic_tape_recording"      },
6995   { TYPE_SWITCH, &si.show_titlescreen,  "show_titlescreen"              },
6996   { TYPE_SWITCH, &si.quick_doors,       "quick_doors"                   },
6997   { TYPE_SWITCH, &si.team_mode,         "team_mode"                     },
6998   { TYPE_SWITCH, &si.handicap,          "handicap"                      },
6999   { TYPE_SWITCH, &si.skip_levels,       "skip_levels"                   },
7000   { TYPE_SWITCH, &si.time_limit,        "time_limit"                    },
7001   { TYPE_SWITCH, &si.fullscreen,        "fullscreen"                    },
7002   { TYPE_STRING, &si.fullscreen_mode,   "fullscreen_mode"               },
7003   { TYPE_SWITCH, &si.ask_on_escape,     "ask_on_escape"                 },
7004   { TYPE_SWITCH, &si.ask_on_escape_editor, "ask_on_escape_editor"       },
7005   { TYPE_SWITCH, &si.quick_switch,      "quick_player_switch"           },
7006   { TYPE_SWITCH, &si.input_on_focus,    "input_on_focus"                },
7007   { TYPE_SWITCH, &si.prefer_aga_graphics, "prefer_aga_graphics"         },
7008   { TYPE_STRING, &si.graphics_set,      "graphics_set"                  },
7009   { TYPE_STRING, &si.sounds_set,        "sounds_set"                    },
7010   { TYPE_STRING, &si.music_set,         "music_set"                     },
7011   { TYPE_SWITCH, &si.override_level_graphics, "override_level_graphics" },
7012   { TYPE_SWITCH, &si.override_level_sounds,   "override_level_sounds"   },
7013   { TYPE_SWITCH, &si.override_level_music,    "override_level_music"    },
7014 };
7015
7016 static boolean not_used = FALSE;
7017 static struct TokenInfo editor_setup_tokens[] =
7018 {
7019 #if 1
7020   { TYPE_SWITCH, &not_used,             "editor.el_boulderdash"         },
7021   { TYPE_SWITCH, &not_used,             "editor.el_emerald_mine"        },
7022   { TYPE_SWITCH, &not_used,             "editor.el_emerald_mine_club"   },
7023   { TYPE_SWITCH, &not_used,             "editor.el_more"                },
7024   { TYPE_SWITCH, &not_used,             "editor.el_sokoban"             },
7025   { TYPE_SWITCH, &not_used,             "editor.el_supaplex"            },
7026   { TYPE_SWITCH, &not_used,             "editor.el_diamond_caves"       },
7027   { TYPE_SWITCH, &not_used,             "editor.el_dx_boulderdash"      },
7028 #else
7029   { TYPE_SWITCH, &sei.el_boulderdash,   "editor.el_boulderdash"         },
7030   { TYPE_SWITCH, &sei.el_emerald_mine,  "editor.el_emerald_mine"        },
7031   { TYPE_SWITCH, &sei.el_emerald_mine_club,"editor.el_emerald_mine_club"},
7032   { TYPE_SWITCH, &sei.el_more,          "editor.el_more"                },
7033   { TYPE_SWITCH, &sei.el_sokoban,       "editor.el_sokoban"             },
7034   { TYPE_SWITCH, &sei.el_supaplex,      "editor.el_supaplex"            },
7035   { TYPE_SWITCH, &sei.el_diamond_caves, "editor.el_diamond_caves"       },
7036   { TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash"      },
7037 #endif
7038   { TYPE_SWITCH, &sei.el_chars,         "editor.el_chars"               },
7039   { TYPE_SWITCH, &sei.el_custom,        "editor.el_custom"              },
7040 #if 1
7041   { TYPE_SWITCH, &not_used,             "editor.el_headlines"           },
7042 #else
7043   { TYPE_SWITCH, &sei.el_headlines,     "editor.el_headlines"           },
7044 #endif
7045   { TYPE_SWITCH, &sei.el_user_defined,  "editor.el_user_defined"        },
7046   { TYPE_SWITCH, &sei.el_dynamic,       "editor.el_dynamic"             },
7047   { TYPE_SWITCH, &sei.el_by_game,       "editor.el_by_game"             },
7048   { TYPE_SWITCH, &sei.el_by_type,       "editor.el_by_type"             },
7049   { TYPE_SWITCH, &sei.show_element_token,"editor.show_element_token"    },
7050 };
7051
7052 static struct TokenInfo editor_cascade_setup_tokens[] =
7053 {
7054   { TYPE_SWITCH, &seci.el_bd,           "editor.cascade.el_bd"          },
7055   { TYPE_SWITCH, &seci.el_em,           "editor.cascade.el_em"          },
7056   { TYPE_SWITCH, &seci.el_emc,          "editor.cascade.el_emc"         },
7057   { TYPE_SWITCH, &seci.el_rnd,          "editor.cascade.el_rnd"         },
7058   { TYPE_SWITCH, &seci.el_sb,           "editor.cascade.el_sb"          },
7059   { TYPE_SWITCH, &seci.el_sp,           "editor.cascade.el_sp"          },
7060   { TYPE_SWITCH, &seci.el_dc,           "editor.cascade.el_dc"          },
7061   { TYPE_SWITCH, &seci.el_dx,           "editor.cascade.el_dx"          },
7062   { TYPE_SWITCH, &seci.el_chars,        "editor.cascade.el_chars"       },
7063   { TYPE_SWITCH, &seci.el_ce,           "editor.cascade.el_ce"          },
7064   { TYPE_SWITCH, &seci.el_ge,           "editor.cascade.el_ge"          },
7065   { TYPE_SWITCH, &seci.el_ref,          "editor.cascade.el_ref"         },
7066   { TYPE_SWITCH, &seci.el_user,         "editor.cascade.el_user"        },
7067   { TYPE_SWITCH, &seci.el_dynamic,      "editor.cascade.el_dynamic"     },
7068 };
7069
7070 static struct TokenInfo shortcut_setup_tokens[] =
7071 {
7072   { TYPE_KEY_X11, &ssi.save_game,       "shortcut.save_game"            },
7073   { TYPE_KEY_X11, &ssi.load_game,       "shortcut.load_game"            },
7074   { TYPE_KEY_X11, &ssi.toggle_pause,    "shortcut.toggle_pause"         },
7075   { TYPE_KEY_X11, &ssi.focus_player[0], "shortcut.focus_player_1"       },
7076   { TYPE_KEY_X11, &ssi.focus_player[1], "shortcut.focus_player_2"       },
7077   { TYPE_KEY_X11, &ssi.focus_player[2], "shortcut.focus_player_3"       },
7078   { TYPE_KEY_X11, &ssi.focus_player[3], "shortcut.focus_player_4"       },
7079   { TYPE_KEY_X11, &ssi.focus_player_all,"shortcut.focus_player_all"     },
7080 };
7081
7082 static struct TokenInfo player_setup_tokens[] =
7083 {
7084   { TYPE_BOOLEAN, &sii.use_joystick,    ".use_joystick"                 },
7085   { TYPE_STRING,  &sii.joy.device_name, ".joy.device_name"              },
7086   { TYPE_INTEGER, &sii.joy.xleft,       ".joy.xleft"                    },
7087   { TYPE_INTEGER, &sii.joy.xmiddle,     ".joy.xmiddle"                  },
7088   { TYPE_INTEGER, &sii.joy.xright,      ".joy.xright"                   },
7089   { TYPE_INTEGER, &sii.joy.yupper,      ".joy.yupper"                   },
7090   { TYPE_INTEGER, &sii.joy.ymiddle,     ".joy.ymiddle"                  },
7091   { TYPE_INTEGER, &sii.joy.ylower,      ".joy.ylower"                   },
7092   { TYPE_INTEGER, &sii.joy.snap,        ".joy.snap_field"               },
7093   { TYPE_INTEGER, &sii.joy.drop,        ".joy.place_bomb"               },
7094   { TYPE_KEY_X11, &sii.key.left,        ".key.move_left"                },
7095   { TYPE_KEY_X11, &sii.key.right,       ".key.move_right"               },
7096   { TYPE_KEY_X11, &sii.key.up,          ".key.move_up"                  },
7097   { TYPE_KEY_X11, &sii.key.down,        ".key.move_down"                },
7098   { TYPE_KEY_X11, &sii.key.snap,        ".key.snap_field"               },
7099   { TYPE_KEY_X11, &sii.key.drop,        ".key.place_bomb"               },
7100 };
7101
7102 static struct TokenInfo system_setup_tokens[] =
7103 {
7104   { TYPE_STRING,  &syi.sdl_audiodriver, "system.sdl_audiodriver"        },
7105   { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size" },
7106 };
7107
7108 static struct TokenInfo options_setup_tokens[] =
7109 {
7110   { TYPE_BOOLEAN, &soi.verbose,         "options.verbose"               },
7111 };
7112
7113 static char *get_corrected_login_name(char *login_name)
7114 {
7115   /* needed because player name must be a fixed length string */
7116   char *login_name_new = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
7117
7118   strncpy(login_name_new, login_name, MAX_PLAYER_NAME_LEN);
7119   login_name_new[MAX_PLAYER_NAME_LEN] = '\0';
7120
7121   if (strlen(login_name) > MAX_PLAYER_NAME_LEN)         /* name has been cut */
7122     if (strchr(login_name_new, ' '))
7123       *strchr(login_name_new, ' ') = '\0';
7124
7125   return login_name_new;
7126 }
7127
7128 static void setSetupInfoToDefaults(struct SetupInfo *si)
7129 {
7130   int i;
7131
7132   si->player_name = get_corrected_login_name(getLoginName());
7133
7134   si->sound = TRUE;
7135   si->sound_loops = TRUE;
7136   si->sound_music = TRUE;
7137   si->sound_simple = TRUE;
7138   si->toons = TRUE;
7139   si->double_buffering = TRUE;
7140   si->direct_draw = !si->double_buffering;
7141   si->scroll_delay = TRUE;
7142   si->soft_scrolling = TRUE;
7143   si->fading = FALSE;
7144   si->autorecord = TRUE;
7145   si->show_titlescreen = TRUE;
7146   si->quick_doors = FALSE;
7147   si->team_mode = FALSE;
7148   si->handicap = TRUE;
7149   si->skip_levels = TRUE;
7150   si->time_limit = TRUE;
7151   si->fullscreen = FALSE;
7152   si->fullscreen_mode = getStringCopy(DEFAULT_FULLSCREEN_MODE);
7153   si->ask_on_escape = TRUE;
7154   si->ask_on_escape_editor = TRUE;
7155   si->quick_switch = FALSE;
7156   si->input_on_focus = FALSE;
7157   si->prefer_aga_graphics = TRUE;
7158
7159   si->graphics_set = getStringCopy(GFX_CLASSIC_SUBDIR);
7160   si->sounds_set = getStringCopy(SND_CLASSIC_SUBDIR);
7161   si->music_set = getStringCopy(MUS_CLASSIC_SUBDIR);
7162   si->override_level_graphics = FALSE;
7163   si->override_level_sounds = FALSE;
7164   si->override_level_music = FALSE;
7165
7166   si->editor.el_boulderdash       = TRUE;
7167   si->editor.el_emerald_mine      = TRUE;
7168   si->editor.el_emerald_mine_club = TRUE;
7169   si->editor.el_more              = TRUE;
7170   si->editor.el_sokoban           = TRUE;
7171   si->editor.el_supaplex          = TRUE;
7172   si->editor.el_diamond_caves     = TRUE;
7173   si->editor.el_dx_boulderdash    = TRUE;
7174   si->editor.el_chars             = TRUE;
7175   si->editor.el_custom            = TRUE;
7176
7177   si->editor.el_headlines = TRUE;
7178   si->editor.el_user_defined = FALSE;
7179   si->editor.el_dynamic = TRUE;
7180
7181   si->editor.show_element_token = FALSE;
7182
7183   si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
7184   si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME;
7185   si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE;
7186
7187   si->shortcut.focus_player[0] = DEFAULT_KEY_FOCUS_PLAYER_1;
7188   si->shortcut.focus_player[1] = DEFAULT_KEY_FOCUS_PLAYER_2;
7189   si->shortcut.focus_player[2] = DEFAULT_KEY_FOCUS_PLAYER_3;
7190   si->shortcut.focus_player[3] = DEFAULT_KEY_FOCUS_PLAYER_4;
7191   si->shortcut.focus_player_all = DEFAULT_KEY_FOCUS_PLAYER_ALL;
7192
7193   for (i = 0; i < MAX_PLAYERS; i++)
7194   {
7195     si->input[i].use_joystick = FALSE;
7196     si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
7197     si->input[i].joy.xleft   = JOYSTICK_XLEFT;
7198     si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
7199     si->input[i].joy.xright  = JOYSTICK_XRIGHT;
7200     si->input[i].joy.yupper  = JOYSTICK_YUPPER;
7201     si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
7202     si->input[i].joy.ylower  = JOYSTICK_YLOWER;
7203     si->input[i].joy.snap  = (i == 0 ? JOY_BUTTON_1 : 0);
7204     si->input[i].joy.drop  = (i == 0 ? JOY_BUTTON_2 : 0);
7205     si->input[i].key.left  = (i == 0 ? DEFAULT_KEY_LEFT  : KSYM_UNDEFINED);
7206     si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
7207     si->input[i].key.up    = (i == 0 ? DEFAULT_KEY_UP    : KSYM_UNDEFINED);
7208     si->input[i].key.down  = (i == 0 ? DEFAULT_KEY_DOWN  : KSYM_UNDEFINED);
7209     si->input[i].key.snap  = (i == 0 ? DEFAULT_KEY_SNAP  : KSYM_UNDEFINED);
7210     si->input[i].key.drop  = (i == 0 ? DEFAULT_KEY_DROP  : KSYM_UNDEFINED);
7211   }
7212
7213   si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT);
7214   si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
7215
7216   si->options.verbose = FALSE;
7217 }
7218
7219 static void setSetupInfoToDefaults_EditorCascade(struct SetupInfo *si)
7220 {
7221   si->editor_cascade.el_bd      = TRUE;
7222   si->editor_cascade.el_em      = TRUE;
7223   si->editor_cascade.el_emc     = TRUE;
7224   si->editor_cascade.el_rnd     = TRUE;
7225   si->editor_cascade.el_sb      = TRUE;
7226   si->editor_cascade.el_sp      = TRUE;
7227   si->editor_cascade.el_dc      = TRUE;
7228   si->editor_cascade.el_dx      = TRUE;
7229
7230   si->editor_cascade.el_chars   = FALSE;
7231   si->editor_cascade.el_ce      = FALSE;
7232   si->editor_cascade.el_ge      = FALSE;
7233   si->editor_cascade.el_ref     = FALSE;
7234   si->editor_cascade.el_user    = FALSE;
7235   si->editor_cascade.el_dynamic = FALSE;
7236 }
7237
7238 static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
7239 {
7240   int i, pnr;
7241
7242   if (!setup_file_hash)
7243     return;
7244
7245   /* global setup */
7246   si = setup;
7247   for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
7248     setSetupInfo(global_setup_tokens, i,
7249                  getHashEntry(setup_file_hash, global_setup_tokens[i].text));
7250   setup = si;
7251
7252   /* editor setup */
7253   sei = setup.editor;
7254   for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
7255     setSetupInfo(editor_setup_tokens, i,
7256                  getHashEntry(setup_file_hash,editor_setup_tokens[i].text));
7257   setup.editor = sei;
7258
7259   /* shortcut setup */
7260   ssi = setup.shortcut;
7261   for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
7262     setSetupInfo(shortcut_setup_tokens, i,
7263                  getHashEntry(setup_file_hash,shortcut_setup_tokens[i].text));
7264   setup.shortcut = ssi;
7265
7266   /* player setup */
7267   for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
7268   {
7269     char prefix[30];
7270
7271     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
7272
7273     sii = setup.input[pnr];
7274     for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
7275     {
7276       char full_token[100];
7277
7278       sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
7279       setSetupInfo(player_setup_tokens, i,
7280                    getHashEntry(setup_file_hash, full_token));
7281     }
7282     setup.input[pnr] = sii;
7283   }
7284
7285   /* system setup */
7286   syi = setup.system;
7287   for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
7288     setSetupInfo(system_setup_tokens, i,
7289                  getHashEntry(setup_file_hash, system_setup_tokens[i].text));
7290   setup.system = syi;
7291
7292   /* options setup */
7293   soi = setup.options;
7294   for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
7295     setSetupInfo(options_setup_tokens, i,
7296                  getHashEntry(setup_file_hash, options_setup_tokens[i].text));
7297   setup.options = soi;
7298 }
7299
7300 static void decodeSetupFileHash_EditorCascade(SetupFileHash *setup_file_hash)
7301 {
7302   int i;
7303
7304   if (!setup_file_hash)
7305     return;
7306
7307   /* editor cascade setup */
7308   seci = setup.editor_cascade;
7309   for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
7310     setSetupInfo(editor_cascade_setup_tokens, i,
7311                  getHashEntry(setup_file_hash,
7312                               editor_cascade_setup_tokens[i].text));
7313   setup.editor_cascade = seci;
7314 }
7315
7316 void LoadSetup()
7317 {
7318   char *filename = getSetupFilename();
7319   SetupFileHash *setup_file_hash = NULL;
7320
7321   /* always start with reliable default values */
7322   setSetupInfoToDefaults(&setup);
7323
7324   setup_file_hash = loadSetupFileHash(filename);
7325
7326   if (setup_file_hash)
7327   {
7328     char *player_name_new;
7329
7330     checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP"));
7331     decodeSetupFileHash(setup_file_hash);
7332
7333     setup.direct_draw = !setup.double_buffering;
7334
7335     freeSetupFileHash(setup_file_hash);
7336
7337     /* needed to work around problems with fixed length strings */
7338     player_name_new = get_corrected_login_name(setup.player_name);
7339     free(setup.player_name);
7340     setup.player_name = player_name_new;
7341   }
7342   else
7343     Error(ERR_WARN, "using default setup values");
7344 }
7345
7346 void LoadSetup_EditorCascade()
7347 {
7348   char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
7349   SetupFileHash *setup_file_hash = NULL;
7350
7351   /* always start with reliable default values */
7352   setSetupInfoToDefaults_EditorCascade(&setup);
7353
7354   setup_file_hash = loadSetupFileHash(filename);
7355
7356   if (setup_file_hash)
7357   {
7358     checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP"));
7359     decodeSetupFileHash_EditorCascade(setup_file_hash);
7360
7361     freeSetupFileHash(setup_file_hash);
7362   }
7363
7364   free(filename);
7365 }
7366
7367 void SaveSetup()
7368 {
7369   char *filename = getSetupFilename();
7370   FILE *file;
7371   int i, pnr;
7372
7373   InitUserDataDirectory();
7374
7375   if (!(file = fopen(filename, MODE_WRITE)))
7376   {
7377     Error(ERR_WARN, "cannot write setup file '%s'", filename);
7378     return;
7379   }
7380
7381   fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
7382                                                getCookie("SETUP")));
7383   fprintf(file, "\n");
7384
7385   /* global setup */
7386   si = setup;
7387   for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
7388   {
7389     /* just to make things nicer :) */
7390     if (i == SETUP_TOKEN_PLAYER_NAME + 1 ||
7391         i == SETUP_TOKEN_GRAPHICS_SET)
7392       fprintf(file, "\n");
7393
7394     fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
7395   }
7396
7397   /* editor setup */
7398   sei = setup.editor;
7399   fprintf(file, "\n");
7400   for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
7401     fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i));
7402
7403   /* shortcut setup */
7404   ssi = setup.shortcut;
7405   fprintf(file, "\n");
7406   for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
7407     fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
7408
7409   /* player setup */
7410   for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
7411   {
7412     char prefix[30];
7413
7414     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
7415     fprintf(file, "\n");
7416
7417     sii = setup.input[pnr];
7418     for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
7419       fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
7420   }
7421
7422   /* system setup */
7423   syi = setup.system;
7424   fprintf(file, "\n");
7425   for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
7426     fprintf(file, "%s\n", getSetupLine(system_setup_tokens, "", i));
7427
7428   /* options setup */
7429   soi = setup.options;
7430   fprintf(file, "\n");
7431   for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
7432     fprintf(file, "%s\n", getSetupLine(options_setup_tokens, "", i));
7433
7434   fclose(file);
7435
7436   SetFilePermissions(filename, PERMS_PRIVATE);
7437 }
7438
7439 void SaveSetup_EditorCascade()
7440 {
7441   char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
7442   FILE *file;
7443   int i;
7444
7445   InitUserDataDirectory();
7446
7447   if (!(file = fopen(filename, MODE_WRITE)))
7448   {
7449     Error(ERR_WARN, "cannot write editor cascade state file '%s'", filename);
7450     free(filename);
7451     return;
7452   }
7453
7454   fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
7455                                                getCookie("SETUP")));
7456   fprintf(file, "\n");
7457
7458   seci = setup.editor_cascade;
7459   fprintf(file, "\n");
7460   for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
7461     fprintf(file, "%s\n", getSetupLine(editor_cascade_setup_tokens, "", i));
7462
7463   fclose(file);
7464
7465   SetFilePermissions(filename, PERMS_PRIVATE);
7466
7467   free(filename);
7468 }
7469
7470 void LoadCustomElementDescriptions()
7471 {
7472   char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
7473   SetupFileHash *setup_file_hash;
7474   int i;
7475
7476   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7477   {
7478     if (element_info[i].custom_description != NULL)
7479     {
7480       free(element_info[i].custom_description);
7481       element_info[i].custom_description = NULL;
7482     }
7483   }
7484
7485   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
7486     return;
7487
7488   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7489   {
7490     char *token = getStringCat2(element_info[i].token_name, ".name");
7491     char *value = getHashEntry(setup_file_hash, token);
7492
7493     if (value != NULL)
7494       element_info[i].custom_description = getStringCopy(value);
7495
7496     free(token);
7497   }
7498
7499   freeSetupFileHash(setup_file_hash);
7500 }
7501
7502 static void LoadSpecialMenuDesignSettingsFromFilename(char *filename)
7503 {
7504   SetupFileHash *setup_file_hash;
7505   int i;
7506
7507 #if 0
7508   printf("LoadSpecialMenuDesignSettings from file '%s' ...\n", filename);
7509 #endif
7510
7511   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
7512     return;
7513
7514   /* special case: initialize with default values that may be overwritten */
7515   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
7516   {
7517     char *value_x = getHashEntry(setup_file_hash, "menu.draw_xoffset");
7518     char *value_y = getHashEntry(setup_file_hash, "menu.draw_yoffset");
7519     char *list_size = getHashEntry(setup_file_hash, "menu.list_size");
7520
7521     if (value_x != NULL)
7522       menu.draw_xoffset[i] = get_integer_from_string(value_x);
7523     if (value_y != NULL)
7524       menu.draw_yoffset[i] = get_integer_from_string(value_y);
7525     if (list_size != NULL)
7526       menu.list_size[i] = get_integer_from_string(list_size);
7527   }
7528
7529   /* read (and overwrite with) values that may be specified in config file */
7530   for (i = 0; image_config_vars[i].token != NULL; i++)
7531   {
7532     char *value = getHashEntry(setup_file_hash, image_config_vars[i].token);
7533
7534     if (value != NULL)
7535       *image_config_vars[i].value =
7536         get_auto_parameter_value(image_config_vars[i].token, value);
7537   }
7538
7539   freeSetupFileHash(setup_file_hash);
7540 }
7541
7542 void LoadSpecialMenuDesignSettings()
7543 {
7544   char *filename_base = UNDEFINED_FILENAME, *filename_local;
7545   int i, j;
7546
7547   /* always start with reliable default values from default config */
7548   for (i = 0; image_config_vars[i].token != NULL; i++)
7549     for (j = 0; image_config[j].token != NULL; j++)
7550       if (strEqual(image_config_vars[i].token, image_config[j].token))
7551         *image_config_vars[i].value =
7552           get_auto_parameter_value(image_config_vars[i].token,
7553                                    image_config[j].value);
7554
7555 #if 1
7556   if (!SETUP_OVERRIDE_ARTWORK(setup, ARTWORK_TYPE_GRAPHICS))
7557   {
7558     /* first look for special settings configured in level series config */
7559     filename_base = getCustomArtworkLevelConfigFilename(ARTWORK_TYPE_GRAPHICS);
7560
7561     if (fileExists(filename_base))
7562       LoadSpecialMenuDesignSettingsFromFilename(filename_base);
7563   }
7564
7565   filename_local = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
7566
7567   if (filename_local != NULL && !strEqual(filename_base, filename_local))
7568     LoadSpecialMenuDesignSettingsFromFilename(filename_local);
7569
7570 #else
7571
7572   filename_local = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
7573
7574   LoadSpecialMenuDesignSettingsFromFilename(filename_local);
7575 #endif
7576 }
7577
7578 void LoadUserDefinedEditorElementList(int **elements, int *num_elements)
7579 {
7580   char *filename = getEditorSetupFilename();
7581   SetupFileList *setup_file_list, *list;
7582   SetupFileHash *element_hash;
7583   int num_unknown_tokens = 0;
7584   int i;
7585
7586   if ((setup_file_list = loadSetupFileList(filename)) == NULL)
7587     return;
7588
7589   element_hash = newSetupFileHash();
7590
7591   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7592     setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
7593
7594   /* determined size may be larger than needed (due to unknown elements) */
7595   *num_elements = 0;
7596   for (list = setup_file_list; list != NULL; list = list->next)
7597     (*num_elements)++;
7598
7599   /* add space for up to 3 more elements for padding that may be needed */
7600   *num_elements += 3;
7601
7602   /* free memory for old list of elements, if needed */
7603   checked_free(*elements);
7604
7605   /* allocate memory for new list of elements */
7606   *elements = checked_malloc(*num_elements * sizeof(int));
7607
7608   *num_elements = 0;
7609   for (list = setup_file_list; list != NULL; list = list->next)
7610   {
7611     char *value = getHashEntry(element_hash, list->token);
7612
7613     if (value == NULL)          /* try to find obsolete token mapping */
7614     {
7615       char *mapped_token = get_mapped_token(list->token);
7616
7617       if (mapped_token != NULL)
7618       {
7619         value = getHashEntry(element_hash, mapped_token);
7620
7621         free(mapped_token);
7622       }
7623     }
7624
7625     if (value != NULL)
7626     {
7627       (*elements)[(*num_elements)++] = atoi(value);
7628     }
7629     else
7630     {
7631       if (num_unknown_tokens == 0)
7632       {
7633         Error(ERR_RETURN_LINE, "-");
7634         Error(ERR_RETURN, "warning: unknown token(s) found in config file:");
7635         Error(ERR_RETURN, "- config file: '%s'", filename);
7636
7637         num_unknown_tokens++;
7638       }
7639
7640       Error(ERR_RETURN, "- token: '%s'", list->token);
7641     }
7642   }
7643
7644   if (num_unknown_tokens > 0)
7645     Error(ERR_RETURN_LINE, "-");
7646
7647   while (*num_elements % 4)     /* pad with empty elements, if needed */
7648     (*elements)[(*num_elements)++] = EL_EMPTY;
7649
7650   freeSetupFileList(setup_file_list);
7651   freeSetupFileHash(element_hash);
7652
7653 #if 0
7654   for (i = 0; i < *num_elements; i++)
7655     printf("editor: element '%s' [%d]\n",
7656            element_info[(*elements)[i]].token_name, (*elements)[i]);
7657 #endif
7658 }
7659
7660 static struct MusicFileInfo *get_music_file_info_ext(char *basename, int music,
7661                                                      boolean is_sound)
7662 {
7663   SetupFileHash *setup_file_hash = NULL;
7664   struct MusicFileInfo tmp_music_file_info, *new_music_file_info;
7665   char *filename_music, *filename_prefix, *filename_info;
7666   struct
7667   {
7668     char *token;
7669     char **value_ptr;
7670   }
7671   token_to_value_ptr[] =
7672   {
7673     { "title_header",   &tmp_music_file_info.title_header       },
7674     { "artist_header",  &tmp_music_file_info.artist_header      },
7675     { "album_header",   &tmp_music_file_info.album_header       },
7676     { "year_header",    &tmp_music_file_info.year_header        },
7677
7678     { "title",          &tmp_music_file_info.title              },
7679     { "artist",         &tmp_music_file_info.artist             },
7680     { "album",          &tmp_music_file_info.album              },
7681     { "year",           &tmp_music_file_info.year               },
7682
7683     { NULL,             NULL                                    },
7684   };
7685   int i;
7686
7687   filename_music = (is_sound ? getCustomSoundFilename(basename) :
7688                     getCustomMusicFilename(basename));
7689
7690   if (filename_music == NULL)
7691     return NULL;
7692
7693   /* ---------- try to replace file extension ---------- */
7694
7695   filename_prefix = getStringCopy(filename_music);
7696   if (strrchr(filename_prefix, '.') != NULL)
7697     *strrchr(filename_prefix, '.') = '\0';
7698   filename_info = getStringCat2(filename_prefix, ".txt");
7699
7700 #if 0
7701   printf("trying to load file '%s'...\n", filename_info);
7702 #endif
7703
7704   if (fileExists(filename_info))
7705     setup_file_hash = loadSetupFileHash(filename_info);
7706
7707   free(filename_prefix);
7708   free(filename_info);
7709
7710   if (setup_file_hash == NULL)
7711   {
7712     /* ---------- try to add file extension ---------- */
7713
7714     filename_prefix = getStringCopy(filename_music);
7715     filename_info = getStringCat2(filename_prefix, ".txt");
7716
7717 #if 0
7718     printf("trying to load file '%s'...\n", filename_info);
7719 #endif
7720
7721     if (fileExists(filename_info))
7722       setup_file_hash = loadSetupFileHash(filename_info);
7723
7724     free(filename_prefix);
7725     free(filename_info);
7726   }
7727
7728   if (setup_file_hash == NULL)
7729     return NULL;
7730
7731   /* ---------- music file info found ---------- */
7732
7733   memset(&tmp_music_file_info, 0, sizeof(struct MusicFileInfo));
7734
7735   for (i = 0; token_to_value_ptr[i].token != NULL; i++)
7736   {
7737     char *value = getHashEntry(setup_file_hash, token_to_value_ptr[i].token);
7738
7739     *token_to_value_ptr[i].value_ptr =
7740       getStringCopy(value != NULL && *value != '\0' ? value : UNKNOWN_NAME);
7741   }
7742
7743   tmp_music_file_info.basename = getStringCopy(basename);
7744   tmp_music_file_info.music = music;
7745   tmp_music_file_info.is_sound = is_sound;
7746
7747   new_music_file_info = checked_malloc(sizeof(struct MusicFileInfo));
7748   *new_music_file_info = tmp_music_file_info;
7749
7750   return new_music_file_info;
7751 }
7752
7753 static struct MusicFileInfo *get_music_file_info(char *basename, int music)
7754 {
7755   return get_music_file_info_ext(basename, music, FALSE);
7756 }
7757
7758 static struct MusicFileInfo *get_sound_file_info(char *basename, int sound)
7759 {
7760   return get_music_file_info_ext(basename, sound, TRUE);
7761 }
7762
7763 static boolean music_info_listed_ext(struct MusicFileInfo *list,
7764                                      char *basename, boolean is_sound)
7765 {
7766   for (; list != NULL; list = list->next)
7767     if (list->is_sound == is_sound && strEqual(list->basename, basename))
7768       return TRUE;
7769
7770   return FALSE;
7771 }
7772
7773 static boolean music_info_listed(struct MusicFileInfo *list, char *basename)
7774 {
7775   return music_info_listed_ext(list, basename, FALSE);
7776 }
7777
7778 static boolean sound_info_listed(struct MusicFileInfo *list, char *basename)
7779 {
7780   return music_info_listed_ext(list, basename, TRUE);
7781 }
7782
7783 void LoadMusicInfo()
7784 {
7785   char *music_directory = getCustomMusicDirectory();
7786   int num_music = getMusicListSize();
7787   int num_music_noconf = 0;
7788   int num_sounds = getSoundListSize();
7789   DIR *dir;
7790   struct dirent *dir_entry;
7791   struct FileInfo *music, *sound;
7792   struct MusicFileInfo *next, **new;
7793   int i;
7794
7795   while (music_file_info != NULL)
7796   {
7797     next = music_file_info->next;
7798
7799     checked_free(music_file_info->basename);
7800
7801     checked_free(music_file_info->title_header);
7802     checked_free(music_file_info->artist_header);
7803     checked_free(music_file_info->album_header);
7804     checked_free(music_file_info->year_header);
7805
7806     checked_free(music_file_info->title);
7807     checked_free(music_file_info->artist);
7808     checked_free(music_file_info->album);
7809     checked_free(music_file_info->year);
7810
7811     free(music_file_info);
7812
7813     music_file_info = next;
7814   }
7815
7816   new = &music_file_info;
7817
7818   for (i = 0; i < num_music; i++)
7819   {
7820     music = getMusicListEntry(i);
7821
7822     if (music->filename == NULL)
7823       continue;
7824
7825     if (strEqual(music->filename, UNDEFINED_FILENAME))
7826       continue;
7827
7828     /* a configured file may be not recognized as music */
7829     if (!FileIsMusic(music->filename))
7830       continue;
7831
7832 #if 0
7833     printf("::: -> '%s' (configured)\n", music->filename);
7834 #endif
7835
7836     if (!music_info_listed(music_file_info, music->filename))
7837     {
7838       *new = get_music_file_info(music->filename, i);
7839       if (*new != NULL)
7840         new = &(*new)->next;
7841     }
7842   }
7843
7844   if ((dir = opendir(music_directory)) == NULL)
7845   {
7846     Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
7847     return;
7848   }
7849
7850   while ((dir_entry = readdir(dir)) != NULL)    /* loop until last dir entry */
7851   {
7852     char *basename = dir_entry->d_name;
7853     boolean music_already_used = FALSE;
7854     int i;
7855
7856     /* skip all music files that are configured in music config file */
7857     for (i = 0; i < num_music; i++)
7858     {
7859       music = getMusicListEntry(i);
7860
7861       if (music->filename == NULL)
7862         continue;
7863
7864       if (strEqual(basename, music->filename))
7865       {
7866         music_already_used = TRUE;
7867         break;
7868       }
7869     }
7870
7871     if (music_already_used)
7872       continue;
7873
7874     if (!FileIsMusic(basename))
7875       continue;
7876
7877 #if 0
7878     printf("::: -> '%s' (found in directory)\n", basename);
7879 #endif
7880
7881     if (!music_info_listed(music_file_info, basename))
7882     {
7883       *new = get_music_file_info(basename, MAP_NOCONF_MUSIC(num_music_noconf));
7884       if (*new != NULL)
7885         new = &(*new)->next;
7886     }
7887
7888     num_music_noconf++;
7889   }
7890
7891   closedir(dir);
7892
7893   for (i = 0; i < num_sounds; i++)
7894   {
7895     sound = getSoundListEntry(i);
7896
7897     if (sound->filename == NULL)
7898       continue;
7899
7900     if (strEqual(sound->filename, UNDEFINED_FILENAME))
7901       continue;
7902
7903     /* a configured file may be not recognized as sound */
7904     if (!FileIsSound(sound->filename))
7905       continue;
7906
7907 #if 0
7908     printf("::: -> '%s' (configured)\n", sound->filename);
7909 #endif
7910
7911     if (!sound_info_listed(music_file_info, sound->filename))
7912     {
7913       *new = get_sound_file_info(sound->filename, i);
7914       if (*new != NULL)
7915         new = &(*new)->next;
7916     }
7917   }
7918
7919 #if 0
7920   for (next = music_file_info; next != NULL; next = next->next)
7921     printf("::: title == '%s'\n", next->title);
7922 #endif
7923 }
7924
7925 void add_helpanim_entry(int element, int action, int direction, int delay,
7926                         int *num_list_entries)
7927 {
7928   struct HelpAnimInfo *new_list_entry;
7929   (*num_list_entries)++;
7930
7931   helpanim_info =
7932     checked_realloc(helpanim_info,
7933                     *num_list_entries * sizeof(struct HelpAnimInfo));
7934   new_list_entry = &helpanim_info[*num_list_entries - 1];
7935
7936   new_list_entry->element = element;
7937   new_list_entry->action = action;
7938   new_list_entry->direction = direction;
7939   new_list_entry->delay = delay;
7940 }
7941
7942 void print_unknown_token(char *filename, char *token, int token_nr)
7943 {
7944   if (token_nr == 0)
7945   {
7946     Error(ERR_RETURN_LINE, "-");
7947     Error(ERR_RETURN, "warning: unknown token(s) found in config file:");
7948     Error(ERR_RETURN, "- config file: '%s'", filename);
7949   }
7950
7951   Error(ERR_RETURN, "- token: '%s'", token);
7952 }
7953
7954 void print_unknown_token_end(int token_nr)
7955 {
7956   if (token_nr > 0)
7957     Error(ERR_RETURN_LINE, "-");
7958 }
7959
7960 void LoadHelpAnimInfo()
7961 {
7962   char *filename = getHelpAnimFilename();
7963   SetupFileList *setup_file_list = NULL, *list;
7964   SetupFileHash *element_hash, *action_hash, *direction_hash;
7965   int num_list_entries = 0;
7966   int num_unknown_tokens = 0;
7967   int i;
7968
7969   if (fileExists(filename))
7970     setup_file_list = loadSetupFileList(filename);
7971
7972   if (setup_file_list == NULL)
7973   {
7974     /* use reliable default values from static configuration */
7975     SetupFileList *insert_ptr;
7976
7977     insert_ptr = setup_file_list =
7978       newSetupFileList(helpanim_config[0].token,
7979                        helpanim_config[0].value);
7980
7981     for (i = 1; helpanim_config[i].token; i++)
7982       insert_ptr = addListEntry(insert_ptr,
7983                                 helpanim_config[i].token,
7984                                 helpanim_config[i].value);
7985   }
7986
7987   element_hash   = newSetupFileHash();
7988   action_hash    = newSetupFileHash();
7989   direction_hash = newSetupFileHash();
7990
7991   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
7992     setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
7993
7994   for (i = 0; i < NUM_ACTIONS; i++)
7995     setHashEntry(action_hash, element_action_info[i].suffix,
7996                  i_to_a(element_action_info[i].value));
7997
7998   /* do not store direction index (bit) here, but direction value! */
7999   for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
8000     setHashEntry(direction_hash, element_direction_info[i].suffix,
8001                  i_to_a(1 << element_direction_info[i].value));
8002
8003   for (list = setup_file_list; list != NULL; list = list->next)
8004   {
8005     char *element_token, *action_token, *direction_token;
8006     char *element_value, *action_value, *direction_value;
8007     int delay = atoi(list->value);
8008
8009     if (strEqual(list->token, "end"))
8010     {
8011       add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
8012
8013       continue;
8014     }
8015
8016     /* first try to break element into element/action/direction parts;
8017        if this does not work, also accept combined "element[.act][.dir]"
8018        elements (like "dynamite.active"), which are unique elements */
8019
8020     if (strchr(list->token, '.') == NULL)       /* token contains no '.' */
8021     {
8022       element_value = getHashEntry(element_hash, list->token);
8023       if (element_value != NULL)        /* element found */
8024         add_helpanim_entry(atoi(element_value), -1, -1, delay,
8025                            &num_list_entries);
8026       else
8027       {
8028         /* no further suffixes found -- this is not an element */
8029         print_unknown_token(filename, list->token, num_unknown_tokens++);
8030       }
8031
8032       continue;
8033     }
8034
8035     /* token has format "<prefix>.<something>" */
8036
8037     action_token = strchr(list->token, '.');    /* suffix may be action ... */
8038     direction_token = action_token;             /* ... or direction */
8039
8040     element_token = getStringCopy(list->token);
8041     *strchr(element_token, '.') = '\0';
8042
8043     element_value = getHashEntry(element_hash, element_token);
8044
8045     if (element_value == NULL)          /* this is no element */
8046     {
8047       element_value = getHashEntry(element_hash, list->token);
8048       if (element_value != NULL)        /* combined element found */
8049         add_helpanim_entry(atoi(element_value), -1, -1, delay,
8050                            &num_list_entries);
8051       else
8052         print_unknown_token(filename, list->token, num_unknown_tokens++);
8053
8054       free(element_token);
8055
8056       continue;
8057     }
8058
8059     action_value = getHashEntry(action_hash, action_token);
8060
8061     if (action_value != NULL)           /* action found */
8062     {
8063       add_helpanim_entry(atoi(element_value), atoi(action_value), -1, delay,
8064                     &num_list_entries);
8065
8066       free(element_token);
8067
8068       continue;
8069     }
8070
8071     direction_value = getHashEntry(direction_hash, direction_token);
8072
8073     if (direction_value != NULL)        /* direction found */
8074     {
8075       add_helpanim_entry(atoi(element_value), -1, atoi(direction_value), delay,
8076                          &num_list_entries);
8077
8078       free(element_token);
8079
8080       continue;
8081     }
8082
8083     if (strchr(action_token + 1, '.') == NULL)
8084     {
8085       /* no further suffixes found -- this is not an action nor direction */
8086
8087       element_value = getHashEntry(element_hash, list->token);
8088       if (element_value != NULL)        /* combined element found */
8089         add_helpanim_entry(atoi(element_value), -1, -1, delay,
8090                            &num_list_entries);
8091       else
8092         print_unknown_token(filename, list->token, num_unknown_tokens++);
8093
8094       free(element_token);
8095
8096       continue;
8097     }
8098
8099     /* token has format "<prefix>.<suffix>.<something>" */
8100
8101     direction_token = strchr(action_token + 1, '.');
8102
8103     action_token = getStringCopy(action_token);
8104     *strchr(action_token + 1, '.') = '\0';
8105
8106     action_value = getHashEntry(action_hash, action_token);
8107
8108     if (action_value == NULL)           /* this is no action */
8109     {
8110       element_value = getHashEntry(element_hash, list->token);
8111       if (element_value != NULL)        /* combined element found */
8112         add_helpanim_entry(atoi(element_value), -1, -1, delay,
8113                            &num_list_entries);
8114       else
8115         print_unknown_token(filename, list->token, num_unknown_tokens++);
8116
8117       free(element_token);
8118       free(action_token);
8119
8120       continue;
8121     }
8122
8123     direction_value = getHashEntry(direction_hash, direction_token);
8124
8125     if (direction_value != NULL)        /* direction found */
8126     {
8127       add_helpanim_entry(atoi(element_value), atoi(action_value),
8128                          atoi(direction_value), delay, &num_list_entries);
8129
8130       free(element_token);
8131       free(action_token);
8132
8133       continue;
8134     }
8135
8136     /* this is no direction */
8137
8138     element_value = getHashEntry(element_hash, list->token);
8139     if (element_value != NULL)          /* combined element found */
8140       add_helpanim_entry(atoi(element_value), -1, -1, delay,
8141                          &num_list_entries);
8142     else
8143       print_unknown_token(filename, list->token, num_unknown_tokens++);
8144
8145     free(element_token);
8146     free(action_token);
8147   }
8148
8149   print_unknown_token_end(num_unknown_tokens);
8150
8151   add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
8152   add_helpanim_entry(HELPANIM_LIST_END,  -1, -1, -1, &num_list_entries);
8153
8154   freeSetupFileList(setup_file_list);
8155   freeSetupFileHash(element_hash);
8156   freeSetupFileHash(action_hash);
8157   freeSetupFileHash(direction_hash);
8158
8159 #if 0
8160   for (i = 0; i < num_list_entries; i++)
8161     printf("::: '%s': %d, %d, %d => %d\n",
8162            EL_NAME(helpanim_info[i].element),
8163            helpanim_info[i].element,
8164            helpanim_info[i].action,
8165            helpanim_info[i].direction,
8166            helpanim_info[i].delay);
8167 #endif
8168 }
8169
8170 void LoadHelpTextInfo()
8171 {
8172   char *filename = getHelpTextFilename();
8173   int i;
8174
8175   if (helptext_info != NULL)
8176   {
8177     freeSetupFileHash(helptext_info);
8178     helptext_info = NULL;
8179   }
8180
8181   if (fileExists(filename))
8182     helptext_info = loadSetupFileHash(filename);
8183
8184   if (helptext_info == NULL)
8185   {
8186     /* use reliable default values from static configuration */
8187     helptext_info = newSetupFileHash();
8188
8189     for (i = 0; helptext_config[i].token; i++)
8190       setHashEntry(helptext_info,
8191                    helptext_config[i].token,
8192                    helptext_config[i].value);
8193   }
8194
8195 #if 0
8196   BEGIN_HASH_ITERATION(helptext_info, itr)
8197   {
8198     printf("::: '%s' => '%s'\n",
8199            HASH_ITERATION_TOKEN(itr), HASH_ITERATION_VALUE(itr));
8200   }
8201   END_HASH_ITERATION(hash, itr)
8202 #endif
8203 }
8204
8205
8206 /* ------------------------------------------------------------------------- *
8207  * convert levels
8208  * ------------------------------------------------------------------------- */
8209
8210 #define MAX_NUM_CONVERT_LEVELS          1000
8211
8212 void ConvertLevels()
8213 {
8214   static LevelDirTree *convert_leveldir = NULL;
8215   static int convert_level_nr = -1;
8216   static int num_levels_handled = 0;
8217   static int num_levels_converted = 0;
8218   static boolean levels_failed[MAX_NUM_CONVERT_LEVELS];
8219   int i;
8220
8221   convert_leveldir = getTreeInfoFromIdentifier(leveldir_first,
8222                                                global.convert_leveldir);
8223
8224   if (convert_leveldir == NULL)
8225     Error(ERR_EXIT, "no such level identifier: '%s'",
8226           global.convert_leveldir);
8227
8228   leveldir_current = convert_leveldir;
8229
8230   if (global.convert_level_nr != -1)
8231   {
8232     convert_leveldir->first_level = global.convert_level_nr;
8233     convert_leveldir->last_level  = global.convert_level_nr;
8234   }
8235
8236   convert_level_nr = convert_leveldir->first_level;
8237
8238   printf_line("=", 79);
8239   printf("Converting levels\n");
8240   printf_line("-", 79);
8241   printf("Level series identifier: '%s'\n", convert_leveldir->identifier);
8242   printf("Level series name:       '%s'\n", convert_leveldir->name);
8243   printf("Level series author:     '%s'\n", convert_leveldir->author);
8244   printf("Number of levels:        %d\n",   convert_leveldir->levels);
8245   printf_line("=", 79);
8246   printf("\n");
8247
8248   for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++)
8249     levels_failed[i] = FALSE;
8250
8251   while (convert_level_nr <= convert_leveldir->last_level)
8252   {
8253     char *level_filename;
8254     boolean new_level;
8255
8256     level_nr = convert_level_nr++;
8257
8258     printf("Level %03d: ", level_nr);
8259
8260     LoadLevel(level_nr);
8261     if (level.no_valid_file)
8262     {
8263       printf("(no level)\n");
8264       continue;
8265     }
8266
8267     printf("converting level ... ");
8268
8269     level_filename = getDefaultLevelFilename(level_nr);
8270     new_level = !fileExists(level_filename);
8271
8272     if (new_level)
8273     {
8274       SaveLevel(level_nr);
8275
8276       num_levels_converted++;
8277
8278       printf("converted.\n");
8279     }
8280     else
8281     {
8282       if (level_nr >= 0 && level_nr < MAX_NUM_CONVERT_LEVELS)
8283         levels_failed[level_nr] = TRUE;
8284
8285       printf("NOT CONVERTED -- LEVEL ALREADY EXISTS.\n");
8286     }
8287
8288     num_levels_handled++;
8289   }
8290
8291   printf("\n");
8292   printf_line("=", 79);
8293   printf("Number of levels handled: %d\n", num_levels_handled);
8294   printf("Number of levels converted: %d (%d%%)\n", num_levels_converted,
8295          (num_levels_handled ?
8296           num_levels_converted * 100 / num_levels_handled : 0));
8297   printf_line("-", 79);
8298   printf("Summary (for automatic parsing by scripts):\n");
8299   printf("LEVELDIR '%s', CONVERTED %d/%d (%d%%)",
8300          convert_leveldir->identifier, num_levels_converted,
8301          num_levels_handled,
8302          (num_levels_handled ?
8303           num_levels_converted * 100 / num_levels_handled : 0));
8304
8305   if (num_levels_handled != num_levels_converted)
8306   {
8307     printf(", FAILED:");
8308     for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++)
8309       if (levels_failed[i])
8310         printf(" %03d", i);
8311   }
8312
8313   printf("\n");
8314   printf_line("=", 79);
8315
8316   CloseAllAndExit(0);
8317 }