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