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