rnd-20091202-1-src
[rocksndiamonds.git] / src / files.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 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_INTEGER,                       CONF_VALUE_32_BIT(2),
188     &li.random_seed,                    0
189   },
190
191   {
192     -1,                                 -1,
193     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(2),
194     &li.use_step_counter,               FALSE
195   },
196
197   {
198     -1,                                 -1,
199     TYPE_BITFIELD,                      CONF_VALUE_8_BIT(4),
200     &li.wind_direction_initial,         MV_NONE
201   },
202
203   {
204     -1,                                 -1,
205     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(5),
206     &li.em_slippery_gems,               FALSE
207   },
208
209   {
210     -1,                                 -1,
211     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(6),
212     &li.use_custom_template,            FALSE
213   },
214
215   {
216     -1,                                 -1,
217     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(1),
218     &li.can_move_into_acid_bits,        ~0      /* default: everything can */
219   },
220
221   {
222     -1,                                 -1,
223     TYPE_BITFIELD,                      CONF_VALUE_8_BIT(7),
224     &li.dont_collide_with_bits,         ~0      /* default: always deadly */
225   },
226
227   {
228     -1,                                 -1,
229     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(8),
230     &li.em_explodes_by_fire,            FALSE
231   },
232
233   {
234     -1,                                 -1,
235     TYPE_INTEGER,                       CONF_VALUE_16_BIT(5),
236     &li.score[SC_TIME_BONUS],           1
237   },
238
239   {
240     -1,                                 -1,
241     -1,                                 -1,
242     NULL,                               -1
243   }
244 };
245
246 static struct LevelFileConfigInfo chunk_config_ELEM[] =
247 {
248   /* (these values are the same for each player) */
249   {
250     EL_PLAYER_1,                        -1,
251     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
252     &li.block_last_field,               FALSE   /* default case for EM levels */
253   },
254   {
255     EL_PLAYER_1,                        -1,
256     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(2),
257     &li.sp_block_last_field,            TRUE    /* default case for SP levels */
258   },
259   {
260     EL_PLAYER_1,                        -1,
261     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(3),
262     &li.instant_relocation,             FALSE
263   },
264   {
265     EL_PLAYER_1,                        -1,
266     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(4),
267     &li.can_pass_to_walkable,           FALSE
268   },
269   {
270     EL_PLAYER_1,                        -1,
271     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(5),
272     &li.block_snap_field,               TRUE
273   },
274   {
275     EL_PLAYER_1,                        -1,
276     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(6),
277     &li.continuous_snapping,            TRUE
278   },
279   {
280     EL_PLAYER_1,                        -1,
281     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(12),
282     &li.shifted_relocation,             FALSE
283   },
284
285   /* (these values are different for each player) */
286   {
287     EL_PLAYER_1,                        -1,
288     TYPE_INTEGER,                       CONF_VALUE_8_BIT(7),
289     &li.initial_player_stepsize[0],     STEPSIZE_NORMAL
290   },
291   {
292     EL_PLAYER_1,                        -1,
293     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(8),
294     &li.initial_player_gravity[0],      FALSE
295   },
296   {
297     EL_PLAYER_1,                        -1,
298     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(9),
299     &li.use_start_element[0],           FALSE
300   },
301   {
302     EL_PLAYER_1,                        -1,
303     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
304     &li.start_element[0],               EL_PLAYER_1
305   },
306   {
307     EL_PLAYER_1,                        -1,
308     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(10),
309     &li.use_artwork_element[0],         FALSE
310   },
311   {
312     EL_PLAYER_1,                        -1,
313     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(2),
314     &li.artwork_element[0],             EL_PLAYER_1
315   },
316   {
317     EL_PLAYER_1,                        -1,
318     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(11),
319     &li.use_explosion_element[0],       FALSE
320   },
321   {
322     EL_PLAYER_1,                        -1,
323     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(3),
324     &li.explosion_element[0],           EL_PLAYER_1
325   },
326   {
327     EL_PLAYER_1,                        -1,
328     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(13),
329     &li.use_initial_inventory[0],       FALSE
330   },
331   {
332     EL_PLAYER_1,                        -1,
333     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(14),
334     &li.initial_inventory_size[0],      1
335   },
336   {
337     EL_PLAYER_1,                        -1,
338     TYPE_ELEMENT_LIST,                  CONF_VALUE_BYTES(1),
339     &li.initial_inventory_content[0][0],EL_EMPTY, NULL,
340     &li.initial_inventory_size[0],      1, MAX_INITIAL_INVENTORY_SIZE
341   },
342
343   {
344     EL_PLAYER_2,                        -1,
345     TYPE_INTEGER,                       CONF_VALUE_8_BIT(7),
346     &li.initial_player_stepsize[1],     STEPSIZE_NORMAL
347   },
348   {
349     EL_PLAYER_2,                        -1,
350     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(8),
351     &li.initial_player_gravity[1],      FALSE
352   },
353   {
354     EL_PLAYER_2,                        -1,
355     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(9),
356     &li.use_start_element[1],           FALSE
357   },
358   {
359     EL_PLAYER_2,                        -1,
360     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
361     &li.start_element[1],               EL_PLAYER_2
362   },
363   {
364     EL_PLAYER_2,                        -1,
365     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(10),
366     &li.use_artwork_element[1],         FALSE
367   },
368   {
369     EL_PLAYER_2,                        -1,
370     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(2),
371     &li.artwork_element[1],             EL_PLAYER_2
372   },
373   {
374     EL_PLAYER_2,                        -1,
375     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(11),
376     &li.use_explosion_element[1],       FALSE
377   },
378   {
379     EL_PLAYER_2,                        -1,
380     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(3),
381     &li.explosion_element[1],           EL_PLAYER_2
382   },
383   {
384     EL_PLAYER_2,                        -1,
385     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(13),
386     &li.use_initial_inventory[1],       FALSE
387   },
388   {
389     EL_PLAYER_2,                        -1,
390     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(14),
391     &li.initial_inventory_size[1],      1
392   },
393   {
394     EL_PLAYER_2,                        -1,
395     TYPE_ELEMENT_LIST,                  CONF_VALUE_BYTES(1),
396     &li.initial_inventory_content[1][0],EL_EMPTY, NULL,
397     &li.initial_inventory_size[1],      1, MAX_INITIAL_INVENTORY_SIZE
398   },
399
400   {
401     EL_PLAYER_3,                        -1,
402     TYPE_INTEGER,                       CONF_VALUE_8_BIT(7),
403     &li.initial_player_stepsize[2],     STEPSIZE_NORMAL
404   },
405   {
406     EL_PLAYER_3,                        -1,
407     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(8),
408     &li.initial_player_gravity[2],      FALSE
409   },
410   {
411     EL_PLAYER_3,                        -1,
412     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(9),
413     &li.use_start_element[2],           FALSE
414   },
415   {
416     EL_PLAYER_3,                        -1,
417     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
418     &li.start_element[2],               EL_PLAYER_3
419   },
420   {
421     EL_PLAYER_3,                        -1,
422     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(10),
423     &li.use_artwork_element[2],         FALSE
424   },
425   {
426     EL_PLAYER_3,                        -1,
427     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(2),
428     &li.artwork_element[2],             EL_PLAYER_3
429   },
430   {
431     EL_PLAYER_3,                        -1,
432     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(11),
433     &li.use_explosion_element[2],       FALSE
434   },
435   {
436     EL_PLAYER_3,                        -1,
437     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(3),
438     &li.explosion_element[2],           EL_PLAYER_3
439   },
440   {
441     EL_PLAYER_3,                        -1,
442     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(13),
443     &li.use_initial_inventory[2],       FALSE
444   },
445   {
446     EL_PLAYER_3,                        -1,
447     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(14),
448     &li.initial_inventory_size[2],      1
449   },
450   {
451     EL_PLAYER_3,                        -1,
452     TYPE_ELEMENT_LIST,                  CONF_VALUE_BYTES(1),
453     &li.initial_inventory_content[2][0],EL_EMPTY, NULL,
454     &li.initial_inventory_size[2],      1, MAX_INITIAL_INVENTORY_SIZE
455   },
456
457   {
458     EL_PLAYER_4,                        -1,
459     TYPE_INTEGER,                       CONF_VALUE_8_BIT(7),
460     &li.initial_player_stepsize[3],     STEPSIZE_NORMAL
461   },
462   {
463     EL_PLAYER_4,                        -1,
464     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(8),
465     &li.initial_player_gravity[3],      FALSE
466   },
467   {
468     EL_PLAYER_4,                        -1,
469     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(9),
470     &li.use_start_element[3],           FALSE
471   },
472   {
473     EL_PLAYER_4,                        -1,
474     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
475     &li.start_element[3],               EL_PLAYER_4
476   },
477   {
478     EL_PLAYER_4,                        -1,
479     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(10),
480     &li.use_artwork_element[3],         FALSE
481   },
482   {
483     EL_PLAYER_4,                        -1,
484     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(2),
485     &li.artwork_element[3],             EL_PLAYER_4
486   },
487   {
488     EL_PLAYER_4,                        -1,
489     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(11),
490     &li.use_explosion_element[3],       FALSE
491   },
492   {
493     EL_PLAYER_4,                        -1,
494     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(3),
495     &li.explosion_element[3],           EL_PLAYER_4
496   },
497   {
498     EL_PLAYER_4,                        -1,
499     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(13),
500     &li.use_initial_inventory[3],       FALSE
501   },
502   {
503     EL_PLAYER_4,                        -1,
504     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(14),
505     &li.initial_inventory_size[3],      1
506   },
507   {
508     EL_PLAYER_4,                        -1,
509     TYPE_ELEMENT_LIST,                  CONF_VALUE_BYTES(1),
510     &li.initial_inventory_content[3][0],EL_EMPTY, NULL,
511     &li.initial_inventory_size[3],      1, MAX_INITIAL_INVENTORY_SIZE
512   },
513
514   {
515     EL_EMERALD,                         -1,
516     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
517     &li.score[SC_EMERALD],              10
518   },
519
520   {
521     EL_DIAMOND,                         -1,
522     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
523     &li.score[SC_DIAMOND],              10
524   },
525
526   {
527     EL_BUG,                             -1,
528     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
529     &li.score[SC_BUG],                  10
530   },
531
532   {
533     EL_SPACESHIP,                       -1,
534     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
535     &li.score[SC_SPACESHIP],            10
536   },
537
538   {
539     EL_PACMAN,                          -1,
540     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
541     &li.score[SC_PACMAN],               10
542   },
543
544   {
545     EL_NUT,                             -1,
546     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
547     &li.score[SC_NUT],                  10
548   },
549
550   {
551     EL_DYNAMITE,                        -1,
552     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
553     &li.score[SC_DYNAMITE],             10
554   },
555
556   {
557     EL_KEY_1,                           -1,
558     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
559     &li.score[SC_KEY],                  10
560   },
561
562   {
563     EL_PEARL,                           -1,
564     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
565     &li.score[SC_PEARL],                10
566   },
567
568   {
569     EL_CRYSTAL,                         -1,
570     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
571     &li.score[SC_CRYSTAL],              10
572   },
573
574   {
575     EL_BD_AMOEBA,                       -1,
576     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
577     &li.amoeba_content,                 EL_DIAMOND
578   },
579   {
580     EL_BD_AMOEBA,                       -1,
581     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
582     &li.amoeba_speed,                   10
583   },
584   {
585     EL_BD_AMOEBA,                       -1,
586     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
587     &li.grow_into_diggable,             TRUE
588   },
589
590   {
591     EL_YAMYAM,                          -1,
592     TYPE_CONTENT_LIST,                  CONF_VALUE_BYTES(1),
593     &li.yamyam_content,                 EL_ROCK, NULL,
594     &li.num_yamyam_contents,            4, MAX_ELEMENT_CONTENTS
595   },
596   {
597     EL_YAMYAM,                          -1,
598     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
599     &li.score[SC_YAMYAM],               10
600   },
601
602   {
603     EL_ROBOT,                           -1,
604     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
605     &li.score[SC_ROBOT],                10
606   },
607   {
608     EL_ROBOT,                           -1,
609     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
610     &li.slurp_score,                    10
611   },
612
613   {
614     EL_ROBOT_WHEEL,                     -1,
615     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
616     &li.time_wheel,                     10
617   },
618
619   {
620     EL_MAGIC_WALL,                      -1,
621     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
622     &li.time_magic_wall,                10
623   },
624
625   {
626     EL_GAME_OF_LIFE,                    -1,
627     TYPE_INTEGER,                       CONF_VALUE_8_BIT(1),
628     &li.game_of_life[0],                2
629   },
630   {
631     EL_GAME_OF_LIFE,                    -1,
632     TYPE_INTEGER,                       CONF_VALUE_8_BIT(2),
633     &li.game_of_life[1],                3
634   },
635   {
636     EL_GAME_OF_LIFE,                    -1,
637     TYPE_INTEGER,                       CONF_VALUE_8_BIT(3),
638     &li.game_of_life[2],                3
639   },
640   {
641     EL_GAME_OF_LIFE,                    -1,
642     TYPE_INTEGER,                       CONF_VALUE_8_BIT(4),
643     &li.game_of_life[3],                3
644   },
645
646   {
647     EL_BIOMAZE,                         -1,
648     TYPE_INTEGER,                       CONF_VALUE_8_BIT(1),
649     &li.biomaze[0],                     2
650   },
651   {
652     EL_BIOMAZE,                         -1,
653     TYPE_INTEGER,                       CONF_VALUE_8_BIT(2),
654     &li.biomaze[1],                     3
655   },
656   {
657     EL_BIOMAZE,                         -1,
658     TYPE_INTEGER,                       CONF_VALUE_8_BIT(3),
659     &li.biomaze[2],                     3
660   },
661   {
662     EL_BIOMAZE,                         -1,
663     TYPE_INTEGER,                       CONF_VALUE_8_BIT(4),
664     &li.biomaze[3],                     3
665   },
666
667   {
668     EL_TIMEGATE_SWITCH,                 -1,
669     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
670     &li.time_timegate,                  10
671   },
672
673   {
674     EL_LIGHT_SWITCH_ACTIVE,             -1,
675     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
676     &li.time_light,                     10
677   },
678
679   {
680     EL_SHIELD_NORMAL,                   -1,
681     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
682     &li.shield_normal_time,             10
683   },
684   {
685     EL_SHIELD_NORMAL,                   -1,
686     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
687     &li.score[SC_SHIELD],               10
688   },
689
690   {
691     EL_SHIELD_DEADLY,                   -1,
692     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
693     &li.shield_deadly_time,             10
694   },
695   {
696     EL_SHIELD_DEADLY,                   -1,
697     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
698     &li.score[SC_SHIELD],               10
699   },
700
701   {
702     EL_EXTRA_TIME,                      -1,
703     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
704     &li.extra_time,                     10
705   },
706   {
707     EL_EXTRA_TIME,                      -1,
708     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
709     &li.extra_time_score,               10
710   },
711
712   {
713     EL_TIME_ORB_FULL,                   -1,
714     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
715     &li.time_orb_time,                  10
716   },
717   {
718     EL_TIME_ORB_FULL,                   -1,
719     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
720     &li.use_time_orb_bug,               FALSE
721   },
722
723   {
724     EL_SPRING,                          -1,
725     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
726     &li.use_spring_bug,                 FALSE
727   },
728
729   {
730     EL_EMC_ANDROID,                     -1,
731     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
732     &li.android_move_time,              10
733   },
734   {
735     EL_EMC_ANDROID,                     -1,
736     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
737     &li.android_clone_time,             10
738   },
739   {
740     EL_EMC_ANDROID,                     -1,
741     TYPE_ELEMENT_LIST,                  CONF_VALUE_BYTES(1),
742     &li.android_clone_element[0],       EL_EMPTY, NULL,
743     &li.num_android_clone_elements,     1, MAX_ANDROID_ELEMENTS
744   },
745
746   {
747     EL_EMC_LENSES,                      -1,
748     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
749     &li.lenses_score,                   10
750   },
751   {
752     EL_EMC_LENSES,                      -1,
753     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
754     &li.lenses_time,                    10
755   },
756
757   {
758     EL_EMC_MAGNIFIER,                   -1,
759     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
760     &li.magnify_score,                  10
761   },
762   {
763     EL_EMC_MAGNIFIER,                   -1,
764     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
765     &li.magnify_time,                   10
766   },
767
768   {
769     EL_EMC_MAGIC_BALL,                  -1,
770     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
771     &li.ball_time,                      10
772   },
773   {
774     EL_EMC_MAGIC_BALL,                  -1,
775     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
776     &li.ball_random,                    FALSE
777   },
778   {
779     EL_EMC_MAGIC_BALL,                  -1,
780     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(2),
781     &li.ball_state_initial,             FALSE
782   },
783   {
784     EL_EMC_MAGIC_BALL,                  -1,
785     TYPE_CONTENT_LIST,                  CONF_VALUE_BYTES(1),
786     &li.ball_content,                   EL_EMPTY, NULL,
787     &li.num_ball_contents,              4, MAX_ELEMENT_CONTENTS
788   },
789
790   /* ---------- unused values ----------------------------------------------- */
791
792   {
793     EL_UNKNOWN,                         SAVE_CONF_NEVER,
794     TYPE_INTEGER,                       CONF_VALUE_16_BIT(1),
795     &li.score[SC_UNKNOWN_14],           10
796   },
797   {
798     EL_UNKNOWN,                         SAVE_CONF_NEVER,
799     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
800     &li.score[SC_UNKNOWN_15],           10
801   },
802
803   {
804     -1,                                 -1,
805     -1,                                 -1,
806     NULL,                               -1
807   }
808 };
809
810 static struct LevelFileConfigInfo chunk_config_NOTE[] =
811 {
812   {
813     -1,                                 -1,
814     TYPE_INTEGER,                       CONF_VALUE_8_BIT(1),
815     &xx_envelope.xsize,                 MAX_ENVELOPE_XSIZE,
816   },
817   {
818     -1,                                 -1,
819     TYPE_INTEGER,                       CONF_VALUE_8_BIT(2),
820     &xx_envelope.ysize,                 MAX_ENVELOPE_YSIZE,
821   },
822
823   {
824     -1,                                 -1,
825     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(3),
826     &xx_envelope.autowrap,              FALSE
827   },
828   {
829     -1,                                 -1,
830     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(4),
831     &xx_envelope.centered,              FALSE
832   },
833
834   {
835     -1,                                 -1,
836     TYPE_STRING,                        CONF_VALUE_BYTES(1),
837     &xx_envelope.text,                  -1, NULL,
838     &xx_string_length_unused,           -1, MAX_ENVELOPE_TEXT_LEN,
839     &xx_default_string_empty[0]
840   },
841
842   {
843     -1,                                 -1,
844     -1,                                 -1,
845     NULL,                               -1
846   }
847 };
848
849 static struct LevelFileConfigInfo chunk_config_CUSX_base[] =
850 {
851   {
852     -1,                                 -1,
853     TYPE_STRING,                        CONF_VALUE_BYTES(1),
854     &xx_ei.description[0],              -1,
855     &yy_ei.description[0],
856     &xx_string_length_unused,           -1, MAX_ELEMENT_NAME_LEN,
857     &xx_default_description[0]
858   },
859
860   {
861     -1,                                 -1,
862     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(1),
863     &xx_ei.properties[EP_BITFIELD_BASE_NR], EP_BITMASK_BASE_DEFAULT,
864     &yy_ei.properties[EP_BITFIELD_BASE_NR]
865   },
866 #if 0
867   /* (reserved) */
868   {
869     -1,                                 -1,
870     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(2),
871     &xx_ei.properties[EP_BITFIELD_BASE_NR + 1], EP_BITMASK_DEFAULT,
872     &yy_ei.properties[EP_BITFIELD_BASE_NR + 1]
873   },
874 #endif
875
876   {
877     -1,                                 -1,
878     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
879     &xx_ei.use_gfx_element,             FALSE,
880     &yy_ei.use_gfx_element
881   },
882   {
883     -1,                                 -1,
884     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
885     &xx_ei.gfx_element_initial,         EL_EMPTY_SPACE,
886     &yy_ei.gfx_element_initial
887   },
888
889   {
890     -1,                                 -1,
891     TYPE_BITFIELD,                      CONF_VALUE_8_BIT(2),
892     &xx_ei.access_direction,            MV_ALL_DIRECTIONS,
893     &yy_ei.access_direction
894   },
895
896   {
897     -1,                                 -1,
898     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
899     &xx_ei.collect_score_initial,       10,
900     &yy_ei.collect_score_initial
901   },
902   {
903     -1,                                 -1,
904     TYPE_INTEGER,                       CONF_VALUE_16_BIT(3),
905     &xx_ei.collect_count_initial,       1,
906     &yy_ei.collect_count_initial
907   },
908
909   {
910     -1,                                 -1,
911     TYPE_INTEGER,                       CONF_VALUE_16_BIT(4),
912     &xx_ei.ce_value_fixed_initial,      0,
913     &yy_ei.ce_value_fixed_initial
914   },
915   {
916     -1,                                 -1,
917     TYPE_INTEGER,                       CONF_VALUE_16_BIT(5),
918     &xx_ei.ce_value_random_initial,     0,
919     &yy_ei.ce_value_random_initial
920   },
921   {
922     -1,                                 -1,
923     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(3),
924     &xx_ei.use_last_ce_value,           FALSE,
925     &yy_ei.use_last_ce_value
926   },
927
928   {
929     -1,                                 -1,
930     TYPE_INTEGER,                       CONF_VALUE_16_BIT(6),
931     &xx_ei.push_delay_fixed,            8,
932     &yy_ei.push_delay_fixed
933   },
934   {
935     -1,                                 -1,
936     TYPE_INTEGER,                       CONF_VALUE_16_BIT(7),
937     &xx_ei.push_delay_random,           8,
938     &yy_ei.push_delay_random
939   },
940   {
941     -1,                                 -1,
942     TYPE_INTEGER,                       CONF_VALUE_16_BIT(8),
943     &xx_ei.drop_delay_fixed,            0,
944     &yy_ei.drop_delay_fixed
945   },
946   {
947     -1,                                 -1,
948     TYPE_INTEGER,                       CONF_VALUE_16_BIT(9),
949     &xx_ei.drop_delay_random,           0,
950     &yy_ei.drop_delay_random
951   },
952   {
953     -1,                                 -1,
954     TYPE_INTEGER,                       CONF_VALUE_16_BIT(10),
955     &xx_ei.move_delay_fixed,            0,
956     &yy_ei.move_delay_fixed
957   },
958   {
959     -1,                                 -1,
960     TYPE_INTEGER,                       CONF_VALUE_16_BIT(11),
961     &xx_ei.move_delay_random,           0,
962     &yy_ei.move_delay_random
963   },
964
965   {
966     -1,                                 -1,
967     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(3),
968     &xx_ei.move_pattern,                MV_ALL_DIRECTIONS,
969     &yy_ei.move_pattern
970   },
971   {
972     -1,                                 -1,
973     TYPE_BITFIELD,                      CONF_VALUE_8_BIT(4),
974     &xx_ei.move_direction_initial,      MV_START_AUTOMATIC,
975     &yy_ei.move_direction_initial
976   },
977   {
978     -1,                                 -1,
979     TYPE_INTEGER,                       CONF_VALUE_8_BIT(5),
980     &xx_ei.move_stepsize,               TILEX / 8,
981     &yy_ei.move_stepsize
982   },
983
984   {
985     -1,                                 -1,
986     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(12),
987     &xx_ei.move_enter_element,          EL_EMPTY_SPACE,
988     &yy_ei.move_enter_element
989   },
990   {
991     -1,                                 -1,
992     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(13),
993     &xx_ei.move_leave_element,          EL_EMPTY_SPACE,
994     &yy_ei.move_leave_element
995   },
996   {
997     -1,                                 -1,
998     TYPE_INTEGER,                       CONF_VALUE_8_BIT(6),
999     &xx_ei.move_leave_type,             LEAVE_TYPE_UNLIMITED,
1000     &yy_ei.move_leave_type
1001   },
1002
1003   {
1004     -1,                                 -1,
1005     TYPE_INTEGER,                       CONF_VALUE_8_BIT(7),
1006     &xx_ei.slippery_type,               SLIPPERY_ANY_RANDOM,
1007     &yy_ei.slippery_type
1008   },
1009
1010   {
1011     -1,                                 -1,
1012     TYPE_INTEGER,                       CONF_VALUE_8_BIT(8),
1013     &xx_ei.explosion_type,              EXPLODES_3X3,
1014     &yy_ei.explosion_type
1015   },
1016   {
1017     -1,                                 -1,
1018     TYPE_INTEGER,                       CONF_VALUE_16_BIT(14),
1019     &xx_ei.explosion_delay,             16,
1020     &yy_ei.explosion_delay
1021   },
1022   {
1023     -1,                                 -1,
1024     TYPE_INTEGER,                       CONF_VALUE_16_BIT(15),
1025     &xx_ei.ignition_delay,              8,
1026     &yy_ei.ignition_delay
1027   },
1028
1029   {
1030     -1,                                 -1,
1031     TYPE_CONTENT_LIST,                  CONF_VALUE_BYTES(2),
1032     &xx_ei.content,                     EL_EMPTY_SPACE,
1033     &yy_ei.content,
1034     &xx_num_contents,                   1, 1
1035   },
1036
1037   /* ---------- "num_change_pages" must be the last entry ------------------- */
1038
1039   {
1040     -1,                                 SAVE_CONF_ALWAYS,
1041     TYPE_INTEGER,                       CONF_VALUE_8_BIT(9),
1042     &xx_ei.num_change_pages,            1,
1043     &yy_ei.num_change_pages
1044   },
1045
1046   {
1047     -1,                                 -1,
1048     -1,                                 -1,
1049     NULL,                               -1,
1050     NULL
1051   }
1052 };
1053
1054 static struct LevelFileConfigInfo chunk_config_CUSX_change[] =
1055 {
1056   /* ---------- "current_change_page" must be the first entry --------------- */
1057
1058   {
1059     -1,                                 SAVE_CONF_ALWAYS,
1060     TYPE_INTEGER,                       CONF_VALUE_8_BIT(1),
1061     &xx_current_change_page,            -1
1062   },
1063
1064   /* ---------- (the remaining entries can be in any order) ----------------- */
1065
1066   {
1067     -1,                                 -1,
1068     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(2),
1069     &xx_change.can_change,              FALSE
1070   },
1071
1072   {
1073     -1,                                 -1,
1074     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(1),
1075     &xx_event_bits[0],                  0
1076   },
1077   {
1078     -1,                                 -1,
1079     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(2),
1080     &xx_event_bits[1],                  0
1081   },
1082
1083   {
1084     -1,                                 -1,
1085     TYPE_BITFIELD,                      CONF_VALUE_8_BIT(3),
1086     &xx_change.trigger_player,          CH_PLAYER_ANY
1087   },
1088   {
1089     -1,                                 -1,
1090     TYPE_BITFIELD,                      CONF_VALUE_8_BIT(4),
1091     &xx_change.trigger_side,            CH_SIDE_ANY
1092   },
1093   {
1094     -1,                                 -1,
1095     TYPE_BITFIELD,                      CONF_VALUE_32_BIT(3),
1096     &xx_change.trigger_page,            CH_PAGE_ANY
1097   },
1098
1099   {
1100     -1,                                 -1,
1101     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
1102     &xx_change.target_element,          EL_EMPTY_SPACE
1103   },
1104
1105   {
1106     -1,                                 -1,
1107     TYPE_INTEGER,                       CONF_VALUE_16_BIT(2),
1108     &xx_change.delay_fixed,             0
1109   },
1110   {
1111     -1,                                 -1,
1112     TYPE_INTEGER,                       CONF_VALUE_16_BIT(3),
1113     &xx_change.delay_random,            0
1114   },
1115   {
1116     -1,                                 -1,
1117     TYPE_INTEGER,                       CONF_VALUE_16_BIT(4),
1118     &xx_change.delay_frames,            FRAMES_PER_SECOND
1119   },
1120
1121   {
1122     -1,                                 -1,
1123     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(5),
1124     &xx_change.initial_trigger_element, EL_EMPTY_SPACE
1125   },
1126
1127   {
1128     -1,                                 -1,
1129     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(6),
1130     &xx_change.explode,                 FALSE
1131   },
1132   {
1133     -1,                                 -1,
1134     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(7),
1135     &xx_change.use_target_content,      FALSE
1136   },
1137   {
1138     -1,                                 -1,
1139     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(8),
1140     &xx_change.only_if_complete,        FALSE
1141   },
1142   {
1143     -1,                                 -1,
1144     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(9),
1145     &xx_change.use_random_replace,      FALSE
1146   },
1147   {
1148     -1,                                 -1,
1149     TYPE_INTEGER,                       CONF_VALUE_8_BIT(10),
1150     &xx_change.random_percentage,       100
1151   },
1152   {
1153     -1,                                 -1,
1154     TYPE_INTEGER,                       CONF_VALUE_8_BIT(11),
1155     &xx_change.replace_when,            CP_WHEN_EMPTY
1156   },
1157
1158   {
1159     -1,                                 -1,
1160     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(12),
1161     &xx_change.has_action,              FALSE
1162   },
1163   {
1164     -1,                                 -1,
1165     TYPE_INTEGER,                       CONF_VALUE_8_BIT(13),
1166     &xx_change.action_type,             CA_NO_ACTION
1167   },
1168   {
1169     -1,                                 -1,
1170     TYPE_INTEGER,                       CONF_VALUE_8_BIT(14),
1171     &xx_change.action_mode,             CA_MODE_UNDEFINED
1172   },
1173   {
1174     -1,                                 -1,
1175     TYPE_INTEGER,                       CONF_VALUE_16_BIT(6),
1176     &xx_change.action_arg,              CA_ARG_UNDEFINED
1177   },
1178
1179   {
1180     -1,                                 -1,
1181     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(7),
1182     &xx_change.action_element,          EL_EMPTY_SPACE
1183   },
1184
1185   {
1186     -1,                                 -1,
1187     TYPE_CONTENT_LIST,                  CONF_VALUE_BYTES(1),
1188     &xx_change.target_content,          EL_EMPTY_SPACE, NULL,
1189     &xx_num_contents,                   1, 1
1190   },
1191
1192   {
1193     -1,                                 -1,
1194     -1,                                 -1,
1195     NULL,                               -1
1196   }
1197 };
1198
1199 static struct LevelFileConfigInfo chunk_config_GRPX[] =
1200 {
1201   {
1202     -1,                                 -1,
1203     TYPE_STRING,                        CONF_VALUE_BYTES(1),
1204     &xx_ei.description[0],              -1, NULL,
1205     &xx_string_length_unused,           -1, MAX_ELEMENT_NAME_LEN,
1206     &xx_default_description[0]
1207   },
1208
1209   {
1210     -1,                                 -1,
1211     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(1),
1212     &xx_ei.use_gfx_element,             FALSE
1213   },
1214   {
1215     -1,                                 -1,
1216     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
1217     &xx_ei.gfx_element_initial,         EL_EMPTY_SPACE
1218   },
1219
1220   {
1221     -1,                                 -1,
1222     TYPE_INTEGER,                       CONF_VALUE_8_BIT(2),
1223     &xx_group.choice_mode,              ANIM_RANDOM
1224   },
1225
1226   {
1227     -1,                                 -1,
1228     TYPE_ELEMENT_LIST,                  CONF_VALUE_BYTES(2),
1229     &xx_group.element[0],               EL_EMPTY_SPACE, NULL,
1230     &xx_group.num_elements,             1, MAX_ELEMENTS_IN_GROUP
1231   },
1232
1233   {
1234     -1,                                 -1,
1235     -1,                                 -1,
1236     NULL,                               -1
1237   }
1238 };
1239
1240 static struct LevelFileConfigInfo chunk_config_CONF[] =         /* (OBSOLETE) */
1241 {
1242   {
1243     EL_PLAYER_1,                        -1,
1244     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(9),
1245     &li.block_snap_field,               TRUE
1246   },
1247   {
1248     EL_PLAYER_1,                        -1,
1249     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(13),
1250     &li.continuous_snapping,            TRUE
1251   },
1252   {
1253     EL_PLAYER_1,                        -1,
1254     TYPE_INTEGER,                       CONF_VALUE_8_BIT(1),
1255     &li.initial_player_stepsize[0],     STEPSIZE_NORMAL
1256   },
1257   {
1258     EL_PLAYER_1,                        -1,
1259     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(10),
1260     &li.use_start_element[0],           FALSE
1261   },
1262   {
1263     EL_PLAYER_1,                        -1,
1264     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(1),
1265     &li.start_element[0],               EL_PLAYER_1
1266   },
1267   {
1268     EL_PLAYER_1,                        -1,
1269     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(11),
1270     &li.use_artwork_element[0],         FALSE
1271   },
1272   {
1273     EL_PLAYER_1,                        -1,
1274     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(2),
1275     &li.artwork_element[0],             EL_PLAYER_1
1276   },
1277   {
1278     EL_PLAYER_1,                        -1,
1279     TYPE_BOOLEAN,                       CONF_VALUE_8_BIT(12),
1280     &li.use_explosion_element[0],       FALSE
1281   },
1282   {
1283     EL_PLAYER_1,                        -1,
1284     TYPE_ELEMENT,                       CONF_VALUE_16_BIT(3),
1285     &li.explosion_element[0],           EL_PLAYER_1
1286   },
1287
1288   {
1289     -1,                                 -1,
1290     -1,                                 -1,
1291     NULL,                               -1
1292   }
1293 };
1294
1295 static struct
1296 {
1297   int filetype;
1298   char *id;
1299 }
1300 filetype_id_list[] =
1301 {
1302   { LEVEL_FILE_TYPE_RND,        "RND"   },
1303   { LEVEL_FILE_TYPE_BD,         "BD"    },
1304   { LEVEL_FILE_TYPE_EM,         "EM"    },
1305   { LEVEL_FILE_TYPE_SP,         "SP"    },
1306   { LEVEL_FILE_TYPE_DX,         "DX"    },
1307   { LEVEL_FILE_TYPE_SB,         "SB"    },
1308   { LEVEL_FILE_TYPE_DC,         "DC"    },
1309   { -1,                         NULL    },
1310 };
1311
1312
1313 /* ========================================================================= */
1314 /* level file functions                                                      */
1315 /* ========================================================================= */
1316
1317 static struct DateInfo getCurrentDate()
1318 {
1319   time_t epoch_seconds = time(NULL);
1320   struct tm *now = localtime(&epoch_seconds);
1321   struct DateInfo date;
1322
1323   date.year  = now->tm_year + 1900;
1324   date.month = now->tm_mon  + 1;
1325   date.day   = now->tm_mday;
1326
1327   return date;
1328 }
1329
1330 static void resetEventFlags(struct ElementChangeInfo *change)
1331 {
1332   int i;
1333
1334   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
1335     change->has_event[i] = FALSE;
1336 }
1337
1338 static void resetEventBits()
1339 {
1340   int i;
1341
1342   for (i = 0; i < NUM_CE_BITFIELDS; i++)
1343     xx_event_bits[i] = 0;
1344 }
1345
1346 static void setEventFlagsFromEventBits(struct ElementChangeInfo *change)
1347 {
1348   int i;
1349
1350   /* important: only change event flag if corresponding event bit is set
1351      (this is because all xx_event_bits[] values are loaded separately,
1352      and all xx_event_bits[] values are set back to zero before loading
1353      another value xx_event_bits[x] (each value representing 32 flags)) */
1354
1355   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
1356     if (xx_event_bits[CH_EVENT_BITFIELD_NR(i)] & CH_EVENT_BIT(i))
1357       change->has_event[i] = TRUE;
1358 }
1359
1360 static void setEventBitsFromEventFlags(struct ElementChangeInfo *change)
1361 {
1362   int i;
1363
1364   /* in contrast to the above function setEventFlagsFromEventBits(), it
1365      would also be possible to set all bits in xx_event_bits[] to 0 or 1
1366      depending on the corresponding change->has_event[i] values here, as
1367      all xx_event_bits[] values are reset in resetEventBits() before */
1368
1369   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
1370     if (change->has_event[i])
1371       xx_event_bits[CH_EVENT_BITFIELD_NR(i)] |= CH_EVENT_BIT(i);
1372 }
1373
1374 static char *getDefaultElementDescription(struct ElementInfo *ei)
1375 {
1376   static char description[MAX_ELEMENT_NAME_LEN + 1];
1377   char *default_description = (ei->custom_description != NULL ?
1378                                ei->custom_description :
1379                                ei->editor_description);
1380   int i;
1381
1382   /* always start with reliable default values */
1383   for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++)
1384     description[i] = '\0';
1385
1386   /* truncate element description to MAX_ELEMENT_NAME_LEN bytes */
1387   strncpy(description, default_description, MAX_ELEMENT_NAME_LEN);
1388
1389   return &description[0];
1390 }
1391
1392 static void setElementDescriptionToDefault(struct ElementInfo *ei)
1393 {
1394   char *default_description = getDefaultElementDescription(ei);
1395   int i;
1396
1397   for (i = 0; i < MAX_ELEMENT_NAME_LEN + 1; i++)
1398     ei->description[i] = default_description[i];
1399 }
1400
1401 static void setConfigToDefaultsFromConfigList(struct LevelFileConfigInfo *conf)
1402 {
1403   int i;
1404
1405   for (i = 0; conf[i].data_type != -1; i++)
1406   {
1407     int default_value = conf[i].default_value;
1408     int data_type = conf[i].data_type;
1409     int conf_type = conf[i].conf_type;
1410     int byte_mask = conf_type & CONF_MASK_BYTES;
1411
1412     if (byte_mask == CONF_MASK_MULTI_BYTES)
1413     {
1414       int default_num_entities = conf[i].default_num_entities;
1415       int max_num_entities = conf[i].max_num_entities;
1416
1417       *(int *)(conf[i].num_entities) = default_num_entities;
1418
1419       if (data_type == TYPE_STRING)
1420       {
1421         char *default_string = conf[i].default_string;
1422         char *string = (char *)(conf[i].value);
1423
1424         strncpy(string, default_string, max_num_entities);
1425       }
1426       else if (data_type == TYPE_ELEMENT_LIST)
1427       {
1428         int *element_array = (int *)(conf[i].value);
1429         int j;
1430
1431         for (j = 0; j < max_num_entities; j++)
1432           element_array[j] = default_value;
1433       }
1434       else if (data_type == TYPE_CONTENT_LIST)
1435       {
1436         struct Content *content = (struct Content *)(conf[i].value);
1437         int c, x, y;
1438
1439         for (c = 0; c < max_num_entities; c++)
1440           for (y = 0; y < 3; y++)
1441             for (x = 0; x < 3; x++)
1442               content[c].e[x][y] = default_value;
1443       }
1444     }
1445     else        /* constant size configuration data (1, 2 or 4 bytes) */
1446     {
1447       if (data_type == TYPE_BOOLEAN)
1448         *(boolean *)(conf[i].value) = default_value;
1449       else
1450         *(int *)    (conf[i].value) = default_value;
1451     }
1452   }
1453 }
1454
1455 static void copyConfigFromConfigList(struct LevelFileConfigInfo *conf)
1456 {
1457   int i;
1458
1459   for (i = 0; conf[i].data_type != -1; i++)
1460   {
1461     int data_type = conf[i].data_type;
1462     int conf_type = conf[i].conf_type;
1463     int byte_mask = conf_type & CONF_MASK_BYTES;
1464
1465     if (byte_mask == CONF_MASK_MULTI_BYTES)
1466     {
1467       int max_num_entities = conf[i].max_num_entities;
1468
1469       if (data_type == TYPE_STRING)
1470       {
1471         char *string      = (char *)(conf[i].value);
1472         char *string_copy = (char *)(conf[i].value_copy);
1473
1474         strncpy(string_copy, string, max_num_entities);
1475       }
1476       else if (data_type == TYPE_ELEMENT_LIST)
1477       {
1478         int *element_array      = (int *)(conf[i].value);
1479         int *element_array_copy = (int *)(conf[i].value_copy);
1480         int j;
1481
1482         for (j = 0; j < max_num_entities; j++)
1483           element_array_copy[j] = element_array[j];
1484       }
1485       else if (data_type == TYPE_CONTENT_LIST)
1486       {
1487         struct Content *content      = (struct Content *)(conf[i].value);
1488         struct Content *content_copy = (struct Content *)(conf[i].value_copy);
1489         int c, x, y;
1490
1491         for (c = 0; c < max_num_entities; c++)
1492           for (y = 0; y < 3; y++)
1493             for (x = 0; x < 3; x++)
1494               content_copy[c].e[x][y] = content[c].e[x][y];
1495       }
1496     }
1497     else        /* constant size configuration data (1, 2 or 4 bytes) */
1498     {
1499       if (data_type == TYPE_BOOLEAN)
1500         *(boolean *)(conf[i].value_copy) = *(boolean *)(conf[i].value);
1501       else
1502         *(int *)    (conf[i].value_copy) = *(int *)    (conf[i].value);
1503     }
1504   }
1505 }
1506
1507 void copyElementInfo(struct ElementInfo *ei_from, struct ElementInfo *ei_to)
1508 {
1509   int i;
1510
1511   xx_ei = *ei_from;     /* copy element data into temporary buffer */
1512   yy_ei = *ei_to;       /* copy element data into temporary buffer */
1513
1514   copyConfigFromConfigList(chunk_config_CUSX_base);
1515
1516   *ei_from = xx_ei;
1517   *ei_to   = yy_ei;
1518
1519   /* ---------- reinitialize and copy change pages ---------- */
1520
1521   ei_to->num_change_pages = ei_from->num_change_pages;
1522   ei_to->current_change_page = ei_from->current_change_page;
1523
1524   setElementChangePages(ei_to, ei_to->num_change_pages);
1525
1526   for (i = 0; i < ei_to->num_change_pages; i++)
1527     ei_to->change_page[i] = ei_from->change_page[i];
1528
1529   /* ---------- copy group element info ---------- */
1530   if (ei_from->group != NULL && ei_to->group != NULL)   /* group or internal */
1531     *ei_to->group = *ei_from->group;
1532
1533   /* mark this custom element as modified */
1534   ei_to->modified_settings = TRUE;
1535 }
1536
1537 void setElementChangePages(struct ElementInfo *ei, int change_pages)
1538 {
1539   int change_page_size = sizeof(struct ElementChangeInfo);
1540
1541   ei->num_change_pages = MAX(1, change_pages);
1542
1543   ei->change_page =
1544     checked_realloc(ei->change_page, ei->num_change_pages * change_page_size);
1545
1546   if (ei->current_change_page >= ei->num_change_pages)
1547     ei->current_change_page = ei->num_change_pages - 1;
1548
1549   ei->change = &ei->change_page[ei->current_change_page];
1550 }
1551
1552 void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
1553 {
1554   xx_change = *change;          /* copy change data into temporary buffer */
1555
1556 #if 0
1557   /* (not needed; set by setConfigToDefaultsFromConfigList()) */
1558   xx_num_contents = 1;
1559 #endif
1560
1561   setConfigToDefaultsFromConfigList(chunk_config_CUSX_change);
1562
1563   *change = xx_change;
1564
1565   resetEventFlags(change);
1566
1567   change->direct_action = 0;
1568   change->other_action = 0;
1569
1570   change->pre_change_function = NULL;
1571   change->change_function = NULL;
1572   change->post_change_function = NULL;
1573 }
1574
1575 static void setLevelInfoToDefaults(struct LevelInfo *level)
1576 {
1577   static boolean clipboard_elements_initialized = FALSE;
1578   int i, x, y;
1579
1580   InitElementPropertiesStatic();
1581
1582   li = *level;          /* copy level data into temporary buffer */
1583
1584   setConfigToDefaultsFromConfigList(chunk_config_INFO);
1585   setConfigToDefaultsFromConfigList(chunk_config_ELEM);
1586
1587   *level = li;          /* copy temporary buffer back to level data */
1588
1589   setLevelInfoToDefaults_EM();
1590   setLevelInfoToDefaults_SP();
1591
1592   level->native_em_level = &native_em_level;
1593   level->native_sp_level = &native_sp_level;
1594
1595   level->file_version = FILE_VERSION_ACTUAL;
1596   level->game_version = GAME_VERSION_ACTUAL;
1597
1598   level->creation_date = getCurrentDate();
1599
1600   level->encoding_16bit_field  = TRUE;
1601   level->encoding_16bit_yamyam = TRUE;
1602   level->encoding_16bit_amoeba = TRUE;
1603
1604   for (x = 0; x < MAX_LEV_FIELDX; x++)
1605     for (y = 0; y < MAX_LEV_FIELDY; y++)
1606       level->field[x][y] = EL_SAND;
1607
1608   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
1609     level->name[i] = '\0';
1610   for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
1611     level->author[i] = '\0';
1612
1613   strcpy(level->name, NAMELESS_LEVEL_NAME);
1614   strcpy(level->author, ANONYMOUS_NAME);
1615
1616   level->field[0][0] = EL_PLAYER_1;
1617   level->field[STD_LEV_FIELDX - 1][STD_LEV_FIELDY - 1] = EL_EXIT_CLOSED;
1618
1619   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
1620   {
1621     int element = i;
1622     struct ElementInfo *ei = &element_info[element];
1623
1624     /* never initialize clipboard elements after the very first time */
1625     /* (to be able to use clipboard elements between several levels) */
1626     if (IS_CLIPBOARD_ELEMENT(element) && clipboard_elements_initialized)
1627       continue;
1628
1629     if (IS_ENVELOPE(element))
1630     {
1631       int envelope_nr = element - EL_ENVELOPE_1;
1632
1633       setConfigToDefaultsFromConfigList(chunk_config_NOTE);
1634
1635       level->envelope[envelope_nr] = xx_envelope;
1636     }
1637
1638     if (IS_CUSTOM_ELEMENT(element) ||
1639         IS_GROUP_ELEMENT(element) ||
1640         IS_INTERNAL_ELEMENT(element))
1641     {
1642       xx_ei = *ei;      /* copy element data into temporary buffer */
1643
1644       setConfigToDefaultsFromConfigList(chunk_config_CUSX_base);
1645
1646       *ei = xx_ei;
1647     }
1648
1649     setElementChangePages(ei, 1);
1650     setElementChangeInfoToDefaults(ei->change);
1651
1652     if (IS_CUSTOM_ELEMENT(element) ||
1653         IS_GROUP_ELEMENT(element) ||
1654         IS_INTERNAL_ELEMENT(element))
1655     {
1656       setElementDescriptionToDefault(ei);
1657
1658       ei->modified_settings = FALSE;
1659     }
1660
1661     if (IS_CUSTOM_ELEMENT(element) ||
1662         IS_INTERNAL_ELEMENT(element))
1663     {
1664       /* internal values used in level editor */
1665
1666       ei->access_type = 0;
1667       ei->access_layer = 0;
1668       ei->access_protected = 0;
1669       ei->walk_to_action = 0;
1670       ei->smash_targets = 0;
1671       ei->deadliness = 0;
1672
1673       ei->can_explode_by_fire = FALSE;
1674       ei->can_explode_smashed = FALSE;
1675       ei->can_explode_impact = FALSE;
1676
1677       ei->current_change_page = 0;
1678     }
1679
1680     if (IS_GROUP_ELEMENT(element) ||
1681         IS_INTERNAL_ELEMENT(element))
1682     {
1683       struct ElementGroupInfo *group;
1684
1685       /* initialize memory for list of elements in group */
1686       if (ei->group == NULL)
1687         ei->group = checked_malloc(sizeof(struct ElementGroupInfo));
1688
1689       group = ei->group;
1690
1691       xx_group = *group;        /* copy group data into temporary buffer */
1692
1693       setConfigToDefaultsFromConfigList(chunk_config_GRPX);
1694
1695       *group = xx_group;
1696     }
1697   }
1698
1699   clipboard_elements_initialized = TRUE;
1700
1701   BorderElement = EL_STEELWALL;
1702
1703   level->no_valid_file = FALSE;
1704
1705   level->changed = FALSE;
1706
1707   /* set all bug compatibility flags to "false" => do not emulate this bug */
1708   level->use_action_after_change_bug = FALSE;
1709
1710   if (leveldir_current == NULL)         /* only when dumping level */
1711     return;
1712
1713   /* try to determine better author name than 'anonymous' */
1714   if (!strEqual(leveldir_current->author, ANONYMOUS_NAME))
1715   {
1716     strncpy(level->author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN);
1717     level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
1718   }
1719   else
1720   {
1721     switch (LEVELCLASS(leveldir_current))
1722     {
1723       case LEVELCLASS_TUTORIAL:
1724         strcpy(level->author, PROGRAM_AUTHOR_STRING);
1725         break;
1726
1727       case LEVELCLASS_CONTRIB:
1728         strncpy(level->author, leveldir_current->name, MAX_LEVEL_AUTHOR_LEN);
1729         level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
1730         break;
1731
1732       case LEVELCLASS_PRIVATE:
1733         strncpy(level->author, getRealName(), MAX_LEVEL_AUTHOR_LEN);
1734         level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
1735         break;
1736
1737       default:
1738         /* keep default value */
1739         break;
1740     }
1741   }
1742 }
1743
1744 static void setFileInfoToDefaults(struct LevelFileInfo *level_file_info)
1745 {
1746   level_file_info->nr = 0;
1747   level_file_info->type = LEVEL_FILE_TYPE_UNKNOWN;
1748   level_file_info->packed = FALSE;
1749   level_file_info->basename = NULL;
1750   level_file_info->filename = NULL;
1751 }
1752
1753 static void ActivateLevelTemplate()
1754 {
1755   /* Currently there is no special action needed to activate the template
1756      data, because 'element_info' property settings overwrite the original
1757      level data, while all other variables do not change. */
1758 }
1759
1760 static char *getLevelFilenameFromBasename(char *basename)
1761 {
1762   static char *filename = NULL;
1763
1764   checked_free(filename);
1765
1766   filename = getPath2(getCurrentLevelDir(), basename);
1767
1768   return filename;
1769 }
1770
1771 static int getFileTypeFromBasename(char *basename)
1772 {
1773   /* !!! ALSO SEE COMMENT IN checkForPackageFromBasename() !!! */
1774
1775   static char *filename = NULL;
1776   struct stat file_status;
1777
1778   /* ---------- try to determine file type from filename ---------- */
1779
1780   /* check for typical filename of a Supaplex level package file */
1781 #if 1
1782   if (strlen(basename) == 10 && strPrefixLower(basename, "levels.d"))
1783     return LEVEL_FILE_TYPE_SP;
1784 #else
1785   if (strlen(basename) == 10 && (strncmp(basename, "levels.d", 8) == 0 ||
1786                                  strncmp(basename, "LEVELS.D", 8) == 0))
1787     return LEVEL_FILE_TYPE_SP;
1788 #endif
1789
1790   /* check for typical filename of a Diamond Caves II level package file */
1791   if (strSuffixLower(basename, ".dc") ||
1792       strSuffixLower(basename, ".dc2"))
1793     return LEVEL_FILE_TYPE_DC;
1794
1795   /* check for typical filename of a Sokoban level package file */
1796   if (strSuffixLower(basename, ".xsb") &&
1797       strchr(basename, '%') == NULL)
1798     return LEVEL_FILE_TYPE_SB;
1799
1800   /* ---------- try to determine file type from filesize ---------- */
1801
1802   checked_free(filename);
1803   filename = getPath2(getCurrentLevelDir(), basename);
1804
1805   if (stat(filename, &file_status) == 0)
1806   {
1807     /* check for typical filesize of a Supaplex level package file */
1808     if (file_status.st_size == 170496)
1809       return LEVEL_FILE_TYPE_SP;
1810   }
1811
1812   return LEVEL_FILE_TYPE_UNKNOWN;
1813 }
1814
1815 static boolean checkForPackageFromBasename(char *basename)
1816 {
1817   /* !!! WON'T WORK ANYMORE IF getFileTypeFromBasename() ALSO DETECTS !!!
1818      !!! SINGLE LEVELS (CURRENTLY ONLY DETECTS LEVEL PACKAGES         !!! */
1819
1820   return (getFileTypeFromBasename(basename) != LEVEL_FILE_TYPE_UNKNOWN);
1821 }
1822
1823 static char *getSingleLevelBasename(int nr)
1824 {
1825   static char basename[MAX_FILENAME_LEN];
1826
1827   if (nr < 0)
1828     sprintf(basename, "template.%s", LEVELFILE_EXTENSION);
1829   else
1830     sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION);
1831
1832   return basename;
1833 }
1834
1835 static char *getPackedLevelBasename(int type)
1836 {
1837   static char basename[MAX_FILENAME_LEN];
1838   char *directory = getCurrentLevelDir();
1839   DIR *dir;
1840   struct dirent *dir_entry;
1841
1842   strcpy(basename, UNDEFINED_FILENAME);         /* default: undefined file */
1843
1844   if ((dir = opendir(directory)) == NULL)
1845   {
1846     Error(ERR_WARN, "cannot read current level directory '%s'", directory);
1847
1848     return basename;
1849   }
1850
1851   while ((dir_entry = readdir(dir)) != NULL)    /* loop until last dir entry */
1852   {
1853     char *entry_basename = dir_entry->d_name;
1854     int entry_type = getFileTypeFromBasename(entry_basename);
1855
1856     if (entry_type != LEVEL_FILE_TYPE_UNKNOWN)  /* found valid level package */
1857     {
1858       if (type == LEVEL_FILE_TYPE_UNKNOWN ||
1859           type == entry_type)
1860       {
1861         strcpy(basename, entry_basename);
1862
1863         break;
1864       }
1865     }
1866   }
1867
1868   closedir(dir);
1869
1870   return basename;
1871 }
1872
1873 static char *getSingleLevelFilename(int nr)
1874 {
1875   return getLevelFilenameFromBasename(getSingleLevelBasename(nr));
1876 }
1877
1878 #if 0
1879 static char *getPackedLevelFilename(int type)
1880 {
1881   return getLevelFilenameFromBasename(getPackedLevelBasename(type));
1882 }
1883 #endif
1884
1885 char *getDefaultLevelFilename(int nr)
1886 {
1887   return getSingleLevelFilename(nr);
1888 }
1889
1890 #if 0
1891 static void setLevelFileInfo_SingleLevelFilename(struct LevelFileInfo *lfi,
1892                                                  int type)
1893 {
1894   lfi->type = type;
1895   lfi->packed = FALSE;
1896   lfi->basename = getSingleLevelBasename(lfi->nr, lfi->type);
1897   lfi->filename = getLevelFilenameFromBasename(lfi->basename);
1898 }
1899 #endif
1900
1901 static void setLevelFileInfo_FormatLevelFilename(struct LevelFileInfo *lfi,
1902                                                  int type, char *format, ...)
1903 {
1904   static char basename[MAX_FILENAME_LEN];
1905   va_list ap;
1906
1907   va_start(ap, format);
1908   vsprintf(basename, format, ap);
1909   va_end(ap);
1910
1911   lfi->type = type;
1912   lfi->packed = FALSE;
1913   lfi->basename = basename;
1914   lfi->filename = getLevelFilenameFromBasename(lfi->basename);
1915 }
1916
1917 static void setLevelFileInfo_PackedLevelFilename(struct LevelFileInfo *lfi,
1918                                                  int type)
1919 {
1920   lfi->type = type;
1921   lfi->packed = TRUE;
1922   lfi->basename = getPackedLevelBasename(lfi->type);
1923   lfi->filename = getLevelFilenameFromBasename(lfi->basename);
1924 }
1925
1926 static int getFiletypeFromID(char *filetype_id)
1927 {
1928   char *filetype_id_lower;
1929   int filetype = LEVEL_FILE_TYPE_UNKNOWN;
1930   int i;
1931
1932   if (filetype_id == NULL)
1933     return LEVEL_FILE_TYPE_UNKNOWN;
1934
1935   filetype_id_lower = getStringToLower(filetype_id);
1936
1937   for (i = 0; filetype_id_list[i].id != NULL; i++)
1938   {
1939     char *id_lower = getStringToLower(filetype_id_list[i].id);
1940     
1941     if (strEqual(filetype_id_lower, id_lower))
1942       filetype = filetype_id_list[i].filetype;
1943
1944     free(id_lower);
1945
1946     if (filetype != LEVEL_FILE_TYPE_UNKNOWN)
1947       break;
1948   }
1949
1950   free(filetype_id_lower);
1951
1952   return filetype;
1953 }
1954
1955 static void determineLevelFileInfo_Filename(struct LevelFileInfo *lfi)
1956 {
1957   int nr = lfi->nr;
1958
1959   /* special case: level number is negative => check for level template file */
1960   if (nr < 0)
1961   {
1962     setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
1963                                          "template.%s", LEVELFILE_EXTENSION);
1964
1965     /* no fallback if template file not existing */
1966     return;
1967   }
1968
1969   /* special case: check for file name/pattern specified in "levelinfo.conf" */
1970   if (leveldir_current->level_filename != NULL)
1971   {
1972     int filetype = getFiletypeFromID(leveldir_current->level_filetype);
1973
1974     setLevelFileInfo_FormatLevelFilename(lfi, filetype,
1975                                          leveldir_current->level_filename, nr);
1976
1977     lfi->packed = checkForPackageFromBasename(leveldir_current->level_filename);
1978
1979     if (fileExists(lfi->filename))
1980       return;
1981   }
1982
1983   /* check for native Rocks'n'Diamonds level file */
1984   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
1985                                        "%03d.%s", nr, LEVELFILE_EXTENSION);
1986   if (fileExists(lfi->filename))
1987     return;
1988
1989   /* check for Emerald Mine level file (V1) */
1990   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "a%c%c",
1991                                        'a' + (nr / 10) % 26, '0' + nr % 10);
1992   if (fileExists(lfi->filename))
1993     return;
1994   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "A%c%c",
1995                                        'A' + (nr / 10) % 26, '0' + nr % 10);
1996   if (fileExists(lfi->filename))
1997     return;
1998
1999   /* check for Emerald Mine level file (V2 to V5) */
2000   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%d", nr);
2001   if (fileExists(lfi->filename))
2002     return;
2003
2004   /* check for Emerald Mine level file (V6 / single mode) */
2005   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02ds", nr);
2006   if (fileExists(lfi->filename))
2007     return;
2008   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dS", nr);
2009   if (fileExists(lfi->filename))
2010     return;
2011
2012   /* check for Emerald Mine level file (V6 / teamwork mode) */
2013   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dt", nr);
2014   if (fileExists(lfi->filename))
2015     return;
2016   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dT", nr);
2017   if (fileExists(lfi->filename))
2018     return;
2019
2020   /* check for various packed level file formats */
2021   setLevelFileInfo_PackedLevelFilename(lfi, LEVEL_FILE_TYPE_UNKNOWN);
2022   if (fileExists(lfi->filename))
2023     return;
2024
2025   /* no known level file found -- use default values (and fail later) */
2026   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
2027                                        "%03d.%s", nr, LEVELFILE_EXTENSION);
2028 }
2029
2030 static void determineLevelFileInfo_Filetype(struct LevelFileInfo *lfi)
2031 {
2032   if (lfi->type == LEVEL_FILE_TYPE_UNKNOWN)
2033     lfi->type = getFileTypeFromBasename(lfi->basename);
2034 }
2035
2036 static void setLevelFileInfo(struct LevelFileInfo *level_file_info, int nr)
2037 {
2038   /* always start with reliable default values */
2039   setFileInfoToDefaults(level_file_info);
2040
2041   level_file_info->nr = nr;     /* set requested level number */
2042
2043   determineLevelFileInfo_Filename(level_file_info);
2044   determineLevelFileInfo_Filetype(level_file_info);
2045 }
2046
2047 /* ------------------------------------------------------------------------- */
2048 /* functions for loading R'n'D level                                         */
2049 /* ------------------------------------------------------------------------- */
2050
2051 int getMappedElement(int element)
2052 {
2053   /* remap some (historic, now obsolete) elements */
2054
2055   switch (element)
2056   {
2057     case EL_PLAYER_OBSOLETE:
2058       element = EL_PLAYER_1;
2059       break;
2060
2061     case EL_KEY_OBSOLETE:
2062       element = EL_KEY_1;
2063       break;
2064
2065     case EL_EM_KEY_1_FILE_OBSOLETE:
2066       element = EL_EM_KEY_1;
2067       break;
2068
2069     case EL_EM_KEY_2_FILE_OBSOLETE:
2070       element = EL_EM_KEY_2;
2071       break;
2072
2073     case EL_EM_KEY_3_FILE_OBSOLETE:
2074       element = EL_EM_KEY_3;
2075       break;
2076
2077     case EL_EM_KEY_4_FILE_OBSOLETE:
2078       element = EL_EM_KEY_4;
2079       break;
2080
2081     case EL_ENVELOPE_OBSOLETE:
2082       element = EL_ENVELOPE_1;
2083       break;
2084
2085     case EL_SP_EMPTY:
2086       element = EL_EMPTY;
2087       break;
2088
2089     default:
2090       if (element >= NUM_FILE_ELEMENTS)
2091       {
2092         Error(ERR_WARN, "invalid level element %d", element);
2093
2094         element = EL_UNKNOWN;
2095       }
2096       break;
2097   }
2098
2099   return element;
2100 }
2101
2102 int getMappedElementByVersion(int element, int game_version)
2103 {
2104   /* remap some elements due to certain game version */
2105
2106   if (game_version <= VERSION_IDENT(2,2,0,0))
2107   {
2108     /* map game font elements */
2109     element = (element == EL_CHAR('[')  ? EL_CHAR_AUMLAUT :
2110                element == EL_CHAR('\\') ? EL_CHAR_OUMLAUT :
2111                element == EL_CHAR(']')  ? EL_CHAR_UUMLAUT :
2112                element == EL_CHAR('^')  ? EL_CHAR_COPYRIGHT : element);
2113   }
2114
2115   if (game_version < VERSION_IDENT(3,0,0,0))
2116   {
2117     /* map Supaplex gravity tube elements */
2118     element = (element == EL_SP_GRAVITY_PORT_LEFT  ? EL_SP_PORT_LEFT  :
2119                element == EL_SP_GRAVITY_PORT_RIGHT ? EL_SP_PORT_RIGHT :
2120                element == EL_SP_GRAVITY_PORT_UP    ? EL_SP_PORT_UP    :
2121                element == EL_SP_GRAVITY_PORT_DOWN  ? EL_SP_PORT_DOWN  :
2122                element);
2123   }
2124
2125   return element;
2126 }
2127
2128 static int LoadLevel_VERS(FILE *file, int chunk_size, struct LevelInfo *level)
2129 {
2130   level->file_version = getFileVersion(file);
2131   level->game_version = getFileVersion(file);
2132
2133   return chunk_size;
2134 }
2135
2136 static int LoadLevel_DATE(FILE *file, int chunk_size, struct LevelInfo *level)
2137 {
2138   level->creation_date.year  = getFile16BitBE(file);
2139   level->creation_date.month = getFile8Bit(file);
2140   level->creation_date.day   = getFile8Bit(file);
2141
2142   return chunk_size;
2143 }
2144
2145 static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
2146 {
2147   int initial_player_stepsize;
2148   int initial_player_gravity;
2149   int i, x, y;
2150
2151   level->fieldx = getFile8Bit(file);
2152   level->fieldy = getFile8Bit(file);
2153
2154   level->time           = getFile16BitBE(file);
2155   level->gems_needed    = getFile16BitBE(file);
2156
2157   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
2158     level->name[i] = getFile8Bit(file);
2159   level->name[MAX_LEVEL_NAME_LEN] = 0;
2160
2161   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
2162     level->score[i] = getFile8Bit(file);
2163
2164   level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
2165   for (i = 0; i < STD_ELEMENT_CONTENTS; i++)
2166     for (y = 0; y < 3; y++)
2167       for (x = 0; x < 3; x++)
2168         level->yamyam_content[i].e[x][y] = getMappedElement(getFile8Bit(file));
2169
2170   level->amoeba_speed           = getFile8Bit(file);
2171   level->time_magic_wall        = getFile8Bit(file);
2172   level->time_wheel             = getFile8Bit(file);
2173   level->amoeba_content         = getMappedElement(getFile8Bit(file));
2174
2175   initial_player_stepsize       = (getFile8Bit(file) == 1 ? STEPSIZE_FAST :
2176                                    STEPSIZE_NORMAL);
2177
2178   for (i = 0; i < MAX_PLAYERS; i++)
2179     level->initial_player_stepsize[i] = initial_player_stepsize;
2180
2181   initial_player_gravity        = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2182
2183   for (i = 0; i < MAX_PLAYERS; i++)
2184     level->initial_player_gravity[i] = initial_player_gravity;
2185
2186   level->encoding_16bit_field   = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2187   level->em_slippery_gems       = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2188
2189   level->use_custom_template    = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2190
2191   level->block_last_field       = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2192   level->sp_block_last_field    = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2193   level->can_move_into_acid_bits = getFile32BitBE(file);
2194   level->dont_collide_with_bits = getFile8Bit(file);
2195
2196   level->use_spring_bug         = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2197   level->use_step_counter       = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2198
2199   level->instant_relocation     = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2200   level->can_pass_to_walkable   = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2201   level->grow_into_diggable     = (getFile8Bit(file) == 1 ? TRUE : FALSE);
2202
2203   level->game_engine_type       = getFile8Bit(file);
2204
2205   ReadUnusedBytesFromFile(file, LEVEL_CHUNK_HEAD_UNUSED);
2206
2207   return chunk_size;
2208 }
2209
2210 static int LoadLevel_NAME(FILE *file, int chunk_size, struct LevelInfo *level)
2211 {
2212   int i;
2213
2214   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
2215     level->name[i] = getFile8Bit(file);
2216   level->name[MAX_LEVEL_NAME_LEN] = 0;
2217
2218   return chunk_size;
2219 }
2220
2221 static int LoadLevel_AUTH(FILE *file, int chunk_size, struct LevelInfo *level)
2222 {
2223   int i;
2224
2225   for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
2226     level->author[i] = getFile8Bit(file);
2227   level->author[MAX_LEVEL_AUTHOR_LEN] = 0;
2228
2229   return chunk_size;
2230 }
2231
2232 static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level)
2233 {
2234   int x, y;
2235   int chunk_size_expected = level->fieldx * level->fieldy;
2236
2237   /* Note: "chunk_size" was wrong before version 2.0 when elements are
2238      stored with 16-bit encoding (and should be twice as big then).
2239      Even worse, playfield data was stored 16-bit when only yamyam content
2240      contained 16-bit elements and vice versa. */
2241
2242   if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
2243     chunk_size_expected *= 2;
2244
2245   if (chunk_size_expected != chunk_size)
2246   {
2247     ReadUnusedBytesFromFile(file, chunk_size);
2248     return chunk_size_expected;
2249   }
2250
2251   for (y = 0; y < level->fieldy; y++)
2252     for (x = 0; x < level->fieldx; x++)
2253       level->field[x][y] =
2254         getMappedElement(level->encoding_16bit_field ? getFile16BitBE(file) :
2255                          getFile8Bit(file));
2256   return chunk_size;
2257 }
2258
2259 static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
2260 {
2261   int i, x, y;
2262   int header_size = 4;
2263   int content_size = MAX_ELEMENT_CONTENTS * 3 * 3;
2264   int chunk_size_expected = header_size + content_size;
2265
2266   /* Note: "chunk_size" was wrong before version 2.0 when elements are
2267      stored with 16-bit encoding (and should be twice as big then).
2268      Even worse, playfield data was stored 16-bit when only yamyam content
2269      contained 16-bit elements and vice versa. */
2270
2271   if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
2272     chunk_size_expected += content_size;
2273
2274   if (chunk_size_expected != chunk_size)
2275   {
2276     ReadUnusedBytesFromFile(file, chunk_size);
2277     return chunk_size_expected;
2278   }
2279
2280   getFile8Bit(file);
2281   level->num_yamyam_contents = getFile8Bit(file);
2282   getFile8Bit(file);
2283   getFile8Bit(file);
2284
2285   /* correct invalid number of content fields -- should never happen */
2286   if (level->num_yamyam_contents < 1 ||
2287       level->num_yamyam_contents > MAX_ELEMENT_CONTENTS)
2288     level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
2289
2290   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
2291     for (y = 0; y < 3; y++)
2292       for (x = 0; x < 3; x++)
2293         level->yamyam_content[i].e[x][y] =
2294           getMappedElement(level->encoding_16bit_field ?
2295                            getFile16BitBE(file) : getFile8Bit(file));
2296   return chunk_size;
2297 }
2298
2299 static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
2300 {
2301   int i, x, y;
2302   int element;
2303   int num_contents, content_xsize, content_ysize;
2304   int content_array[MAX_ELEMENT_CONTENTS][3][3];
2305
2306   element = getMappedElement(getFile16BitBE(file));
2307   num_contents = getFile8Bit(file);
2308   content_xsize = getFile8Bit(file);
2309   content_ysize = getFile8Bit(file);
2310
2311   ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED);
2312
2313   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
2314     for (y = 0; y < 3; y++)
2315       for (x = 0; x < 3; x++)
2316         content_array[i][x][y] = getMappedElement(getFile16BitBE(file));
2317
2318   /* correct invalid number of content fields -- should never happen */
2319   if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS)
2320     num_contents = STD_ELEMENT_CONTENTS;
2321
2322   if (element == EL_YAMYAM)
2323   {
2324     level->num_yamyam_contents = num_contents;
2325
2326     for (i = 0; i < num_contents; i++)
2327       for (y = 0; y < 3; y++)
2328         for (x = 0; x < 3; x++)
2329           level->yamyam_content[i].e[x][y] = content_array[i][x][y];
2330   }
2331   else if (element == EL_BD_AMOEBA)
2332   {
2333     level->amoeba_content = content_array[0][0][0];
2334   }
2335   else
2336   {
2337     Error(ERR_WARN, "cannot load content for element '%d'", element);
2338   }
2339
2340   return chunk_size;
2341 }
2342
2343 static int LoadLevel_CNT3(FILE *file, int chunk_size, struct LevelInfo *level)
2344 {
2345   int i;
2346   int element;
2347   int envelope_nr;
2348   int envelope_len;
2349   int chunk_size_expected;
2350
2351   element = getMappedElement(getFile16BitBE(file));
2352   if (!IS_ENVELOPE(element))
2353     element = EL_ENVELOPE_1;
2354
2355   envelope_nr = element - EL_ENVELOPE_1;
2356
2357   envelope_len = getFile16BitBE(file);
2358
2359   level->envelope[envelope_nr].xsize = getFile8Bit(file);
2360   level->envelope[envelope_nr].ysize = getFile8Bit(file);
2361
2362   ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT3_UNUSED);
2363
2364   chunk_size_expected = LEVEL_CHUNK_CNT3_SIZE(envelope_len);
2365   if (chunk_size_expected != chunk_size)
2366   {
2367     ReadUnusedBytesFromFile(file, chunk_size - LEVEL_CHUNK_CNT3_HEADER);
2368     return chunk_size_expected;
2369   }
2370
2371   for (i = 0; i < envelope_len; i++)
2372     level->envelope[envelope_nr].text[i] = getFile8Bit(file);
2373
2374   return chunk_size;
2375 }
2376
2377 static int LoadLevel_CUS1(FILE *file, int chunk_size, struct LevelInfo *level)
2378 {
2379   int num_changed_custom_elements = getFile16BitBE(file);
2380   int chunk_size_expected = 2 + num_changed_custom_elements * 6;
2381   int i;
2382
2383   if (chunk_size_expected != chunk_size)
2384   {
2385     ReadUnusedBytesFromFile(file, chunk_size - 2);
2386     return chunk_size_expected;
2387   }
2388
2389   for (i = 0; i < num_changed_custom_elements; i++)
2390   {
2391     int element = getMappedElement(getFile16BitBE(file));
2392     int properties = getFile32BitBE(file);
2393
2394     if (IS_CUSTOM_ELEMENT(element))
2395       element_info[element].properties[EP_BITFIELD_BASE_NR] = properties;
2396     else
2397       Error(ERR_WARN, "invalid custom element number %d", element);
2398
2399     /* older game versions that wrote level files with CUS1 chunks used
2400        different default push delay values (not yet stored in level file) */
2401     element_info[element].push_delay_fixed = 2;
2402     element_info[element].push_delay_random = 8;
2403   }
2404
2405   return chunk_size;
2406 }
2407
2408 static int LoadLevel_CUS2(FILE *file, int chunk_size, struct LevelInfo *level)
2409 {
2410   int num_changed_custom_elements = getFile16BitBE(file);
2411   int chunk_size_expected = 2 + num_changed_custom_elements * 4;
2412   int i;
2413
2414   if (chunk_size_expected != chunk_size)
2415   {
2416     ReadUnusedBytesFromFile(file, chunk_size - 2);
2417     return chunk_size_expected;
2418   }
2419
2420   for (i = 0; i < num_changed_custom_elements; i++)
2421   {
2422     int element = getMappedElement(getFile16BitBE(file));
2423     int custom_target_element = getMappedElement(getFile16BitBE(file));
2424
2425     if (IS_CUSTOM_ELEMENT(element))
2426       element_info[element].change->target_element = custom_target_element;
2427     else
2428       Error(ERR_WARN, "invalid custom element number %d", element);
2429   }
2430
2431   return chunk_size;
2432 }
2433
2434 static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level)
2435 {
2436   int num_changed_custom_elements = getFile16BitBE(file);
2437   int chunk_size_expected = LEVEL_CHUNK_CUS3_SIZE(num_changed_custom_elements);
2438   int i, j, x, y;
2439
2440   if (chunk_size_expected != chunk_size)
2441   {
2442     ReadUnusedBytesFromFile(file, chunk_size - 2);
2443     return chunk_size_expected;
2444   }
2445
2446   for (i = 0; i < num_changed_custom_elements; i++)
2447   {
2448     int element = getMappedElement(getFile16BitBE(file));
2449     struct ElementInfo *ei = &element_info[element];
2450     unsigned int event_bits;
2451
2452     if (!IS_CUSTOM_ELEMENT(element))
2453     {
2454       Error(ERR_WARN, "invalid custom element number %d", element);
2455
2456       element = EL_INTERNAL_DUMMY;
2457     }
2458
2459     for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++)
2460       ei->description[j] = getFile8Bit(file);
2461     ei->description[MAX_ELEMENT_NAME_LEN] = 0;
2462
2463     ei->properties[EP_BITFIELD_BASE_NR] = getFile32BitBE(file);
2464
2465     /* some free bytes for future properties and padding */
2466     ReadUnusedBytesFromFile(file, 7);
2467
2468     ei->use_gfx_element = getFile8Bit(file);
2469     ei->gfx_element_initial = getMappedElement(getFile16BitBE(file));
2470
2471     ei->collect_score_initial = getFile8Bit(file);
2472     ei->collect_count_initial = getFile8Bit(file);
2473
2474     ei->push_delay_fixed = getFile16BitBE(file);
2475     ei->push_delay_random = getFile16BitBE(file);
2476     ei->move_delay_fixed = getFile16BitBE(file);
2477     ei->move_delay_random = getFile16BitBE(file);
2478
2479     ei->move_pattern = getFile16BitBE(file);
2480     ei->move_direction_initial = getFile8Bit(file);
2481     ei->move_stepsize = getFile8Bit(file);
2482
2483     for (y = 0; y < 3; y++)
2484       for (x = 0; x < 3; x++)
2485         ei->content.e[x][y] = getMappedElement(getFile16BitBE(file));
2486
2487     event_bits = getFile32BitBE(file);
2488     for (j = 0; j < NUM_CHANGE_EVENTS; j++)
2489       if (event_bits & (1 << j))
2490         ei->change->has_event[j] = TRUE;
2491
2492     ei->change->target_element = getMappedElement(getFile16BitBE(file));
2493
2494     ei->change->delay_fixed = getFile16BitBE(file);
2495     ei->change->delay_random = getFile16BitBE(file);
2496     ei->change->delay_frames = getFile16BitBE(file);
2497
2498     ei->change->initial_trigger_element= getMappedElement(getFile16BitBE(file));
2499
2500     ei->change->explode = getFile8Bit(file);
2501     ei->change->use_target_content = getFile8Bit(file);
2502     ei->change->only_if_complete = getFile8Bit(file);
2503     ei->change->use_random_replace = getFile8Bit(file);
2504
2505     ei->change->random_percentage = getFile8Bit(file);
2506     ei->change->replace_when = getFile8Bit(file);
2507
2508     for (y = 0; y < 3; y++)
2509       for (x = 0; x < 3; x++)
2510         ei->change->target_content.e[x][y] =
2511           getMappedElement(getFile16BitBE(file));
2512
2513     ei->slippery_type = getFile8Bit(file);
2514
2515     /* some free bytes for future properties and padding */
2516     ReadUnusedBytesFromFile(file, LEVEL_CPART_CUS3_UNUSED);
2517
2518     /* mark that this custom element has been modified */
2519     ei->modified_settings = TRUE;
2520   }
2521
2522   return chunk_size;
2523 }
2524
2525 static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
2526 {
2527   struct ElementInfo *ei;
2528   int chunk_size_expected;
2529   int element;
2530   int i, j, x, y;
2531
2532   /* ---------- custom element base property values (96 bytes) ------------- */
2533
2534   element = getMappedElement(getFile16BitBE(file));
2535
2536   if (!IS_CUSTOM_ELEMENT(element))
2537   {
2538     Error(ERR_WARN, "invalid custom element number %d", element);
2539
2540     ReadUnusedBytesFromFile(file, chunk_size - 2);
2541     return chunk_size;
2542   }
2543
2544   ei = &element_info[element];
2545
2546   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
2547     ei->description[i] = getFile8Bit(file);
2548   ei->description[MAX_ELEMENT_NAME_LEN] = 0;
2549
2550   ei->properties[EP_BITFIELD_BASE_NR] = getFile32BitBE(file);
2551
2552   ReadUnusedBytesFromFile(file, 4);     /* reserved for more base properties */
2553
2554   ei->num_change_pages = getFile8Bit(file);
2555
2556   chunk_size_expected = LEVEL_CHUNK_CUS4_SIZE(ei->num_change_pages);
2557   if (chunk_size_expected != chunk_size)
2558   {
2559     ReadUnusedBytesFromFile(file, chunk_size - 43);
2560     return chunk_size_expected;
2561   }
2562
2563   ei->ce_value_fixed_initial = getFile16BitBE(file);
2564   ei->ce_value_random_initial = getFile16BitBE(file);
2565   ei->use_last_ce_value = getFile8Bit(file);
2566
2567   ei->use_gfx_element = getFile8Bit(file);
2568   ei->gfx_element_initial = getMappedElement(getFile16BitBE(file));
2569
2570   ei->collect_score_initial = getFile8Bit(file);
2571   ei->collect_count_initial = getFile8Bit(file);
2572
2573   ei->drop_delay_fixed = getFile8Bit(file);
2574   ei->push_delay_fixed = getFile8Bit(file);
2575   ei->drop_delay_random = getFile8Bit(file);
2576   ei->push_delay_random = getFile8Bit(file);
2577   ei->move_delay_fixed = getFile16BitBE(file);
2578   ei->move_delay_random = getFile16BitBE(file);
2579
2580   /* bits 0 - 15 of "move_pattern" ... */
2581   ei->move_pattern = getFile16BitBE(file);
2582   ei->move_direction_initial = getFile8Bit(file);
2583   ei->move_stepsize = getFile8Bit(file);
2584
2585   ei->slippery_type = getFile8Bit(file);
2586
2587   for (y = 0; y < 3; y++)
2588     for (x = 0; x < 3; x++)
2589       ei->content.e[x][y] = getMappedElement(getFile16BitBE(file));
2590
2591   ei->move_enter_element = getMappedElement(getFile16BitBE(file));
2592   ei->move_leave_element = getMappedElement(getFile16BitBE(file));
2593   ei->move_leave_type = getFile8Bit(file);
2594
2595   /* ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible) */
2596   ei->move_pattern |= (getFile16BitBE(file) << 16);
2597
2598   ei->access_direction = getFile8Bit(file);
2599
2600   ei->explosion_delay = getFile8Bit(file);
2601   ei->ignition_delay = getFile8Bit(file);
2602   ei->explosion_type = getFile8Bit(file);
2603
2604   /* some free bytes for future custom property values and padding */
2605   ReadUnusedBytesFromFile(file, 1);
2606
2607   /* ---------- change page property values (48 bytes) --------------------- */
2608
2609   setElementChangePages(ei, ei->num_change_pages);
2610
2611   for (i = 0; i < ei->num_change_pages; i++)
2612   {
2613     struct ElementChangeInfo *change = &ei->change_page[i];
2614     unsigned int event_bits;
2615
2616     /* always start with reliable default values */
2617     setElementChangeInfoToDefaults(change);
2618
2619     /* bits 0 - 31 of "has_event[]" ... */
2620     event_bits = getFile32BitBE(file);
2621     for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
2622       if (event_bits & (1 << j))
2623         change->has_event[j] = TRUE;
2624
2625     change->target_element = getMappedElement(getFile16BitBE(file));
2626
2627     change->delay_fixed = getFile16BitBE(file);
2628     change->delay_random = getFile16BitBE(file);
2629     change->delay_frames = getFile16BitBE(file);
2630
2631     change->initial_trigger_element = getMappedElement(getFile16BitBE(file));
2632
2633     change->explode = getFile8Bit(file);
2634     change->use_target_content = getFile8Bit(file);
2635     change->only_if_complete = getFile8Bit(file);
2636     change->use_random_replace = getFile8Bit(file);
2637
2638     change->random_percentage = getFile8Bit(file);
2639     change->replace_when = getFile8Bit(file);
2640
2641     for (y = 0; y < 3; y++)
2642       for (x = 0; x < 3; x++)
2643         change->target_content.e[x][y]= getMappedElement(getFile16BitBE(file));
2644
2645     change->can_change = getFile8Bit(file);
2646
2647     change->trigger_side = getFile8Bit(file);
2648
2649     change->trigger_player = getFile8Bit(file);
2650     change->trigger_page = getFile8Bit(file);
2651
2652     change->trigger_page = (change->trigger_page == CH_PAGE_ANY_FILE ?
2653                             CH_PAGE_ANY : (1 << change->trigger_page));
2654
2655     change->has_action = getFile8Bit(file);
2656     change->action_type = getFile8Bit(file);
2657     change->action_mode = getFile8Bit(file);
2658     change->action_arg = getFile16BitBE(file);
2659
2660     /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */
2661     event_bits = getFile8Bit(file);
2662     for (j = 32; j < NUM_CHANGE_EVENTS; j++)
2663       if (event_bits & (1 << (j - 32)))
2664         change->has_event[j] = TRUE;
2665   }
2666
2667   /* mark this custom element as modified */
2668   ei->modified_settings = TRUE;
2669
2670   return chunk_size;
2671 }
2672
2673 static int LoadLevel_GRP1(FILE *file, int chunk_size, struct LevelInfo *level)
2674 {
2675   struct ElementInfo *ei;
2676   struct ElementGroupInfo *group;
2677   int element;
2678   int i;
2679
2680   element = getMappedElement(getFile16BitBE(file));
2681
2682   if (!IS_GROUP_ELEMENT(element))
2683   {
2684     Error(ERR_WARN, "invalid group element number %d", element);
2685
2686     ReadUnusedBytesFromFile(file, chunk_size - 2);
2687     return chunk_size;
2688   }
2689
2690   ei = &element_info[element];
2691
2692   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
2693     ei->description[i] = getFile8Bit(file);
2694   ei->description[MAX_ELEMENT_NAME_LEN] = 0;
2695
2696   group = element_info[element].group;
2697
2698   group->num_elements = getFile8Bit(file);
2699
2700   ei->use_gfx_element = getFile8Bit(file);
2701   ei->gfx_element_initial = getMappedElement(getFile16BitBE(file));
2702
2703   group->choice_mode = getFile8Bit(file);
2704
2705   /* some free bytes for future values and padding */
2706   ReadUnusedBytesFromFile(file, 3);
2707
2708   for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
2709     group->element[i] = getMappedElement(getFile16BitBE(file));
2710
2711   /* mark this group element as modified */
2712   element_info[element].modified_settings = TRUE;
2713
2714   return chunk_size;
2715 }
2716
2717 static int LoadLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *conf,
2718                                 int element, int real_element)
2719 {
2720   int micro_chunk_size = 0;
2721   int conf_type = getFile8Bit(file);
2722   int byte_mask = conf_type & CONF_MASK_BYTES;
2723   boolean element_found = FALSE;
2724   int i;
2725
2726   micro_chunk_size += 1;
2727
2728   if (byte_mask == CONF_MASK_MULTI_BYTES)
2729   {
2730     int num_bytes = getFile16BitBE(file);
2731     byte *buffer = checked_malloc(num_bytes);
2732
2733     ReadBytesFromFile(file, buffer, num_bytes);
2734
2735     for (i = 0; conf[i].data_type != -1; i++)
2736     {
2737       if (conf[i].element == element &&
2738           conf[i].conf_type == conf_type)
2739       {
2740         int data_type = conf[i].data_type;
2741         int num_entities = num_bytes / CONF_ENTITY_NUM_BYTES(data_type);
2742         int max_num_entities = conf[i].max_num_entities;
2743
2744         if (num_entities > max_num_entities)
2745         {
2746           Error(ERR_WARN,
2747                 "truncating number of entities for element %d from %d to %d",
2748                 element, num_entities, max_num_entities);
2749
2750           num_entities = max_num_entities;
2751         }
2752
2753         if (num_entities == 0 && (data_type == TYPE_ELEMENT_LIST ||
2754                                   data_type == TYPE_CONTENT_LIST))
2755         {
2756           /* for element and content lists, zero entities are not allowed */
2757           Error(ERR_WARN, "found empty list of entities for element %d",
2758                 element);
2759
2760           /* do not set "num_entities" here to prevent reading behind buffer */
2761
2762           *(int *)(conf[i].num_entities) = 1;   /* at least one is required */
2763         }
2764         else
2765         {
2766           *(int *)(conf[i].num_entities) = num_entities;
2767         }
2768
2769         element_found = TRUE;
2770
2771         if (data_type == TYPE_STRING)
2772         {
2773           char *string = (char *)(conf[i].value);
2774           int j;
2775
2776           for (j = 0; j < max_num_entities; j++)
2777             string[j] = (j < num_entities ? buffer[j] : '\0');
2778         }
2779         else if (data_type == TYPE_ELEMENT_LIST)
2780         {
2781           int *element_array = (int *)(conf[i].value);
2782           int j;
2783
2784           for (j = 0; j < num_entities; j++)
2785             element_array[j] =
2786               getMappedElement(CONF_ELEMENTS_ELEMENT(buffer, j));
2787         }
2788         else if (data_type == TYPE_CONTENT_LIST)
2789         {
2790           struct Content *content= (struct Content *)(conf[i].value);
2791           int c, x, y;
2792
2793           for (c = 0; c < num_entities; c++)
2794             for (y = 0; y < 3; y++)
2795               for (x = 0; x < 3; x++)
2796                 content[c].e[x][y] =
2797                   getMappedElement(CONF_CONTENTS_ELEMENT(buffer, c, x, y));
2798         }
2799         else
2800           element_found = FALSE;
2801
2802         break;
2803       }
2804     }
2805
2806     checked_free(buffer);
2807
2808     micro_chunk_size += 2 + num_bytes;
2809   }
2810   else          /* constant size configuration data (1, 2 or 4 bytes) */
2811   {
2812     int value = (byte_mask == CONF_MASK_1_BYTE ? getFile8Bit   (file) :
2813                  byte_mask == CONF_MASK_2_BYTE ? getFile16BitBE(file) :
2814                  byte_mask == CONF_MASK_4_BYTE ? getFile32BitBE(file) : 0);
2815
2816     for (i = 0; conf[i].data_type != -1; i++)
2817     {
2818       if (conf[i].element == element &&
2819           conf[i].conf_type == conf_type)
2820       {
2821         int data_type = conf[i].data_type;
2822
2823         if (data_type == TYPE_ELEMENT)
2824           value = getMappedElement(value);
2825
2826         if (data_type == TYPE_BOOLEAN)
2827           *(boolean *)(conf[i].value) = value;
2828         else
2829           *(int *)    (conf[i].value) = value;
2830
2831         element_found = TRUE;
2832
2833         break;
2834       }
2835     }
2836
2837     micro_chunk_size += CONF_VALUE_NUM_BYTES(byte_mask);
2838   }
2839
2840   if (!element_found)
2841   {
2842     char *error_conf_chunk_bytes =
2843       (byte_mask == CONF_MASK_1_BYTE ? "CONF_VALUE_8_BIT" :
2844        byte_mask == CONF_MASK_2_BYTE ? "CONF_VALUE_16_BIT" :
2845        byte_mask == CONF_MASK_4_BYTE ? "CONF_VALUE_32_BIT" :"CONF_VALUE_BYTES");
2846     int error_conf_chunk_token = conf_type & CONF_MASK_TOKEN;
2847     int error_element = real_element;
2848
2849     Error(ERR_WARN, "cannot load micro chunk '%s(%d)' value for element %d ['%s']",
2850           error_conf_chunk_bytes, error_conf_chunk_token,
2851           error_element, EL_NAME(error_element));
2852   }
2853
2854   return micro_chunk_size;
2855 }
2856
2857 static int LoadLevel_INFO(FILE *file, int chunk_size, struct LevelInfo *level)
2858 {
2859   int real_chunk_size = 0;
2860
2861   li = *level;          /* copy level data into temporary buffer */
2862
2863   while (!feof(file))
2864   {
2865     real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_INFO, -1, -1);
2866
2867     if (real_chunk_size >= chunk_size)
2868       break;
2869   }
2870
2871   *level = li;          /* copy temporary buffer back to level data */
2872
2873   return real_chunk_size;
2874 }
2875
2876 static int LoadLevel_CONF(FILE *file, int chunk_size, struct LevelInfo *level)
2877 {
2878   int real_chunk_size = 0;
2879
2880   li = *level;          /* copy level data into temporary buffer */
2881
2882   while (!feof(file))
2883   {
2884     int element = getMappedElement(getFile16BitBE(file));
2885
2886     real_chunk_size += 2;
2887     real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CONF,
2888                                             element, element);
2889     if (real_chunk_size >= chunk_size)
2890       break;
2891   }
2892
2893   *level = li;          /* copy temporary buffer back to level data */
2894
2895   return real_chunk_size;
2896 }
2897
2898 static int LoadLevel_ELEM(FILE *file, int chunk_size, struct LevelInfo *level)
2899 {
2900   int real_chunk_size = 0;
2901
2902   li = *level;          /* copy level data into temporary buffer */
2903
2904   while (!feof(file))
2905   {
2906     int element = getMappedElement(getFile16BitBE(file));
2907
2908     real_chunk_size += 2;
2909     real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_ELEM,
2910                                             element, element);
2911     if (real_chunk_size >= chunk_size)
2912       break;
2913   }
2914
2915   *level = li;          /* copy temporary buffer back to level data */
2916
2917   return real_chunk_size;
2918 }
2919
2920 static int LoadLevel_NOTE(FILE *file, int chunk_size, struct LevelInfo *level)
2921 {
2922   int element = getMappedElement(getFile16BitBE(file));
2923   int envelope_nr = element - EL_ENVELOPE_1;
2924   int real_chunk_size = 2;
2925
2926   while (!feof(file))
2927   {
2928     real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_NOTE,
2929                                             -1, element);
2930
2931     if (real_chunk_size >= chunk_size)
2932       break;
2933   }
2934
2935   level->envelope[envelope_nr] = xx_envelope;
2936
2937   return real_chunk_size;
2938 }
2939
2940 static int LoadLevel_CUSX(FILE *file, int chunk_size, struct LevelInfo *level)
2941 {
2942   int element = getMappedElement(getFile16BitBE(file));
2943   int real_chunk_size = 2;
2944   struct ElementInfo *ei = &element_info[element];
2945   int i;
2946
2947   xx_ei = *ei;          /* copy element data into temporary buffer */
2948
2949   xx_ei.num_change_pages = -1;
2950
2951   while (!feof(file))
2952   {
2953     real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CUSX_base,
2954                                             -1, element);
2955     if (xx_ei.num_change_pages != -1)
2956       break;
2957
2958     if (real_chunk_size >= chunk_size)
2959       break;
2960   }
2961
2962   *ei = xx_ei;
2963
2964   if (ei->num_change_pages == -1)
2965   {
2966     Error(ERR_WARN, "LoadLevel_CUSX(): missing 'num_change_pages' for '%s'",
2967           EL_NAME(element));
2968
2969     ei->num_change_pages = 1;
2970
2971     setElementChangePages(ei, 1);
2972     setElementChangeInfoToDefaults(ei->change);
2973
2974     return real_chunk_size;
2975   }
2976
2977   /* initialize number of change pages stored for this custom element */
2978   setElementChangePages(ei, ei->num_change_pages);
2979   for (i = 0; i < ei->num_change_pages; i++)
2980     setElementChangeInfoToDefaults(&ei->change_page[i]);
2981
2982   /* start with reading properties for the first change page */
2983   xx_current_change_page = 0;
2984
2985   while (!feof(file))
2986   {
2987     struct ElementChangeInfo *change = &ei->change_page[xx_current_change_page];
2988
2989     xx_change = *change;        /* copy change data into temporary buffer */
2990
2991     resetEventBits();           /* reset bits; change page might have changed */
2992
2993     real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_CUSX_change,
2994                                             -1, element);
2995
2996     *change = xx_change;
2997
2998     setEventFlagsFromEventBits(change);
2999
3000     if (real_chunk_size >= chunk_size)
3001       break;
3002   }
3003
3004   return real_chunk_size;
3005 }
3006
3007 static int LoadLevel_GRPX(FILE *file, int chunk_size, struct LevelInfo *level)
3008 {
3009   int element = getMappedElement(getFile16BitBE(file));
3010   int real_chunk_size = 2;
3011   struct ElementInfo *ei = &element_info[element];
3012   struct ElementGroupInfo *group = ei->group;
3013
3014   xx_ei = *ei;          /* copy element data into temporary buffer */
3015   xx_group = *group;    /* copy group data into temporary buffer */
3016
3017   while (!feof(file))
3018   {
3019     real_chunk_size += LoadLevel_MicroChunk(file, chunk_config_GRPX,
3020                                             -1, element);
3021
3022     if (real_chunk_size >= chunk_size)
3023       break;
3024   }
3025
3026   *ei = xx_ei;
3027   *group = xx_group;
3028
3029   return real_chunk_size;
3030 }
3031
3032 static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
3033                                       struct LevelFileInfo *level_file_info)
3034 {
3035   char *filename = level_file_info->filename;
3036   char cookie[MAX_LINE_LEN];
3037   char chunk_name[CHUNK_ID_LEN + 1];
3038   int chunk_size;
3039   FILE *file;
3040
3041   if (!(file = fopen(filename, MODE_READ)))
3042   {
3043     level->no_valid_file = TRUE;
3044
3045     if (level != &level_template)
3046       Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
3047
3048     return;
3049   }
3050
3051   getFileChunkBE(file, chunk_name, NULL);
3052   if (strEqual(chunk_name, "RND1"))
3053   {
3054     getFile32BitBE(file);               /* not used */
3055
3056     getFileChunkBE(file, chunk_name, NULL);
3057     if (!strEqual(chunk_name, "CAVE"))
3058     {
3059       level->no_valid_file = TRUE;
3060
3061       Error(ERR_WARN, "unknown format of level file '%s'", filename);
3062       fclose(file);
3063       return;
3064     }
3065   }
3066   else  /* check for pre-2.0 file format with cookie string */
3067   {
3068     strcpy(cookie, chunk_name);
3069     fgets(&cookie[4], MAX_LINE_LEN - 4, file);
3070     if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
3071       cookie[strlen(cookie) - 1] = '\0';
3072
3073     if (!checkCookieString(cookie, LEVEL_COOKIE_TMPL))
3074     {
3075       level->no_valid_file = TRUE;
3076
3077       Error(ERR_WARN, "unknown format of level file '%s'", filename);
3078       fclose(file);
3079       return;
3080     }
3081
3082     if ((level->file_version = getFileVersionFromCookieString(cookie)) == -1)
3083     {
3084       level->no_valid_file = TRUE;
3085
3086       Error(ERR_WARN, "unsupported version of level file '%s'", filename);
3087       fclose(file);
3088       return;
3089     }
3090
3091     /* pre-2.0 level files have no game version, so use file version here */
3092     level->game_version = level->file_version;
3093   }
3094
3095   if (level->file_version < FILE_VERSION_1_2)
3096   {
3097     /* level files from versions before 1.2.0 without chunk structure */
3098     LoadLevel_HEAD(file, LEVEL_CHUNK_HEAD_SIZE,         level);
3099     LoadLevel_BODY(file, level->fieldx * level->fieldy, level);
3100   }
3101   else
3102   {
3103     static struct
3104     {
3105       char *name;
3106       int size;
3107       int (*loader)(FILE *, int, struct LevelInfo *);
3108     }
3109     chunk_info[] =
3110     {
3111       { "VERS", LEVEL_CHUNK_VERS_SIZE,  LoadLevel_VERS },
3112       { "DATE", LEVEL_CHUNK_DATE_SIZE,  LoadLevel_DATE },
3113       { "HEAD", LEVEL_CHUNK_HEAD_SIZE,  LoadLevel_HEAD },
3114       { "NAME", LEVEL_CHUNK_NAME_SIZE,  LoadLevel_NAME },
3115       { "AUTH", LEVEL_CHUNK_AUTH_SIZE,  LoadLevel_AUTH },
3116       { "INFO", -1,                     LoadLevel_INFO },
3117       { "BODY", -1,                     LoadLevel_BODY },
3118       { "CONT", -1,                     LoadLevel_CONT },
3119       { "CNT2", LEVEL_CHUNK_CNT2_SIZE,  LoadLevel_CNT2 },
3120       { "CNT3", -1,                     LoadLevel_CNT3 },
3121       { "CUS1", -1,                     LoadLevel_CUS1 },
3122       { "CUS2", -1,                     LoadLevel_CUS2 },
3123       { "CUS3", -1,                     LoadLevel_CUS3 },
3124       { "CUS4", -1,                     LoadLevel_CUS4 },
3125       { "GRP1", -1,                     LoadLevel_GRP1 },
3126       { "CONF", -1,                     LoadLevel_CONF },
3127       { "ELEM", -1,                     LoadLevel_ELEM },
3128       { "NOTE", -1,                     LoadLevel_NOTE },
3129       { "CUSX", -1,                     LoadLevel_CUSX },
3130       { "GRPX", -1,                     LoadLevel_GRPX },
3131
3132       {  NULL,  0,                      NULL }
3133     };
3134
3135     while (getFileChunkBE(file, chunk_name, &chunk_size))
3136     {
3137       int i = 0;
3138
3139       while (chunk_info[i].name != NULL &&
3140              !strEqual(chunk_name, chunk_info[i].name))
3141         i++;
3142
3143       if (chunk_info[i].name == NULL)
3144       {
3145         Error(ERR_WARN, "unknown chunk '%s' in level file '%s'",
3146               chunk_name, filename);
3147         ReadUnusedBytesFromFile(file, chunk_size);
3148       }
3149       else if (chunk_info[i].size != -1 &&
3150                chunk_info[i].size != chunk_size)
3151       {
3152         Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
3153               chunk_size, chunk_name, filename);
3154         ReadUnusedBytesFromFile(file, chunk_size);
3155       }
3156       else
3157       {
3158         /* call function to load this level chunk */
3159         int chunk_size_expected =
3160           (chunk_info[i].loader)(file, chunk_size, level);
3161
3162         /* the size of some chunks cannot be checked before reading other
3163            chunks first (like "HEAD" and "BODY") that contain some header
3164            information, so check them here */
3165         if (chunk_size_expected != chunk_size)
3166         {
3167           Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
3168                 chunk_size, chunk_name, filename);
3169         }
3170       }
3171     }
3172   }
3173
3174   fclose(file);
3175 }
3176
3177 /* ------------------------------------------------------------------------- */
3178 /* functions for loading EM level                                            */
3179 /* ------------------------------------------------------------------------- */
3180
3181 #if 0
3182
3183 static int map_em_element_yam(int element)
3184 {
3185   switch (element)
3186   {
3187     case 0x00:  return EL_EMPTY;
3188     case 0x01:  return EL_EMERALD;
3189     case 0x02:  return EL_DIAMOND;
3190     case 0x03:  return EL_ROCK;
3191     case 0x04:  return EL_ROBOT;
3192     case 0x05:  return EL_SPACESHIP_UP;
3193     case 0x06:  return EL_BOMB;
3194     case 0x07:  return EL_BUG_UP;
3195     case 0x08:  return EL_AMOEBA_DROP;
3196     case 0x09:  return EL_NUT;
3197     case 0x0a:  return EL_YAMYAM;
3198     case 0x0b:  return EL_QUICKSAND_FULL;
3199     case 0x0c:  return EL_SAND;
3200     case 0x0d:  return EL_WALL_SLIPPERY;
3201     case 0x0e:  return EL_STEELWALL;
3202     case 0x0f:  return EL_WALL;
3203     case 0x10:  return EL_EM_KEY_1;
3204     case 0x11:  return EL_EM_KEY_2;
3205     case 0x12:  return EL_EM_KEY_4;
3206     case 0x13:  return EL_EM_KEY_3;
3207     case 0x14:  return EL_MAGIC_WALL;
3208     case 0x15:  return EL_ROBOT_WHEEL;
3209     case 0x16:  return EL_DYNAMITE;
3210
3211     case 0x17:  return EL_EM_KEY_1;                     /* EMC */
3212     case 0x18:  return EL_BUG_UP;                       /* EMC */
3213     case 0x1a:  return EL_DIAMOND;                      /* EMC */
3214     case 0x1b:  return EL_EMERALD;                      /* EMC */
3215     case 0x25:  return EL_NUT;                          /* EMC */
3216     case 0x80:  return EL_EMPTY;                        /* EMC */
3217     case 0x85:  return EL_EM_KEY_1;                     /* EMC */
3218     case 0x86:  return EL_EM_KEY_2;                     /* EMC */
3219     case 0x87:  return EL_EM_KEY_4;                     /* EMC */
3220     case 0x88:  return EL_EM_KEY_3;                     /* EMC */
3221     case 0x94:  return EL_QUICKSAND_EMPTY;              /* EMC */
3222     case 0x9a:  return EL_AMOEBA_WET;                   /* EMC */
3223     case 0xaf:  return EL_DYNAMITE;                     /* EMC */
3224     case 0xbd:  return EL_SAND;                         /* EMC */
3225
3226     default:
3227       Error(ERR_WARN, "invalid level element %d", element);
3228       return EL_UNKNOWN;
3229   }
3230 }
3231
3232 static int map_em_element_field(int element)
3233 {
3234   if (element >= 0xc8 && element <= 0xe1)
3235     return EL_CHAR_A + (element - 0xc8);
3236   else if (element >= 0xe2 && element <= 0xeb)
3237     return EL_CHAR_0 + (element - 0xe2);
3238
3239   switch (element)
3240   {
3241     case 0x00:  return EL_ROCK;
3242     case 0x01:  return EL_ROCK;                         /* EMC */
3243     case 0x02:  return EL_DIAMOND;
3244     case 0x03:  return EL_DIAMOND;
3245     case 0x04:  return EL_ROBOT;
3246     case 0x05:  return EL_ROBOT;                        /* EMC */
3247     case 0x06:  return EL_EMPTY_SPACE;                  /* EMC */
3248     case 0x07:  return EL_EMPTY_SPACE;                  /* EMC */
3249     case 0x08:  return EL_SPACESHIP_UP;
3250     case 0x09:  return EL_SPACESHIP_RIGHT;
3251     case 0x0a:  return EL_SPACESHIP_DOWN;
3252     case 0x0b:  return EL_SPACESHIP_LEFT;
3253     case 0x0c:  return EL_SPACESHIP_UP;
3254     case 0x0d:  return EL_SPACESHIP_RIGHT;
3255     case 0x0e:  return EL_SPACESHIP_DOWN;
3256     case 0x0f:  return EL_SPACESHIP_LEFT;
3257
3258     case 0x10:  return EL_BOMB;
3259     case 0x11:  return EL_BOMB;                         /* EMC */
3260     case 0x12:  return EL_EMERALD;
3261     case 0x13:  return EL_EMERALD;
3262     case 0x14:  return EL_BUG_UP;
3263     case 0x15:  return EL_BUG_RIGHT;
3264     case 0x16:  return EL_BUG_DOWN;
3265     case 0x17:  return EL_BUG_LEFT;
3266     case 0x18:  return EL_BUG_UP;
3267     case 0x19:  return EL_BUG_RIGHT;
3268     case 0x1a:  return EL_BUG_DOWN;
3269     case 0x1b:  return EL_BUG_LEFT;
3270     case 0x1c:  return EL_AMOEBA_DROP;
3271     case 0x1d:  return EL_AMOEBA_DROP;                  /* EMC */
3272     case 0x1e:  return EL_AMOEBA_DROP;                  /* EMC */
3273     case 0x1f:  return EL_AMOEBA_DROP;                  /* EMC */
3274
3275     case 0x20:  return EL_ROCK;
3276     case 0x21:  return EL_BOMB;                         /* EMC */
3277     case 0x22:  return EL_DIAMOND;                      /* EMC */
3278     case 0x23:  return EL_EMERALD;                      /* EMC */
3279     case 0x24:  return EL_MAGIC_WALL;
3280     case 0x25:  return EL_NUT;
3281     case 0x26:  return EL_NUT;                          /* EMC */
3282     case 0x27:  return EL_NUT;                          /* EMC */
3283
3284       /* looks like magic wheel, but is _always_ activated */
3285     case 0x28:  return EL_ROBOT_WHEEL;                  /* EMC */
3286
3287     case 0x29:  return EL_YAMYAM;       /* up */
3288     case 0x2a:  return EL_YAMYAM;       /* down */
3289     case 0x2b:  return EL_YAMYAM;       /* left */      /* EMC */
3290     case 0x2c:  return EL_YAMYAM;       /* right */     /* EMC */
3291     case 0x2d:  return EL_QUICKSAND_FULL;
3292     case 0x2e:  return EL_EMPTY_SPACE;                  /* EMC */
3293     case 0x2f:  return EL_EMPTY_SPACE;                  /* EMC */
3294
3295     case 0x30:  return EL_EMPTY_SPACE;                  /* EMC */
3296     case 0x31:  return EL_SAND;                         /* EMC */
3297     case 0x32:  return EL_SAND;                         /* EMC */
3298     case 0x33:  return EL_SAND;                         /* EMC */
3299     case 0x34:  return EL_QUICKSAND_FULL;               /* EMC */
3300     case 0x35:  return EL_QUICKSAND_FULL;               /* EMC */
3301     case 0x36:  return EL_QUICKSAND_FULL;               /* EMC */
3302     case 0x37:  return EL_SAND;                         /* EMC */
3303     case 0x38:  return EL_ROCK;                         /* EMC */
3304     case 0x39:  return EL_EXPANDABLE_WALL_HORIZONTAL;   /* EMC */
3305     case 0x3a:  return EL_EXPANDABLE_WALL_VERTICAL;     /* EMC */
3306     case 0x3b:  return EL_DYNAMITE_ACTIVE;      /* 1 */
3307     case 0x3c:  return EL_DYNAMITE_ACTIVE;      /* 2 */
3308     case 0x3d:  return EL_DYNAMITE_ACTIVE;      /* 3 */
3309     case 0x3e:  return EL_DYNAMITE_ACTIVE;      /* 4 */
3310     case 0x3f:  return EL_ACID_POOL_BOTTOM;
3311
3312     case 0x40:  return EL_EXIT_OPEN;    /* 1 */
3313     case 0x41:  return EL_EXIT_OPEN;    /* 2 */
3314     case 0x42:  return EL_EXIT_OPEN;    /* 3 */
3315     case 0x43:  return EL_BALLOON;                      /* EMC */
3316     case 0x44:  return EL_UNKNOWN;                      /* EMC ("plant") */
3317     case 0x45:  return EL_SPRING;                       /* EMC */
3318     case 0x46:  return EL_SPRING;       /* falling */   /* EMC */
3319     case 0x47:  return EL_SPRING;       /* left */      /* EMC */
3320     case 0x48:  return EL_SPRING;       /* right */     /* EMC */
3321     case 0x49:  return EL_UNKNOWN;                      /* EMC ("ball 1") */
3322     case 0x4a:  return EL_UNKNOWN;                      /* EMC ("ball 2") */
3323     case 0x4b:  return EL_UNKNOWN;                      /* EMC ("android") */
3324     case 0x4c:  return EL_EMPTY_SPACE;                  /* EMC */
3325     case 0x4d:  return EL_UNKNOWN;                      /* EMC ("android") */
3326     case 0x4e:  return EL_INVISIBLE_WALL;               /* EMC (? "android") */
3327     case 0x4f:  return EL_UNKNOWN;                      /* EMC ("android") */
3328
3329     case 0x50:  return EL_UNKNOWN;                      /* EMC ("android") */
3330     case 0x51:  return EL_UNKNOWN;                      /* EMC ("android") */
3331     case 0x52:  return EL_UNKNOWN;                      /* EMC ("android") */
3332     case 0x53:  return EL_UNKNOWN;                      /* EMC ("android") */
3333     case 0x54:  return EL_UNKNOWN;                      /* EMC ("android") */
3334     case 0x55:  return EL_EMPTY_SPACE;                  /* EMC */
3335     case 0x56:  return EL_EMPTY_SPACE;                  /* EMC */
3336     case 0x57:  return EL_EMPTY_SPACE;                  /* EMC */
3337     case 0x58:  return EL_EMPTY_SPACE;                  /* EMC */
3338     case 0x59:  return EL_EMPTY_SPACE;                  /* EMC */
3339     case 0x5a:  return EL_EMPTY_SPACE;                  /* EMC */
3340     case 0x5b:  return EL_EMPTY_SPACE;                  /* EMC */
3341     case 0x5c:  return EL_EMPTY_SPACE;                  /* EMC */
3342     case 0x5d:  return EL_EMPTY_SPACE;                  /* EMC */
3343     case 0x5e:  return EL_EMPTY_SPACE;                  /* EMC */
3344     case 0x5f:  return EL_EMPTY_SPACE;                  /* EMC */
3345
3346     case 0x60:  return EL_EMPTY_SPACE;                  /* EMC */
3347     case 0x61:  return EL_EMPTY_SPACE;                  /* EMC */
3348     case 0x62:  return EL_EMPTY_SPACE;                  /* EMC */
3349     case 0x63:  return EL_SPRING;       /* left */      /* EMC */
3350     case 0x64:  return EL_SPRING;       /* right */     /* EMC */
3351     case 0x65:  return EL_ACID;         /* 1 */         /* EMC */
3352     case 0x66:  return EL_ACID;         /* 2 */         /* EMC */
3353     case 0x67:  return EL_ACID;         /* 3 */         /* EMC */
3354     case 0x68:  return EL_ACID;         /* 4 */         /* EMC */
3355     case 0x69:  return EL_ACID;         /* 5 */         /* EMC */
3356     case 0x6a:  return EL_ACID;         /* 6 */         /* EMC */
3357     case 0x6b:  return EL_ACID;         /* 7 */         /* EMC */
3358     case 0x6c:  return EL_ACID;         /* 8 */         /* EMC */
3359     case 0x6d:  return EL_EMPTY_SPACE;                  /* EMC */
3360     case 0x6e:  return EL_EMPTY_SPACE;                  /* EMC */
3361     case 0x6f:  return EL_EMPTY_SPACE;                  /* EMC */
3362
3363     case 0x70:  return EL_EMPTY_SPACE;                  /* EMC */
3364     case 0x71:  return EL_EMPTY_SPACE;                  /* EMC */
3365     case 0x72:  return EL_NUT;          /* left */      /* EMC */
3366     case 0x73:  return EL_SAND;                         /* EMC (? "nut") */
3367     case 0x74:  return EL_STEELWALL;
3368     case 0x75:  return EL_EMPTY_SPACE;                  /* EMC */
3369     case 0x76:  return EL_EMPTY_SPACE;                  /* EMC */
3370     case 0x77:  return EL_BOMB;         /* left */      /* EMC */
3371     case 0x78:  return EL_BOMB;         /* right */     /* EMC */
3372     case 0x79:  return EL_ROCK;         /* left */      /* EMC */
3373     case 0x7a:  return EL_ROCK;         /* right */     /* EMC */
3374     case 0x7b:  return EL_ACID;                         /* (? EMC "blank") */
3375     case 0x7c:  return EL_EMPTY_SPACE;                  /* EMC */
3376     case 0x7d:  return EL_EMPTY_SPACE;                  /* EMC */
3377     case 0x7e:  return EL_EMPTY_SPACE;                  /* EMC */
3378     case 0x7f:  return EL_EMPTY_SPACE;                  /* EMC */
3379
3380     case 0x80:  return EL_EMPTY;
3381     case 0x81:  return EL_WALL_SLIPPERY;
3382     case 0x82:  return EL_SAND;
3383     case 0x83:  return EL_STEELWALL;
3384     case 0x84:  return EL_WALL;
3385     case 0x85:  return EL_EM_KEY_1;
3386     case 0x86:  return EL_EM_KEY_2;
3387     case 0x87:  return EL_EM_KEY_4;
3388     case 0x88:  return EL_EM_KEY_3;
3389     case 0x89:  return EL_EM_GATE_1;
3390     case 0x8a:  return EL_EM_GATE_2;
3391     case 0x8b:  return EL_EM_GATE_4;
3392     case 0x8c:  return EL_EM_GATE_3;
3393     case 0x8d:  return EL_INVISIBLE_WALL;               /* EMC (? "dripper") */
3394     case 0x8e:  return EL_EM_GATE_1_GRAY;
3395     case 0x8f:  return EL_EM_GATE_2_GRAY;
3396
3397     case 0x90:  return EL_EM_GATE_4_GRAY;
3398     case 0x91:  return EL_EM_GATE_3_GRAY;
3399     case 0x92:  return EL_MAGIC_WALL;
3400     case 0x93:  return EL_ROBOT_WHEEL;
3401     case 0x94:  return EL_QUICKSAND_EMPTY;              /* (? EMC "sand") */
3402     case 0x95:  return EL_ACID_POOL_TOPLEFT;
3403     case 0x96:  return EL_ACID_POOL_TOPRIGHT;
3404     case 0x97:  return EL_ACID_POOL_BOTTOMLEFT;
3405     case 0x98:  return EL_ACID_POOL_BOTTOMRIGHT;
3406     case 0x99:  return EL_ACID;                 /* (? EMC "fake blank") */
3407     case 0x9a:  return EL_AMOEBA_DEAD;          /* 1 */
3408     case 0x9b:  return EL_AMOEBA_DEAD;          /* 2 */
3409     case 0x9c:  return EL_AMOEBA_DEAD;          /* 3 */
3410     case 0x9d:  return EL_AMOEBA_DEAD;          /* 4 */
3411     case 0x9e:  return EL_EXIT_CLOSED;
3412     case 0x9f:  return EL_CHAR_LESS;            /* arrow left */
3413
3414       /* looks like normal sand, but behaves like wall */
3415     case 0xa0:  return EL_UNKNOWN;              /* EMC ("fake grass") */
3416     case 0xa1:  return EL_UNKNOWN;              /* EMC ("lenses") */
3417     case 0xa2:  return EL_UNKNOWN;              /* EMC ("magnify") */
3418     case 0xa3:  return EL_UNKNOWN;              /* EMC ("fake blank") */
3419     case 0xa4:  return EL_UNKNOWN;              /* EMC ("fake grass") */
3420     case 0xa5:  return EL_UNKNOWN;              /* EMC ("switch") */
3421     case 0xa6:  return EL_UNKNOWN;              /* EMC ("switch") */
3422     case 0xa7:  return EL_EMPTY_SPACE;                  /* EMC */
3423     case 0xa8:  return EL_EMC_WALL_1;                   /* EMC ("decor 8") */
3424     case 0xa9:  return EL_EMC_WALL_2;                   /* EMC ("decor 9") */
3425     case 0xaa:  return EL_EMC_WALL_3;                   /* EMC ("decor 10") */
3426     case 0xab:  return EL_EMC_WALL_7;                   /* EMC ("decor 5") */
3427     case 0xac:  return EL_CHAR_COMMA;                   /* EMC */
3428     case 0xad:  return EL_CHAR_QUOTEDBL;                /* EMC */
3429     case 0xae:  return EL_CHAR_MINUS;                   /* EMC */
3430     case 0xaf:  return EL_DYNAMITE;
3431
3432     case 0xb0:  return EL_EMC_STEELWALL_1;              /* EMC ("steel 3") */
3433     case 0xb1:  return EL_EMC_WALL_8;                   /* EMC ("decor 6") */
3434     case 0xb2:  return EL_UNKNOWN;                      /* EMC ("decor 7") */
3435     case 0xb3:  return EL_STEELWALL;            /* 2 */ /* EMC */
3436     case 0xb4:  return EL_WALL_SLIPPERY;        /* 2 */ /* EMC */
3437     case 0xb5:  return EL_EMC_WALL_6;                   /* EMC ("decor 2") */
3438     case 0xb6:  return EL_EMC_WALL_5;                   /* EMC ("decor 4") */
3439     case 0xb7:  return EL_EMC_WALL_4;                   /* EMC ("decor 3") */
3440     case 0xb8:  return EL_BALLOON_SWITCH_ANY;           /* EMC */
3441     case 0xb9:  return EL_BALLOON_SWITCH_RIGHT;         /* EMC */
3442     case 0xba:  return EL_BALLOON_SWITCH_DOWN;          /* EMC */
3443     case 0xbb:  return EL_BALLOON_SWITCH_LEFT;          /* EMC */
3444     case 0xbc:  return EL_BALLOON_SWITCH_UP;            /* EMC */
3445     case 0xbd:  return EL_SAND;                         /* EMC ("dirt") */
3446     case 0xbe:  return EL_UNKNOWN;                      /* EMC ("plant") */
3447     case 0xbf:  return EL_UNKNOWN;                      /* EMC ("key 5") */
3448
3449     case 0xc0:  return EL_UNKNOWN;                      /* EMC ("key 6") */
3450     case 0xc1:  return EL_UNKNOWN;                      /* EMC ("key 7") */
3451     case 0xc2:  return EL_UNKNOWN;                      /* EMC ("key 8") */
3452     case 0xc3:  return EL_UNKNOWN;                      /* EMC ("door 5") */
3453     case 0xc4:  return EL_UNKNOWN;                      /* EMC ("door 6") */
3454     case 0xc5:  return EL_UNKNOWN;                      /* EMC ("door 7") */
3455     case 0xc6:  return EL_UNKNOWN;                      /* EMC ("door 8") */
3456     case 0xc7:  return EL_UNKNOWN;                      /* EMC ("bumper") */
3457
3458       /* characters: see above */
3459
3460     case 0xec:  return EL_CHAR_PERIOD;
3461     case 0xed:  return EL_CHAR_EXCLAM;
3462     case 0xee:  return EL_CHAR_COLON;
3463     case 0xef:  return EL_CHAR_QUESTION;
3464
3465     case 0xf0:  return EL_CHAR_GREATER;                 /* arrow right */
3466     case 0xf1:  return EL_CHAR_COPYRIGHT;               /* EMC: "decor 1" */
3467     case 0xf2:  return EL_UNKNOWN;              /* EMC ("fake door 5") */
3468     case 0xf3:  return EL_UNKNOWN;              /* EMC ("fake door 6") */
3469     case 0xf4:  return EL_UNKNOWN;              /* EMC ("fake door 7") */
3470     case 0xf5:  return EL_UNKNOWN;              /* EMC ("fake door 8") */
3471     case 0xf6:  return EL_EMPTY_SPACE;                  /* EMC */
3472     case 0xf7:  return EL_EMPTY_SPACE;                  /* EMC */
3473
3474     case 0xf8:  return EL_EMPTY_SPACE;                  /* EMC */
3475     case 0xf9:  return EL_EMPTY_SPACE;                  /* EMC */
3476     case 0xfa:  return EL_EMPTY_SPACE;                  /* EMC */
3477     case 0xfb:  return EL_EMPTY_SPACE;                  /* EMC */
3478     case 0xfc:  return EL_EMPTY_SPACE;                  /* EMC */
3479     case 0xfd:  return EL_EMPTY_SPACE;                  /* EMC */
3480
3481     case 0xfe:  return EL_PLAYER_1;                     /* EMC: "blank" */
3482     case 0xff:  return EL_PLAYER_2;                     /* EMC: "blank" */
3483
3484     default:
3485       /* should never happen (all 8-bit value cases should be handled) */
3486       Error(ERR_WARN, "invalid level element %d", element);
3487       return EL_UNKNOWN;
3488   }
3489 }
3490
3491 #define EM_LEVEL_SIZE                   2106
3492 #define EM_LEVEL_XSIZE                  64
3493 #define EM_LEVEL_YSIZE                  32
3494
3495 static void OLD_LoadLevelFromFileInfo_EM(struct LevelInfo *level,
3496                                          struct LevelFileInfo *level_file_info)
3497 {
3498   char *filename = level_file_info->filename;
3499   FILE *file;
3500   unsigned char leveldata[EM_LEVEL_SIZE];
3501   unsigned char *header = &leveldata[EM_LEVEL_XSIZE * EM_LEVEL_YSIZE];
3502   int nr = level_file_info->nr;
3503   int i, x, y;
3504
3505   if (!(file = fopen(filename, MODE_READ)))
3506   {
3507     level->no_valid_file = TRUE;
3508
3509     Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
3510
3511     return;
3512   }
3513
3514   for (i = 0; i < EM_LEVEL_SIZE; i++)
3515     leveldata[i] = fgetc(file);
3516
3517   fclose(file);
3518
3519   /* check if level data is crypted by testing against known starting bytes
3520      of the few existing crypted level files (from Emerald Mine 1 + 2) */
3521
3522   if ((leveldata[0] == 0xf1 ||
3523        leveldata[0] == 0xf5) && leveldata[2] == 0xe7 && leveldata[3] == 0xee)
3524   {
3525     unsigned char code0 = 0x65;
3526     unsigned char code1 = 0x11;
3527
3528     if (leveldata[0] == 0xf5)   /* error in crypted Emerald Mine 2 levels */
3529       leveldata[0] = 0xf1;
3530
3531     /* decode crypted level data */
3532
3533     for (i = 0; i < EM_LEVEL_SIZE; i++)
3534     {
3535       leveldata[i] ^= code0;
3536       leveldata[i] -= code1;
3537
3538       code0 = (code0 + 7) & 0xff;
3539     }
3540   }
3541
3542   level->fieldx = EM_LEVEL_XSIZE;
3543   level->fieldy = EM_LEVEL_YSIZE;
3544
3545   level->time           = header[46] * 10;
3546   level->gems_needed    = header[47];
3547
3548   /* The original Emerald Mine levels have their level number stored
3549      at the second byte of the level file...
3550      Do not trust this information at other level files, e.g. EMC,
3551      but correct it anyway (normally the first row is completely
3552      steel wall, so the correction does not hurt anyway). */
3553
3554   if (leveldata[1] == nr)
3555     leveldata[1] = leveldata[2];        /* correct level number field */
3556
3557   sprintf(level->name, "Level %d", nr);         /* set level name */
3558
3559   level->score[SC_EMERALD]      = header[36];
3560   level->score[SC_DIAMOND]      = header[37];
3561   level->score[SC_ROBOT]        = header[38];
3562   level->score[SC_SPACESHIP]    = header[39];
3563   level->score[SC_BUG]          = header[40];
3564   level->score[SC_YAMYAM]       = header[41];
3565   level->score[SC_NUT]          = header[42];
3566   level->score[SC_DYNAMITE]     = header[43];
3567   level->score[SC_TIME_BONUS]   = header[44];
3568
3569   level->num_yamyam_contents = 4;
3570
3571   for (i = 0; i < level->num_yamyam_contents; i++)
3572     for (y = 0; y < 3; y++)
3573       for (x = 0; x < 3; x++)
3574         level->yamyam_content[i].e[x][y] =
3575           map_em_element_yam(header[i * 9 + y * 3 + x]);
3576
3577   level->amoeba_speed           = (header[52] * 256 + header[53]) % 256;
3578   level->time_magic_wall        = (header[54] * 256 + header[55]) * 16 / 100;
3579   level->time_wheel             = (header[56] * 256 + header[57]) * 16 / 100;
3580   level->amoeba_content         = EL_DIAMOND;
3581
3582   for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
3583   {
3584     int new_element = map_em_element_field(leveldata[y * EM_LEVEL_XSIZE + x]);
3585
3586     if (new_element == EL_AMOEBA_DEAD && level->amoeba_speed)
3587       new_element = EL_AMOEBA_WET;
3588
3589     level->field[x][y] = new_element;
3590   }
3591
3592   x = (header[48] * 256 + header[49]) % EM_LEVEL_XSIZE;
3593   y = (header[48] * 256 + header[49]) / EM_LEVEL_XSIZE;
3594   level->field[x][y] = EL_PLAYER_1;
3595
3596   x = (header[50] * 256 + header[51]) % EM_LEVEL_XSIZE;
3597   y = (header[50] * 256 + header[51]) / EM_LEVEL_XSIZE;
3598   level->field[x][y] = EL_PLAYER_2;
3599 }
3600
3601 #endif
3602
3603 void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
3604 {
3605   static int ball_xy[8][2] =
3606   {
3607     { 0, 0 },
3608     { 1, 0 },
3609     { 2, 0 },
3610     { 0, 1 },
3611     { 2, 1 },
3612     { 0, 2 },
3613     { 1, 2 },
3614     { 2, 2 },
3615   };
3616   struct LevelInfo_EM *level_em = level->native_em_level;
3617   struct LEVEL *lev = level_em->lev;
3618   struct PLAYER **ply = level_em->ply;
3619   int i, j, x, y;
3620
3621   lev->width  = MIN(level->fieldx, EM_MAX_CAVE_WIDTH);
3622   lev->height = MIN(level->fieldy, EM_MAX_CAVE_HEIGHT);
3623
3624   lev->time_seconds     = level->time;
3625   lev->required_initial = level->gems_needed;
3626
3627   lev->emerald_score    = level->score[SC_EMERALD];
3628   lev->diamond_score    = level->score[SC_DIAMOND];
3629   lev->alien_score      = level->score[SC_ROBOT];
3630   lev->tank_score       = level->score[SC_SPACESHIP];
3631   lev->bug_score        = level->score[SC_BUG];
3632   lev->eater_score      = level->score[SC_YAMYAM];
3633   lev->nut_score        = level->score[SC_NUT];
3634   lev->dynamite_score   = level->score[SC_DYNAMITE];
3635   lev->key_score        = level->score[SC_KEY];
3636   lev->exit_score       = level->score[SC_TIME_BONUS];
3637
3638   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3639     for (y = 0; y < 3; y++)
3640       for (x = 0; x < 3; x++)
3641         lev->eater_array[i][y * 3 + x] =
3642           map_element_RND_to_EM(level->yamyam_content[i].e[x][y]);
3643
3644   lev->amoeba_time              = level->amoeba_speed;
3645   lev->wonderwall_time_initial  = level->time_magic_wall;
3646   lev->wheel_time               = level->time_wheel;
3647
3648   lev->android_move_time        = level->android_move_time;
3649   lev->android_clone_time       = level->android_clone_time;
3650   lev->ball_random              = level->ball_random;
3651   lev->ball_state_initial       = level->ball_state_initial;
3652   lev->ball_time                = level->ball_time;
3653   lev->num_ball_arrays          = level->num_ball_contents;
3654
3655   lev->lenses_score             = level->lenses_score;
3656   lev->magnify_score            = level->magnify_score;
3657   lev->slurp_score              = level->slurp_score;
3658
3659   lev->lenses_time              = level->lenses_time;
3660   lev->magnify_time             = level->magnify_time;
3661
3662   lev->wind_direction_initial =
3663     map_direction_RND_to_EM(level->wind_direction_initial);
3664   lev->wind_cnt_initial = (level->wind_direction_initial != MV_NONE ?
3665                            lev->wind_time : 0);
3666
3667   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3668     for (j = 0; j < 8; j++)
3669       lev->ball_array[i][j] =
3670         map_element_RND_to_EM(level->
3671                               ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
3672
3673   map_android_clone_elements_RND_to_EM(level);
3674
3675   /* first fill the complete playfield with the default border element */
3676   for (y = 0; y < EM_MAX_CAVE_HEIGHT; y++)
3677     for (x = 0; x < EM_MAX_CAVE_WIDTH; x++)
3678       level_em->cave[x][y] = ZBORDER;
3679
3680   if (BorderElement == EL_STEELWALL)
3681   {
3682     for (y = 0; y < lev->height + 2; y++)
3683       for (x = 0; x < lev->width + 2; x++)
3684         level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_STEELWALL);
3685   }
3686
3687   /* then copy the real level contents from level file into the playfield */
3688   for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
3689   {
3690     int new_element = map_element_RND_to_EM(level->field[x][y]);
3691     int offset = (BorderElement == EL_STEELWALL ? 1 : 0);
3692     int xx = x + 1 + offset;
3693     int yy = y + 1 + offset;
3694
3695     if (level->field[x][y] == EL_AMOEBA_DEAD)
3696       new_element = map_element_RND_to_EM(EL_AMOEBA_WET);
3697
3698     level_em->cave[xx][yy] = new_element;
3699   }
3700
3701   for (i = 0; i < MAX_PLAYERS; i++)
3702   {
3703     ply[i]->x_initial = 0;
3704     ply[i]->y_initial = 0;
3705   }
3706
3707   /* initialize player positions and delete players from the playfield */
3708   for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
3709   {
3710     if (ELEM_IS_PLAYER(level->field[x][y]))
3711     {
3712       int player_nr = GET_PLAYER_NR(level->field[x][y]);
3713       int offset = (BorderElement == EL_STEELWALL ? 1 : 0);
3714       int xx = x + 1 + offset;
3715       int yy = y + 1 + offset;
3716
3717       ply[player_nr]->x_initial = xx;
3718       ply[player_nr]->y_initial = yy;
3719
3720       level_em->cave[xx][yy] = map_element_RND_to_EM(EL_EMPTY);
3721     }
3722   }
3723
3724   if (BorderElement == EL_STEELWALL)
3725   {
3726     lev->width  += 2;
3727     lev->height += 2;
3728   }
3729 }
3730
3731 void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
3732 {
3733   static int ball_xy[8][2] =
3734   {
3735     { 0, 0 },
3736     { 1, 0 },
3737     { 2, 0 },
3738     { 0, 1 },
3739     { 2, 1 },
3740     { 0, 2 },
3741     { 1, 2 },
3742     { 2, 2 },
3743   };
3744   struct LevelInfo_EM *level_em = level->native_em_level;
3745   struct LEVEL *lev = level_em->lev;
3746   struct PLAYER **ply = level_em->ply;
3747   int i, j, x, y;
3748
3749   level->fieldx = MIN(lev->width,  MAX_LEV_FIELDX);
3750   level->fieldy = MIN(lev->height, MAX_LEV_FIELDY);
3751
3752   level->time        = lev->time_seconds;
3753   level->gems_needed = lev->required_initial;
3754
3755   sprintf(level->name, "Level %d", level->file_info.nr);
3756
3757   level->score[SC_EMERALD]      = lev->emerald_score;
3758   level->score[SC_DIAMOND]      = lev->diamond_score;
3759   level->score[SC_ROBOT]        = lev->alien_score;
3760   level->score[SC_SPACESHIP]    = lev->tank_score;
3761   level->score[SC_BUG]          = lev->bug_score;
3762   level->score[SC_YAMYAM]       = lev->eater_score;
3763   level->score[SC_NUT]          = lev->nut_score;
3764   level->score[SC_DYNAMITE]     = lev->dynamite_score;
3765   level->score[SC_KEY]          = lev->key_score;
3766   level->score[SC_TIME_BONUS]   = lev->exit_score;
3767
3768   level->num_yamyam_contents = MAX_ELEMENT_CONTENTS;
3769
3770   for (i = 0; i < level->num_yamyam_contents; i++)
3771     for (y = 0; y < 3; y++)
3772       for (x = 0; x < 3; x++)
3773         level->yamyam_content[i].e[x][y] =
3774           map_element_EM_to_RND(lev->eater_array[i][y * 3 + x]);
3775
3776   level->amoeba_speed           = lev->amoeba_time;
3777   level->time_magic_wall        = lev->wonderwall_time_initial;
3778   level->time_wheel             = lev->wheel_time;
3779
3780   level->android_move_time      = lev->android_move_time;
3781   level->android_clone_time     = lev->android_clone_time;
3782   level->ball_random            = lev->ball_random;
3783   level->ball_state_initial     = lev->ball_state_initial;
3784   level->ball_time              = lev->ball_time;
3785   level->num_ball_contents      = lev->num_ball_arrays;
3786
3787   level->lenses_score           = lev->lenses_score;
3788   level->magnify_score          = lev->magnify_score;
3789   level->slurp_score            = lev->slurp_score;
3790
3791   level->lenses_time            = lev->lenses_time;
3792   level->magnify_time           = lev->magnify_time;
3793
3794   level->wind_direction_initial =
3795     map_direction_EM_to_RND(lev->wind_direction_initial);
3796
3797   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3798     for (j = 0; j < 8; j++)
3799       level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]] =
3800         map_element_EM_to_RND(lev->ball_array[i][j]);
3801
3802   map_android_clone_elements_EM_to_RND(level);
3803
3804   /* convert the playfield (some elements need special treatment) */
3805   for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
3806   {
3807     int new_element = map_element_EM_to_RND(level_em->cave[x + 1][y + 1]);
3808
3809     if (new_element == EL_AMOEBA_WET && level->amoeba_speed == 0)
3810       new_element = EL_AMOEBA_DEAD;
3811
3812     level->field[x][y] = new_element;
3813   }
3814
3815   for (i = 0; i < MAX_PLAYERS; i++)
3816   {
3817     /* in case of all players set to the same field, use the first player */
3818     int nr = MAX_PLAYERS - i - 1;
3819     int jx = ply[nr]->x_initial - 1;
3820     int jy = ply[nr]->y_initial - 1;
3821
3822     if (jx != -1 && jy != -1)
3823       level->field[jx][jy] = EL_PLAYER_1 + nr;
3824   }
3825 }
3826
3827
3828 /* ------------------------------------------------------------------------- */
3829 /* functions for loading SP level                                            */
3830 /* ------------------------------------------------------------------------- */
3831
3832 #if 0
3833
3834 #define NUM_SUPAPLEX_LEVELS_PER_PACKAGE 111
3835 #define SP_LEVEL_SIZE                   1536
3836 #define SP_LEVEL_XSIZE                  60
3837 #define SP_LEVEL_YSIZE                  24
3838 #define SP_LEVEL_NAME_LEN               23
3839
3840 static void LoadLevelFromFileStream_SP(FILE *file, struct LevelInfo *level,
3841                                        int nr)
3842 {
3843   int initial_player_gravity;
3844   int num_special_ports;
3845   int i, x, y;
3846
3847   /* for details of the Supaplex level format, see Herman Perk's Supaplex
3848      documentation file "SPFIX63.DOC" from his Supaplex "SpeedFix" package */
3849
3850   /* read level body (width * height == 60 * 24 tiles == 1440 bytes) */
3851   for (y = 0; y < SP_LEVEL_YSIZE; y++)
3852   {
3853     for (x = 0; x < SP_LEVEL_XSIZE; x++)
3854     {
3855       int element_old = fgetc(file);
3856       int element_new;
3857
3858       if (element_old <= 0x27)
3859         element_new = getMappedElement(EL_SP_START + element_old);
3860       else if (element_old == 0x28)
3861         element_new = EL_INVISIBLE_WALL;
3862       else
3863       {
3864         Error(ERR_WARN, "in level %d, at position %d, %d:", nr, x, y);
3865         Error(ERR_WARN, "invalid level element %d", element_old);
3866
3867         element_new = EL_UNKNOWN;
3868       }
3869
3870       level->field[x][y] = element_new;
3871     }
3872   }
3873
3874   ReadUnusedBytesFromFile(file, 4);     /* (not used by Supaplex engine) */
3875
3876   /* initial gravity: 1 == "on", anything else (0) == "off" */
3877   initial_player_gravity = (fgetc(file) == 1 ? TRUE : FALSE);
3878
3879   for (i = 0; i < MAX_PLAYERS; i++)
3880     level->initial_player_gravity[i] = initial_player_gravity;
3881
3882   ReadUnusedBytesFromFile(file, 1);     /* (not used by Supaplex engine) */
3883
3884   /* level title in uppercase letters, padded with dashes ("-") (23 bytes) */
3885   for (i = 0; i < SP_LEVEL_NAME_LEN; i++)
3886     level->name[i] = fgetc(file);
3887   level->name[SP_LEVEL_NAME_LEN] = '\0';
3888
3889   /* initial "freeze zonks": 2 == "on", anything else (0, 1) == "off" */
3890   ReadUnusedBytesFromFile(file, 1);     /* (not used by R'n'D engine) */
3891
3892   /* number of infotrons needed; 0 means that Supaplex will count the total
3893      amount of infotrons in the level and use the low byte of that number
3894      (a multiple of 256 infotrons will result in "0 infotrons needed"!) */
3895   level->gems_needed = fgetc(file);
3896
3897   /* number of special ("gravity") port entries below (maximum 10 allowed) */
3898   num_special_ports = fgetc(file);
3899
3900   /* database of properties of up to 10 special ports (6 bytes per port) */
3901   for (i = 0; i < 10; i++)
3902   {
3903     int port_location, port_x, port_y, port_element;
3904     int gravity;
3905
3906     /* high and low byte of the location of a special port; if (x, y) are the
3907        coordinates of a port in the field and (0, 0) is the top-left corner,
3908        the 16 bit value here calculates as 2 * (x + (y * 60)) (this is twice
3909        of what may be expected: Supaplex works with a game field in memory
3910        which is 2 bytes per tile) */
3911     port_location = getFile16BitBE(file);
3912
3913     /* change gravity: 1 == "turn on", anything else (0) == "turn off" */
3914     gravity = fgetc(file);
3915
3916     /* "freeze zonks": 2 == "turn on", anything else (0, 1) == "turn off" */
3917     ReadUnusedBytesFromFile(file, 1);   /* (not used by R'n'D engine) */
3918
3919     /* "freeze enemies": 1 == "turn on", anything else (0) == "turn off" */
3920     ReadUnusedBytesFromFile(file, 1);   /* (not used by R'n'D engine) */
3921
3922     ReadUnusedBytesFromFile(file, 1);   /* (not used by Supaplex engine) */
3923
3924     if (i >= num_special_ports)
3925       continue;
3926
3927     port_x = (port_location / 2) % SP_LEVEL_XSIZE;
3928     port_y = (port_location / 2) / SP_LEVEL_XSIZE;
3929
3930     if (port_x < 0 || port_x >= SP_LEVEL_XSIZE ||
3931         port_y < 0 || port_y >= SP_LEVEL_YSIZE)
3932     {
3933       Error(ERR_WARN, "special port position (%d, %d) out of bounds",
3934             port_x, port_y);
3935
3936       continue;
3937     }
3938
3939     port_element = level->field[port_x][port_y];
3940
3941     if (port_element < EL_SP_GRAVITY_PORT_RIGHT ||
3942         port_element > EL_SP_GRAVITY_PORT_UP)
3943     {
3944       Error(ERR_WARN, "no special port at position (%d, %d)", port_x, port_y);
3945
3946       continue;
3947     }
3948
3949     /* change previous (wrong) gravity inverting special port to either
3950        gravity enabling special port or gravity disabling special port */
3951     level->field[port_x][port_y] +=
3952       (gravity == 1 ? EL_SP_GRAVITY_ON_PORT_RIGHT :
3953        EL_SP_GRAVITY_OFF_PORT_RIGHT) - EL_SP_GRAVITY_PORT_RIGHT;
3954   }
3955
3956   ReadUnusedBytesFromFile(file, 4);     /* (not used by Supaplex engine) */
3957
3958   /* change special gravity ports without database entries to normal ports */
3959   for (y = 0; y < SP_LEVEL_YSIZE; y++)
3960     for (x = 0; x < SP_LEVEL_XSIZE; x++)
3961       if (level->field[x][y] >= EL_SP_GRAVITY_PORT_RIGHT &&
3962           level->field[x][y] <= EL_SP_GRAVITY_PORT_UP)
3963         level->field[x][y] += EL_SP_PORT_RIGHT - EL_SP_GRAVITY_PORT_RIGHT;
3964
3965   /* auto-determine number of infotrons if it was stored as "0" -- see above */
3966   if (level->gems_needed == 0)
3967   {
3968     for (y = 0; y < SP_LEVEL_YSIZE; y++)
3969       for (x = 0; x < SP_LEVEL_XSIZE; x++)
3970         if (level->field[x][y] == EL_SP_INFOTRON)
3971           level->gems_needed++;
3972
3973     level->gems_needed &= 0xff;         /* only use low byte -- see above */
3974   }
3975
3976   level->fieldx = SP_LEVEL_XSIZE;
3977   level->fieldy = SP_LEVEL_YSIZE;
3978
3979   level->time = 0;                      /* no time limit */
3980   level->amoeba_speed = 0;
3981   level->time_magic_wall = 0;
3982   level->time_wheel = 0;
3983   level->amoeba_content = EL_EMPTY;
3984
3985 #if 1
3986   /* original Supaplex does not use score values -- use default values */
3987 #else
3988   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
3989     level->score[i] = 0;
3990 #endif
3991
3992   /* there are no yamyams in supaplex levels */
3993   for (i = 0; i < level->num_yamyam_contents; i++)
3994     for (y = 0; y < 3; y++)
3995       for (x = 0; x < 3; x++)
3996         level->yamyam_content[i].e[x][y] = EL_EMPTY;
3997 }
3998
3999 static void LoadLevelFromFileInfo_SP(struct LevelInfo *level,
4000                                      struct LevelFileInfo *level_file_info)
4001 {
4002   char *filename = level_file_info->filename;
4003   FILE *file;
4004   int nr = level_file_info->nr - leveldir_current->first_level;
4005   int i, l, x, y;
4006   char name_first, name_last;
4007   struct LevelInfo multipart_level;
4008   int multipart_xpos, multipart_ypos;
4009   boolean is_multipart_level;
4010   boolean is_first_part;
4011   boolean reading_multipart_level = FALSE;
4012   boolean use_empty_level = FALSE;
4013
4014   if (!(file = fopen(filename, MODE_READ)))
4015   {
4016     level->no_valid_file = TRUE;
4017
4018     Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
4019
4020     return;
4021   }
4022
4023   /* position file stream to the requested level inside the level package */
4024   if (level_file_info->packed &&
4025       fseek(file, nr * SP_LEVEL_SIZE, SEEK_SET) != 0)
4026   {
4027     level->no_valid_file = TRUE;
4028
4029     Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level", filename);
4030
4031     return;
4032   }
4033
4034   /* there exist Supaplex level package files with multi-part levels which
4035      can be detected as follows: instead of leading and trailing dashes ('-')
4036      to pad the level name, they have leading and trailing numbers which are
4037      the x and y coordinations of the current part of the multi-part level;
4038      if there are '?' characters instead of numbers on the left or right side
4039      of the level name, the multi-part level consists of only horizontal or
4040      vertical parts */
4041
4042   for (l = nr; l < NUM_SUPAPLEX_LEVELS_PER_PACKAGE; l++)
4043   {
4044     LoadLevelFromFileStream_SP(file, level, l);
4045
4046     /* check if this level is a part of a bigger multi-part level */
4047
4048     name_first = level->name[0];
4049     name_last  = level->name[SP_LEVEL_NAME_LEN - 1];
4050
4051     is_multipart_level =
4052       ((name_first == '?' || (name_first >= '0' && name_first <= '9')) &&
4053        (name_last  == '?' || (name_last  >= '0' && name_last  <= '9')));
4054
4055     is_first_part =
4056       ((name_first == '?' || name_first == '1') &&
4057        (name_last  == '?' || name_last  == '1'));
4058
4059     /* correct leading multipart level meta information in level name */
4060     for (i = 0; i < SP_LEVEL_NAME_LEN && level->name[i] == name_first; i++)
4061       level->name[i] = '-';
4062
4063     /* correct trailing multipart level meta information in level name */
4064     for (i = SP_LEVEL_NAME_LEN - 1; i >= 0 && level->name[i] == name_last; i--)
4065       level->name[i] = '-';
4066
4067     /* ---------- check for normal single level ---------- */
4068
4069     if (!reading_multipart_level && !is_multipart_level)
4070     {
4071       /* the current level is simply a normal single-part level, and we are
4072          not reading a multi-part level yet, so return the level as it is */
4073
4074       break;
4075     }
4076
4077     /* ---------- check for empty level (unused multi-part) ---------- */
4078
4079     if (!reading_multipart_level && is_multipart_level && !is_first_part)
4080     {
4081       /* this is a part of a multi-part level, but not the first part
4082          (and we are not already reading parts of a multi-part level);
4083          in this case, use an empty level instead of the single part */
4084
4085       use_empty_level = TRUE;
4086
4087       break;
4088     }
4089
4090     /* ---------- check for finished multi-part level ---------- */
4091
4092     if (reading_multipart_level &&
4093         (!is_multipart_level ||
4094          !strEqual(level->name, multipart_level.name)))
4095     {
4096       /* we are already reading parts of a multi-part level, but this level is
4097          either not a multi-part level, or a part of a different multi-part
4098          level; in both cases, the multi-part level seems to be complete */
4099
4100       break;
4101     }
4102
4103     /* ---------- here we have one part of a multi-part level ---------- */
4104
4105     reading_multipart_level = TRUE;
4106
4107     if (is_first_part)  /* start with first part of new multi-part level */
4108     {
4109       /* copy level info structure from first part */
4110       multipart_level = *level;
4111
4112       /* clear playfield of new multi-part level */
4113       for (y = 0; y < MAX_LEV_FIELDY; y++)
4114         for (x = 0; x < MAX_LEV_FIELDX; x++)
4115           multipart_level.field[x][y] = EL_EMPTY;
4116     }
4117
4118     if (name_first == '?')
4119       name_first = '1';
4120     if (name_last == '?')
4121       name_last = '1';
4122
4123     multipart_xpos = (int)(name_first - '0');
4124     multipart_ypos = (int)(name_last  - '0');
4125
4126 #if 0
4127     printf("----------> part (%d/%d) of multi-part level '%s'\n",
4128            multipart_xpos, multipart_ypos, multipart_level.name);
4129 #endif
4130
4131     if (multipart_xpos * SP_LEVEL_XSIZE > MAX_LEV_FIELDX ||
4132         multipart_ypos * SP_LEVEL_YSIZE > MAX_LEV_FIELDY)
4133     {
4134       Error(ERR_WARN, "multi-part level is too big -- ignoring part of it");
4135
4136       break;
4137     }
4138
4139     multipart_level.fieldx = MAX(multipart_level.fieldx,
4140                                  multipart_xpos * SP_LEVEL_XSIZE);
4141     multipart_level.fieldy = MAX(multipart_level.fieldy,
4142                                  multipart_ypos * SP_LEVEL_YSIZE);
4143
4144     /* copy level part at the right position of multi-part level */
4145     for (y = 0; y < SP_LEVEL_YSIZE; y++)
4146     {
4147       for (x = 0; x < SP_LEVEL_XSIZE; x++)
4148       {
4149         int start_x = (multipart_xpos - 1) * SP_LEVEL_XSIZE;
4150         int start_y = (multipart_ypos - 1) * SP_LEVEL_YSIZE;
4151
4152         multipart_level.field[start_x + x][start_y + y] = level->field[x][y];
4153       }
4154     }
4155   }
4156
4157   fclose(file);
4158
4159   if (use_empty_level)
4160   {
4161     setLevelInfoToDefaults(level);
4162
4163     level->fieldx = SP_LEVEL_XSIZE;
4164     level->fieldy = SP_LEVEL_YSIZE;
4165
4166     for (y = 0; y < SP_LEVEL_YSIZE; y++)
4167       for (x = 0; x < SP_LEVEL_XSIZE; x++)
4168         level->field[x][y] = EL_EMPTY;
4169
4170     strcpy(level->name, "-------- EMPTY --------");
4171
4172     Error(ERR_WARN, "single part of multi-part level -- using empty level");
4173   }
4174
4175   if (reading_multipart_level)
4176     *level = multipart_level;
4177 }
4178
4179 #endif
4180
4181 void CopyNativeLevel_RND_to_SP(struct LevelInfo *level)
4182 {
4183   struct LevelInfo_SP *level_sp = level->native_sp_level;
4184   LevelInfoType *header = &level_sp->header;
4185   int i, x, y;
4186
4187   level_sp->width = level->fieldx;
4188   level_sp->height = level->fieldy;
4189
4190   for (x = 0; x < level->fieldx; x++)
4191   {
4192     for (y = 0; y < level->fieldy; y++)
4193     {
4194       int element_old = level->field[x][y];
4195       int element_new;
4196
4197       if (element_old >= EL_SP_START &&
4198           element_old <= EL_SP_END)
4199         element_new = element_old - EL_SP_START;
4200       else if (element_old == EL_EMPTY_SPACE)
4201         element_new = 0x00;
4202       else if (element_old == EL_INVISIBLE_WALL)
4203         element_new = 0x28;
4204       else
4205         element_new = 0x20;     /* map unknown elements to yellow "hardware" */
4206
4207       level_sp->playfield[x][y] = element_new;
4208     }
4209   }
4210
4211   header->InitialGravity = (level->initial_player_gravity[0] ? 1 : 0);
4212
4213   for (i = 0; i < SP_LEVEL_NAME_LEN; i++)
4214     header->LevelTitle[i] = level->name[i];
4215   /* !!! NO STRING TERMINATION IN SUPAPLEX VB CODE YET -- FIX THIS !!! */
4216
4217   header->InfotronsNeeded = level->gems_needed;
4218
4219   /* !!! ADD SPECIAL PORT DATABASE STUFF !!! */
4220 }
4221
4222 void CopyNativeLevel_SP_to_RND(struct LevelInfo *level)
4223 {
4224   struct LevelInfo_SP *level_sp = level->native_sp_level;
4225   LevelInfoType *header = &level_sp->header;
4226   int i, x, y;
4227
4228   level->fieldx = level_sp->width;
4229   level->fieldy = level_sp->height;
4230
4231   for (x = 0; x < level->fieldx; x++)
4232   {
4233     for (y = 0; y < level->fieldy; y++)
4234     {
4235       int element_old = level_sp->playfield[x][y];
4236       int element_new;
4237
4238       if (element_old <= 0x27)
4239         element_new = getMappedElement(EL_SP_START + element_old);
4240       else if (element_old == 0x28)
4241         element_new = EL_INVISIBLE_WALL;
4242       else
4243       {
4244         Error(ERR_WARN, "invalid element %d at position %d, %d",
4245               element_old, x, y);
4246
4247         element_new = EL_UNKNOWN;
4248       }
4249
4250       level->field[x][y] = element_new;
4251     }
4252   }
4253
4254   for (i = 0; i < MAX_PLAYERS; i++)
4255     level->initial_player_gravity[i] =
4256       (header->InitialGravity == 1 ? TRUE : FALSE);
4257
4258   for (i = 0; i < SP_LEVEL_NAME_LEN; i++)
4259     level->name[i] = header->LevelTitle[i];
4260   level->name[SP_LEVEL_NAME_LEN] = '\0';
4261
4262   level->gems_needed = header->InfotronsNeeded;
4263
4264   for (i = 0; i < header->SpecialPortCount; i++)
4265   {
4266     SpecialPortType *port = &header->SpecialPort[i];
4267     int port_location = port->PortLocation;
4268     int gravity = port->Gravity;
4269     int port_x, port_y, port_element;
4270
4271     port_x = (port_location / 2) % level->fieldx;
4272     port_y = (port_location / 2) / level->fieldx;
4273
4274     if (port_x < 0 || port_x >= level->fieldx ||
4275         port_y < 0 || port_y >= level->fieldy)
4276     {
4277       Error(ERR_WARN, "special port position (%d, %d) out of bounds",
4278             port_x, port_y);
4279
4280       continue;
4281     }
4282
4283     port_element = level->field[port_x][port_y];
4284
4285     if (port_element < EL_SP_GRAVITY_PORT_RIGHT ||
4286         port_element > EL_SP_GRAVITY_PORT_UP)
4287     {
4288       Error(ERR_WARN, "no special port at position (%d, %d)", port_x, port_y);
4289
4290       continue;
4291     }
4292
4293     /* change previous (wrong) gravity inverting special port to either
4294        gravity enabling special port or gravity disabling special port */
4295     level->field[port_x][port_y] +=
4296       (gravity == 1 ? EL_SP_GRAVITY_ON_PORT_RIGHT :
4297        EL_SP_GRAVITY_OFF_PORT_RIGHT) - EL_SP_GRAVITY_PORT_RIGHT;
4298   }
4299
4300   /* change special gravity ports without database entries to normal ports */
4301   for (x = 0; x < level->fieldx; x++)
4302     for (y = 0; y < level->fieldy; y++)
4303       if (level->field[x][y] >= EL_SP_GRAVITY_PORT_RIGHT &&
4304           level->field[x][y] <= EL_SP_GRAVITY_PORT_UP)
4305         level->field[x][y] += EL_SP_PORT_RIGHT - EL_SP_GRAVITY_PORT_RIGHT;
4306
4307   level->time = 0;                      /* no time limit */
4308   level->amoeba_speed = 0;
4309   level->time_magic_wall = 0;
4310   level->time_wheel = 0;
4311   level->amoeba_content = EL_EMPTY;
4312
4313 #if 1
4314   /* original Supaplex does not use score values -- use default values */
4315 #else
4316   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
4317     level->score[i] = 0;
4318 #endif
4319
4320   /* there are no yamyams in supaplex levels */
4321   for (i = 0; i < level->num_yamyam_contents; i++)
4322     for (x = 0; x < 3; x++)
4323       for (y = 0; y < 3; y++)
4324         level->yamyam_content[i].e[x][y] = EL_EMPTY;
4325 }
4326
4327 static void setTapeInfoToDefaults();
4328
4329 static void CopyNativeTape_SP_to_RND(struct LevelInfo *level)
4330 {
4331   struct LevelInfo_SP *level_sp = level->native_sp_level;
4332   struct DemoInfo_SP *demo = &level_sp->demo;
4333   int i;
4334
4335   /* always start with reliable default values */
4336   setTapeInfoToDefaults();
4337
4338   tape.level_nr = demo->level_nr;       /* (currently not used) */
4339   tape.length = demo->length - 1;       /* without "end of demo" byte */
4340   tape.random_seed = level_sp->header.DemoRandomSeed;
4341
4342   // tape.date = <SET FROM FILE DATE OF *.SP FILE>
4343
4344   for (i = 0; i < demo->length - 1; i++)
4345   {
4346     int demo_action = demo->data[i] & 0x0f;
4347     int demo_repeat = (demo->data[i] & 0xf0) >> 4;
4348
4349     tape.pos[i].action[0] = map_key_SP_to_RND(demo_action);
4350     tape.pos[i].delay = demo_repeat + 1;
4351   }
4352
4353   tape.length_seconds = GetTapeLength();
4354 }
4355
4356
4357 /* ------------------------------------------------------------------------- */
4358 /* functions for loading DC level                                            */
4359 /* ------------------------------------------------------------------------- */
4360
4361 #define DC_LEVEL_HEADER_SIZE            344
4362
4363 unsigned short getDecodedWord_DC(unsigned short data_encoded, boolean init)
4364 {
4365   static int last_data_encoded;
4366   static int offset1;
4367   static int offset2;
4368   int diff;
4369   int diff_hi, diff_lo;
4370   int data_hi, data_lo;
4371   unsigned short data_decoded;
4372
4373   if (init)
4374   {
4375     last_data_encoded = 0;
4376     offset1 = -1;
4377     offset2 = 0;
4378
4379     return 0;
4380   }
4381
4382   diff = data_encoded - last_data_encoded;
4383   diff_hi = diff & ~0xff;
4384   diff_lo = diff &  0xff;
4385
4386   offset2 += diff_lo;
4387
4388   data_hi = diff_hi - (offset1 << 8) + (offset2 & 0xff00);
4389   data_lo = (diff_lo + (data_hi >> 16)) & 0x00ff;
4390   data_hi = data_hi & 0xff00;
4391
4392   data_decoded = data_hi | data_lo;
4393
4394   last_data_encoded = data_encoded;
4395
4396   offset1 = (offset1 + 1) % 31;
4397   offset2 = offset2 & 0xff;
4398
4399   return data_decoded;
4400 }
4401
4402 int getMappedElement_DC(int element)
4403 {
4404   switch (element)
4405   {
4406     case 0x0000:
4407       element = EL_ROCK;
4408       break;
4409
4410       /* 0x0117 - 0x036e: (?) */
4411       /* EL_DIAMOND */
4412
4413       /* 0x042d - 0x0684: (?) */
4414       /* EL_EMERALD */
4415
4416     case 0x06f1:
4417       element = EL_NUT;
4418       break;
4419
4420     case 0x074c:
4421       element = EL_BOMB;
4422       break;
4423
4424     case 0x07a4:
4425       element = EL_PEARL;
4426       break;
4427
4428     case 0x0823:
4429       element = EL_CRYSTAL;
4430       break;
4431
4432     case 0x0e77:        /* quicksand (boulder) */
4433       element = EL_QUICKSAND_FAST_FULL;
4434       break;
4435
4436     case 0x0e99:        /* slow quicksand (boulder) */
4437       element = EL_QUICKSAND_FULL;
4438       break;
4439
4440     case 0x0ed2:
4441       element = EL_EM_EXIT_OPEN;
4442       break;
4443
4444     case 0x0ee3:
4445       element = EL_EM_EXIT_CLOSED;
4446       break;
4447
4448     case 0x0eeb:
4449       element = EL_EM_STEEL_EXIT_OPEN;
4450       break;
4451
4452     case 0x0efc:
4453       element = EL_EM_STEEL_EXIT_CLOSED;
4454       break;
4455
4456     case 0x0f4f:        /* dynamite (lit 1) */
4457       element = EL_EM_DYNAMITE_ACTIVE;
4458       break;
4459
4460     case 0x0f57:        /* dynamite (lit 2) */
4461       element = EL_EM_DYNAMITE_ACTIVE;
4462       break;
4463
4464     case 0x0f5f:        /* dynamite (lit 3) */
4465       element = EL_EM_DYNAMITE_ACTIVE;
4466       break;
4467
4468     case 0x0f67:        /* dynamite (lit 4) */
4469       element = EL_EM_DYNAMITE_ACTIVE;
4470       break;
4471
4472     case 0x0f81:
4473     case 0x0f82:
4474     case 0x0f83:
4475     case 0x0f84:
4476       element = EL_AMOEBA_WET;
4477       break;
4478
4479     case 0x0f85:
4480       element = EL_AMOEBA_DROP;
4481       break;
4482
4483     case 0x0fb9:
4484       element = EL_DC_MAGIC_WALL;
4485       break;
4486
4487     case 0x0fd0:
4488       element = EL_SPACESHIP_UP;
4489       break;
4490
4491     case 0x0fd9:
4492       element = EL_SPACESHIP_DOWN;
4493       break;
4494
4495     case 0x0ff1:
4496       element = EL_SPACESHIP_LEFT;
4497       break;
4498
4499     case 0x0ff9:
4500       element = EL_SPACESHIP_RIGHT;
4501       break;
4502
4503     case 0x1057:
4504       element = EL_BUG_UP;
4505       break;
4506
4507     case 0x1060:
4508       element = EL_BUG_DOWN;
4509       break;
4510
4511     case 0x1078:
4512       element = EL_BUG_LEFT;
4513       break;
4514
4515     case 0x1080:
4516       element = EL_BUG_RIGHT;
4517       break;
4518
4519     case 0x10de:
4520       element = EL_MOLE_UP;
4521       break;
4522
4523     case 0x10e7:
4524       element = EL_MOLE_DOWN;
4525       break;
4526
4527     case 0x10ff:
4528       element = EL_MOLE_LEFT;
4529       break;
4530
4531     case 0x1107:
4532       element = EL_MOLE_RIGHT;
4533       break;
4534
4535     case 0x11c0:
4536       element = EL_ROBOT;
4537       break;
4538
4539     case 0x13f5:
4540       element = EL_YAMYAM;
4541       break;
4542
4543     case 0x1425:
4544       element = EL_SWITCHGATE_OPEN;
4545       break;
4546
4547     case 0x1426:
4548       element = EL_SWITCHGATE_CLOSED;
4549       break;
4550
4551     case 0x1437:
4552       element = EL_DC_SWITCHGATE_SWITCH_UP;
4553       break;
4554
4555     case 0x143a:
4556       element = EL_TIMEGATE_CLOSED;
4557       break;
4558
4559     case 0x144c:        /* conveyor belt switch (green) */
4560       element = EL_CONVEYOR_BELT_3_SWITCH_MIDDLE;
4561       break;
4562
4563     case 0x144f:        /* conveyor belt switch (red) */
4564       element = EL_CONVEYOR_BELT_1_SWITCH_MIDDLE;
4565       break;
4566
4567     case 0x1452:        /* conveyor belt switch (blue) */
4568       element = EL_CONVEYOR_BELT_4_SWITCH_MIDDLE;
4569       break;
4570
4571     case 0x145b:
4572       element = EL_CONVEYOR_BELT_3_MIDDLE;
4573       break;
4574
4575     case 0x1463:
4576       element = EL_CONVEYOR_BELT_3_LEFT;
4577       break;
4578
4579     case 0x146b:
4580       element = EL_CONVEYOR_BELT_3_RIGHT;
4581       break;
4582
4583     case 0x1473:
4584       element = EL_CONVEYOR_BELT_1_MIDDLE;
4585       break;
4586
4587     case 0x147b:
4588       element = EL_CONVEYOR_BELT_1_LEFT;
4589       break;
4590
4591     case 0x1483:
4592       element = EL_CONVEYOR_BELT_1_RIGHT;
4593       break;
4594
4595     case 0x148b:
4596       element = EL_CONVEYOR_BELT_4_MIDDLE;
4597       break;
4598
4599     case 0x1493:
4600       element = EL_CONVEYOR_BELT_4_LEFT;
4601       break;
4602
4603     case 0x149b:
4604       element = EL_CONVEYOR_BELT_4_RIGHT;
4605       break;
4606
4607     case 0x14ac:
4608       element = EL_EXPANDABLE_WALL_HORIZONTAL;
4609       break;
4610
4611     case 0x14bd:
4612       element = EL_EXPANDABLE_WALL_VERTICAL;
4613       break;
4614
4615     case 0x14c6:
4616       element = EL_EXPANDABLE_WALL_ANY;
4617       break;
4618
4619     case 0x14ce:        /* growing steel wall (left/right) */
4620       element = EL_EXPANDABLE_STEELWALL_HORIZONTAL;
4621       break;
4622
4623     case 0x14df:        /* growing steel wall (up/down) */
4624       element = EL_EXPANDABLE_STEELWALL_VERTICAL;
4625       break;
4626
4627     case 0x14e8:        /* growing steel wall (up/down/left/right) */
4628       element = EL_EXPANDABLE_STEELWALL_ANY;
4629       break;
4630
4631     case 0x14e9:
4632       element = EL_SHIELD_DEADLY;
4633       break;
4634
4635     case 0x1501:
4636       element = EL_EXTRA_TIME;
4637       break;
4638
4639     case 0x154f:
4640       element = EL_ACID;
4641       break;
4642
4643     case 0x1577:
4644       element = EL_EMPTY_SPACE;
4645       break;
4646
4647     case 0x1578:        /* quicksand (empty) */
4648       element = EL_QUICKSAND_FAST_EMPTY;
4649       break;
4650
4651     case 0x1579:        /* slow quicksand (empty) */
4652       element = EL_QUICKSAND_EMPTY;
4653       break;
4654
4655       /* 0x157c - 0x158b: */
4656       /* EL_SAND */
4657
4658       /* 0x1590 - 0x159f: */
4659       /* EL_DC_LANDMINE */
4660
4661     case 0x15a0:
4662       element = EL_EM_DYNAMITE;
4663       break;
4664
4665     case 0x15a1:        /* key (red) */
4666       element = EL_EM_KEY_1;
4667       break;
4668
4669     case 0x15a2:        /* key (yellow) */
4670       element = EL_EM_KEY_2;
4671       break;
4672
4673     case 0x15a3:        /* key (blue) */
4674       element = EL_EM_KEY_4;
4675       break;
4676
4677     case 0x15a4:        /* key (green) */
4678       element = EL_EM_KEY_3;
4679       break;
4680
4681     case 0x15a5:        /* key (white) */
4682       element = EL_DC_KEY_WHITE;
4683       break;
4684
4685     case 0x15a6:
4686       element = EL_WALL_SLIPPERY;
4687       break;
4688
4689     case 0x15a7:
4690       element = EL_WALL;
4691       break;
4692
4693     case 0x15a8:        /* wall (not round) */
4694       element = EL_WALL;
4695       break;
4696
4697     case 0x15a9:        /* (blue) */
4698       element = EL_CHAR_A;
4699       break;
4700
4701     case 0x15aa:        /* (blue) */
4702       element = EL_CHAR_B;
4703       break;
4704
4705     case 0x15ab:        /* (blue) */
4706       element = EL_CHAR_C;
4707       break;
4708
4709     case 0x15ac:        /* (blue) */
4710       element = EL_CHAR_D;
4711       break;
4712
4713     case 0x15ad:        /* (blue) */
4714       element = EL_CHAR_E;
4715       break;
4716
4717     case 0x15ae:        /* (blue) */
4718       element = EL_CHAR_F;
4719       break;
4720
4721     case 0x15af:        /* (blue) */
4722       element = EL_CHAR_G;
4723       break;
4724
4725     case 0x15b0:        /* (blue) */
4726       element = EL_CHAR_H;
4727       break;
4728
4729     case 0x15b1:        /* (blue) */
4730       element = EL_CHAR_I;
4731       break;
4732
4733     case 0x15b2:        /* (blue) */
4734       element = EL_CHAR_J;
4735       break;
4736
4737     case 0x15b3:        /* (blue) */
4738       element = EL_CHAR_K;
4739       break;
4740
4741     case 0x15b4:        /* (blue) */
4742       element = EL_CHAR_L;
4743       break;
4744
4745     case 0x15b5:        /* (blue) */
4746       element = EL_CHAR_M;
4747       break;
4748
4749     case 0x15b6:        /* (blue) */
4750       element = EL_CHAR_N;
4751       break;
4752
4753     case 0x15b7:        /* (blue) */
4754       element = EL_CHAR_O;
4755       break;
4756
4757     case 0x15b8:        /* (blue) */
4758       element = EL_CHAR_P;
4759       break;
4760
4761     case 0x15b9:        /* (blue) */
4762       element = EL_CHAR_Q;
4763       break;
4764
4765     case 0x15ba:        /* (blue) */
4766       element = EL_CHAR_R;
4767       break;
4768
4769     case 0x15bb:        /* (blue) */
4770       element = EL_CHAR_S;
4771       break;
4772
4773     case 0x15bc:        /* (blue) */
4774       element = EL_CHAR_T;
4775       break;
4776
4777     case 0x15bd:        /* (blue) */
4778       element = EL_CHAR_U;
4779       break;
4780
4781     case 0x15be:        /* (blue) */
4782       element = EL_CHAR_V;
4783       break;
4784
4785     case 0x15bf:        /* (blue) */
4786       element = EL_CHAR_W;
4787       break;
4788
4789     case 0x15c0:        /* (blue) */
4790       element = EL_CHAR_X;
4791       break;
4792
4793     case 0x15c1:        /* (blue) */
4794       element = EL_CHAR_Y;
4795       break;
4796
4797     case 0x15c2:        /* (blue) */
4798       element = EL_CHAR_Z;
4799       break;
4800
4801     case 0x15c3:        /* (blue) */
4802       element = EL_CHAR_AUMLAUT;
4803       break;
4804
4805     case 0x15c4:        /* (blue) */
4806       element = EL_CHAR_OUMLAUT;
4807       break;
4808
4809     case 0x15c5:        /* (blue) */
4810       element = EL_CHAR_UUMLAUT;
4811       break;
4812
4813     case 0x15c6:        /* (blue) */
4814       element = EL_CHAR_0;
4815       break;
4816
4817     case 0x15c7:        /* (blue) */
4818       element = EL_CHAR_1;
4819       break;
4820
4821     case 0x15c8:        /* (blue) */
4822       element = EL_CHAR_2;
4823       break;
4824
4825     case 0x15c9:        /* (blue) */
4826       element = EL_CHAR_3;
4827       break;
4828
4829     case 0x15ca:        /* (blue) */
4830       element = EL_CHAR_4;
4831       break;
4832
4833     case 0x15cb:        /* (blue) */
4834       element = EL_CHAR_5;
4835       break;
4836
4837     case 0x15cc:        /* (blue) */
4838       element = EL_CHAR_6;
4839       break;
4840
4841     case 0x15cd:        /* (blue) */
4842       element = EL_CHAR_7;
4843       break;
4844
4845     case 0x15ce:        /* (blue) */
4846       element = EL_CHAR_8;
4847       break;
4848
4849     case 0x15cf:        /* (blue) */
4850       element = EL_CHAR_9;
4851       break;
4852
4853     case 0x15d0:        /* (blue) */
4854       element = EL_CHAR_PERIOD;
4855       break;
4856
4857     case 0x15d1:        /* (blue) */
4858       element = EL_CHAR_EXCLAM;
4859       break;
4860
4861     case 0x15d2:        /* (blue) */
4862       element = EL_CHAR_COLON;
4863       break;
4864
4865     case 0x15d3:        /* (blue) */
4866       element = EL_CHAR_LESS;
4867       break;
4868
4869     case 0x15d4:        /* (blue) */
4870       element = EL_CHAR_GREATER;
4871       break;
4872
4873     case 0x15d5:        /* (blue) */
4874       element = EL_CHAR_QUESTION;
4875       break;
4876
4877     case 0x15d6:        /* (blue) */
4878       element = EL_CHAR_COPYRIGHT;
4879       break;
4880
4881     case 0x15d7:        /* (blue) */
4882       element = EL_CHAR_UP;
4883       break;
4884
4885     case 0x15d8:        /* (blue) */
4886       element = EL_CHAR_DOWN;
4887       break;
4888
4889     case 0x15d9:        /* (blue) */
4890       element = EL_CHAR_BUTTON;
4891       break;
4892
4893     case 0x15da:        /* (blue) */
4894       element = EL_CHAR_PLUS;
4895       break;
4896
4897     case 0x15db:        /* (blue) */
4898       element = EL_CHAR_MINUS;
4899       break;
4900
4901     case 0x15dc:        /* (blue) */
4902       element = EL_CHAR_APOSTROPHE;
4903       break;
4904
4905     case 0x15dd:        /* (blue) */
4906       element = EL_CHAR_PARENLEFT;
4907       break;
4908
4909     case 0x15de:        /* (blue) */
4910       element = EL_CHAR_PARENRIGHT;
4911       break;
4912
4913     case 0x15df:        /* (green) */
4914       element = EL_CHAR_A;
4915       break;
4916
4917     case 0x15e0:        /* (green) */
4918       element = EL_CHAR_B;
4919       break;
4920
4921     case 0x15e1:        /* (green) */
4922       element = EL_CHAR_C;
4923       break;
4924
4925     case 0x15e2:        /* (green) */
4926       element = EL_CHAR_D;
4927       break;
4928
4929     case 0x15e3:        /* (green) */
4930       element = EL_CHAR_E;
4931       break;
4932
4933     case 0x15e4:        /* (green) */
4934       element = EL_CHAR_F;
4935       break;
4936
4937     case 0x15e5:        /* (green) */
4938       element = EL_CHAR_G;
4939       break;
4940
4941     case 0x15e6:        /* (green) */
4942       element = EL_CHAR_H;
4943       break;
4944
4945     case 0x15e7:        /* (green) */
4946       element = EL_CHAR_I;
4947       break;
4948
4949     case 0x15e8:        /* (green) */
4950       element = EL_CHAR_J;
4951       break;
4952
4953     case 0x15e9:        /* (green) */
4954       element = EL_CHAR_K;
4955       break;
4956
4957     case 0x15ea:        /* (green) */
4958       element = EL_CHAR_L;
4959       break;
4960
4961     case 0x15eb:        /* (green) */
4962       element = EL_CHAR_M;
4963       break;
4964
4965     case 0x15ec:        /* (green) */
4966       element = EL_CHAR_N;
4967       break;
4968
4969     case 0x15ed:        /* (green) */
4970       element = EL_CHAR_O;
4971       break;
4972
4973     case 0x15ee:        /* (green) */
4974       element = EL_CHAR_P;
4975       break;
4976
4977     case 0x15ef:        /* (green) */
4978       element = EL_CHAR_Q;
4979       break;
4980
4981     case 0x15f0:        /* (green) */
4982       element = EL_CHAR_R;
4983       break;
4984
4985     case 0x15f1:        /* (green) */
4986       element = EL_CHAR_S;
4987       break;
4988
4989     case 0x15f2:        /* (green) */
4990       element = EL_CHAR_T;
4991       break;
4992
4993     case 0x15f3:        /* (green) */
4994       element = EL_CHAR_U;
4995       break;
4996
4997     case 0x15f4:        /* (green) */
4998       element = EL_CHAR_V;
4999       break;
5000
5001     case 0x15f5:        /* (green) */
5002       element = EL_CHAR_W;
5003       break;
5004
5005     case 0x15f6:        /* (green) */
5006       element = EL_CHAR_X;
5007       break;
5008
5009     case 0x15f7:        /* (green) */
5010       element = EL_CHAR_Y;
5011       break;
5012
5013     case 0x15f8:        /* (green) */
5014       element = EL_CHAR_Z;
5015       break;
5016
5017     case 0x15f9:        /* (green) */
5018       element = EL_CHAR_AUMLAUT;
5019       break;
5020
5021     case 0x15fa:        /* (green) */
5022       element = EL_CHAR_OUMLAUT;
5023       break;
5024
5025     case 0x15fb:        /* (green) */
5026       element = EL_CHAR_UUMLAUT;
5027       break;
5028
5029     case 0x15fc:        /* (green) */
5030       element = EL_CHAR_0;
5031       break;
5032
5033     case 0x15fd:        /* (green) */
5034       element = EL_CHAR_1;
5035       break;
5036
5037     case 0x15fe:        /* (green) */
5038       element = EL_CHAR_2;
5039       break;
5040
5041     case 0x15ff:        /* (green) */
5042       element = EL_CHAR_3;
5043       break;
5044
5045     case 0x1600:        /* (green) */
5046       element = EL_CHAR_4;
5047       break;
5048
5049     case 0x1601:        /* (green) */
5050       element = EL_CHAR_5;
5051       break;
5052
5053     case 0x1602:        /* (green) */
5054       element = EL_CHAR_6;
5055       break;
5056
5057     case 0x1603:        /* (green) */
5058       element = EL_CHAR_7;
5059       break;
5060
5061     case 0x1604:        /* (green) */
5062       element = EL_CHAR_8;
5063       break;
5064
5065     case 0x1605:        /* (green) */
5066       element = EL_CHAR_9;
5067       break;
5068
5069     case 0x1606:        /* (green) */
5070       element = EL_CHAR_PERIOD;
5071       break;
5072
5073     case 0x1607:        /* (green) */
5074       element = EL_CHAR_EXCLAM;
5075       break;
5076
5077     case 0x1608:        /* (green) */
5078       element = EL_CHAR_COLON;
5079       break;
5080
5081     case 0x1609:        /* (green) */
5082       element = EL_CHAR_LESS;
5083       break;
5084
5085     case 0x160a:        /* (green) */
5086       element = EL_CHAR_GREATER;
5087       break;
5088
5089     case 0x160b:        /* (green) */
5090       element = EL_CHAR_QUESTION;
5091       break;
5092
5093     case 0x160c:        /* (green) */
5094       element = EL_CHAR_COPYRIGHT;
5095       break;
5096
5097     case 0x160d:        /* (green) */
5098       element = EL_CHAR_UP;
5099       break;
5100
5101     case 0x160e:        /* (green) */
5102       element = EL_CHAR_DOWN;
5103       break;
5104
5105     case 0x160f:        /* (green) */
5106       element = EL_CHAR_BUTTON;
5107       break;
5108
5109     case 0x1610:        /* (green) */
5110       element = EL_CHAR_PLUS;
5111       break;
5112
5113     case 0x1611:        /* (green) */
5114       element = EL_CHAR_MINUS;
5115       break;
5116
5117     case 0x1612:        /* (green) */
5118       element = EL_CHAR_APOSTROPHE;
5119       break;
5120
5121     case 0x1613:        /* (green) */
5122       element = EL_CHAR_PARENLEFT;
5123       break;
5124
5125     case 0x1614:        /* (green) */
5126       element = EL_CHAR_PARENRIGHT;
5127       break;
5128
5129     case 0x1615:        /* (blue steel) */
5130       element = EL_STEEL_CHAR_A;
5131       break;
5132
5133     case 0x1616:        /* (blue steel) */
5134       element = EL_STEEL_CHAR_B;
5135       break;
5136
5137     case 0x1617:        /* (blue steel) */
5138       element = EL_STEEL_CHAR_C;
5139       break;
5140
5141     case 0x1618:        /* (blue steel) */
5142       element = EL_STEEL_CHAR_D;
5143       break;
5144
5145     case 0x1619:        /* (blue steel) */
5146       element = EL_STEEL_CHAR_E;
5147       break;
5148
5149     case 0x161a:        /* (blue steel) */
5150       element = EL_STEEL_CHAR_F;
5151       break;
5152
5153     case 0x161b:        /* (blue steel) */
5154       element = EL_STEEL_CHAR_G;
5155       break;
5156
5157     case 0x161c:        /* (blue steel) */
5158       element = EL_STEEL_CHAR_H;
5159       break;
5160
5161     case 0x161d:        /* (blue steel) */
5162       element = EL_STEEL_CHAR_I;
5163       break;
5164
5165     case 0x161e:        /* (blue steel) */
5166       element = EL_STEEL_CHAR_J;
5167       break;
5168
5169     case 0x161f:        /* (blue steel) */
5170       element = EL_STEEL_CHAR_K;
5171       break;
5172
5173     case 0x1620:        /* (blue steel) */
5174       element = EL_STEEL_CHAR_L;
5175       break;
5176
5177     case 0x1621:        /* (blue steel) */
5178       element = EL_STEEL_CHAR_M;
5179       break;
5180
5181     case 0x1622:        /* (blue steel) */
5182       element = EL_STEEL_CHAR_N;
5183       break;
5184
5185     case 0x1623:        /* (blue steel) */
5186       element = EL_STEEL_CHAR_O;
5187       break;
5188
5189     case 0x1624:        /* (blue steel) */
5190       element = EL_STEEL_CHAR_P;
5191       break;
5192
5193     case 0x1625:        /* (blue steel) */
5194       element = EL_STEEL_CHAR_Q;
5195       break;
5196
5197     case 0x1626:        /* (blue steel) */
5198       element = EL_STEEL_CHAR_R;
5199       break;
5200
5201     case 0x1627:        /* (blue steel) */
5202       element = EL_STEEL_CHAR_S;
5203       break;
5204
5205     case 0x1628:        /* (blue steel) */
5206       element = EL_STEEL_CHAR_T;
5207       break;
5208
5209     case 0x1629:        /* (blue steel) */
5210       element = EL_STEEL_CHAR_U;
5211       break;
5212
5213     case 0x162a:        /* (blue steel) */
5214       element = EL_STEEL_CHAR_V;
5215       break;
5216
5217     case 0x162b:        /* (blue steel) */
5218       element = EL_STEEL_CHAR_W;
5219       break;
5220
5221     case 0x162c:        /* (blue steel) */
5222       element = EL_STEEL_CHAR_X;
5223       break;
5224
5225     case 0x162d:        /* (blue steel) */
5226       element = EL_STEEL_CHAR_Y;
5227       break;
5228
5229     case 0x162e:        /* (blue steel) */
5230       element = EL_STEEL_CHAR_Z;
5231       break;
5232
5233     case 0x162f:        /* (blue steel) */
5234       element = EL_STEEL_CHAR_AUMLAUT;
5235       break;
5236
5237     case 0x1630:        /* (blue steel) */
5238       element = EL_STEEL_CHAR_OUMLAUT;
5239       break;
5240
5241     case 0x1631:        /* (blue steel) */
5242       element = EL_STEEL_CHAR_UUMLAUT;
5243       break;
5244
5245     case 0x1632:        /* (blue steel) */
5246       element = EL_STEEL_CHAR_0;
5247       break;
5248
5249     case 0x1633:        /* (blue steel) */
5250       element = EL_STEEL_CHAR_1;
5251       break;
5252
5253     case 0x1634:        /* (blue steel) */
5254       element = EL_STEEL_CHAR_2;
5255       break;
5256
5257     case 0x1635:        /* (blue steel) */
5258       element = EL_STEEL_CHAR_3;
5259       break;
5260
5261     case 0x1636:        /* (blue steel) */
5262       element = EL_STEEL_CHAR_4;
5263       break;
5264
5265     case 0x1637:        /* (blue steel) */
5266       element = EL_STEEL_CHAR_5;
5267       break;
5268
5269     case 0x1638:        /* (blue steel) */
5270       element = EL_STEEL_CHAR_6;
5271       break;
5272
5273     case 0x1639:        /* (blue steel) */
5274       element = EL_STEEL_CHAR_7;
5275       break;
5276
5277     case 0x163a:        /* (blue steel) */
5278       element = EL_STEEL_CHAR_8;
5279       break;
5280
5281     case 0x163b:        /* (blue steel) */
5282       element = EL_STEEL_CHAR_9;
5283       break;
5284
5285     case 0x163c:        /* (blue steel) */
5286       element = EL_STEEL_CHAR_PERIOD;
5287       break;
5288
5289     case 0x163d:        /* (blue steel) */
5290       element = EL_STEEL_CHAR_EXCLAM;
5291       break;
5292
5293     case 0x163e:        /* (blue steel) */
5294       element = EL_STEEL_CHAR_COLON;
5295       break;
5296
5297     case 0x163f:        /* (blue steel) */
5298       element = EL_STEEL_CHAR_LESS;
5299       break;
5300
5301     case 0x1640:        /* (blue steel) */
5302       element = EL_STEEL_CHAR_GREATER;
5303       break;
5304
5305     case 0x1641:        /* (blue steel) */
5306       element = EL_STEEL_CHAR_QUESTION;
5307       break;
5308
5309     case 0x1642:        /* (blue steel) */
5310       element = EL_STEEL_CHAR_COPYRIGHT;
5311       break;
5312
5313     case 0x1643:        /* (blue steel) */
5314       element = EL_STEEL_CHAR_UP;
5315       break;
5316
5317     case 0x1644:        /* (blue steel) */
5318       element = EL_STEEL_CHAR_DOWN;
5319       break;
5320
5321     case 0x1645:        /* (blue steel) */
5322       element = EL_STEEL_CHAR_BUTTON;
5323       break;
5324
5325     case 0x1646:        /* (blue steel) */
5326       element = EL_STEEL_CHAR_PLUS;
5327       break;
5328
5329     case 0x1647:        /* (blue steel) */
5330       element = EL_STEEL_CHAR_MINUS;
5331       break;
5332
5333     case 0x1648:        /* (blue steel) */
5334       element = EL_STEEL_CHAR_APOSTROPHE;
5335       break;
5336
5337     case 0x1649:        /* (blue steel) */
5338       element = EL_STEEL_CHAR_PARENLEFT;
5339       break;
5340
5341     case 0x164a:        /* (blue steel) */
5342       element = EL_STEEL_CHAR_PARENRIGHT;
5343       break;
5344
5345     case 0x164b:        /* (green steel) */
5346       element = EL_STEEL_CHAR_A;
5347       break;
5348
5349     case 0x164c:        /* (green steel) */
5350       element = EL_STEEL_CHAR_B;
5351       break;
5352
5353     case 0x164d:        /* (green steel) */
5354       element = EL_STEEL_CHAR_C;
5355       break;
5356
5357     case 0x164e:        /* (green steel) */
5358       element = EL_STEEL_CHAR_D;
5359       break;
5360
5361     case 0x164f:        /* (green steel) */
5362       element = EL_STEEL_CHAR_E;
5363       break;
5364
5365     case 0x1650:        /* (green steel) */
5366       element = EL_STEEL_CHAR_F;
5367       break;
5368
5369     case 0x1651:        /* (green steel) */
5370       element = EL_STEEL_CHAR_G;
5371       break;
5372
5373     case 0x1652:        /* (green steel) */
5374       element = EL_STEEL_CHAR_H;
5375       break;
5376
5377     case 0x1653:        /* (green steel) */
5378       element = EL_STEEL_CHAR_I;
5379       break;
5380
5381     case 0x1654:        /* (green steel) */
5382       element = EL_STEEL_CHAR_J;
5383       break;
5384
5385     case 0x1655:        /* (green steel) */
5386       element = EL_STEEL_CHAR_K;
5387       break;
5388
5389     case 0x1656:        /* (green steel) */
5390       element = EL_STEEL_CHAR_L;
5391       break;
5392
5393     case 0x1657:        /* (green steel) */
5394       element = EL_STEEL_CHAR_M;
5395       break;
5396
5397     case 0x1658:        /* (green steel) */
5398       element = EL_STEEL_CHAR_N;
5399       break;
5400
5401     case 0x1659:        /* (green steel) */
5402       element = EL_STEEL_CHAR_O;
5403       break;
5404
5405     case 0x165a:        /* (green steel) */
5406       element = EL_STEEL_CHAR_P;
5407       break;
5408
5409     case 0x165b:        /* (green steel) */
5410       element = EL_STEEL_CHAR_Q;
5411       break;
5412
5413     case 0x165c:        /* (green steel) */
5414       element = EL_STEEL_CHAR_R;
5415       break;
5416
5417     case 0x165d:        /* (green steel) */
5418       element = EL_STEEL_CHAR_S;
5419       break;
5420
5421     case 0x165e:        /* (green steel) */
5422       element = EL_STEEL_CHAR_T;
5423       break;
5424
5425     case 0x165f:        /* (green steel) */
5426       element = EL_STEEL_CHAR_U;
5427       break;
5428
5429     case 0x1660:        /* (green steel) */
5430       element = EL_STEEL_CHAR_V;
5431       break;
5432
5433     case 0x1661:        /* (green steel) */
5434       element = EL_STEEL_CHAR_W;
5435       break;
5436
5437     case 0x1662:        /* (green steel) */
5438       element = EL_STEEL_CHAR_X;
5439       break;
5440
5441     case 0x1663:        /* (green steel) */
5442       element = EL_STEEL_CHAR_Y;
5443       break;
5444
5445     case 0x1664:        /* (green steel) */
5446       element = EL_STEEL_CHAR_Z;
5447       break;
5448
5449     case 0x1665:        /* (green steel) */
5450       element = EL_STEEL_CHAR_AUMLAUT;
5451       break;
5452
5453     case 0x1666:        /* (green steel) */
5454       element = EL_STEEL_CHAR_OUMLAUT;
5455       break;
5456
5457     case 0x1667:        /* (green steel) */
5458       element = EL_STEEL_CHAR_UUMLAUT;
5459       break;
5460
5461     case 0x1668:        /* (green steel) */
5462       element = EL_STEEL_CHAR_0;
5463       break;
5464
5465     case 0x1669:        /* (green steel) */
5466       element = EL_STEEL_CHAR_1;
5467       break;
5468
5469     case 0x166a:        /* (green steel) */
5470       element = EL_STEEL_CHAR_2;
5471       break;
5472
5473     case 0x166b:        /* (green steel) */
5474       element = EL_STEEL_CHAR_3;
5475       break;
5476
5477     case 0x166c:        /* (green steel) */
5478       element = EL_STEEL_CHAR_4;
5479       break;
5480
5481     case 0x166d:        /* (green steel) */
5482       element = EL_STEEL_CHAR_5;
5483       break;
5484
5485     case 0x166e:        /* (green steel) */
5486       element = EL_STEEL_CHAR_6;
5487       break;
5488
5489     case 0x166f:        /* (green steel) */
5490       element = EL_STEEL_CHAR_7;
5491       break;
5492
5493     case 0x1670:        /* (green steel) */
5494       element = EL_STEEL_CHAR_8;
5495       break;
5496
5497     case 0x1671:        /* (green steel) */
5498       element = EL_STEEL_CHAR_9;
5499       break;
5500
5501     case 0x1672:        /* (green steel) */
5502       element = EL_STEEL_CHAR_PERIOD;
5503       break;
5504
5505     case 0x1673:        /* (green steel) */
5506       element = EL_STEEL_CHAR_EXCLAM;
5507       break;
5508
5509     case 0x1674:        /* (green steel) */
5510       element = EL_STEEL_CHAR_COLON;
5511       break;
5512
5513     case 0x1675:        /* (green steel) */
5514       element = EL_STEEL_CHAR_LESS;
5515       break;
5516
5517     case 0x1676:        /* (green steel) */
5518       element = EL_STEEL_CHAR_GREATER;
5519       break;
5520
5521     case 0x1677:        /* (green steel) */
5522       element = EL_STEEL_CHAR_QUESTION;
5523       break;
5524
5525     case 0x1678:        /* (green steel) */
5526       element = EL_STEEL_CHAR_COPYRIGHT;
5527       break;
5528
5529     case 0x1679:        /* (green steel) */
5530       element = EL_STEEL_CHAR_UP;
5531       break;
5532
5533     case 0x167a:        /* (green steel) */
5534       element = EL_STEEL_CHAR_DOWN;
5535       break;
5536
5537     case 0x167b:        /* (green steel) */
5538       element = EL_STEEL_CHAR_BUTTON;
5539       break;
5540
5541     case 0x167c:        /* (green steel) */
5542       element = EL_STEEL_CHAR_PLUS;
5543       break;
5544
5545     case 0x167d:        /* (green steel) */
5546       element = EL_STEEL_CHAR_MINUS;
5547       break;
5548
5549     case 0x167e:        /* (green steel) */
5550       element = EL_STEEL_CHAR_APOSTROPHE;
5551       break;
5552
5553     case 0x167f:        /* (green steel) */
5554       element = EL_STEEL_CHAR_PARENLEFT;
5555       break;
5556
5557     case 0x1680:        /* (green steel) */
5558       element = EL_STEEL_CHAR_PARENRIGHT;
5559       break;
5560
5561     case 0x1681:        /* gate (red) */
5562       element = EL_EM_GATE_1;
5563       break;
5564
5565     case 0x1682:        /* secret gate (red) */
5566       element = EL_GATE_1_GRAY;
5567       break;
5568
5569     case 0x1683:        /* gate (yellow) */
5570       element = EL_EM_GATE_2;
5571       break;
5572
5573     case 0x1684:        /* secret gate (yellow) */
5574       element = EL_GATE_2_GRAY;
5575       break;
5576
5577     case 0x1685:        /* gate (blue) */
5578       element = EL_EM_GATE_4;
5579       break;
5580
5581     case 0x1686:        /* secret gate (blue) */
5582       element = EL_GATE_4_GRAY;
5583       break;
5584
5585     case 0x1687:        /* gate (green) */
5586       element = EL_EM_GATE_3;
5587       break;
5588
5589     case 0x1688:        /* secret gate (green) */
5590       element = EL_GATE_3_GRAY;
5591       break;
5592
5593     case 0x1689:        /* gate (white) */
5594       element = EL_DC_GATE_WHITE;
5595       break;
5596
5597     case 0x168a:        /* secret gate (white) */
5598       element = EL_DC_GATE_WHITE_GRAY;
5599       break;
5600
5601     case 0x168b:        /* secret gate (no key) */
5602       element = EL_DC_GATE_FAKE_GRAY;
5603       break;
5604
5605     case 0x168c:
5606       element = EL_ROBOT_WHEEL;
5607       break;
5608
5609     case 0x168d:
5610       element = EL_DC_TIMEGATE_SWITCH;
5611       break;
5612
5613     case 0x168e:
5614       element = EL_ACID_POOL_BOTTOM;
5615       break;
5616
5617     case 0x168f:
5618       element = EL_ACID_POOL_TOPLEFT;
5619       break;
5620
5621     case 0x1690:
5622       element = EL_ACID_POOL_TOPRIGHT;
5623       break;
5624
5625     case 0x1691:
5626       element = EL_ACID_POOL_BOTTOMLEFT;
5627       break;
5628
5629     case 0x1692:
5630       element = EL_ACID_POOL_BOTTOMRIGHT;
5631       break;
5632
5633     case 0x1693:
5634       element = EL_STEELWALL;
5635       break;
5636
5637     case 0x1694:
5638       element = EL_STEELWALL_SLIPPERY;
5639       break;
5640
5641     case 0x1695:        /* steel wall (not round) */
5642       element = EL_STEELWALL;
5643       break;
5644
5645     case 0x1696:        /* steel wall (left) */
5646       element = EL_DC_STEELWALL_1_LEFT;
5647       break;
5648
5649     case 0x1697:        /* steel wall (bottom) */
5650       element = EL_DC_STEELWALL_1_BOTTOM;
5651       break;
5652
5653     case 0x1698:        /* steel wall (right) */
5654       element = EL_DC_STEELWALL_1_RIGHT;
5655       break;
5656
5657     case 0x1699:        /* steel wall (top) */
5658       element = EL_DC_STEELWALL_1_TOP;
5659       break;
5660
5661     case 0x169a:        /* steel wall (left/bottom) */
5662       element = EL_DC_STEELWALL_1_BOTTOMLEFT;
5663       break;
5664
5665     case 0x169b:        /* steel wall (right/bottom) */
5666       element = EL_DC_STEELWALL_1_BOTTOMRIGHT;
5667       break;
5668
5669     case 0x169c:        /* steel wall (right/top) */
5670       element = EL_DC_STEELWALL_1_TOPRIGHT;
5671       break;
5672
5673     case 0x169d:        /* steel wall (left/top) */
5674       element = EL_DC_STEELWALL_1_TOPLEFT;
5675       break;
5676
5677     case 0x169e:        /* steel wall (right/bottom small) */
5678       element = EL_DC_STEELWALL_1_BOTTOMRIGHT_2;
5679       break;
5680
5681     case 0x169f:        /* steel wall (left/bottom small) */
5682       element = EL_DC_STEELWALL_1_BOTTOMLEFT_2;
5683       break;
5684
5685     case 0x16a0:        /* steel wall (right/top small) */
5686       element = EL_DC_STEELWALL_1_TOPRIGHT_2;
5687       break;
5688
5689     case 0x16a1:        /* steel wall (left/top small) */
5690       element = EL_DC_STEELWALL_1_TOPLEFT_2;
5691       break;
5692
5693     case 0x16a2:        /* steel wall (left/right) */
5694       element = EL_DC_STEELWALL_1_VERTICAL;
5695       break;
5696
5697     case 0x16a3:        /* steel wall (top/bottom) */
5698       element = EL_DC_STEELWALL_1_HORIZONTAL;
5699       break;
5700
5701     case 0x16a4:        /* steel wall 2 (left end) */
5702       element = EL_DC_STEELWALL_2_LEFT;
5703       break;
5704
5705     case 0x16a5:        /* steel wall 2 (right end) */
5706       element = EL_DC_STEELWALL_2_RIGHT;
5707       break;
5708
5709     case 0x16a6:        /* steel wall 2 (top end) */
5710       element = EL_DC_STEELWALL_2_TOP;
5711       break;
5712
5713     case 0x16a7:        /* steel wall 2 (bottom end) */
5714       element = EL_DC_STEELWALL_2_BOTTOM;
5715       break;
5716
5717     case 0x16a8:        /* steel wall 2 (left/right) */
5718       element = EL_DC_STEELWALL_2_HORIZONTAL;
5719       break;
5720
5721     case 0x16a9:        /* steel wall 2 (up/down) */
5722       element = EL_DC_STEELWALL_2_VERTICAL;
5723       break;
5724
5725     case 0x16aa:        /* steel wall 2 (mid) */
5726       element = EL_DC_STEELWALL_2_MIDDLE;
5727       break;
5728
5729     case 0x16ab:
5730       element = EL_SIGN_EXCLAMATION;
5731       break;
5732
5733     case 0x16ac:
5734       element = EL_SIGN_RADIOACTIVITY;
5735       break;
5736
5737     case 0x16ad:
5738       element = EL_SIGN_STOP;
5739       break;
5740
5741     case 0x16ae:
5742       element = EL_SIGN_WHEELCHAIR;
5743       break;
5744
5745     case 0x16af:
5746       element = EL_SIGN_PARKING;
5747       break;
5748
5749     case 0x16b0:
5750       element = EL_SIGN_NO_ENTRY;
5751       break;
5752
5753     case 0x16b1:
5754       element = EL_SIGN_HEART;
5755       break;
5756
5757     case 0x16b2:
5758       element = EL_SIGN_GIVE_WAY;
5759       break;
5760
5761     case 0x16b3:
5762       element = EL_SIGN_ENTRY_FORBIDDEN;
5763       break;
5764
5765     case 0x16b4:
5766       element = EL_SIGN_EMERGENCY_EXIT;
5767       break;
5768
5769     case 0x16b5:
5770       element = EL_SIGN_YIN_YANG;
5771       break;
5772
5773     case 0x16b6:
5774       element = EL_WALL_EMERALD;
5775       break;
5776
5777     case 0x16b7:
5778       element = EL_WALL_DIAMOND;
5779       break;
5780
5781     case 0x16b8:
5782       element = EL_WALL_PEARL;
5783       break;
5784
5785     case 0x16b9:
5786       element = EL_WALL_CRYSTAL;
5787       break;
5788
5789     case 0x16ba:
5790       element = EL_INVISIBLE_WALL;
5791       break;
5792
5793     case 0x16bb:
5794       element = EL_INVISIBLE_STEELWALL;
5795       break;
5796
5797       /* 0x16bc - 0x16cb: */
5798       /* EL_INVISIBLE_SAND */
5799
5800     case 0x16cc:
5801       element = EL_LIGHT_SWITCH;
5802       break;
5803
5804     case 0x16cd:
5805       element = EL_ENVELOPE_1;
5806       break;
5807
5808     default:
5809       if (element >= 0x0117 && element <= 0x036e)       /* (?) */
5810         element = EL_DIAMOND;
5811       else if (element >= 0x042d && element <= 0x0684)  /* (?) */
5812         element = EL_EMERALD;
5813       else if (element >= 0x157c && element <= 0x158b)
5814         element = EL_SAND;
5815       else if (element >= 0x1590 && element <= 0x159f)
5816         element = EL_DC_LANDMINE;
5817       else if (element >= 0x16bc && element <= 0x16cb)
5818         element = EL_INVISIBLE_SAND;
5819       else
5820       {
5821         Error(ERR_WARN, "unknown Diamond Caves element 0x%04x", element);
5822         element = EL_UNKNOWN;
5823       }
5824       break;
5825   }
5826
5827   return getMappedElement(element);
5828 }
5829
5830 #if 1
5831
5832 static void LoadLevelFromFileStream_DC(FILE *file, struct LevelInfo *level,
5833                                        int nr)
5834 {
5835   byte header[DC_LEVEL_HEADER_SIZE];
5836   int envelope_size;
5837   int envelope_header_pos = 62;
5838   int envelope_content_pos = 94;
5839   int level_name_pos = 251;
5840   int level_author_pos = 292;
5841   int envelope_header_len;
5842   int envelope_content_len;
5843   int level_name_len;
5844   int level_author_len;
5845   int fieldx, fieldy;
5846   int num_yamyam_contents;
5847   int i, x, y;
5848
5849   getDecodedWord_DC(0, TRUE);           /* initialize DC2 decoding engine */
5850
5851   for (i = 0; i < DC_LEVEL_HEADER_SIZE / 2; i++)
5852   {
5853     unsigned short header_word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
5854
5855     header[i * 2 + 0] = header_word >> 8;
5856     header[i * 2 + 1] = header_word & 0xff;
5857   }
5858
5859   /* read some values from level header to check level decoding integrity */
5860   fieldx = header[6] | (header[7] << 8);
5861   fieldy = header[8] | (header[9] << 8);
5862   num_yamyam_contents = header[60] | (header[61] << 8);
5863
5864   /* do some simple sanity checks to ensure that level was correctly decoded */
5865   if (fieldx < 1 || fieldx > 256 ||
5866       fieldy < 1 || fieldy > 256 ||
5867       num_yamyam_contents < 1 || num_yamyam_contents > 8)
5868   {
5869     level->no_valid_file = TRUE;
5870
5871     Error(ERR_WARN, "cannot decode level from stream -- using empty level");
5872
5873     return;
5874   }
5875
5876   /* maximum envelope header size is 31 bytes */
5877   envelope_header_len   = header[envelope_header_pos];
5878   /* maximum envelope content size is 110 (156?) bytes */
5879   envelope_content_len  = header[envelope_content_pos];
5880
5881   /* maximum level title size is 40 bytes */
5882   level_name_len        = MIN(header[level_name_pos],   MAX_LEVEL_NAME_LEN);
5883   /* maximum level author size is 30 (51?) bytes */
5884   level_author_len      = MIN(header[level_author_pos], MAX_LEVEL_AUTHOR_LEN);
5885
5886   envelope_size = 0;
5887
5888   for (i = 0; i < envelope_header_len; i++)
5889     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
5890       level->envelope[0].text[envelope_size++] =
5891         header[envelope_header_pos + 1 + i];
5892
5893   if (envelope_header_len > 0 && envelope_content_len > 0)
5894   {
5895     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
5896       level->envelope[0].text[envelope_size++] = '\n';
5897     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
5898       level->envelope[0].text[envelope_size++] = '\n';
5899   }
5900
5901   for (i = 0; i < envelope_content_len; i++)
5902     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
5903       level->envelope[0].text[envelope_size++] =
5904         header[envelope_content_pos + 1 + i];
5905
5906   level->envelope[0].text[envelope_size] = '\0';
5907
5908   level->envelope[0].xsize = MAX_ENVELOPE_XSIZE;
5909   level->envelope[0].ysize = 10;
5910   level->envelope[0].autowrap = TRUE;
5911   level->envelope[0].centered = TRUE;
5912
5913   for (i = 0; i < level_name_len; i++)
5914     level->name[i] = header[level_name_pos + 1 + i];
5915   level->name[level_name_len] = '\0';
5916
5917   for (i = 0; i < level_author_len; i++)
5918     level->author[i] = header[level_author_pos + 1 + i];
5919   level->author[level_author_len] = '\0';
5920
5921   num_yamyam_contents = header[60] | (header[61] << 8);
5922   level->num_yamyam_contents =
5923     MIN(MAX(MIN_ELEMENT_CONTENTS, num_yamyam_contents), MAX_ELEMENT_CONTENTS);
5924
5925   for (i = 0; i < num_yamyam_contents; i++)
5926   {
5927     for (y = 0; y < 3; y++) for (x = 0; x < 3; x++)
5928     {
5929       unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
5930 #if 1
5931       int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff);
5932 #else
5933       int element_dc = word;
5934 #endif
5935
5936       if (i < MAX_ELEMENT_CONTENTS)
5937         level->yamyam_content[i].e[x][y] = getMappedElement_DC(element_dc);
5938     }
5939   }
5940
5941   fieldx = header[6] | (header[7] << 8);
5942   fieldy = header[8] | (header[9] << 8);
5943   level->fieldx = MIN(MAX(MIN_LEV_FIELDX, fieldx), MAX_LEV_FIELDX);
5944   level->fieldy = MIN(MAX(MIN_LEV_FIELDY, fieldy), MAX_LEV_FIELDY);
5945
5946   for (y = 0; y < fieldy; y++) for (x = 0; x < fieldx; x++)
5947   {
5948     unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
5949 #if 1
5950     int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff);
5951 #else
5952     int element_dc = word;
5953 #endif
5954
5955     if (x < MAX_LEV_FIELDX && y < MAX_LEV_FIELDY)
5956       level->field[x][y] = getMappedElement_DC(element_dc);
5957   }
5958
5959   x = MIN(MAX(0, (header[10] | (header[11] << 8)) - 1), MAX_LEV_FIELDX - 1);
5960   y = MIN(MAX(0, (header[12] | (header[13] << 8)) - 1), MAX_LEV_FIELDY - 1);
5961   level->field[x][y] = EL_PLAYER_1;
5962
5963   x = MIN(MAX(0, (header[14] | (header[15] << 8)) - 1), MAX_LEV_FIELDX - 1);
5964   y = MIN(MAX(0, (header[16] | (header[17] << 8)) - 1), MAX_LEV_FIELDY - 1);
5965   level->field[x][y] = EL_PLAYER_2;
5966
5967   level->gems_needed            = header[18] | (header[19] << 8);
5968
5969   level->score[SC_EMERALD]      = header[20] | (header[21] << 8);
5970   level->score[SC_DIAMOND]      = header[22] | (header[23] << 8);
5971   level->score[SC_PEARL]        = header[24] | (header[25] << 8);
5972   level->score[SC_CRYSTAL]      = header[26] | (header[27] << 8);
5973   level->score[SC_NUT]          = header[28] | (header[29] << 8);
5974   level->score[SC_ROBOT]        = header[30] | (header[31] << 8);
5975   level->score[SC_SPACESHIP]    = header[32] | (header[33] << 8);
5976   level->score[SC_BUG]          = header[34] | (header[35] << 8);
5977   level->score[SC_YAMYAM]       = header[36] | (header[37] << 8);
5978   level->score[SC_DYNAMITE]     = header[38] | (header[39] << 8);
5979   level->score[SC_KEY]          = header[40] | (header[41] << 8);
5980   level->score[SC_TIME_BONUS]   = header[42] | (header[43] << 8);
5981
5982   level->time                   = header[44] | (header[45] << 8);
5983
5984   level->amoeba_speed           = header[46] | (header[47] << 8);
5985   level->time_light             = header[48] | (header[49] << 8);
5986   level->time_timegate          = header[50] | (header[51] << 8);
5987   level->time_wheel             = header[52] | (header[53] << 8);
5988   level->time_magic_wall        = header[54] | (header[55] << 8);
5989   level->extra_time             = header[56] | (header[57] << 8);
5990   level->shield_normal_time     = header[58] | (header[59] << 8);
5991
5992   /* Diamond Caves has the same (strange) behaviour as Emerald Mine that gems
5993      can slip down from flat walls, like normal walls and steel walls */
5994   level->em_slippery_gems = TRUE;
5995
5996 #if 0
5997   /* Diamond Caves II levels are always surrounded by indestructible wall, but
5998      not necessarily in a rectangular way -- fill with invisible steel wall */
5999
6000   /* !!! not always true !!! keep level and set BorderElement instead !!! */
6001
6002   for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
6003   {
6004 #if 1
6005     if ((x == 0 || x == level->fieldx - 1 ||
6006          y == 0 || y == level->fieldy - 1) &&
6007         level->field[x][y] == EL_EMPTY)
6008       level->field[x][y] = EL_INVISIBLE_STEELWALL;
6009 #else
6010     if ((x == 0 || x == level->fieldx - 1 ||
6011          y == 0 || y == level->fieldy - 1) &&
6012         level->field[x][y] == EL_EMPTY)
6013       FloodFillLevel(x, y, EL_INVISIBLE_STEELWALL,
6014                      level->field, level->fieldx, level->fieldy);
6015 #endif
6016   }
6017 #endif
6018 }
6019
6020 static void LoadLevelFromFileInfo_DC(struct LevelInfo *level,
6021                                      struct LevelFileInfo *level_file_info)
6022 {
6023   char *filename = level_file_info->filename;
6024   FILE *file;
6025   int num_magic_bytes = 8;
6026   char magic_bytes[num_magic_bytes + 1];
6027   int num_levels_to_skip = level_file_info->nr - leveldir_current->first_level;
6028
6029   if (!(file = fopen(filename, MODE_READ)))
6030   {
6031     level->no_valid_file = TRUE;
6032
6033     Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
6034
6035     return;
6036   }
6037
6038   // fseek(file, 0x0000, SEEK_SET);
6039
6040   if (level_file_info->packed)
6041   {
6042     /* read "magic bytes" from start of file */
6043     fgets(magic_bytes, num_magic_bytes + 1, file);
6044
6045     /* check "magic bytes" for correct file format */
6046     if (!strPrefix(magic_bytes, "DC2"))
6047     {
6048       level->no_valid_file = TRUE;
6049
6050       Error(ERR_WARN, "unknown DC level file '%s' -- using empty level",
6051             filename);
6052
6053       return;
6054     }
6055
6056     if (strPrefix(magic_bytes, "DC2Win95") ||
6057         strPrefix(magic_bytes, "DC2Win98"))
6058     {
6059       int position_first_level = 0x00fa;
6060       int extra_bytes = 4;
6061       int skip_bytes;
6062
6063       /* advance file stream to first level inside the level package */
6064       skip_bytes = position_first_level - num_magic_bytes - extra_bytes;
6065
6066       /* each block of level data is followed by block of non-level data */
6067       num_levels_to_skip *= 2;
6068
6069       /* at least skip header bytes, therefore use ">= 0" instead of "> 0" */
6070       while (num_levels_to_skip >= 0)
6071       {
6072         /* advance file stream to next level inside the level package */
6073         if (fseek(file, skip_bytes, SEEK_CUR) != 0)
6074         {
6075           level->no_valid_file = TRUE;
6076
6077           Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level",
6078                 filename);
6079
6080           return;
6081         }
6082
6083         /* skip apparently unused extra bytes following each level */
6084         ReadUnusedBytesFromFile(file, extra_bytes);
6085
6086         /* read size of next level in level package */
6087         skip_bytes = getFile32BitLE(file);
6088
6089         num_levels_to_skip--;
6090       }
6091     }
6092     else
6093     {
6094       level->no_valid_file = TRUE;
6095
6096       Error(ERR_WARN, "unknown DC2 level file '%s' -- using empty level",
6097             filename);
6098
6099       return;
6100     }
6101   }
6102
6103   LoadLevelFromFileStream_DC(file, level, level_file_info->nr);
6104
6105   fclose(file);
6106 }
6107
6108 #else
6109
6110 static void LoadLevelFromFileInfo_DC(struct LevelInfo *level,
6111                                      struct LevelFileInfo *level_file_info)
6112 {
6113   char *filename = level_file_info->filename;
6114   FILE *file;
6115 #if 0
6116   int nr = level_file_info->nr - leveldir_current->first_level;
6117 #endif
6118   byte header[DC_LEVEL_HEADER_SIZE];
6119   int envelope_size;
6120   int envelope_header_pos = 62;
6121   int envelope_content_pos = 94;
6122   int level_name_pos = 251;
6123   int level_author_pos = 292;
6124   int envelope_header_len;
6125   int envelope_content_len;
6126   int level_name_len;
6127   int level_author_len;
6128   int fieldx, fieldy;
6129   int num_yamyam_contents;
6130   int i, x, y;
6131
6132   if (!(file = fopen(filename, MODE_READ)))
6133   {
6134     level->no_valid_file = TRUE;
6135
6136     Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
6137
6138     return;
6139   }
6140
6141 #if 0
6142   /* position file stream to the requested level inside the level package */
6143   if (fseek(file, nr * SP_LEVEL_SIZE, SEEK_SET) != 0)
6144   {
6145     level->no_valid_file = TRUE;
6146
6147     Error(ERR_WARN, "cannot fseek in file '%s' -- using empty level", filename);
6148
6149     return;
6150   }
6151 #endif
6152
6153   getDecodedWord_DC(0, TRUE);           /* initialize DC2 decoding engine */
6154
6155   for (i = 0; i < DC_LEVEL_HEADER_SIZE / 2; i++)
6156   {
6157     unsigned short header_word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
6158
6159     header[i * 2 + 0] = header_word >> 8;
6160     header[i * 2 + 1] = header_word & 0xff;
6161   }
6162
6163   /* read some values from level header to check level decoding integrity */
6164   fieldx = header[6] | (header[7] << 8);
6165   fieldy = header[8] | (header[9] << 8);
6166   num_yamyam_contents = header[60] | (header[61] << 8);
6167
6168   /* do some simple sanity checks to ensure that level was correctly decoded */
6169   if (fieldx < 1 || fieldx > 256 ||
6170       fieldy < 1 || fieldy > 256 ||
6171       num_yamyam_contents < 1 || num_yamyam_contents > 8)
6172   {
6173     level->no_valid_file = TRUE;
6174
6175     Error(ERR_WARN, "cannot read level from file '%s' -- using empty level",
6176           filename);
6177
6178     return;
6179   }
6180
6181   /* maximum envelope header size is 31 bytes */
6182   envelope_header_len   = header[envelope_header_pos];
6183   /* maximum envelope content size is 110 (156?) bytes */
6184   envelope_content_len  = header[envelope_content_pos];
6185
6186   /* maximum level title size is 40 bytes */
6187   level_name_len        = MIN(header[level_name_pos],   MAX_LEVEL_NAME_LEN);
6188   /* maximum level author size is 30 (51?) bytes */
6189   level_author_len      = MIN(header[level_author_pos], MAX_LEVEL_AUTHOR_LEN);
6190
6191   envelope_size = 0;
6192
6193   for (i = 0; i < envelope_header_len; i++)
6194     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
6195       level->envelope[0].text[envelope_size++] =
6196         header[envelope_header_pos + 1 + i];
6197
6198   if (envelope_header_len > 0 && envelope_content_len > 0)
6199   {
6200     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
6201       level->envelope[0].text[envelope_size++] = '\n';
6202     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
6203       level->envelope[0].text[envelope_size++] = '\n';
6204   }
6205
6206   for (i = 0; i < envelope_content_len; i++)
6207     if (envelope_size < MAX_ENVELOPE_TEXT_LEN)
6208       level->envelope[0].text[envelope_size++] =
6209         header[envelope_content_pos + 1 + i];
6210
6211   level->envelope[0].text[envelope_size] = '\0';
6212
6213   level->envelope[0].xsize = MAX_ENVELOPE_XSIZE;
6214   level->envelope[0].ysize = 10;
6215   level->envelope[0].autowrap = TRUE;
6216   level->envelope[0].centered = TRUE;
6217
6218   for (i = 0; i < level_name_len; i++)
6219     level->name[i] = header[level_name_pos + 1 + i];
6220   level->name[level_name_len] = '\0';
6221
6222   for (i = 0; i < level_author_len; i++)
6223     level->author[i] = header[level_author_pos + 1 + i];
6224   level->author[level_author_len] = '\0';
6225
6226   num_yamyam_contents = header[60] | (header[61] << 8);
6227   level->num_yamyam_contents =
6228     MIN(MAX(MIN_ELEMENT_CONTENTS, num_yamyam_contents), MAX_ELEMENT_CONTENTS);
6229
6230   for (i = 0; i < num_yamyam_contents; i++)
6231   {
6232     for (y = 0; y < 3; y++) for (x = 0; x < 3; x++)
6233     {
6234       unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
6235 #if 1
6236       int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff);
6237 #else
6238       int element_dc = word;
6239 #endif
6240
6241       if (i < MAX_ELEMENT_CONTENTS)
6242         level->yamyam_content[i].e[x][y] = getMappedElement_DC(element_dc);
6243     }
6244   }
6245
6246   fieldx = header[6] | (header[7] << 8);
6247   fieldy = header[8] | (header[9] << 8);
6248   level->fieldx = MIN(MAX(MIN_LEV_FIELDX, fieldx), MAX_LEV_FIELDX);
6249   level->fieldy = MIN(MAX(MIN_LEV_FIELDY, fieldy), MAX_LEV_FIELDY);
6250
6251   for (y = 0; y < fieldy; y++) for (x = 0; x < fieldx; x++)
6252   {
6253     unsigned short word = getDecodedWord_DC(getFile16BitBE(file), FALSE);
6254 #if 1
6255     int element_dc = ((word & 0xff) << 8) | ((word >> 8) & 0xff);
6256 #else
6257     int element_dc = word;
6258 #endif
6259
6260     if (x < MAX_LEV_FIELDX && y < MAX_LEV_FIELDY)
6261       level->field[x][y] = getMappedElement_DC(element_dc);
6262   }
6263
6264   x = MIN(MAX(0, (header[10] | (header[11] << 8)) - 1), MAX_LEV_FIELDX - 1);
6265   y = MIN(MAX(0, (header[12] | (header[13] << 8)) - 1), MAX_LEV_FIELDY - 1);
6266   level->field[x][y] = EL_PLAYER_1;
6267
6268   x = MIN(MAX(0, (header[14] | (header[15] << 8)) - 1), MAX_LEV_FIELDX - 1);
6269   y = MIN(MAX(0, (header[16] | (header[17] << 8)) - 1), MAX_LEV_FIELDY - 1);
6270   level->field[x][y] = EL_PLAYER_2;
6271
6272   level->gems_needed            = header[18] | (header[19] << 8);
6273
6274   level->score[SC_EMERALD]      = header[20] | (header[21] << 8);
6275   level->score[SC_DIAMOND]      = header[22] | (header[23] << 8);
6276   level->score[SC_PEARL]        = header[24] | (header[25] << 8);
6277   level->score[SC_CRYSTAL]      = header[26] | (header[27] << 8);
6278   level->score[SC_NUT]          = header[28] | (header[29] << 8);
6279   level->score[SC_ROBOT]        = header[30] | (header[31] << 8);
6280   level->score[SC_SPACESHIP]    = header[32] | (header[33] << 8);
6281   level->score[SC_BUG]          = header[34] | (header[35] << 8);
6282   level->score[SC_YAMYAM]       = header[36] | (header[37] << 8);
6283   level->score[SC_DYNAMITE]     = header[38] | (header[39] << 8);
6284   level->score[SC_KEY]          = header[40] | (header[41] << 8);
6285   level->score[SC_TIME_BONUS]   = header[42] | (header[43] << 8);
6286
6287   level->time                   = header[44] | (header[45] << 8);
6288
6289   level->amoeba_speed           = header[46] | (header[47] << 8);
6290   level->time_light             = header[48] | (header[49] << 8);
6291   level->time_timegate          = header[50] | (header[51] << 8);
6292   level->time_wheel             = header[52] | (header[53] << 8);
6293   level->time_magic_wall        = header[54] | (header[55] << 8);
6294   level->extra_time             = header[56] | (header[57] << 8);
6295   level->shield_normal_time     = header[58] | (header[59] << 8);
6296
6297   fclose(file);
6298
6299   /* Diamond Caves has the same (strange) behaviour as Emerald Mine that gems
6300      can slip down from flat walls, like normal walls and steel walls */
6301   level->em_slippery_gems = TRUE;
6302
6303 #if 0
6304   /* Diamond Caves II levels are always surrounded by indestructible wall, but
6305      not necessarily in a rectangular way -- fill with invisible steel wall */
6306
6307   /* !!! not always true !!! keep level and set BorderElement instead !!! */
6308
6309   for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
6310   {
6311 #if 1
6312     if ((x == 0 || x == level->fieldx - 1 ||
6313          y == 0 || y == level->fieldy - 1) &&
6314         level->field[x][y] == EL_EMPTY)
6315       level->field[x][y] = EL_INVISIBLE_STEELWALL;
6316 #else
6317     if ((x == 0 || x == level->fieldx - 1 ||
6318          y == 0 || y == level->fieldy - 1) &&
6319         level->field[x][y] == EL_EMPTY)
6320       FloodFillLevel(x, y, EL_INVISIBLE_STEELWALL,
6321                      level->field, level->fieldx, level->fieldy);
6322 #endif
6323   }
6324 #endif
6325 }
6326
6327 #endif
6328
6329
6330 /* ------------------------------------------------------------------------- */
6331 /* functions for loading SB level                                            */
6332 /* ------------------------------------------------------------------------- */
6333
6334 static void LoadLevelFromFileInfo_SB(struct LevelInfo *level,
6335                                      struct LevelFileInfo *level_file_info)
6336 {
6337   char *filename = level_file_info->filename;
6338   char line[MAX_LINE_LEN], line_raw[MAX_LINE_LEN], previous_line[MAX_LINE_LEN];
6339   char last_comment[MAX_LINE_LEN];
6340   char level_name[MAX_LINE_LEN];
6341   char *line_ptr;
6342   FILE *file;
6343   int num_levels_to_skip = level_file_info->nr - leveldir_current->first_level;
6344   boolean read_continued_line = FALSE;
6345   boolean reading_playfield = FALSE;
6346   boolean got_valid_playfield_line = FALSE;
6347   boolean invalid_playfield_char = FALSE;
6348   int file_level_nr = 0;
6349   int line_nr = 0;
6350   int x, y;
6351
6352   if (!(file = fopen(filename, MODE_READ)))
6353   {
6354     level->no_valid_file = TRUE;
6355
6356     Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
6357
6358     return;
6359   }
6360
6361 #if 0
6362   printf("::: looking for level number %d [%d]\n",
6363          level_file_info->nr, num_levels_to_skip);
6364 #endif
6365
6366   last_comment[0] = '\0';
6367   level_name[0] = '\0';
6368
6369   while (!feof(file))
6370   {
6371     /* level successfully read, but next level may follow here */
6372     if (!got_valid_playfield_line && reading_playfield)
6373     {
6374 #if 0
6375       printf("::: read complete playfield\n");
6376 #endif
6377
6378       /* read playfield from single level file -- skip remaining file */
6379       if (!level_file_info->packed)
6380         break;
6381
6382       if (file_level_nr >= num_levels_to_skip)
6383         break;
6384
6385       file_level_nr++;
6386
6387       last_comment[0] = '\0';
6388       level_name[0] = '\0';
6389
6390       reading_playfield = FALSE;
6391     }
6392
6393     got_valid_playfield_line = FALSE;
6394
6395     /* read next line of input file */
6396     if (!fgets(line, MAX_LINE_LEN, file))
6397       break;
6398
6399     /* check if line was completely read and is terminated by line break */
6400     if (strlen(line) > 0 && line[strlen(line) - 1] == '\n')
6401       line_nr++;
6402
6403     /* cut trailing line break (this can be newline and/or carriage return) */
6404     for (line_ptr = &line[strlen(line)]; line_ptr >= line; line_ptr--)
6405       if ((*line_ptr == '\n' || *line_ptr == '\r') && *(line_ptr + 1) == '\0')
6406         *line_ptr = '\0';
6407
6408     /* copy raw input line for later use (mainly debugging output) */
6409     strcpy(line_raw, line);
6410
6411     if (read_continued_line)
6412     {
6413       /* append new line to existing line, if there is enough space */
6414       if (strlen(previous_line) + strlen(line_ptr) < MAX_LINE_LEN)
6415         strcat(previous_line, line_ptr);
6416
6417       strcpy(line, previous_line);      /* copy storage buffer to line */
6418
6419       read_continued_line = FALSE;
6420     }
6421
6422     /* if the last character is '\', continue at next line */
6423     if (strlen(line) > 0 && line[strlen(line) - 1] == '\\')
6424     {
6425       line[strlen(line) - 1] = '\0';    /* cut off trailing backslash */
6426       strcpy(previous_line, line);      /* copy line to storage buffer */
6427
6428       read_continued_line = TRUE;
6429
6430       continue;
6431     }
6432
6433     /* skip empty lines */
6434     if (line[0] == '\0')
6435       continue;
6436
6437     /* extract comment text from comment line */
6438     if (line[0] == ';')
6439     {
6440       for (line_ptr = line; *line_ptr; line_ptr++)
6441         if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != ';')
6442           break;
6443
6444       strcpy(last_comment, line_ptr);
6445
6446 #if 0
6447       printf("::: found comment '%s' in line %d\n", last_comment, line_nr);
6448 #endif
6449
6450       continue;
6451     }
6452
6453     /* extract level title text from line containing level title */
6454     if (line[0] == '\'')
6455     {
6456       strcpy(level_name, &line[1]);
6457
6458       if (strlen(level_name) > 0 && level_name[strlen(level_name) - 1] == '\'')
6459         level_name[strlen(level_name) - 1] = '\0';
6460
6461 #if 0
6462       printf("::: found level name '%s' in line %d\n", level_name, line_nr);
6463 #endif
6464
6465       continue;
6466     }
6467
6468     /* skip lines containing only spaces (or empty lines) */
6469     for (line_ptr = line; *line_ptr; line_ptr++)
6470       if (*line_ptr != ' ')
6471         break;
6472     if (*line_ptr == '\0')
6473       continue;
6474
6475     /* at this point, we have found a line containing part of a playfield */
6476
6477 #if 0
6478     printf("::: found playfield row in line %d\n", line_nr);
6479 #endif
6480
6481     got_valid_playfield_line = TRUE;
6482
6483     if (!reading_playfield)
6484     {
6485       reading_playfield = TRUE;
6486       invalid_playfield_char = FALSE;
6487
6488       for (x = 0; x < MAX_LEV_FIELDX; x++)
6489         for (y = 0; y < MAX_LEV_FIELDY; y++)
6490           level->field[x][y] = EL_EMPTY;
6491
6492       level->fieldx = 0;
6493       level->fieldy = 0;
6494
6495       /* start with topmost tile row */
6496       y = 0;
6497     }
6498
6499     /* skip playfield line if larger row than allowed */
6500     if (y >= MAX_LEV_FIELDY)
6501       continue;
6502
6503     /* start with leftmost tile column */
6504     x = 0;
6505
6506     /* read playfield elements from line */
6507     for (line_ptr = line; *line_ptr; line_ptr++)
6508     {
6509       /* stop parsing playfield line if larger column than allowed */
6510       if (x >= MAX_LEV_FIELDX)
6511         break;
6512
6513       switch (*line_ptr)
6514       {
6515         case '#':               /* wall */
6516           level->field[x][y] = EL_STEELWALL;
6517           break;
6518
6519         case '@':               /* player */
6520           level->field[x][y] = EL_PLAYER_1;
6521           break;
6522
6523         case '+':               /* player on goal square */
6524           level->field[x][y] = EL_SOKOBAN_FIELD_PLAYER;
6525           break;
6526
6527         case '$':               /* box */
6528           level->field[x][y] = EL_SOKOBAN_OBJECT;
6529           break;
6530
6531         case '*':               /* box on goal square */
6532           level->field[x][y] = EL_SOKOBAN_FIELD_FULL;
6533           break;
6534
6535         case '.':               /* goal square */
6536           level->field[x][y] = EL_SOKOBAN_FIELD_EMPTY;
6537           break;
6538
6539         case ' ':               /* floor (space) */
6540           level->field[x][y] = EL_EMPTY;
6541           break;
6542
6543         default:
6544           invalid_playfield_char = TRUE;
6545           break;
6546       }
6547
6548       if (invalid_playfield_char)
6549         break;
6550
6551       /* continue with next tile column */
6552       x++;
6553
6554       level->fieldx = MAX(x, level->fieldx);
6555     }
6556
6557     if (invalid_playfield_char)
6558     {
6559       /* if first playfield line, treat invalid lines as comment lines */
6560       if (y == 0)
6561         reading_playfield = FALSE;
6562
6563       continue;
6564     }
6565
6566     /* continue with next tile row */
6567     y++;
6568   }
6569
6570   level->fieldy = y;
6571
6572   level->fieldx = MIN(MAX(MIN_LEV_FIELDX, level->fieldx), MAX_LEV_FIELDX);
6573   level->fieldy = MIN(MAX(MIN_LEV_FIELDY, level->fieldy), MAX_LEV_FIELDY);
6574
6575   fclose(file);
6576
6577   if (!reading_playfield)
6578   {
6579     level->no_valid_file = TRUE;
6580
6581     Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
6582
6583     return;
6584   }
6585
6586   if (*level_name != '\0')
6587   {
6588     strncpy(level->name, level_name, MAX_LEVEL_NAME_LEN);
6589     level->name[MAX_LEVEL_NAME_LEN] = '\0';
6590
6591 #if 0
6592     printf(":1: level name: '%s'\n", level->name);
6593 #endif
6594   }
6595   else if (*last_comment != '\0')
6596   {
6597     strncpy(level->name, last_comment, MAX_LEVEL_NAME_LEN);
6598     level->name[MAX_LEVEL_NAME_LEN] = '\0';
6599
6600 #if 0
6601     printf(":2: level name: '%s'\n", level->name);
6602 #endif
6603   }
6604   else
6605   {
6606     sprintf(level->name, "--> Level %d <--", level_file_info->nr);
6607   }
6608 }
6609
6610
6611 /* ------------------------------------------------------------------------- */
6612 /* functions for handling native levels                                      */
6613 /* ------------------------------------------------------------------------- */
6614
6615 static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,
6616                                      struct LevelFileInfo *level_file_info)
6617 {
6618   if (!LoadNativeLevel_EM(level_file_info->filename))
6619     level->no_valid_file = TRUE;
6620 }
6621
6622 static void LoadLevelFromFileInfo_SP(struct LevelInfo *level,
6623                                      struct LevelFileInfo *level_file_info)
6624 {
6625   int pos = 0;
6626
6627   /* determine position of requested level inside level package */
6628   if (level_file_info->packed)
6629     pos = level_file_info->nr - leveldir_current->first_level;
6630
6631   if (!LoadNativeLevel_SP(level_file_info->filename, pos))
6632     level->no_valid_file = TRUE;
6633 }
6634
6635 void CopyNativeLevel_RND_to_Native(struct LevelInfo *level)
6636 {
6637   if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
6638     CopyNativeLevel_RND_to_EM(level);
6639   else if (level->game_engine_type == GAME_ENGINE_TYPE_SP)
6640     CopyNativeLevel_RND_to_SP(level);
6641 }
6642
6643 void CopyNativeLevel_Native_to_RND(struct LevelInfo *level)
6644 {
6645   if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
6646     CopyNativeLevel_EM_to_RND(level);
6647   else if (level->game_engine_type == GAME_ENGINE_TYPE_SP)
6648     CopyNativeLevel_SP_to_RND(level);
6649 }
6650
6651
6652 /* ------------------------------------------------------------------------- */
6653 /* functions for loading generic level                                       */
6654 /* ------------------------------------------------------------------------- */
6655
6656 void LoadLevelFromFileInfo(struct LevelInfo *level,
6657                            struct LevelFileInfo *level_file_info)
6658 {
6659   /* always start with reliable default values */
6660   setLevelInfoToDefaults(level);
6661
6662   switch (level_file_info->type)
6663   {
6664     case LEVEL_FILE_TYPE_RND:
6665       LoadLevelFromFileInfo_RND(level, level_file_info);
6666       break;
6667
6668     case LEVEL_FILE_TYPE_EM:
6669       LoadLevelFromFileInfo_EM(level, level_file_info);
6670       level->game_engine_type = GAME_ENGINE_TYPE_EM;
6671       break;
6672
6673     case LEVEL_FILE_TYPE_SP:
6674       LoadLevelFromFileInfo_SP(level, level_file_info);
6675       level->game_engine_type = GAME_ENGINE_TYPE_SP;
6676       break;
6677
6678     case LEVEL_FILE_TYPE_DC:
6679       LoadLevelFromFileInfo_DC(level, level_file_info);
6680       break;
6681
6682     case LEVEL_FILE_TYPE_SB:
6683       LoadLevelFromFileInfo_SB(level, level_file_info);
6684       break;
6685
6686     default:
6687       LoadLevelFromFileInfo_RND(level, level_file_info);
6688       break;
6689   }
6690
6691   /* if level file is invalid, restore level structure to default values */
6692   if (level->no_valid_file)
6693     setLevelInfoToDefaults(level);
6694
6695   if (level->game_engine_type == GAME_ENGINE_TYPE_UNKNOWN)
6696     level->game_engine_type = GAME_ENGINE_TYPE_RND;
6697
6698   if (level_file_info->type != LEVEL_FILE_TYPE_RND)
6699     CopyNativeLevel_Native_to_RND(level);
6700 }
6701
6702 void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
6703 {
6704   static struct LevelFileInfo level_file_info;
6705
6706   /* always start with reliable default values */
6707   setFileInfoToDefaults(&level_file_info);
6708
6709   level_file_info.nr = 0;                       /* unknown level number */
6710   level_file_info.type = LEVEL_FILE_TYPE_RND;   /* no others supported yet */
6711   level_file_info.filename = filename;
6712
6713   LoadLevelFromFileInfo(level, &level_file_info);
6714 }
6715
6716 static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
6717 {
6718   int i, j;
6719
6720   if (leveldir_current == NULL)         /* only when dumping level */
6721     return;
6722
6723   /* all engine modifications also valid for levels which use latest engine */
6724   if (level->game_version < VERSION_IDENT(3,2,0,5))
6725   {
6726     /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */
6727     level->score[SC_TIME_BONUS] /= 10;
6728   }
6729
6730 #if 0
6731   leveldir_current->latest_engine = TRUE;       /* !!! TEST ONLY !!! */
6732 #endif
6733
6734   if (leveldir_current->latest_engine)
6735   {
6736     /* ---------- use latest game engine ----------------------------------- */
6737
6738     /* For all levels which are forced to use the latest game engine version
6739        (normally all but user contributed, private and undefined levels), set
6740        the game engine version to the actual version; this allows for actual
6741        corrections in the game engine to take effect for existing, converted
6742        levels (from "classic" or other existing games) to make the emulation
6743        of the corresponding game more accurate, while (hopefully) not breaking
6744        existing levels created from other players. */
6745
6746     level->game_version = GAME_VERSION_ACTUAL;
6747
6748     /* Set special EM style gems behaviour: EM style gems slip down from
6749        normal, steel and growing wall. As this is a more fundamental change,
6750        it seems better to set the default behaviour to "off" (as it is more
6751        natural) and make it configurable in the level editor (as a property
6752        of gem style elements). Already existing converted levels (neither
6753        private nor contributed levels) are changed to the new behaviour. */
6754
6755     if (level->file_version < FILE_VERSION_2_0)
6756       level->em_slippery_gems = TRUE;
6757
6758     return;
6759   }
6760
6761   /* ---------- use game engine the level was created with ----------------- */
6762
6763   /* For all levels which are not forced to use the latest game engine
6764      version (normally user contributed, private and undefined levels),
6765      use the version of the game engine the levels were created for.
6766
6767      Since 2.0.1, the game engine version is now directly stored
6768      in the level file (chunk "VERS"), so there is no need anymore
6769      to set the game version from the file version (except for old,
6770      pre-2.0 levels, where the game version is still taken from the
6771      file format version used to store the level -- see above). */
6772
6773   /* player was faster than enemies in 1.0.0 and before */
6774   if (level->file_version == FILE_VERSION_1_0)
6775     for (i = 0; i < MAX_PLAYERS; i++)
6776       level->initial_player_stepsize[i] = STEPSIZE_FAST;
6777
6778   /* default behaviour for EM style gems was "slippery" only in 2.0.1 */
6779   if (level->game_version == VERSION_IDENT(2,0,1,0))
6780     level->em_slippery_gems = TRUE;
6781
6782   /* springs could be pushed over pits before (pre-release version) 2.2.0 */
6783   if (level->game_version < VERSION_IDENT(2,2,0,0))
6784     level->use_spring_bug = TRUE;
6785
6786   if (level->game_version < VERSION_IDENT(3,2,0,5))
6787   {
6788     /* time orb caused limited time in endless time levels before 3.2.0-5 */
6789     level->use_time_orb_bug = TRUE;
6790
6791     /* default behaviour for snapping was "no snap delay" before 3.2.0-5 */
6792     level->block_snap_field = FALSE;
6793
6794     /* extra time score was same value as time left score before 3.2.0-5 */
6795     level->extra_time_score = level->score[SC_TIME_BONUS];
6796
6797 #if 0
6798     /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */
6799     level->score[SC_TIME_BONUS] /= 10;
6800 #endif
6801   }
6802
6803   if (level->game_version < VERSION_IDENT(3,2,0,7))
6804   {
6805     /* default behaviour for snapping was "not continuous" before 3.2.0-7 */
6806     level->continuous_snapping = FALSE;
6807   }
6808
6809   /* only few elements were able to actively move into acid before 3.1.0 */
6810   /* trigger settings did not exist before 3.1.0; set to default "any" */
6811   if (level->game_version < VERSION_IDENT(3,1,0,0))
6812   {
6813     /* correct "can move into acid" settings (all zero in old levels) */
6814
6815     level->can_move_into_acid_bits = 0; /* nothing can move into acid */
6816     level->dont_collide_with_bits = 0; /* nothing is deadly when colliding */
6817
6818     setMoveIntoAcidProperty(level, EL_ROBOT,     TRUE);
6819     setMoveIntoAcidProperty(level, EL_SATELLITE, TRUE);
6820     setMoveIntoAcidProperty(level, EL_PENGUIN,   TRUE);
6821     setMoveIntoAcidProperty(level, EL_BALLOON,   TRUE);
6822
6823     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6824       SET_PROPERTY(EL_CUSTOM_START + i, EP_CAN_MOVE_INTO_ACID, TRUE);
6825
6826     /* correct trigger settings (stored as zero == "none" in old levels) */
6827
6828     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6829     {
6830       int element = EL_CUSTOM_START + i;
6831       struct ElementInfo *ei = &element_info[element];
6832
6833       for (j = 0; j < ei->num_change_pages; j++)
6834       {
6835         struct ElementChangeInfo *change = &ei->change_page[j];
6836
6837         change->trigger_player = CH_PLAYER_ANY;
6838         change->trigger_page = CH_PAGE_ANY;
6839       }
6840     }
6841   }
6842
6843   /* try to detect and fix "Snake Bite" levels, which are broken with 3.2.0 */
6844   {
6845     int element = EL_CUSTOM_256;
6846     struct ElementInfo *ei = &element_info[element];
6847     struct ElementChangeInfo *change = &ei->change_page[0];
6848
6849     /* This is needed to fix a problem that was caused by a bugfix in function
6850        game.c/CreateFieldExt() introduced with 3.2.0 that corrects the behaviour
6851        when a custom element changes to EL_SOKOBAN_FIELD_PLAYER (before, it did
6852        not replace walkable elements, but instead just placed the player on it,
6853        without placing the Sokoban field under the player). Unfortunately, this
6854        breaks "Snake Bite" style levels when the snake is halfway through a door
6855        that just closes (the snake head is still alive and can be moved in this
6856        case). This can be fixed by replacing the EL_SOKOBAN_FIELD_PLAYER by the
6857        player (without Sokoban element) which then gets killed as designed). */
6858
6859     if ((strncmp(leveldir_current->identifier, "snake_bite", 10) == 0 ||
6860          strncmp(ei->description, "pause b4 death", 14) == 0) &&
6861         change->target_element == EL_SOKOBAN_FIELD_PLAYER)
6862       change->target_element = EL_PLAYER_1;
6863   }
6864
6865 #if 1
6866   /* try to detect and fix "Zelda" style levels, which are broken with 3.2.5 */
6867   if (level->game_version < VERSION_IDENT(3,2,5,0))
6868   {
6869     /* This is needed to fix a problem that was caused by a bugfix in function
6870        game.c/CheckTriggeredElementChangeExt() introduced with 3.2.5 that
6871        corrects the behaviour when a custom element changes to another custom
6872        element with a higher element number that has change actions defined.
6873        Normally, only one change per frame is allowed for custom elements.
6874        Therefore, it is checked if a custom element already changed in the
6875        current frame; if it did, subsequent changes are suppressed.
6876        Unfortunately, this is only checked for element changes, but not for
6877        change actions, which are still executed. As the function above loops
6878        through all custom elements from lower to higher, an element change
6879        resulting in a lower CE number won't be checked again, while a target
6880        element with a higher number will also be checked, and potential change
6881        actions will get executed for this CE, too (which is wrong), while
6882        further changes are ignored (which is correct). As this bugfix breaks
6883        Zelda II (and introduces graphical bugs to Zelda I, and also breaks a
6884        few other levels like Alan Bond's "FMV"), allow the previous, incorrect
6885        behaviour for existing levels and tapes that make use of this bug */
6886
6887     level->use_action_after_change_bug = TRUE;
6888   }
6889 #else
6890   /* !!! THIS DOES NOT FIX "Zelda I" (GRAPHICALLY) AND "Alan's FMV" LEVELS */
6891   /* try to detect and fix "Zelda II" levels, which are broken with 3.2.5 */
6892   {
6893     int element = EL_CUSTOM_16;
6894     struct ElementInfo *ei = &element_info[element];
6895
6896     /* This is needed to fix a problem that was caused by a bugfix in function
6897        game.c/CheckTriggeredElementChangeExt() introduced with 3.2.5 that
6898        corrects the behaviour when a custom element changes to another custom
6899        element with a higher element number that has change actions defined.
6900        Normally, only one change per frame is allowed for custom elements.
6901        Therefore, it is checked if a custom element already changed in the
6902        current frame; if it did, subsequent changes are suppressed.
6903        Unfortunately, this is only checked for element changes, but not for
6904        change actions, which are still executed. As the function above loops
6905        through all custom elements from lower to higher, an element change
6906        resulting in a lower CE number won't be checked again, while a target
6907        element with a higher number will also be checked, and potential change
6908        actions will get executed for this CE, too (which is wrong), while
6909        further changes are ignored (which is correct). As this bugfix breaks
6910        Zelda II (but no other levels), allow the previous, incorrect behaviour
6911        for this outstanding level set to not break the game or existing tapes */
6912
6913     if (strncmp(leveldir_current->identifier, "zelda2", 6) == 0 ||
6914         strncmp(ei->description, "scanline - row 1", 16) == 0)
6915       level->use_action_after_change_bug = TRUE;
6916   }
6917 #endif
6918
6919   /* not centering level after relocating player was default only in 3.2.3 */
6920   if (level->game_version == VERSION_IDENT(3,2,3,0))    /* (no pre-releases) */
6921     level->shifted_relocation = TRUE;
6922
6923   /* EM style elements always chain-exploded in R'n'D engine before 3.2.6 */
6924   if (level->game_version < VERSION_IDENT(3,2,6,0))
6925     level->em_explodes_by_fire = TRUE;
6926 }
6927
6928 static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
6929 {
6930   int i, j, x, y;
6931
6932   /* map custom element change events that have changed in newer versions
6933      (these following values were accidentally changed in version 3.0.1)
6934      (this seems to be needed only for 'ab_levelset3' and 'ab_levelset4') */
6935   if (level->game_version <= VERSION_IDENT(3,0,0,0))
6936   {
6937     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6938     {
6939       int element = EL_CUSTOM_START + i;
6940
6941       /* order of checking and copying events to be mapped is important */
6942       /* (do not change the start and end value -- they are constant) */
6943       for (j = CE_BY_OTHER_ACTION; j >= CE_VALUE_GETS_ZERO; j--)
6944       {
6945         if (HAS_CHANGE_EVENT(element, j - 2))
6946         {
6947           SET_CHANGE_EVENT(element, j - 2, FALSE);
6948           SET_CHANGE_EVENT(element, j, TRUE);
6949         }
6950       }
6951
6952       /* order of checking and copying events to be mapped is important */
6953       /* (do not change the start and end value -- they are constant) */
6954       for (j = CE_PLAYER_COLLECTS_X; j >= CE_HITTING_SOMETHING; j--)
6955       {
6956         if (HAS_CHANGE_EVENT(element, j - 1))
6957         {
6958           SET_CHANGE_EVENT(element, j - 1, FALSE);
6959           SET_CHANGE_EVENT(element, j, TRUE);
6960         }
6961       }
6962     }
6963   }
6964
6965   /* initialize "can_change" field for old levels with only one change page */
6966   if (level->game_version <= VERSION_IDENT(3,0,2,0))
6967   {
6968     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6969     {
6970       int element = EL_CUSTOM_START + i;
6971
6972       if (CAN_CHANGE(element))
6973         element_info[element].change->can_change = TRUE;
6974     }
6975   }
6976
6977   /* correct custom element values (for old levels without these options) */
6978   if (level->game_version < VERSION_IDENT(3,1,1,0))
6979   {
6980     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6981     {
6982       int element = EL_CUSTOM_START + i;
6983       struct ElementInfo *ei = &element_info[element];
6984
6985       if (ei->access_direction == MV_NO_DIRECTION)
6986         ei->access_direction = MV_ALL_DIRECTIONS;
6987     }
6988   }
6989
6990   /* correct custom element values (fix invalid values for all versions) */
6991   if (1)
6992   {
6993     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
6994     {
6995       int element = EL_CUSTOM_START + i;
6996       struct ElementInfo *ei = &element_info[element];
6997
6998       for (j = 0; j < ei->num_change_pages; j++)
6999       {
7000         struct ElementChangeInfo *change = &ei->change_page[j];
7001
7002         if (change->trigger_player == CH_PLAYER_NONE)
7003           change->trigger_player = CH_PLAYER_ANY;
7004
7005         if (change->trigger_side == CH_SIDE_NONE)
7006           change->trigger_side = CH_SIDE_ANY;
7007       }
7008     }
7009   }
7010
7011   /* initialize "can_explode" field for old levels which did not store this */
7012   /* !!! CHECK THIS -- "<= 3,1,0,0" IS PROBABLY WRONG !!! */
7013   if (level->game_version <= VERSION_IDENT(3,1,0,0))
7014   {
7015     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
7016     {
7017       int element = EL_CUSTOM_START + i;
7018
7019       if (EXPLODES_1X1_OLD(element))
7020         element_info[element].explosion_type = EXPLODES_1X1;
7021
7022       SET_PROPERTY(element, EP_CAN_EXPLODE, (EXPLODES_BY_FIRE(element) ||
7023                                              EXPLODES_SMASHED(element) ||
7024                                              EXPLODES_IMPACT(element)));
7025     }
7026   }
7027
7028   /* correct previously hard-coded move delay values for maze runner style */
7029   if (level->game_version < VERSION_IDENT(3,1,1,0))
7030   {
7031     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
7032     {
7033       int element = EL_CUSTOM_START + i;
7034
7035       if (element_info[element].move_pattern & MV_MAZE_RUNNER_STYLE)
7036       {
7037         /* previously hard-coded and therefore ignored */
7038         element_info[element].move_delay_fixed = 9;
7039         element_info[element].move_delay_random = 0;
7040       }
7041     }
7042   }
7043
7044   /* map elements that have changed in newer versions */
7045   level->amoeba_content = getMappedElementByVersion(level->amoeba_content,
7046                                                     level->game_version);
7047   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
7048     for (x = 0; x < 3; x++)
7049       for (y = 0; y < 3; y++)
7050         level->yamyam_content[i].e[x][y] =
7051           getMappedElementByVersion(level->yamyam_content[i].e[x][y],
7052                                     level->game_version);
7053
7054   /* initialize element properties for level editor etc. */
7055   InitElementPropertiesEngine(level->game_version);
7056   InitElementPropertiesAfterLoading(level->game_version);
7057   InitElementPropertiesGfxElement();
7058 }
7059
7060 static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
7061 {
7062   int x, y;
7063
7064   /* map elements that have changed in newer versions */
7065   for (y = 0; y < level->fieldy; y++)
7066     for (x = 0; x < level->fieldx; x++)
7067       level->field[x][y] = getMappedElementByVersion(level->field[x][y],
7068                                                      level->game_version);
7069
7070   /* copy elements to runtime playfield array */
7071   for (x = 0; x < MAX_LEV_FIELDX; x++)
7072     for (y = 0; y < MAX_LEV_FIELDY; y++)
7073       Feld[x][y] = level->field[x][y];
7074
7075   /* initialize level size variables for faster access */
7076   lev_fieldx = level->fieldx;
7077   lev_fieldy = level->fieldy;
7078
7079   /* determine border element for this level */
7080   if (level->file_info.type == LEVEL_FILE_TYPE_DC ||
7081       level->file_info.type == LEVEL_FILE_TYPE_SB)
7082     BorderElement = EL_EMPTY;   /* (in editor, SetBorderElement() is used) */
7083   else
7084     SetBorderElement();
7085 }
7086
7087 static void LoadLevel_InitNativeEngines(struct LevelInfo *level,char *filename)
7088 {
7089   struct LevelFileInfo *level_file_info = &level->file_info;
7090
7091   if (level_file_info->type == LEVEL_FILE_TYPE_RND)
7092     CopyNativeLevel_RND_to_Native(level);
7093 }
7094
7095 void LoadLevelTemplate(int nr)
7096 {
7097   char *filename;
7098
7099   setLevelFileInfo(&level_template.file_info, nr);
7100   filename = level_template.file_info.filename;
7101
7102   LoadLevelFromFileInfo(&level_template, &level_template.file_info);
7103
7104   LoadLevel_InitVersion(&level_template, filename);
7105   LoadLevel_InitElements(&level_template, filename);
7106
7107   ActivateLevelTemplate();
7108 }
7109
7110 void LoadLevel(int nr)
7111 {
7112   char *filename;
7113
7114   setLevelFileInfo(&level.file_info, nr);
7115   filename = level.file_info.filename;
7116
7117   LoadLevelFromFileInfo(&level, &level.file_info);
7118
7119   if (level.use_custom_template)
7120     LoadLevelTemplate(-1);
7121
7122   LoadLevel_InitVersion(&level, filename);
7123   LoadLevel_InitElements(&level, filename);
7124   LoadLevel_InitPlayfield(&level, filename);
7125
7126   LoadLevel_InitNativeEngines(&level, filename);
7127 }
7128
7129 static int SaveLevel_VERS(FILE *file, struct LevelInfo *level)
7130 {
7131   int chunk_size = 0;
7132
7133   chunk_size += putFileVersion(file, level->file_version);
7134   chunk_size += putFileVersion(file, level->game_version);
7135
7136   return chunk_size;
7137 }
7138
7139 static int SaveLevel_DATE(FILE *file, struct LevelInfo *level)
7140 {
7141   int chunk_size = 0;
7142
7143   chunk_size += putFile16BitBE(file, level->creation_date.year);
7144   chunk_size += putFile8Bit(file,    level->creation_date.month);
7145   chunk_size += putFile8Bit(file,    level->creation_date.day);
7146
7147   return chunk_size;
7148 }
7149
7150 #if 0
7151 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
7152 {
7153   int i, x, y;
7154
7155   putFile8Bit(file, level->fieldx);
7156   putFile8Bit(file, level->fieldy);
7157
7158   putFile16BitBE(file, level->time);
7159   putFile16BitBE(file, level->gems_needed);
7160
7161   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
7162     putFile8Bit(file, level->name[i]);
7163
7164   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
7165     putFile8Bit(file, level->score[i]);
7166
7167   for (i = 0; i < STD_ELEMENT_CONTENTS; i++)
7168     for (y = 0; y < 3; y++)
7169       for (x = 0; x < 3; x++)
7170         putFile8Bit(file, (level->encoding_16bit_yamyam ? EL_EMPTY :
7171                            level->yamyam_content[i].e[x][y]));
7172   putFile8Bit(file, level->amoeba_speed);
7173   putFile8Bit(file, level->time_magic_wall);
7174   putFile8Bit(file, level->time_wheel);
7175   putFile8Bit(file, (level->encoding_16bit_amoeba ? EL_EMPTY :
7176                      level->amoeba_content));
7177   putFile8Bit(file, (level->initial_player_stepsize == STEPSIZE_FAST ? 1 : 0));
7178   putFile8Bit(file, (level->initial_gravity ? 1 : 0));
7179   putFile8Bit(file, (level->encoding_16bit_field ? 1 : 0));
7180   putFile8Bit(file, (level->em_slippery_gems ? 1 : 0));
7181
7182   putFile8Bit(file, (level->use_custom_template ? 1 : 0));
7183
7184   putFile8Bit(file, (level->block_last_field ? 1 : 0));
7185   putFile8Bit(file, (level->sp_block_last_field ? 1 : 0));
7186   putFile32BitBE(file, level->can_move_into_acid_bits);
7187   putFile8Bit(file, level->dont_collide_with_bits);
7188
7189   putFile8Bit(file, (level->use_spring_bug ? 1 : 0));
7190   putFile8Bit(file, (level->use_step_counter ? 1 : 0));
7191
7192   putFile8Bit(file, (level->instant_relocation ? 1 : 0));
7193   putFile8Bit(file, (level->can_pass_to_walkable ? 1 : 0));
7194   putFile8Bit(file, (level->grow_into_diggable ? 1 : 0));
7195
7196   putFile8Bit(file, level->game_engine_type);
7197
7198   WriteUnusedBytesToFile(file, LEVEL_CHUNK_HEAD_UNUSED);
7199 }
7200 #endif
7201
7202 static int SaveLevel_NAME(FILE *file, struct LevelInfo *level)
7203 {
7204   int chunk_size = 0;
7205   int i;
7206
7207   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
7208     chunk_size += putFile8Bit(file, level->name[i]);
7209
7210   return chunk_size;
7211 }
7212
7213 static int SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
7214 {
7215   int chunk_size = 0;
7216   int i;
7217
7218   for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
7219     chunk_size += putFile8Bit(file, level->author[i]);
7220
7221   return chunk_size;
7222 }
7223
7224 #if 0
7225 static int SaveLevel_BODY(FILE *file, struct LevelInfo *level)
7226 {
7227   int chunk_size = 0;
7228   int x, y;
7229
7230   for (y = 0; y < level->fieldy; y++) 
7231     for (x = 0; x < level->fieldx; x++) 
7232       if (level->encoding_16bit_field)
7233         chunk_size += putFile16BitBE(file, level->field[x][y]);
7234       else
7235         chunk_size += putFile8Bit(file, level->field[x][y]);
7236
7237   return chunk_size;
7238 }
7239 #endif
7240
7241 static int SaveLevel_BODY(FILE *file, struct LevelInfo *level)
7242 {
7243   int chunk_size = 0;
7244   int x, y;
7245
7246   for (y = 0; y < level->fieldy; y++) 
7247     for (x = 0; x < level->fieldx; x++) 
7248       chunk_size += putFile16BitBE(file, level->field[x][y]);
7249
7250   return chunk_size;
7251 }
7252
7253 #if 0
7254 static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
7255 {
7256   int i, x, y;
7257
7258   putFile8Bit(file, EL_YAMYAM);
7259   putFile8Bit(file, level->num_yamyam_contents);
7260   putFile8Bit(file, 0);
7261   putFile8Bit(file, 0);
7262
7263   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
7264     for (y = 0; y < 3; y++)
7265       for (x = 0; x < 3; x++)
7266         if (level->encoding_16bit_field)
7267           putFile16BitBE(file, level->yamyam_content[i].e[x][y]);
7268         else
7269           putFile8Bit(file, level->yamyam_content[i].e[x][y]);
7270 }
7271 #endif
7272
7273 #if 0
7274 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
7275 {
7276   int i, x, y;
7277   int num_contents, content_xsize, content_ysize;
7278   int content_array[MAX_ELEMENT_CONTENTS][3][3];
7279
7280   if (element == EL_YAMYAM)
7281   {
7282     num_contents = level->num_yamyam_contents;
7283     content_xsize = 3;
7284     content_ysize = 3;
7285
7286     for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
7287       for (y = 0; y < 3; y++)
7288         for (x = 0; x < 3; x++)
7289           content_array[i][x][y] = level->yamyam_content[i].e[x][y];
7290   }
7291   else if (element == EL_BD_AMOEBA)
7292   {
7293     num_contents = 1;
7294     content_xsize = 1;
7295     content_ysize = 1;
7296
7297     for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
7298       for (y = 0; y < 3; y++)
7299         for (x = 0; x < 3; x++)
7300           content_array[i][x][y] = EL_EMPTY;
7301     content_array[0][0][0] = level->amoeba_content;
7302   }
7303   else
7304   {
7305     /* chunk header already written -- write empty chunk data */
7306     WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_SIZE);
7307
7308     Error(ERR_WARN, "cannot save content for element '%d'", element);
7309     return;
7310   }
7311
7312   putFile16BitBE(file, element);
7313   putFile8Bit(file, num_contents);
7314   putFile8Bit(file, content_xsize);
7315   putFile8Bit(file, content_ysize);
7316
7317   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED);
7318
7319   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
7320     for (y = 0; y < 3; y++)
7321       for (x = 0; x < 3; x++)
7322         putFile16BitBE(file, content_array[i][x][y]);
7323 }
7324 #endif
7325
7326 #if 0
7327 static int SaveLevel_CNT3(FILE *file, struct LevelInfo *level, int element)
7328 {
7329   int envelope_nr = element - EL_ENVELOPE_1;
7330   int envelope_len = strlen(level->envelope_text[envelope_nr]) + 1;
7331   int chunk_size = 0;
7332   int i;
7333
7334   chunk_size += putFile16BitBE(file, element);
7335   chunk_size += putFile16BitBE(file, envelope_len);
7336   chunk_size += putFile8Bit(file, level->envelope_xsize[envelope_nr]);
7337   chunk_size += putFile8Bit(file, level->envelope_ysize[envelope_nr]);
7338
7339   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT3_UNUSED);
7340   chunk_size += LEVEL_CHUNK_CNT3_UNUSED;
7341
7342   for (i = 0; i < envelope_len; i++)
7343     chunk_size += putFile8Bit(file, level->envelope_text[envelope_nr][i]);
7344
7345   return chunk_size;
7346 }
7347 #endif
7348
7349 #if 0
7350 static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level,
7351                            int num_changed_custom_elements)
7352 {
7353   int i, check = 0;
7354
7355   putFile16BitBE(file, num_changed_custom_elements);
7356
7357   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
7358   {
7359     int element = EL_CUSTOM_START + i;
7360
7361     struct ElementInfo *ei = &element_info[element];
7362
7363     if (ei->properties[EP_BITFIELD_BASE_NR] != EP_BITMASK_DEFAULT)
7364     {
7365       if (check < num_changed_custom_elements)
7366       {
7367         putFile16BitBE(file, element);
7368         putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
7369       }
7370
7371       check++;
7372     }
7373   }
7374
7375   if (check != num_changed_custom_elements)     /* should not happen */
7376     Error(ERR_WARN, "inconsistent number of custom element properties");
7377 }
7378 #endif
7379
7380 #if 0
7381 static void SaveLevel_CUS2(FILE *file, struct LevelInfo *level,
7382                            int num_changed_custom_elements)
7383 {
7384   int i, check = 0;
7385
7386   putFile16BitBE(file, num_changed_custom_elements);
7387
7388   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
7389   {
7390     int element = EL_CUSTOM_START + i;
7391
7392     if (element_info[element].change->target_element != EL_EMPTY_SPACE)
7393     {
7394       if (check < num_changed_custom_elements)
7395       {
7396         putFile16BitBE(file, element);
7397         putFile16BitBE(file, element_info[element].change->target_element);
7398       }
7399
7400       check++;
7401     }
7402   }
7403
7404   if (check != num_changed_custom_elements)     /* should not happen */
7405     Error(ERR_WARN, "inconsistent number of custom target elements");
7406 }
7407 #endif
7408
7409 #if 0
7410 static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
7411                            int num_changed_custom_elements)
7412 {
7413   int i, j, x, y, check = 0;
7414
7415   putFile16BitBE(file, num_changed_custom_elements);
7416
7417   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
7418   {
7419     int element = EL_CUSTOM_START + i;
7420     struct ElementInfo *ei = &element_info[element];
7421
7422     if (ei->modified_settings)
7423     {
7424       if (check < num_changed_custom_elements)
7425       {
7426         putFile16BitBE(file, element);
7427
7428         for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++)
7429           putFile8Bit(file, ei->description[j]);
7430
7431         putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
7432
7433         /* some free bytes for future properties and padding */
7434         WriteUnusedBytesToFile(file, 7);
7435
7436         putFile8Bit(file, ei->use_gfx_element);
7437         putFile16BitBE(file, ei->gfx_element_initial);
7438
7439         putFile8Bit(file, ei->collect_score_initial);
7440         putFile8Bit(file, ei->collect_count_initial);
7441
7442         putFile16BitBE(file, ei->push_delay_fixed);
7443         putFile16BitBE(file, ei->push_delay_random);
7444         putFile16BitBE(file, ei->move_delay_fixed);
7445         putFile16BitBE(file, ei->move_delay_random);
7446
7447         putFile16BitBE(file, ei->move_pattern);
7448         putFile8Bit(file, ei->move_direction_initial);
7449         putFile8Bit(file, ei->move_stepsize);
7450
7451         for (y = 0; y < 3; y++)
7452           for (x = 0; x < 3; x++)
7453             putFile16BitBE(file, ei->content.e[x][y]);
7454
7455         putFile32BitBE(file, ei->change->events);
7456
7457         putFile16BitBE(file, ei->change->target_element);
7458
7459         putFile16BitBE(file, ei->change->delay_fixed);
7460         putFile16BitBE(file, ei->change->delay_random);
7461         putFile16BitBE(file, ei->change->delay_frames);
7462
7463         putFile16BitBE(file, ei->change->initial_trigger_element);
7464
7465         putFile8Bit(file, ei->change->explode);
7466         putFile8Bit(file, ei->change->use_target_content);
7467         putFile8Bit(file, ei->change->only_if_complete);
7468         putFile8Bit(file, ei->change->use_random_replace);
7469
7470         putFile8Bit(file, ei->change->random_percentage);
7471         putFile8Bit(file, ei->change->replace_when);
7472
7473         for (y = 0; y < 3; y++)
7474           for (x = 0; x < 3; x++)
7475             putFile16BitBE(file, ei->change->content.e[x][y]);
7476
7477         putFile8Bit(file, ei->slippery_type);
7478
7479         /* some free bytes for future properties and padding */
7480         WriteUnusedBytesToFile(file, LEVEL_CPART_CUS3_UNUSED);
7481       }
7482
7483       check++;
7484     }
7485   }
7486
7487   if (check != num_changed_custom_elements)     /* should not happen */
7488     Error(ERR_WARN, "inconsistent number of custom element properties");
7489 }
7490 #endif
7491
7492 #if 0
7493 static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
7494 {
7495   struct ElementInfo *ei = &element_info[element];
7496   int i, j, x, y;
7497
7498   /* ---------- custom element base property values (96 bytes) ------------- */
7499
7500   putFile16BitBE(file, element);
7501
7502   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
7503     putFile8Bit(file, ei->description[i]);
7504
7505   putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE_NR]);
7506
7507   WriteUnusedBytesToFile(file, 4);      /* reserved for more base properties */
7508
7509   putFile8Bit(file, ei->num_change_pages);
7510
7511   putFile16BitBE(file, ei->ce_value_fixed_initial);
7512   putFile16BitBE(file, ei->ce_value_random_initial);
7513   putFile8Bit(file, ei->use_last_ce_value);
7514
7515   putFile8Bit(file, ei->use_gfx_element);
7516   putFile16BitBE(file, ei->gfx_element_initial);
7517
7518   putFile8Bit(file, ei->collect_score_initial);
7519   putFile8Bit(file, ei->collect_count_initial);
7520
7521   putFile8Bit(file, ei->drop_delay_fixed);
7522   putFile8Bit(file, ei->push_delay_fixed);
7523   putFile8Bit(file, ei->drop_delay_random);
7524   putFile8Bit(file, ei->push_delay_random);
7525   putFile16BitBE(file, ei->move_delay_fixed);
7526   putFile16BitBE(file, ei->move_delay_random);
7527
7528   /* bits 0 - 15 of "move_pattern" ... */
7529   putFile16BitBE(file, ei->move_pattern & 0xffff);
7530   putFile8Bit(file, ei->move_direction_initial);
7531   putFile8Bit(file, ei->move_stepsize);
7532
7533   putFile8Bit(file, ei->slippery_type);
7534
7535   for (y = 0; y < 3; y++)
7536     for (x = 0; x < 3; x++)
7537       putFile16BitBE(file, ei->content.e[x][y]);
7538
7539   putFile16BitBE(file, ei->move_enter_element);
7540   putFile16BitBE(file, ei->move_leave_element);
7541   putFile8Bit(file, ei->move_leave_type);
7542
7543   /* ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible) */
7544   putFile16BitBE(file, (ei->move_pattern >> 16) & 0xffff);
7545
7546   putFile8Bit(file, ei->access_direction);
7547
7548   putFile8Bit(file, ei->explosion_delay);
7549   putFile8Bit(file, ei->ignition_delay);
7550   putFile8Bit(file, ei->explosion_type);
7551
7552   /* some free bytes for future custom property values and padding */
7553   WriteUnusedBytesToFile(file, 1);
7554
7555   /* ---------- change page property values (48 bytes) --------------------- */
7556
7557   for (i = 0; i < ei->num_change_pages; i++)
7558   {
7559     struct ElementChangeInfo *change = &ei->change_page[i];
7560     unsigned int event_bits;
7561
7562     /* bits 0 - 31 of "has_event[]" ... */
7563     event_bits = 0;
7564     for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
7565       if (change->has_event[j])
7566         event_bits |= (1 << j);
7567     putFile32BitBE(file, event_bits);
7568
7569     putFile16BitBE(file, change->target_element);
7570
7571     putFile16BitBE(file, change->delay_fixed);
7572     putFile16BitBE(file, change->delay_random);
7573     putFile16BitBE(file, change->delay_frames);
7574
7575     putFile16BitBE(file, change->initial_trigger_element);
7576
7577     putFile8Bit(file, change->explode);
7578     putFile8Bit(file, change->use_target_content);
7579     putFile8Bit(file, change->only_if_complete);
7580     putFile8Bit(file, change->use_random_replace);
7581
7582     putFile8Bit(file, change->random_percentage);
7583     putFile8Bit(file, change->replace_when);
7584
7585     for (y = 0; y < 3; y++)
7586       for (x = 0; x < 3; x++)
7587         putFile16BitBE(file, change->target_content.e[x][y]);
7588
7589     putFile8Bit(file, change->can_change);
7590
7591     putFile8Bit(file, change->trigger_side);
7592
7593     putFile8Bit(file, change->trigger_player);
7594     putFile8Bit(file, (change->trigger_page == CH_PAGE_ANY ? CH_PAGE_ANY_FILE :
7595                        log_2(change->trigger_page)));
7596
7597     putFile8Bit(file, change->has_action);
7598     putFile8Bit(file, change->action_type);
7599     putFile8Bit(file, change->action_mode);
7600     putFile16BitBE(file, change->action_arg);
7601
7602     /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */
7603     event_bits = 0;
7604     for (j = 32; j < NUM_CHANGE_EVENTS; j++)
7605       if (change->has_event[j])
7606         event_bits |= (1 << (j - 32));
7607     putFile8Bit(file, event_bits);
7608   }
7609 }
7610 #endif
7611
7612 #if 0
7613 static void SaveLevel_GRP1(FILE *file, struct LevelInfo *level, int element)
7614 {
7615   struct ElementInfo *ei = &element_info[element];
7616   struct ElementGroupInfo *group = ei->group;
7617   int i;
7618
7619   putFile16BitBE(file, element);
7620
7621   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
7622     putFile8Bit(file, ei->description[i]);
7623
7624   putFile8Bit(file, group->num_elements);
7625
7626   putFile8Bit(file, ei->use_gfx_element);
7627   putFile16BitBE(file, ei->gfx_element_initial);
7628
7629   putFile8Bit(file, group->choice_mode);
7630
7631   /* some free bytes for future values and padding */
7632   WriteUnusedBytesToFile(file, 3);
7633
7634   for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
7635     putFile16BitBE(file, group->element[i]);
7636 }
7637 #endif
7638
7639 static int SaveLevel_MicroChunk(FILE *file, struct LevelFileConfigInfo *entry,
7640                                 boolean write_element)
7641 {
7642   int save_type = entry->save_type;
7643   int data_type = entry->data_type;
7644   int conf_type = entry->conf_type;
7645   int byte_mask = conf_type & CONF_MASK_BYTES;
7646   int element = entry->element;
7647   int default_value = entry->default_value;
7648   int num_bytes = 0;
7649   boolean modified = FALSE;
7650
7651   if (byte_mask != CONF_MASK_MULTI_BYTES)
7652   {
7653     void *value_ptr = entry->value;
7654     int value = (data_type == TYPE_BOOLEAN ? *(boolean *)value_ptr :
7655                  *(int *)value_ptr);
7656
7657     /* check if any settings have been modified before saving them */
7658     if (value != default_value)
7659       modified = TRUE;
7660
7661     /* do not save if explicitly told or if unmodified default settings */
7662     if ((save_type == SAVE_CONF_NEVER) ||
7663         (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
7664       return 0;
7665
7666     if (write_element)
7667       num_bytes += putFile16BitBE(file, element);
7668
7669     num_bytes += putFile8Bit(file, conf_type);
7670     num_bytes += (byte_mask == CONF_MASK_1_BYTE ? putFile8Bit   (file, value) :
7671                   byte_mask == CONF_MASK_2_BYTE ? putFile16BitBE(file, value) :
7672                   byte_mask == CONF_MASK_4_BYTE ? putFile32BitBE(file, value) :
7673                   0);
7674   }
7675   else if (data_type == TYPE_STRING)
7676   {
7677     char *default_string = entry->default_string;
7678     char *string = (char *)(entry->value);
7679     int string_length = strlen(string);
7680     int i;
7681
7682     /* check if any settings have been modified before saving them */
7683     if (!strEqual(string, default_string))
7684       modified = TRUE;
7685
7686     /* do not save if explicitly told or if unmodified default settings */
7687     if ((save_type == SAVE_CONF_NEVER) ||
7688         (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
7689       return 0;
7690
7691     if (write_element)
7692       num_bytes += putFile16BitBE(file, element);
7693
7694     num_bytes += putFile8Bit(file, conf_type);
7695     num_bytes += putFile16BitBE(file, string_length);
7696
7697     for (i = 0; i < string_length; i++)
7698       num_bytes += putFile8Bit(file, string[i]);
7699   }
7700   else if (data_type == TYPE_ELEMENT_LIST)
7701   {
7702     int *element_array = (int *)(entry->value);
7703     int num_elements = *(int *)(entry->num_entities);
7704     int i;
7705
7706     /* check if any settings have been modified before saving them */
7707     for (i = 0; i < num_elements; i++)
7708       if (element_array[i] != default_value)
7709         modified = TRUE;
7710
7711     /* do not save if explicitly told or if unmodified default settings */
7712     if ((save_type == SAVE_CONF_NEVER) ||
7713         (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
7714       return 0;
7715
7716     if (write_element)
7717       num_bytes += putFile16BitBE(file, element);
7718
7719     num_bytes += putFile8Bit(file, conf_type);
7720     num_bytes += putFile16BitBE(file, num_elements * CONF_ELEMENT_NUM_BYTES);
7721
7722     for (i = 0; i < num_elements; i++)
7723       num_bytes += putFile16BitBE(file, element_array[i]);
7724   }
7725   else if (data_type == TYPE_CONTENT_LIST)
7726   {
7727     struct Content *content = (struct Content *)(entry->value);
7728     int num_contents = *(int *)(entry->num_entities);
7729     int i, x, y;
7730
7731     /* check if any settings have been modified before saving them */
7732     for (i = 0; i < num_contents; i++)
7733       for (y = 0; y < 3; y++)
7734         for (x = 0; x < 3; x++)
7735           if (content[i].e[x][y] != default_value)
7736             modified = TRUE;
7737
7738     /* do not save if explicitly told or if unmodified default settings */
7739     if ((save_type == SAVE_CONF_NEVER) ||
7740         (save_type == SAVE_CONF_WHEN_CHANGED && !modified))
7741       return 0;
7742
7743     if (write_element)
7744       num_bytes += putFile16BitBE(file, element);
7745
7746     num_bytes += putFile8Bit(file, conf_type);
7747     num_bytes += putFile16BitBE(file, num_contents * CONF_CONTENT_NUM_BYTES);
7748
7749     for (i = 0; i < num_contents; i++)
7750       for (y = 0; y < 3; y++)
7751         for (x = 0; x < 3; x++)
7752           num_bytes += putFile16BitBE(file, content[i].e[x][y]);
7753   }
7754
7755   return num_bytes;
7756 }
7757
7758 static int SaveLevel_INFO(FILE *file, struct LevelInfo *level)
7759 {
7760   int chunk_size = 0;
7761   int i;
7762
7763   li = *level;          /* copy level data into temporary buffer */
7764
7765   for (i = 0; chunk_config_INFO[i].data_type != -1; i++)
7766     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_INFO[i], FALSE);
7767
7768   return chunk_size;
7769 }
7770
7771 static int SaveLevel_ELEM(FILE *file, struct LevelInfo *level)
7772 {
7773   int chunk_size = 0;
7774   int i;
7775
7776   li = *level;          /* copy level data into temporary buffer */
7777
7778   for (i = 0; chunk_config_ELEM[i].data_type != -1; i++)
7779     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_ELEM[i], TRUE);
7780
7781   return chunk_size;
7782 }
7783
7784 static int SaveLevel_NOTE(FILE *file, struct LevelInfo *level, int element)
7785 {
7786   int envelope_nr = element - EL_ENVELOPE_1;
7787   int chunk_size = 0;
7788   int i;
7789
7790   chunk_size += putFile16BitBE(file, element);
7791
7792   /* copy envelope data into temporary buffer */
7793   xx_envelope = level->envelope[envelope_nr];
7794
7795   for (i = 0; chunk_config_NOTE[i].data_type != -1; i++)
7796     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_NOTE[i], FALSE);
7797
7798   return chunk_size;
7799 }
7800
7801 static int SaveLevel_CUSX(FILE *file, struct LevelInfo *level, int element)
7802 {
7803   struct ElementInfo *ei = &element_info[element];
7804   int chunk_size = 0;
7805   int i, j;
7806
7807   chunk_size += putFile16BitBE(file, element);
7808
7809   xx_ei = *ei;          /* copy element data into temporary buffer */
7810
7811   /* set default description string for this specific element */
7812   strcpy(xx_default_description, getDefaultElementDescription(ei));
7813
7814 #if 0
7815   /* set (fixed) number of content areas (may be wrong by broken level file) */
7816   /* (this is now directly corrected for broken level files after loading) */
7817   xx_num_contents = 1;
7818 #endif
7819
7820   for (i = 0; chunk_config_CUSX_base[i].data_type != -1; i++)
7821     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_CUSX_base[i], FALSE);
7822
7823   for (i = 0; i < ei->num_change_pages; i++)
7824   {
7825     struct ElementChangeInfo *change = &ei->change_page[i];
7826
7827     xx_current_change_page = i;
7828
7829     xx_change = *change;        /* copy change data into temporary buffer */
7830
7831     resetEventBits();
7832     setEventBitsFromEventFlags(change);
7833
7834     for (j = 0; chunk_config_CUSX_change[j].data_type != -1; j++)
7835       chunk_size += SaveLevel_MicroChunk(file, &chunk_config_CUSX_change[j],
7836                                          FALSE);
7837   }
7838
7839   return chunk_size;
7840 }
7841
7842 static int SaveLevel_GRPX(FILE *file, struct LevelInfo *level, int element)
7843 {
7844   struct ElementInfo *ei = &element_info[element];
7845   struct ElementGroupInfo *group = ei->group;
7846   int chunk_size = 0;
7847   int i;
7848
7849   chunk_size += putFile16BitBE(file, element);
7850
7851   xx_ei = *ei;          /* copy element data into temporary buffer */
7852   xx_group = *group;    /* copy group data into temporary buffer */
7853
7854   /* set default description string for this specific element */
7855   strcpy(xx_default_description, getDefaultElementDescription(ei));
7856
7857   for (i = 0; chunk_config_GRPX[i].data_type != -1; i++)
7858     chunk_size += SaveLevel_MicroChunk(file, &chunk_config_GRPX[i], FALSE);
7859
7860   return chunk_size;
7861 }
7862
7863 static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
7864 {
7865   int chunk_size;
7866   int i;
7867   FILE *file;
7868
7869   if (!(file = fopen(filename, MODE_WRITE)))
7870   {
7871     Error(ERR_WARN, "cannot save level file '%s'", filename);
7872     return;
7873   }
7874
7875   level->file_version = FILE_VERSION_ACTUAL;
7876   level->game_version = GAME_VERSION_ACTUAL;
7877
7878   level->creation_date = getCurrentDate();
7879
7880   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
7881   putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
7882
7883   chunk_size = SaveLevel_VERS(NULL, level);
7884   putFileChunkBE(file, "VERS", chunk_size);
7885   SaveLevel_VERS(file, level);
7886
7887   chunk_size = SaveLevel_DATE(NULL, level);
7888   putFileChunkBE(file, "DATE", chunk_size);
7889   SaveLevel_DATE(file, level);
7890
7891   chunk_size = SaveLevel_NAME(NULL, level);
7892   putFileChunkBE(file, "NAME", chunk_size);
7893   SaveLevel_NAME(file, level);
7894
7895   chunk_size = SaveLevel_AUTH(NULL, level);
7896   putFileChunkBE(file, "AUTH", chunk_size);
7897   SaveLevel_AUTH(file, level);
7898
7899   chunk_size = SaveLevel_INFO(NULL, level);
7900   putFileChunkBE(file, "INFO", chunk_size);
7901   SaveLevel_INFO(file, level);
7902
7903   chunk_size = SaveLevel_BODY(NULL, level);
7904   putFileChunkBE(file, "BODY", chunk_size);
7905   SaveLevel_BODY(file, level);
7906
7907   chunk_size = SaveLevel_ELEM(NULL, level);
7908   if (chunk_size > LEVEL_CHUNK_ELEM_UNCHANGED)          /* save if changed */
7909   {
7910     putFileChunkBE(file, "ELEM", chunk_size);
7911     SaveLevel_ELEM(file, level);
7912   }
7913
7914   for (i = 0; i < NUM_ENVELOPES; i++)
7915   {
7916     int element = EL_ENVELOPE_1 + i;
7917
7918     chunk_size = SaveLevel_NOTE(NULL, level, element);
7919     if (chunk_size > LEVEL_CHUNK_NOTE_UNCHANGED)        /* save if changed */
7920     {
7921       putFileChunkBE(file, "NOTE", chunk_size);
7922       SaveLevel_NOTE(file, level, element);
7923     }
7924   }
7925
7926   /* if not using template level, check for non-default custom/group elements */
7927   if (!level->use_custom_template)
7928   {
7929     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
7930     {
7931       int element = EL_CUSTOM_START + i;
7932
7933       chunk_size = SaveLevel_CUSX(NULL, level, element);
7934       if (chunk_size > LEVEL_CHUNK_CUSX_UNCHANGED)      /* save if changed */
7935       {
7936         putFileChunkBE(file, "CUSX", chunk_size);
7937         SaveLevel_CUSX(file, level, element);
7938       }
7939     }
7940
7941     for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
7942     {
7943       int element = EL_GROUP_START + i;
7944
7945       chunk_size = SaveLevel_GRPX(NULL, level, element);
7946       if (chunk_size > LEVEL_CHUNK_GRPX_UNCHANGED)      /* save if changed */
7947       {
7948         putFileChunkBE(file, "GRPX", chunk_size);
7949         SaveLevel_GRPX(file, level, element);
7950       }
7951     }
7952   }
7953
7954   fclose(file);
7955
7956   SetFilePermissions(filename, PERMS_PRIVATE);
7957 }
7958
7959 void SaveLevel(int nr)
7960 {
7961   char *filename = getDefaultLevelFilename(nr);
7962
7963   SaveLevelFromFilename(&level, filename);
7964 }
7965
7966 void SaveLevelTemplate()
7967 {
7968   char *filename = getDefaultLevelFilename(-1);
7969
7970   SaveLevelFromFilename(&level, filename);
7971 }
7972
7973 boolean SaveLevelChecked(int nr)
7974 {
7975   char *filename = getDefaultLevelFilename(nr);
7976   boolean new_level = !fileExists(filename);
7977   boolean level_saved = FALSE;
7978
7979   if (new_level || Request("Save this level and kill the old ?", REQ_ASK))
7980   {
7981     SaveLevel(nr);
7982
7983     if (new_level)
7984       Request("Level saved !", REQ_CONFIRM);
7985
7986     level_saved = TRUE;
7987   }
7988
7989   return level_saved;
7990 }
7991
7992 void DumpLevel(struct LevelInfo *level)
7993 {
7994   if (level->no_valid_file)
7995   {
7996     Error(ERR_WARN, "cannot dump -- no valid level file found");
7997
7998     return;
7999   }
8000
8001   printf_line("-", 79);
8002   printf("Level xxx (file version %08d, game version %08d)\n",
8003          level->file_version, level->game_version);
8004   printf_line("-", 79);
8005
8006   printf("Level author: '%s'\n", level->author);
8007   printf("Level title:  '%s'\n", level->name);
8008   printf("\n");
8009   printf("Playfield size: %d x %d\n", level->fieldx, level->fieldy);
8010   printf("\n");
8011   printf("Level time:  %d seconds\n", level->time);
8012   printf("Gems needed: %d\n", level->gems_needed);
8013   printf("\n");
8014   printf("Time for magic wall: %d seconds\n", level->time_magic_wall);
8015   printf("Time for wheel:      %d seconds\n", level->time_wheel);
8016   printf("Time for light:      %d seconds\n", level->time_light);
8017   printf("Time for timegate:   %d seconds\n", level->time_timegate);
8018   printf("\n");
8019   printf("Amoeba speed: %d\n", level->amoeba_speed);
8020   printf("\n");
8021
8022   printf("EM style slippery gems:      %s\n", (level->em_slippery_gems ? "yes" : "no"));
8023   printf("Player blocks last field:    %s\n", (level->block_last_field ? "yes" : "no"));
8024   printf("SP player blocks last field: %s\n", (level->sp_block_last_field ? "yes" : "no"));
8025   printf("use spring bug: %s\n", (level->use_spring_bug ? "yes" : "no"));
8026   printf("use step counter: %s\n", (level->use_step_counter ? "yes" : "no"));
8027
8028   printf_line("-", 79);
8029 }
8030
8031
8032 /* ========================================================================= */
8033 /* tape file functions                                                       */
8034 /* ========================================================================= */
8035
8036 static void setTapeInfoToDefaults()
8037 {
8038   int i;
8039
8040   /* always start with reliable default values (empty tape) */
8041   TapeErase();
8042
8043   /* default values (also for pre-1.2 tapes) with only the first player */
8044   tape.player_participates[0] = TRUE;
8045   for (i = 1; i < MAX_PLAYERS; i++)
8046     tape.player_participates[i] = FALSE;
8047
8048   /* at least one (default: the first) player participates in every tape */
8049   tape.num_participating_players = 1;
8050
8051   tape.level_nr = level_nr;
8052   tape.counter = 0;
8053   tape.changed = FALSE;
8054
8055   tape.recording = FALSE;
8056   tape.playing = FALSE;
8057   tape.pausing = FALSE;
8058
8059   tape.no_valid_file = FALSE;
8060 }
8061
8062 static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
8063 {
8064   tape->file_version = getFileVersion(file);
8065   tape->game_version = getFileVersion(file);
8066
8067   return chunk_size;
8068 }
8069
8070 static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
8071 {
8072   int i;
8073
8074   tape->random_seed = getFile32BitBE(file);
8075   tape->date        = getFile32BitBE(file);
8076   tape->length      = getFile32BitBE(file);
8077
8078   /* read header fields that are new since version 1.2 */
8079   if (tape->file_version >= FILE_VERSION_1_2)
8080   {
8081     byte store_participating_players = getFile8Bit(file);
8082     int engine_version;
8083
8084     /* since version 1.2, tapes store which players participate in the tape */
8085     tape->num_participating_players = 0;
8086     for (i = 0; i < MAX_PLAYERS; i++)
8087     {
8088       tape->player_participates[i] = FALSE;
8089
8090       if (store_participating_players & (1 << i))
8091       {
8092         tape->player_participates[i] = TRUE;
8093         tape->num_participating_players++;
8094       }
8095     }
8096
8097     ReadUnusedBytesFromFile(file, TAPE_CHUNK_HEAD_UNUSED);
8098
8099     engine_version = getFileVersion(file);
8100     if (engine_version > 0)
8101       tape->engine_version = engine_version;
8102     else
8103       tape->engine_version = tape->game_version;
8104   }
8105
8106   return chunk_size;
8107 }
8108
8109 static int LoadTape_INFO(FILE *file, int chunk_size, struct TapeInfo *tape)
8110 {
8111   int level_identifier_size;
8112   int i;
8113
8114   level_identifier_size = getFile16BitBE(file);
8115
8116   tape->level_identifier =
8117     checked_realloc(tape->level_identifier, level_identifier_size);
8118
8119   for (i = 0; i < level_identifier_size; i++)
8120     tape->level_identifier[i] = getFile8Bit(file);
8121
8122   tape->level_nr = getFile16BitBE(file);
8123
8124   chunk_size = 2 + level_identifier_size + 2;
8125
8126   return chunk_size;
8127 }
8128
8129 static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
8130 {
8131   int i, j;
8132   int chunk_size_expected =
8133     (tape->num_participating_players + 1) * tape->length;
8134
8135   if (chunk_size_expected != chunk_size)
8136   {
8137     ReadUnusedBytesFromFile(file, chunk_size);
8138     return chunk_size_expected;
8139   }
8140
8141   for (i = 0; i < tape->length; i++)
8142   {
8143     if (i >= MAX_TAPE_LEN)
8144       break;
8145
8146     for (j = 0; j < MAX_PLAYERS; j++)
8147     {
8148       tape->pos[i].action[j] = MV_NONE;
8149
8150       if (tape->player_participates[j])
8151         tape->pos[i].action[j] = getFile8Bit(file);
8152     }
8153
8154     tape->pos[i].delay = getFile8Bit(file);
8155
8156     if (tape->file_version == FILE_VERSION_1_0)
8157     {
8158       /* eliminate possible diagonal moves in old tapes */
8159       /* this is only for backward compatibility */
8160
8161       byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
8162       byte action = tape->pos[i].action[0];
8163       int k, num_moves = 0;
8164
8165       for (k = 0; k<4; k++)
8166       {
8167         if (action & joy_dir[k])
8168         {
8169           tape->pos[i + num_moves].action[0] = joy_dir[k];
8170           if (num_moves > 0)
8171             tape->pos[i + num_moves].delay = 0;
8172           num_moves++;
8173         }
8174       }
8175
8176       if (num_moves > 1)
8177       {
8178         num_moves--;
8179         i += num_moves;
8180         tape->length += num_moves;
8181       }
8182     }
8183     else if (tape->file_version < FILE_VERSION_2_0)
8184     {
8185       /* convert pre-2.0 tapes to new tape format */
8186
8187       if (tape->pos[i].delay > 1)
8188       {
8189         /* action part */
8190         tape->pos[i + 1] = tape->pos[i];
8191         tape->pos[i + 1].delay = 1;
8192
8193         /* delay part */
8194         for (j = 0; j < MAX_PLAYERS; j++)
8195           tape->pos[i].action[j] = MV_NONE;
8196         tape->pos[i].delay--;
8197
8198         i++;
8199         tape->length++;
8200       }
8201     }
8202
8203     if (feof(file))
8204       break;
8205   }
8206
8207   if (i != tape->length)
8208     chunk_size = (tape->num_participating_players + 1) * i;
8209
8210   return chunk_size;
8211 }
8212
8213 void LoadTapeFromFilename(char *filename)
8214 {
8215   char cookie[MAX_LINE_LEN];
8216   char chunk_name[CHUNK_ID_LEN + 1];
8217   FILE *file;
8218   int chunk_size;
8219
8220   /* always start with reliable default values */
8221   setTapeInfoToDefaults();
8222
8223   if (!(file = fopen(filename, MODE_READ)))
8224   {
8225     tape.no_valid_file = TRUE;
8226
8227     return;
8228   }
8229
8230   getFileChunkBE(file, chunk_name, NULL);
8231   if (strEqual(chunk_name, "RND1"))
8232   {
8233     getFile32BitBE(file);               /* not used */
8234
8235     getFileChunkBE(file, chunk_name, NULL);
8236     if (!strEqual(chunk_name, "TAPE"))
8237     {
8238       tape.no_valid_file = TRUE;
8239
8240       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
8241       fclose(file);
8242       return;
8243     }
8244   }
8245   else  /* check for pre-2.0 file format with cookie string */
8246   {
8247     strcpy(cookie, chunk_name);
8248     fgets(&cookie[4], MAX_LINE_LEN - 4, file);
8249     if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
8250       cookie[strlen(cookie) - 1] = '\0';
8251
8252     if (!checkCookieString(cookie, TAPE_COOKIE_TMPL))
8253     {
8254       tape.no_valid_file = TRUE;
8255
8256       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
8257       fclose(file);
8258       return;
8259     }
8260
8261     if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1)
8262     {
8263       tape.no_valid_file = TRUE;
8264
8265       Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
8266       fclose(file);
8267       return;
8268     }
8269
8270     /* pre-2.0 tape files have no game version, so use file version here */
8271     tape.game_version = tape.file_version;
8272   }
8273
8274   if (tape.file_version < FILE_VERSION_1_2)
8275   {
8276     /* tape files from versions before 1.2.0 without chunk structure */
8277     LoadTape_HEAD(file, TAPE_CHUNK_HEAD_SIZE, &tape);
8278     LoadTape_BODY(file, 2 * tape.length,      &tape);
8279   }
8280   else
8281   {
8282     static struct
8283     {
8284       char *name;
8285       int size;
8286       int (*loader)(FILE *, int, struct TapeInfo *);
8287     }
8288     chunk_info[] =
8289     {
8290       { "VERS", TAPE_CHUNK_VERS_SIZE,   LoadTape_VERS },
8291       { "HEAD", TAPE_CHUNK_HEAD_SIZE,   LoadTape_HEAD },
8292       { "INFO", -1,                     LoadTape_INFO },
8293       { "BODY", -1,                     LoadTape_BODY },
8294       {  NULL,  0,                      NULL }
8295     };
8296
8297     while (getFileChunkBE(file, chunk_name, &chunk_size))
8298     {
8299       int i = 0;
8300
8301       while (chunk_info[i].name != NULL &&
8302              !strEqual(chunk_name, chunk_info[i].name))
8303         i++;
8304
8305       if (chunk_info[i].name == NULL)
8306       {
8307         Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'",
8308               chunk_name, filename);
8309         ReadUnusedBytesFromFile(file, chunk_size);
8310       }
8311       else if (chunk_info[i].size != -1 &&
8312                chunk_info[i].size != chunk_size)
8313       {
8314         Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
8315               chunk_size, chunk_name, filename);
8316         ReadUnusedBytesFromFile(file, chunk_size);
8317       }
8318       else
8319       {
8320         /* call function to load this tape chunk */
8321         int chunk_size_expected =
8322           (chunk_info[i].loader)(file, chunk_size, &tape);
8323
8324         /* the size of some chunks cannot be checked before reading other
8325            chunks first (like "HEAD" and "BODY") that contain some header
8326            information, so check them here */
8327         if (chunk_size_expected != chunk_size)
8328         {
8329           Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
8330                 chunk_size, chunk_name, filename);
8331         }
8332       }
8333     }
8334   }
8335
8336   fclose(file);
8337
8338   tape.length_seconds = GetTapeLength();
8339
8340 #if 0
8341   printf("::: tape file version: %d\n", tape.file_version);
8342   printf("::: tape game version: %d\n", tape.game_version);
8343   printf("::: tape engine version: %d\n", tape.engine_version);
8344 #endif
8345 }
8346
8347 void LoadTape(int nr)
8348 {
8349   char *filename = getTapeFilename(nr);
8350
8351   LoadTapeFromFilename(filename);
8352 }
8353
8354 void LoadSolutionTape(int nr)
8355 {
8356   char *filename = getSolutionTapeFilename(nr);
8357
8358   LoadTapeFromFilename(filename);
8359
8360 #if 1
8361   if (TAPE_IS_EMPTY(tape) &&
8362       level.game_engine_type == GAME_ENGINE_TYPE_SP &&
8363       level.native_sp_level->demo.is_available)
8364     CopyNativeTape_SP_to_RND(&level);
8365 #endif
8366 }
8367
8368 static void SaveTape_VERS(FILE *file, struct TapeInfo *tape)
8369 {
8370   putFileVersion(file, tape->file_version);
8371   putFileVersion(file, tape->game_version);
8372 }
8373
8374 static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
8375 {
8376   int i;
8377   byte store_participating_players = 0;
8378
8379   /* set bits for participating players for compact storage */
8380   for (i = 0; i < MAX_PLAYERS; i++)
8381     if (tape->player_participates[i])
8382       store_participating_players |= (1 << i);
8383
8384   putFile32BitBE(file, tape->random_seed);
8385   putFile32BitBE(file, tape->date);
8386   putFile32BitBE(file, tape->length);
8387
8388   putFile8Bit(file, store_participating_players);
8389
8390   /* unused bytes not at the end here for 4-byte alignment of engine_version */
8391   WriteUnusedBytesToFile(file, TAPE_CHUNK_HEAD_UNUSED);
8392
8393   putFileVersion(file, tape->engine_version);
8394 }
8395
8396 static void SaveTape_INFO(FILE *file, struct TapeInfo *tape)
8397 {
8398   int level_identifier_size = strlen(tape->level_identifier) + 1;
8399   int i;
8400
8401   putFile16BitBE(file, level_identifier_size);
8402
8403   for (i = 0; i < level_identifier_size; i++)
8404     putFile8Bit(file, tape->level_identifier[i]);
8405
8406   putFile16BitBE(file, tape->level_nr);
8407 }
8408
8409 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
8410 {
8411   int i, j;
8412
8413   for (i = 0; i < tape->length; i++)
8414   {
8415     for (j = 0; j < MAX_PLAYERS; j++)
8416       if (tape->player_participates[j])
8417         putFile8Bit(file, tape->pos[i].action[j]);
8418
8419     putFile8Bit(file, tape->pos[i].delay);
8420   }
8421 }
8422
8423 void SaveTape(int nr)
8424 {
8425   char *filename = getTapeFilename(nr);
8426   FILE *file;
8427 #if 0
8428   boolean new_tape = TRUE;
8429 #endif
8430   int num_participating_players = 0;
8431   int info_chunk_size;
8432   int body_chunk_size;
8433   int i;
8434
8435   InitTapeDirectory(leveldir_current->subdir);
8436
8437 #if 0
8438   /* if a tape still exists, ask to overwrite it */
8439   if (fileExists(filename))
8440   {
8441     new_tape = FALSE;
8442     if (!Request("Replace old tape ?", REQ_ASK))
8443       return;
8444   }
8445 #endif
8446
8447   if (!(file = fopen(filename, MODE_WRITE)))
8448   {
8449     Error(ERR_WARN, "cannot save level recording file '%s'", filename);
8450     return;
8451   }
8452
8453   tape.file_version = FILE_VERSION_ACTUAL;
8454   tape.game_version = GAME_VERSION_ACTUAL;
8455
8456   /* count number of participating players  */
8457   for (i = 0; i < MAX_PLAYERS; i++)
8458     if (tape.player_participates[i])
8459       num_participating_players++;
8460
8461   info_chunk_size = 2 + (strlen(tape.level_identifier) + 1) + 2;
8462   body_chunk_size = (num_participating_players + 1) * tape.length;
8463
8464   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
8465   putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
8466
8467   putFileChunkBE(file, "VERS", TAPE_CHUNK_VERS_SIZE);
8468   SaveTape_VERS(file, &tape);
8469
8470   putFileChunkBE(file, "HEAD", TAPE_CHUNK_HEAD_SIZE);
8471   SaveTape_HEAD(file, &tape);
8472
8473   putFileChunkBE(file, "INFO", info_chunk_size);
8474   SaveTape_INFO(file, &tape);
8475
8476   putFileChunkBE(file, "BODY", body_chunk_size);
8477   SaveTape_BODY(file, &tape);
8478
8479   fclose(file);
8480
8481   SetFilePermissions(filename, PERMS_PRIVATE);
8482
8483   tape.changed = FALSE;
8484
8485 #if 0
8486   if (new_tape)
8487     Request("Tape saved !", REQ_CONFIRM);
8488 #endif
8489 }
8490
8491 boolean SaveTapeChecked(int nr)
8492 {
8493   char *filename = getTapeFilename(nr);
8494   boolean new_tape = !fileExists(filename);
8495   boolean tape_saved = FALSE;
8496
8497   if (new_tape || Request("Replace old tape ?", REQ_ASK))
8498   {
8499     SaveTape(nr);
8500
8501     if (new_tape)
8502       Request("Tape saved !", REQ_CONFIRM);
8503
8504     tape_saved = TRUE;
8505   }
8506
8507   return tape_saved;
8508 }
8509
8510 void DumpTape(struct TapeInfo *tape)
8511 {
8512   int tape_frame_counter;
8513   int i, j;
8514
8515   if (tape->no_valid_file)
8516   {
8517     Error(ERR_WARN, "cannot dump -- no valid tape file found");
8518
8519     return;
8520   }
8521
8522   printf_line("-", 79);
8523   printf("Tape of Level %03d (file version %08d, game version %08d)\n",
8524          tape->level_nr, tape->file_version, tape->game_version);
8525   printf("                  (effective engine version %08d)\n",
8526          tape->engine_version);
8527   printf("Level series identifier: '%s'\n", tape->level_identifier);
8528   printf_line("-", 79);
8529
8530   tape_frame_counter = 0;
8531
8532   for (i = 0; i < tape->length; i++)
8533   {
8534     if (i >= MAX_TAPE_LEN)
8535       break;
8536
8537     printf("%04d: ", i);
8538
8539     for (j = 0; j < MAX_PLAYERS; j++)
8540     {
8541       if (tape->player_participates[j])
8542       {
8543         int action = tape->pos[i].action[j];
8544
8545         printf("%d:%02x ", j, action);
8546         printf("[%c%c%c%c|%c%c] - ",
8547                (action & JOY_LEFT ? '<' : ' '),
8548                (action & JOY_RIGHT ? '>' : ' '),
8549                (action & JOY_UP ? '^' : ' '),
8550                (action & JOY_DOWN ? 'v' : ' '),
8551                (action & JOY_BUTTON_1 ? '1' : ' '),
8552                (action & JOY_BUTTON_2 ? '2' : ' '));
8553       }
8554     }
8555
8556     printf("(%03d) ", tape->pos[i].delay);
8557     printf("[%05d]\n", tape_frame_counter);
8558
8559     tape_frame_counter += tape->pos[i].delay;
8560   }
8561
8562   printf_line("-", 79);
8563 }
8564
8565
8566 /* ========================================================================= */
8567 /* score file functions                                                      */
8568 /* ========================================================================= */
8569
8570 void LoadScore(int nr)
8571 {
8572   int i;
8573   char *filename = getScoreFilename(nr);
8574   char cookie[MAX_LINE_LEN];
8575   char line[MAX_LINE_LEN];
8576   char *line_ptr;
8577   FILE *file;
8578
8579   /* always start with reliable default values */
8580   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
8581   {
8582     strcpy(highscore[i].Name, EMPTY_PLAYER_NAME);
8583     highscore[i].Score = 0;
8584   }
8585
8586   if (!(file = fopen(filename, MODE_READ)))
8587     return;
8588
8589   /* check file identifier */
8590   fgets(cookie, MAX_LINE_LEN, file);
8591   if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
8592     cookie[strlen(cookie) - 1] = '\0';
8593
8594   if (!checkCookieString(cookie, SCORE_COOKIE))
8595   {
8596     Error(ERR_WARN, "unknown format of score file '%s'", filename);
8597     fclose(file);
8598     return;
8599   }
8600
8601   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
8602   {
8603     fscanf(file, "%d", &highscore[i].Score);
8604     fgets(line, MAX_LINE_LEN, file);
8605
8606     if (line[strlen(line) - 1] == '\n')
8607       line[strlen(line) - 1] = '\0';
8608
8609     for (line_ptr = line; *line_ptr; line_ptr++)
8610     {
8611       if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
8612       {
8613         strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN);
8614         highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0';
8615         break;
8616       }
8617     }
8618   }
8619
8620   fclose(file);
8621 }
8622
8623 void SaveScore(int nr)
8624 {
8625   int i;
8626   char *filename = getScoreFilename(nr);
8627   FILE *file;
8628
8629   InitScoreDirectory(leveldir_current->subdir);
8630
8631   if (!(file = fopen(filename, MODE_WRITE)))
8632   {
8633     Error(ERR_WARN, "cannot save score for level %d", nr);
8634     return;
8635   }
8636
8637   fprintf(file, "%s\n\n", SCORE_COOKIE);
8638
8639   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
8640     fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name);
8641
8642   fclose(file);
8643
8644   SetFilePermissions(filename, PERMS_PUBLIC);
8645 }
8646
8647
8648 /* ========================================================================= */
8649 /* setup file functions                                                      */
8650 /* ========================================================================= */
8651
8652 #define TOKEN_STR_PLAYER_PREFIX                 "player_"
8653
8654 /* global setup */
8655 #define SETUP_TOKEN_PLAYER_NAME                 0
8656 #define SETUP_TOKEN_SOUND                       1
8657 #define SETUP_TOKEN_SOUND_LOOPS                 2
8658 #define SETUP_TOKEN_SOUND_MUSIC                 3
8659 #define SETUP_TOKEN_SOUND_SIMPLE                4
8660 #define SETUP_TOKEN_TOONS                       5
8661 #define SETUP_TOKEN_SCROLL_DELAY                6
8662 #define SETUP_TOKEN_SCROLL_DELAY_VALUE          7
8663 #define SETUP_TOKEN_SOFT_SCROLLING              8
8664 #define SETUP_TOKEN_FADE_SCREENS                9
8665 #define SETUP_TOKEN_AUTORECORD                  10
8666 #define SETUP_TOKEN_SHOW_TITLESCREEN            11
8667 #define SETUP_TOKEN_QUICK_DOORS                 12
8668 #define SETUP_TOKEN_TEAM_MODE                   13
8669 #define SETUP_TOKEN_HANDICAP                    14
8670 #define SETUP_TOKEN_SKIP_LEVELS                 15
8671 #define SETUP_TOKEN_TIME_LIMIT                  16
8672 #define SETUP_TOKEN_FULLSCREEN                  17
8673 #define SETUP_TOKEN_FULLSCREEN_MODE             18
8674 #define SETUP_TOKEN_ASK_ON_ESCAPE               19
8675 #define SETUP_TOKEN_ASK_ON_ESCAPE_EDITOR        20
8676 #define SETUP_TOKEN_QUICK_SWITCH                21
8677 #define SETUP_TOKEN_INPUT_ON_FOCUS              22
8678 #define SETUP_TOKEN_PREFER_AGA_GRAPHICS         23
8679 #define SETUP_TOKEN_GAME_FRAME_DELAY            24
8680 #define SETUP_TOKEN_GRAPHICS_SET                25
8681 #define SETUP_TOKEN_SOUNDS_SET                  26
8682 #define SETUP_TOKEN_MUSIC_SET                   27
8683 #define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS     28
8684 #define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS       29
8685 #define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC        30
8686
8687 #define NUM_GLOBAL_SETUP_TOKENS                 31
8688
8689 /* editor setup */
8690 #define SETUP_TOKEN_EDITOR_EL_BOULDERDASH       0
8691 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE      1
8692 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE_CLUB 2
8693 #define SETUP_TOKEN_EDITOR_EL_MORE              3
8694 #define SETUP_TOKEN_EDITOR_EL_SOKOBAN           4
8695 #define SETUP_TOKEN_EDITOR_EL_SUPAPLEX          5
8696 #define SETUP_TOKEN_EDITOR_EL_DIAMOND_CAVES     6
8697 #define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH    7
8698 #define SETUP_TOKEN_EDITOR_EL_CHARS             8
8699 #define SETUP_TOKEN_EDITOR_EL_STEEL_CHARS       9
8700 #define SETUP_TOKEN_EDITOR_EL_CUSTOM            10
8701 #define SETUP_TOKEN_EDITOR_EL_HEADLINES         11
8702 #define SETUP_TOKEN_EDITOR_EL_USER_DEFINED      12
8703 #define SETUP_TOKEN_EDITOR_EL_DYNAMIC           13
8704 #define SETUP_TOKEN_EDITOR_EL_BY_GAME           14
8705 #define SETUP_TOKEN_EDITOR_EL_BY_TYPE           15
8706 #define SETUP_TOKEN_EDITOR_SHOW_ELEMENT_TOKEN   16
8707
8708 #define NUM_EDITOR_SETUP_TOKENS                 17
8709
8710 /* editor cascade setup */
8711 #define SETUP_TOKEN_EDITOR_CASCADE_BD           0
8712 #define SETUP_TOKEN_EDITOR_CASCADE_EM           1
8713 #define SETUP_TOKEN_EDITOR_CASCADE_EMC          2
8714 #define SETUP_TOKEN_EDITOR_CASCADE_RND          3
8715 #define SETUP_TOKEN_EDITOR_CASCADE_SB           4
8716 #define SETUP_TOKEN_EDITOR_CASCADE_SP           5
8717 #define SETUP_TOKEN_EDITOR_CASCADE_DC           6
8718 #define SETUP_TOKEN_EDITOR_CASCADE_DX           7
8719 #define SETUP_TOKEN_EDITOR_CASCADE_TEXT         8
8720 #define SETUP_TOKEN_EDITOR_CASCADE_STEELTEXT    9
8721 #define SETUP_TOKEN_EDITOR_CASCADE_CE           10
8722 #define SETUP_TOKEN_EDITOR_CASCADE_GE           11
8723 #define SETUP_TOKEN_EDITOR_CASCADE_REF          12
8724 #define SETUP_TOKEN_EDITOR_CASCADE_USER         13
8725 #define SETUP_TOKEN_EDITOR_CASCADE_DYNAMIC      14
8726
8727 #define NUM_EDITOR_CASCADE_SETUP_TOKENS         15
8728
8729 /* shortcut setup */
8730 #define SETUP_TOKEN_SHORTCUT_SAVE_GAME          0
8731 #define SETUP_TOKEN_SHORTCUT_LOAD_GAME          1
8732 #define SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE       2
8733 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_1     3
8734 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_2     4
8735 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_3     5
8736 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_4     6
8737 #define SETUP_TOKEN_SHORTCUT_FOCUS_PLAYER_ALL   7
8738
8739 #define NUM_SHORTCUT_SETUP_TOKENS               8
8740
8741 /* player setup */
8742 #define SETUP_TOKEN_PLAYER_USE_JOYSTICK         0
8743 #define SETUP_TOKEN_PLAYER_JOY_DEVICE_NAME      1
8744 #define SETUP_TOKEN_PLAYER_JOY_XLEFT            2
8745 #define SETUP_TOKEN_PLAYER_JOY_XMIDDLE          3
8746 #define SETUP_TOKEN_PLAYER_JOY_XRIGHT           4
8747 #define SETUP_TOKEN_PLAYER_JOY_YUPPER           5
8748 #define SETUP_TOKEN_PLAYER_JOY_YMIDDLE          6
8749 #define SETUP_TOKEN_PLAYER_JOY_YLOWER           7
8750 #define SETUP_TOKEN_PLAYER_JOY_SNAP             8
8751 #define SETUP_TOKEN_PLAYER_JOY_DROP             9
8752 #define SETUP_TOKEN_PLAYER_KEY_LEFT             10
8753 #define SETUP_TOKEN_PLAYER_KEY_RIGHT            11
8754 #define SETUP_TOKEN_PLAYER_KEY_UP               12
8755 #define SETUP_TOKEN_PLAYER_KEY_DOWN             13
8756 #define SETUP_TOKEN_PLAYER_KEY_SNAP             14
8757 #define SETUP_TOKEN_PLAYER_KEY_DROP             15
8758
8759 #define NUM_PLAYER_SETUP_TOKENS                 16
8760
8761 /* system setup */
8762 #define SETUP_TOKEN_SYSTEM_SDL_VIDEODRIVER      0
8763 #define SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER      1
8764 #define SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE  2
8765
8766 #define NUM_SYSTEM_SETUP_TOKENS                 3
8767
8768 /* options setup */
8769 #define SETUP_TOKEN_OPTIONS_VERBOSE             0
8770
8771 #define NUM_OPTIONS_SETUP_TOKENS                1
8772
8773
8774 static struct SetupInfo si;
8775 static struct SetupEditorInfo sei;
8776 static struct SetupEditorCascadeInfo seci;
8777 static struct SetupShortcutInfo ssi;
8778 static struct SetupInputInfo sii;
8779 static struct SetupSystemInfo syi;
8780 static struct OptionInfo soi;
8781
8782 static struct TokenInfo global_setup_tokens[] =
8783 {
8784   { TYPE_STRING, &si.player_name,       "player_name"                   },
8785   { TYPE_SWITCH, &si.sound,             "sound"                         },
8786   { TYPE_SWITCH, &si.sound_loops,       "repeating_sound_loops"         },
8787   { TYPE_SWITCH, &si.sound_music,       "background_music"              },
8788   { TYPE_SWITCH, &si.sound_simple,      "simple_sound_effects"          },
8789   { TYPE_SWITCH, &si.toons,             "toons"                         },
8790   { TYPE_SWITCH, &si.scroll_delay,      "scroll_delay"                  },
8791   { TYPE_INTEGER,&si.scroll_delay_value,"scroll_delay_value"            },
8792   { TYPE_SWITCH, &si.soft_scrolling,    "soft_scrolling"                },
8793   { TYPE_SWITCH, &si.fade_screens,      "fade_screens"                  },
8794   { TYPE_SWITCH, &si.autorecord,        "automatic_tape_recording"      },
8795   { TYPE_SWITCH, &si.show_titlescreen,  "show_titlescreen"              },
8796   { TYPE_SWITCH, &si.quick_doors,       "quick_doors"                   },
8797   { TYPE_SWITCH, &si.team_mode,         "team_mode"                     },
8798   { TYPE_SWITCH, &si.handicap,          "handicap"                      },
8799   { TYPE_SWITCH, &si.skip_levels,       "skip_levels"                   },
8800   { TYPE_SWITCH, &si.time_limit,        "time_limit"                    },
8801   { TYPE_SWITCH, &si.fullscreen,        "fullscreen"                    },
8802   { TYPE_STRING, &si.fullscreen_mode,   "fullscreen_mode"               },
8803   { TYPE_SWITCH, &si.ask_on_escape,     "ask_on_escape"                 },
8804   { TYPE_SWITCH, &si.ask_on_escape_editor, "ask_on_escape_editor"       },
8805   { TYPE_SWITCH, &si.quick_switch,      "quick_player_switch"           },
8806   { TYPE_SWITCH, &si.input_on_focus,    "input_on_focus"                },
8807   { TYPE_SWITCH, &si.prefer_aga_graphics, "prefer_aga_graphics"         },
8808   { TYPE_INTEGER,&si.game_frame_delay,  "game_frame_delay"              },
8809   { TYPE_STRING, &si.graphics_set,      "graphics_set"                  },
8810   { TYPE_STRING, &si.sounds_set,        "sounds_set"                    },
8811   { TYPE_STRING, &si.music_set,         "music_set"                     },
8812   { TYPE_SWITCH3,&si.override_level_graphics, "override_level_graphics" },
8813   { TYPE_SWITCH3,&si.override_level_sounds,   "override_level_sounds"   },
8814   { TYPE_SWITCH3,&si.override_level_music,    "override_level_music"    },
8815 };
8816
8817 static boolean not_used = FALSE;
8818 static struct TokenInfo editor_setup_tokens[] =
8819 {
8820 #if 1
8821   { TYPE_SWITCH, &not_used,             "editor.el_boulderdash"         },
8822   { TYPE_SWITCH, &not_used,             "editor.el_emerald_mine"        },
8823   { TYPE_SWITCH, &not_used,             "editor.el_emerald_mine_club"   },
8824   { TYPE_SWITCH, &not_used,             "editor.el_more"                },
8825   { TYPE_SWITCH, &not_used,             "editor.el_sokoban"             },
8826   { TYPE_SWITCH, &not_used,             "editor.el_supaplex"            },
8827   { TYPE_SWITCH, &not_used,             "editor.el_diamond_caves"       },
8828   { TYPE_SWITCH, &not_used,             "editor.el_dx_boulderdash"      },
8829 #else
8830   { TYPE_SWITCH, &sei.el_boulderdash,   "editor.el_boulderdash"         },
8831   { TYPE_SWITCH, &sei.el_emerald_mine,  "editor.el_emerald_mine"        },
8832   { TYPE_SWITCH, &sei.el_emerald_mine_club,"editor.el_emerald_mine_club"},
8833   { TYPE_SWITCH, &sei.el_more,          "editor.el_more"                },
8834   { TYPE_SWITCH, &sei.el_sokoban,       "editor.el_sokoban"             },
8835   { TYPE_SWITCH, &sei.el_supaplex,      "editor.el_supaplex"            },
8836   { TYPE_SWITCH, &sei.el_diamond_caves, "editor.el_diamond_caves"       },
8837   { TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash"      },
8838 #endif
8839   { TYPE_SWITCH, &sei.el_chars,         "editor.el_chars"               },
8840   { TYPE_SWITCH, &sei.el_steel_chars,   "editor.el_steel_chars"         },
8841   { TYPE_SWITCH, &sei.el_custom,        "editor.el_custom"              },
8842 #if 1
8843   { TYPE_SWITCH, &not_used,             "editor.el_headlines"           },
8844 #else
8845   { TYPE_SWITCH, &sei.el_headlines,     "editor.el_headlines"           },
8846 #endif
8847   { TYPE_SWITCH, &sei.el_user_defined,  "editor.el_user_defined"        },
8848   { TYPE_SWITCH, &sei.el_dynamic,       "editor.el_dynamic"             },
8849   { TYPE_SWITCH, &sei.el_by_game,       "editor.el_by_game"             },
8850   { TYPE_SWITCH, &sei.el_by_type,       "editor.el_by_type"             },
8851   { TYPE_SWITCH, &sei.show_element_token,"editor.show_element_token"    },
8852 };
8853
8854 static struct TokenInfo editor_cascade_setup_tokens[] =
8855 {
8856   { TYPE_SWITCH, &seci.el_bd,           "editor.cascade.el_bd"          },
8857   { TYPE_SWITCH, &seci.el_em,           "editor.cascade.el_em"          },
8858   { TYPE_SWITCH, &seci.el_emc,          "editor.cascade.el_emc"         },
8859   { TYPE_SWITCH, &seci.el_rnd,          "editor.cascade.el_rnd"         },
8860   { TYPE_SWITCH, &seci.el_sb,           "editor.cascade.el_sb"          },
8861   { TYPE_SWITCH, &seci.el_sp,           "editor.cascade.el_sp"          },
8862   { TYPE_SWITCH, &seci.el_dc,           "editor.cascade.el_dc"          },
8863   { TYPE_SWITCH, &seci.el_dx,           "editor.cascade.el_dx"          },
8864   { TYPE_SWITCH, &seci.el_chars,        "editor.cascade.el_chars"       },
8865   { TYPE_SWITCH, &seci.el_steel_chars,  "editor.cascade.el_steel_chars" },
8866   { TYPE_SWITCH, &seci.el_ce,           "editor.cascade.el_ce"          },
8867   { TYPE_SWITCH, &seci.el_ge,           "editor.cascade.el_ge"          },
8868   { TYPE_SWITCH, &seci.el_ref,          "editor.cascade.el_ref"         },
8869   { TYPE_SWITCH, &seci.el_user,         "editor.cascade.el_user"        },
8870   { TYPE_SWITCH, &seci.el_dynamic,      "editor.cascade.el_dynamic"     },
8871 };
8872
8873 static struct TokenInfo shortcut_setup_tokens[] =
8874 {
8875   { TYPE_KEY_X11, &ssi.save_game,       "shortcut.save_game"            },
8876   { TYPE_KEY_X11, &ssi.load_game,       "shortcut.load_game"            },
8877   { TYPE_KEY_X11, &ssi.toggle_pause,    "shortcut.toggle_pause"         },
8878   { TYPE_KEY_X11, &ssi.focus_player[0], "shortcut.focus_player_1"       },
8879   { TYPE_KEY_X11, &ssi.focus_player[1], "shortcut.focus_player_2"       },
8880   { TYPE_KEY_X11, &ssi.focus_player[2], "shortcut.focus_player_3"       },
8881   { TYPE_KEY_X11, &ssi.focus_player[3], "shortcut.focus_player_4"       },
8882   { TYPE_KEY_X11, &ssi.focus_player_all,"shortcut.focus_player_all"     },
8883 };
8884
8885 static struct TokenInfo player_setup_tokens[] =
8886 {
8887   { TYPE_BOOLEAN, &sii.use_joystick,    ".use_joystick"                 },
8888   { TYPE_STRING,  &sii.joy.device_name, ".joy.device_name"              },
8889   { TYPE_INTEGER, &sii.joy.xleft,       ".joy.xleft"                    },
8890   { TYPE_INTEGER, &sii.joy.xmiddle,     ".joy.xmiddle"                  },
8891   { TYPE_INTEGER, &sii.joy.xright,      ".joy.xright"                   },
8892   { TYPE_INTEGER, &sii.joy.yupper,      ".joy.yupper"                   },
8893   { TYPE_INTEGER, &sii.joy.ymiddle,     ".joy.ymiddle"                  },
8894   { TYPE_INTEGER, &sii.joy.ylower,      ".joy.ylower"                   },
8895   { TYPE_INTEGER, &sii.joy.snap,        ".joy.snap_field"               },
8896   { TYPE_INTEGER, &sii.joy.drop,        ".joy.place_bomb"               },
8897   { TYPE_KEY_X11, &sii.key.left,        ".key.move_left"                },
8898   { TYPE_KEY_X11, &sii.key.right,       ".key.move_right"               },
8899   { TYPE_KEY_X11, &sii.key.up,          ".key.move_up"                  },
8900   { TYPE_KEY_X11, &sii.key.down,        ".key.move_down"                },
8901   { TYPE_KEY_X11, &sii.key.snap,        ".key.snap_field"               },
8902   { TYPE_KEY_X11, &sii.key.drop,        ".key.place_bomb"               },
8903 };
8904
8905 static struct TokenInfo system_setup_tokens[] =
8906 {
8907   { TYPE_STRING,  &syi.sdl_videodriver, "system.sdl_videodriver"        },
8908   { TYPE_STRING,  &syi.sdl_audiodriver, "system.sdl_audiodriver"        },
8909   { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size" },
8910 };
8911
8912 static struct TokenInfo options_setup_tokens[] =
8913 {
8914   { TYPE_BOOLEAN, &soi.verbose,         "options.verbose"               },
8915 };
8916
8917 static char *get_corrected_login_name(char *login_name)
8918 {
8919   /* needed because player name must be a fixed length string */
8920   char *login_name_new = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
8921
8922   strncpy(login_name_new, login_name, MAX_PLAYER_NAME_LEN);
8923   login_name_new[MAX_PLAYER_NAME_LEN] = '\0';
8924
8925   if (strlen(login_name) > MAX_PLAYER_NAME_LEN)         /* name has been cut */
8926     if (strchr(login_name_new, ' '))
8927       *strchr(login_name_new, ' ') = '\0';
8928
8929   return login_name_new;
8930 }
8931
8932 static void setSetupInfoToDefaults(struct SetupInfo *si)
8933 {
8934   int i;
8935
8936   si->player_name = get_corrected_login_name(getLoginName());
8937
8938   si->sound = TRUE;
8939   si->sound_loops = TRUE;
8940   si->sound_music = TRUE;
8941   si->sound_simple = TRUE;
8942   si->toons = TRUE;
8943   si->scroll_delay = TRUE;
8944   si->scroll_delay_value = STD_SCROLL_DELAY;
8945   si->soft_scrolling = TRUE;
8946   si->fade_screens = TRUE;
8947   si->autorecord = TRUE;
8948   si->show_titlescreen = TRUE;
8949   si->quick_doors = FALSE;
8950   si->team_mode = FALSE;
8951   si->handicap = TRUE;
8952   si->skip_levels = TRUE;
8953   si->time_limit = TRUE;
8954   si->fullscreen = FALSE;
8955   si->fullscreen_mode = getStringCopy(DEFAULT_FULLSCREEN_MODE);
8956   si->ask_on_escape = TRUE;
8957   si->ask_on_escape_editor = TRUE;
8958   si->quick_switch = FALSE;
8959   si->input_on_focus = FALSE;
8960   si->prefer_aga_graphics = TRUE;
8961   si->game_frame_delay = GAME_FRAME_DELAY;
8962
8963   si->graphics_set = getStringCopy(GFX_DEFAULT_SUBDIR);
8964   si->sounds_set = getStringCopy(SND_DEFAULT_SUBDIR);
8965   si->music_set = getStringCopy(MUS_DEFAULT_SUBDIR);
8966   si->override_level_graphics = FALSE;
8967   si->override_level_sounds = FALSE;
8968   si->override_level_music = FALSE;
8969
8970   si->editor.el_boulderdash             = TRUE;
8971   si->editor.el_emerald_mine            = TRUE;
8972   si->editor.el_emerald_mine_club       = TRUE;
8973   si->editor.el_more                    = TRUE;
8974   si->editor.el_sokoban                 = TRUE;
8975   si->editor.el_supaplex                = TRUE;
8976   si->editor.el_diamond_caves           = TRUE;
8977   si->editor.el_dx_boulderdash          = TRUE;
8978   si->editor.el_chars                   = TRUE;
8979   si->editor.el_steel_chars             = TRUE;
8980   si->editor.el_custom                  = TRUE;
8981
8982   si->editor.el_headlines = TRUE;
8983   si->editor.el_user_defined = FALSE;
8984   si->editor.el_dynamic = TRUE;
8985
8986   si->editor.show_element_token = FALSE;
8987
8988   si->shortcut.save_game        = DEFAULT_KEY_SAVE_GAME;
8989   si->shortcut.load_game        = DEFAULT_KEY_LOAD_GAME;
8990   si->shortcut.toggle_pause     = DEFAULT_KEY_TOGGLE_PAUSE;
8991
8992   si->shortcut.focus_player[0]  = DEFAULT_KEY_FOCUS_PLAYER_1;
8993   si->shortcut.focus_player[1]  = DEFAULT_KEY_FOCUS_PLAYER_2;
8994   si->shortcut.focus_player[2]  = DEFAULT_KEY_FOCUS_PLAYER_3;
8995   si->shortcut.focus_player[3]  = DEFAULT_KEY_FOCUS_PLAYER_4;
8996   si->shortcut.focus_player_all = DEFAULT_KEY_FOCUS_PLAYER_ALL;
8997
8998   for (i = 0; i < MAX_PLAYERS; i++)
8999   {
9000     si->input[i].use_joystick = FALSE;
9001     si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
9002     si->input[i].joy.xleft   = JOYSTICK_XLEFT;
9003     si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
9004     si->input[i].joy.xright  = JOYSTICK_XRIGHT;
9005     si->input[i].joy.yupper  = JOYSTICK_YUPPER;
9006     si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
9007     si->input[i].joy.ylower  = JOYSTICK_YLOWER;
9008     si->input[i].joy.snap  = (i == 0 ? JOY_BUTTON_1 : 0);
9009     si->input[i].joy.drop  = (i == 0 ? JOY_BUTTON_2 : 0);
9010     si->input[i].key.left  = (i == 0 ? DEFAULT_KEY_LEFT  : KSYM_UNDEFINED);
9011     si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
9012     si->input[i].key.up    = (i == 0 ? DEFAULT_KEY_UP    : KSYM_UNDEFINED);
9013     si->input[i].key.down  = (i == 0 ? DEFAULT_KEY_DOWN  : KSYM_UNDEFINED);
9014     si->input[i].key.snap  = (i == 0 ? DEFAULT_KEY_SNAP  : KSYM_UNDEFINED);
9015     si->input[i].key.drop  = (i == 0 ? DEFAULT_KEY_DROP  : KSYM_UNDEFINED);
9016   }
9017
9018   si->system.sdl_videodriver = getStringCopy(ARG_DEFAULT);
9019   si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT);
9020   si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
9021
9022   si->options.verbose = FALSE;
9023
9024 #if defined(CREATE_SPECIAL_EDITION_RND_JUE)
9025   si->handicap = FALSE;
9026   si->fullscreen = TRUE;
9027   si->override_level_graphics = AUTO;
9028   si->override_level_sounds = AUTO;
9029   si->override_level_music = AUTO;
9030 #endif
9031 }
9032
9033 static void setSetupInfoToDefaults_EditorCascade(struct SetupInfo *si)
9034 {
9035   si->editor_cascade.el_bd              = TRUE;
9036   si->editor_cascade.el_em              = TRUE;
9037   si->editor_cascade.el_emc             = TRUE;
9038   si->editor_cascade.el_rnd             = TRUE;
9039   si->editor_cascade.el_sb              = TRUE;
9040   si->editor_cascade.el_sp              = TRUE;
9041   si->editor_cascade.el_dc              = TRUE;
9042   si->editor_cascade.el_dx              = TRUE;
9043
9044   si->editor_cascade.el_chars           = FALSE;
9045   si->editor_cascade.el_steel_chars     = FALSE;
9046   si->editor_cascade.el_ce              = FALSE;
9047   si->editor_cascade.el_ge              = FALSE;
9048   si->editor_cascade.el_ref             = FALSE;
9049   si->editor_cascade.el_user            = FALSE;
9050   si->editor_cascade.el_dynamic         = FALSE;
9051 }
9052
9053 static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
9054 {
9055   int i, pnr;
9056
9057   if (!setup_file_hash)
9058     return;
9059
9060   /* global setup */
9061   si = setup;
9062   for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
9063     setSetupInfo(global_setup_tokens, i,
9064                  getHashEntry(setup_file_hash, global_setup_tokens[i].text));
9065   setup = si;
9066
9067   /* editor setup */
9068   sei = setup.editor;
9069   for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
9070     setSetupInfo(editor_setup_tokens, i,
9071                  getHashEntry(setup_file_hash,editor_setup_tokens[i].text));
9072   setup.editor = sei;
9073
9074   /* shortcut setup */
9075   ssi = setup.shortcut;
9076   for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
9077     setSetupInfo(shortcut_setup_tokens, i,
9078                  getHashEntry(setup_file_hash,shortcut_setup_tokens[i].text));
9079   setup.shortcut = ssi;
9080
9081   /* player setup */
9082   for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
9083   {
9084     char prefix[30];
9085
9086     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
9087
9088     sii = setup.input[pnr];
9089     for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
9090     {
9091       char full_token[100];
9092
9093       sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
9094       setSetupInfo(player_setup_tokens, i,
9095                    getHashEntry(setup_file_hash, full_token));
9096     }
9097     setup.input[pnr] = sii;
9098   }
9099
9100   /* system setup */
9101   syi = setup.system;
9102   for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
9103     setSetupInfo(system_setup_tokens, i,
9104                  getHashEntry(setup_file_hash, system_setup_tokens[i].text));
9105   setup.system = syi;
9106
9107   /* options setup */
9108   soi = setup.options;
9109   for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
9110     setSetupInfo(options_setup_tokens, i,
9111                  getHashEntry(setup_file_hash, options_setup_tokens[i].text));
9112   setup.options = soi;
9113 }
9114
9115 static void decodeSetupFileHash_EditorCascade(SetupFileHash *setup_file_hash)
9116 {
9117   int i;
9118
9119   if (!setup_file_hash)
9120     return;
9121
9122   /* editor cascade setup */
9123   seci = setup.editor_cascade;
9124   for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
9125     setSetupInfo(editor_cascade_setup_tokens, i,
9126                  getHashEntry(setup_file_hash,
9127                               editor_cascade_setup_tokens[i].text));
9128   setup.editor_cascade = seci;
9129 }
9130
9131 void LoadSetup()
9132 {
9133   char *filename = getSetupFilename();
9134   SetupFileHash *setup_file_hash = NULL;
9135
9136   /* always start with reliable default values */
9137   setSetupInfoToDefaults(&setup);
9138
9139   setup_file_hash = loadSetupFileHash(filename);
9140
9141   if (setup_file_hash)
9142   {
9143     char *player_name_new;
9144
9145     checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP"));
9146     decodeSetupFileHash(setup_file_hash);
9147
9148     freeSetupFileHash(setup_file_hash);
9149
9150     /* needed to work around problems with fixed length strings */
9151     player_name_new = get_corrected_login_name(setup.player_name);
9152     free(setup.player_name);
9153     setup.player_name = player_name_new;
9154
9155     /* "scroll_delay: on(3) / off(0)" was replaced by scroll delay value */
9156     if (setup.scroll_delay == FALSE)
9157     {
9158       setup.scroll_delay_value = MIN_SCROLL_DELAY;
9159       setup.scroll_delay = TRUE;                        /* now always "on" */
9160     }
9161
9162     /* make sure that scroll delay value stays inside valid range */
9163     setup.scroll_delay_value =
9164       MIN(MAX(MIN_SCROLL_DELAY, setup.scroll_delay_value), MAX_SCROLL_DELAY);
9165   }
9166   else
9167     Error(ERR_WARN, "using default setup values");
9168 }
9169
9170 void LoadSetup_EditorCascade()
9171 {
9172   char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
9173   SetupFileHash *setup_file_hash = NULL;
9174
9175   /* always start with reliable default values */
9176   setSetupInfoToDefaults_EditorCascade(&setup);
9177
9178   setup_file_hash = loadSetupFileHash(filename);
9179
9180   if (setup_file_hash)
9181   {
9182     checkSetupFileHashIdentifier(setup_file_hash, filename,getCookie("SETUP"));
9183     decodeSetupFileHash_EditorCascade(setup_file_hash);
9184
9185     freeSetupFileHash(setup_file_hash);
9186   }
9187
9188   free(filename);
9189 }
9190
9191 void SaveSetup()
9192 {
9193   char *filename = getSetupFilename();
9194   FILE *file;
9195   int i, pnr;
9196
9197   InitUserDataDirectory();
9198
9199   if (!(file = fopen(filename, MODE_WRITE)))
9200   {
9201     Error(ERR_WARN, "cannot write setup file '%s'", filename);
9202     return;
9203   }
9204
9205   fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
9206                                                getCookie("SETUP")));
9207   fprintf(file, "\n");
9208
9209   /* global setup */
9210   si = setup;
9211   for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
9212   {
9213     /* just to make things nicer :) */
9214     if (i == SETUP_TOKEN_PLAYER_NAME + 1 ||
9215         i == SETUP_TOKEN_GRAPHICS_SET)
9216       fprintf(file, "\n");
9217
9218     fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
9219   }
9220
9221   /* editor setup */
9222   sei = setup.editor;
9223   fprintf(file, "\n");
9224   for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
9225     fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i));
9226
9227   /* shortcut setup */
9228   ssi = setup.shortcut;
9229   fprintf(file, "\n");
9230   for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
9231     fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
9232
9233   /* player setup */
9234   for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
9235   {
9236     char prefix[30];
9237
9238     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
9239     fprintf(file, "\n");
9240
9241     sii = setup.input[pnr];
9242     for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
9243       fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
9244   }
9245
9246   /* system setup */
9247   syi = setup.system;
9248   fprintf(file, "\n");
9249   for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
9250     fprintf(file, "%s\n", getSetupLine(system_setup_tokens, "", i));
9251
9252   /* options setup */
9253   soi = setup.options;
9254   fprintf(file, "\n");
9255   for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
9256     fprintf(file, "%s\n", getSetupLine(options_setup_tokens, "", i));
9257
9258   fclose(file);
9259
9260   SetFilePermissions(filename, PERMS_PRIVATE);
9261 }
9262
9263 void SaveSetup_EditorCascade()
9264 {
9265   char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
9266   FILE *file;
9267   int i;
9268
9269   InitUserDataDirectory();
9270
9271   if (!(file = fopen(filename, MODE_WRITE)))
9272   {
9273     Error(ERR_WARN, "cannot write editor cascade state file '%s'", filename);
9274     free(filename);
9275     return;
9276   }
9277
9278   fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
9279                                                getCookie("SETUP")));
9280   fprintf(file, "\n");
9281
9282   seci = setup.editor_cascade;
9283   fprintf(file, "\n");
9284   for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
9285     fprintf(file, "%s\n", getSetupLine(editor_cascade_setup_tokens, "", i));
9286
9287   fclose(file);
9288
9289   SetFilePermissions(filename, PERMS_PRIVATE);
9290
9291   free(filename);
9292 }
9293
9294 void LoadCustomElementDescriptions()
9295 {
9296   char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
9297   SetupFileHash *setup_file_hash;
9298   int i;
9299
9300   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9301   {
9302     if (element_info[i].custom_description != NULL)
9303     {
9304       free(element_info[i].custom_description);
9305       element_info[i].custom_description = NULL;
9306     }
9307   }
9308
9309   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
9310     return;
9311
9312   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9313   {
9314     char *token = getStringCat2(element_info[i].token_name, ".name");
9315     char *value = getHashEntry(setup_file_hash, token);
9316
9317     if (value != NULL)
9318       element_info[i].custom_description = getStringCopy(value);
9319
9320     free(token);
9321   }
9322
9323   freeSetupFileHash(setup_file_hash);
9324 }
9325
9326 static int getElementFromToken(char *token)
9327 {
9328 #if 1
9329   char *value = getHashEntry(element_token_hash, token);
9330
9331   if (value != NULL)
9332     return atoi(value);
9333 #else
9334   int i;
9335
9336   /* !!! OPTIMIZE THIS BY USING HASH !!! */
9337   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
9338     if (strEqual(token, element_info[i].token_name))
9339       return i;
9340 #endif
9341
9342   Error(ERR_WARN, "unknown element token '%s'", token);
9343
9344   return EL_UNDEFINED;
9345 }
9346
9347 static int get_token_parameter_value(char *token, char *value_raw)
9348 {
9349   char *suffix;
9350
9351   if (token == NULL || value_raw == NULL)
9352     return ARG_UNDEFINED_VALUE;
9353
9354   suffix = strrchr(token, '.');
9355   if (suffix == NULL)
9356     suffix = token;
9357
9358 #if 1
9359   if (strEqual(suffix, ".element"))
9360     return getElementFromToken(value_raw);
9361 #endif
9362
9363 #if 0
9364   if (strncmp(suffix, ".font", 5) == 0)
9365   {
9366     int i;
9367
9368     /* !!! OPTIMIZE THIS BY USING HASH !!! */
9369     for (i = 0; i < NUM_FONTS; i++)
9370       if (strEqual(value_raw, font_info[i].token_name))
9371         return i;
9372
9373     /* if font not found, use reliable default value */
9374     return FONT_INITIAL_1;
9375   }
9376 #endif
9377
9378   /* !!! USE CORRECT VALUE TYPE (currently works also for TYPE_BOOLEAN) !!! */
9379   return get_parameter_value(value_raw, suffix, TYPE_INTEGER);
9380 }
9381
9382 void InitMenuDesignSettings_Static()
9383 {
9384 #if 0
9385   static SetupFileHash *image_config_hash = NULL;
9386 #endif
9387   int i;
9388
9389 #if 0
9390   if (image_config_hash == NULL)
9391   {
9392     image_config_hash = newSetupFileHash();
9393
9394     for (i = 0; image_config[i].token != NULL; i++)
9395       setHashEntry(image_config_hash,
9396                    image_config[i].token,
9397                    image_config[i].value);
9398   }
9399 #endif
9400
9401 #if 1
9402   /* always start with reliable default values from static default config */
9403   for (i = 0; image_config_vars[i].token != NULL; i++)
9404   {
9405     char *value = getHashEntry(image_config_hash, image_config_vars[i].token);
9406
9407     if (value != NULL)
9408       *image_config_vars[i].value =
9409         get_token_parameter_value(image_config_vars[i].token, value);
9410   }
9411
9412 #else
9413
9414   int j;
9415
9416   /* always start with reliable default values from static default config */
9417   for (i = 0; image_config_vars[i].token != NULL; i++)
9418     for (j = 0; image_config[j].token != NULL; j++)
9419       if (strEqual(image_config_vars[i].token, image_config[j].token))
9420         *image_config_vars[i].value =
9421           get_token_parameter_value(image_config_vars[i].token,
9422                                     image_config[j].value);
9423 #endif
9424 }
9425
9426 static void InitMenuDesignSettings_SpecialPreProcessing()
9427 {
9428   int i;
9429
9430   /* the following initializes hierarchical values from static configuration */
9431
9432   /* special case: initialize "ARG_DEFAULT" values in static default config */
9433   /* (e.g., initialize "[titlemessage].fade_mode" from "[title].fade_mode") */
9434   titlemessage_initial_default.fade_mode  = title_initial_default.fade_mode;
9435   titlemessage_initial_default.fade_delay = title_initial_default.fade_delay;
9436   titlemessage_initial_default.post_delay = title_initial_default.post_delay;
9437   titlemessage_initial_default.auto_delay = title_initial_default.auto_delay;
9438   titlemessage_default.fade_mode  = title_default.fade_mode;
9439   titlemessage_default.fade_delay = title_default.fade_delay;
9440   titlemessage_default.post_delay = title_default.post_delay;
9441   titlemessage_default.auto_delay = title_default.auto_delay;
9442
9443   /* special case: initialize "ARG_DEFAULT" values in static default config */
9444   /* (e.g., init "titlemessage_1.fade_mode" from "[titlemessage].fade_mode") */
9445   for (i = 0; i < MAX_NUM_TITLE_MESSAGES; i++)
9446   {
9447     titlemessage_initial[i] = titlemessage_initial_default;
9448     titlemessage[i] = titlemessage_default;
9449   }
9450
9451   /* special case: initialize "ARG_DEFAULT" values in static default config */
9452   /* (eg, init "menu.enter_screen.SCORES.xyz" from "menu.enter_screen.xyz") */
9453   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
9454   {
9455     menu.enter_screen[i] = menu.enter_screen[GFX_SPECIAL_ARG_DEFAULT];
9456     menu.leave_screen[i] = menu.leave_screen[GFX_SPECIAL_ARG_DEFAULT];
9457   }
9458 }
9459
9460 static void InitMenuDesignSettings_SpecialPostProcessing()
9461 {
9462   /* special case: initialize later added SETUP list size from LEVELS value */
9463   if (menu.list_size[GAME_MODE_SETUP] == -1)
9464     menu.list_size[GAME_MODE_SETUP] = menu.list_size[GAME_MODE_LEVELS];
9465 }
9466
9467 static void LoadMenuDesignSettingsFromFilename(char *filename)
9468 {
9469   static struct TitleMessageInfo tmi;
9470   static struct TokenInfo titlemessage_tokens[] =
9471   {
9472     { TYPE_INTEGER,     &tmi.x,                 ".x"                    },
9473     { TYPE_INTEGER,     &tmi.y,                 ".y"                    },
9474     { TYPE_INTEGER,     &tmi.width,             ".width"                },
9475     { TYPE_INTEGER,     &tmi.height,            ".height"               },
9476     { TYPE_INTEGER,     &tmi.chars,             ".chars"                },
9477     { TYPE_INTEGER,     &tmi.lines,             ".lines"                },
9478     { TYPE_INTEGER,     &tmi.align,             ".align"                },
9479     { TYPE_INTEGER,     &tmi.valign,            ".valign"               },
9480     { TYPE_INTEGER,     &tmi.font,              ".font"                 },
9481     { TYPE_BOOLEAN,     &tmi.autowrap,          ".autowrap"             },
9482     { TYPE_BOOLEAN,     &tmi.centered,          ".centered"             },
9483     { TYPE_BOOLEAN,     &tmi.parse_comments,    ".parse_comments"       },
9484     { TYPE_INTEGER,     &tmi.sort_priority,     ".sort_priority"        },
9485     { TYPE_INTEGER,     &tmi.fade_mode,         ".fade_mode"            },
9486     { TYPE_INTEGER,     &tmi.fade_delay,        ".fade_delay"           },
9487     { TYPE_INTEGER,     &tmi.post_delay,        ".post_delay"           },
9488     { TYPE_INTEGER,     &tmi.auto_delay,        ".auto_delay"           },
9489
9490     { -1,               NULL,                   NULL                    }
9491   };
9492   static struct
9493   {
9494     struct TitleMessageInfo *array;
9495     char *text;
9496   }
9497   titlemessage_arrays[] =
9498   {
9499     { titlemessage_initial,             "[titlemessage_initial]"        },
9500     { titlemessage,                     "[titlemessage]"                },
9501
9502     { NULL,                             NULL                            }
9503   };
9504   SetupFileHash *setup_file_hash;
9505   int i, j, k;
9506
9507 #if 0
9508   printf("LoadMenuDesignSettings from file '%s' ...\n", filename);
9509 #endif
9510
9511   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
9512     return;
9513
9514   /* the following initializes hierarchical values from dynamic configuration */
9515
9516   /* special case: initialize with default values that may be overwritten */
9517   /* (e.g., init "menu.draw_xoffset.INFO" from "menu.draw_xoffset") */
9518   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
9519   {
9520     char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset");
9521     char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset");
9522     char *value_3 = getHashEntry(setup_file_hash, "menu.list_size");
9523
9524     if (value_1 != NULL)
9525       menu.draw_xoffset[i] = get_integer_from_string(value_1);
9526     if (value_2 != NULL)
9527       menu.draw_yoffset[i] = get_integer_from_string(value_2);
9528     if (value_3 != NULL)
9529       menu.list_size[i] = get_integer_from_string(value_3);
9530   }
9531
9532   /* special case: initialize with default values that may be overwritten */
9533   /* (eg, init "menu.draw_xoffset.INFO[XXX]" from "menu.draw_xoffset.INFO") */
9534   for (i = 0; i < NUM_SPECIAL_GFX_INFO_ARGS; i++)
9535   {
9536     char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset.INFO");
9537     char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset.INFO");
9538
9539     if (value_1 != NULL)
9540       menu.draw_xoffset_info[i] = get_integer_from_string(value_1);
9541     if (value_2 != NULL)
9542       menu.draw_yoffset_info[i] = get_integer_from_string(value_2);
9543   }
9544
9545   /* special case: initialize with default values that may be overwritten */
9546   /* (eg, init "menu.draw_xoffset.SETUP[XXX]" from "menu.draw_xoffset.SETUP") */
9547   for (i = 0; i < NUM_SPECIAL_GFX_SETUP_ARGS; i++)
9548   {
9549     char *value_1 = getHashEntry(setup_file_hash, "menu.draw_xoffset.SETUP");
9550     char *value_2 = getHashEntry(setup_file_hash, "menu.draw_yoffset.SETUP");
9551
9552     if (value_1 != NULL)
9553       menu.draw_xoffset_setup[i] = get_integer_from_string(value_1);
9554     if (value_2 != NULL)
9555       menu.draw_yoffset_setup[i] = get_integer_from_string(value_2);
9556   }
9557
9558   /* special case: initialize with default values that may be overwritten */
9559   /* (eg, init "menu.enter_screen.SCORES.xyz" from "menu.enter_screen.xyz") */
9560   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
9561   {
9562     char *token_1 = "menu.enter_screen.fade_mode";
9563     char *token_2 = "menu.enter_screen.fade_delay";
9564     char *token_3 = "menu.enter_screen.post_delay";
9565     char *token_4 = "menu.leave_screen.fade_mode";
9566     char *token_5 = "menu.leave_screen.fade_delay";
9567     char *token_6 = "menu.leave_screen.post_delay";
9568     char *value_1 = getHashEntry(setup_file_hash, token_1);
9569     char *value_2 = getHashEntry(setup_file_hash, token_2);
9570     char *value_3 = getHashEntry(setup_file_hash, token_3);
9571     char *value_4 = getHashEntry(setup_file_hash, token_4);
9572     char *value_5 = getHashEntry(setup_file_hash, token_5);
9573     char *value_6 = getHashEntry(setup_file_hash, token_6);
9574
9575     if (value_1 != NULL)
9576       menu.enter_screen[i].fade_mode = get_token_parameter_value(token_1,
9577                                                                  value_1);
9578     if (value_2 != NULL)
9579       menu.enter_screen[i].fade_delay = get_token_parameter_value(token_2,
9580                                                                   value_2);
9581     if (value_3 != NULL)
9582       menu.enter_screen[i].post_delay = get_token_parameter_value(token_3,
9583                                                                   value_3);
9584     if (value_4 != NULL)
9585       menu.leave_screen[i].fade_mode = get_token_parameter_value(token_4,
9586                                                                  value_4);
9587     if (value_5 != NULL)
9588       menu.leave_screen[i].fade_delay = get_token_parameter_value(token_5,
9589                                                                   value_5);
9590     if (value_6 != NULL)
9591       menu.leave_screen[i].post_delay = get_token_parameter_value(token_6,
9592                                                                   value_6);
9593   }
9594
9595   /* special case: initialize with default values that may be overwritten */
9596   /* (e.g., init "titlemessage_1.fade_mode" from "[titlemessage].fade_mode") */
9597   for (i = 0; titlemessage_arrays[i].array != NULL; i++)
9598   {
9599     struct TitleMessageInfo *array = titlemessage_arrays[i].array;
9600     char *base_token = titlemessage_arrays[i].text;
9601
9602     for (j = 0; titlemessage_tokens[j].type != -1; j++)
9603     {
9604       char *token = getStringCat2(base_token, titlemessage_tokens[j].text);
9605       char *value = getHashEntry(setup_file_hash, token);
9606
9607       if (value != NULL)
9608       {
9609         int parameter_value = get_token_parameter_value(token, value);
9610
9611         for (k = 0; k < MAX_NUM_TITLE_MESSAGES; k++)
9612         {
9613           tmi = array[k];
9614
9615           if (titlemessage_tokens[j].type == TYPE_INTEGER)
9616             *(boolean *)titlemessage_tokens[j].value = (boolean)parameter_value;
9617           else
9618             *(int     *)titlemessage_tokens[j].value = (int)parameter_value;
9619
9620           array[k] = tmi;
9621         }
9622       }
9623
9624       free(token);
9625     }
9626   }
9627
9628   /* read (and overwrite with) values that may be specified in config file */
9629   for (i = 0; image_config_vars[i].token != NULL; i++)
9630   {
9631     char *value = getHashEntry(setup_file_hash, image_config_vars[i].token);
9632
9633     /* (ignore definitions set to "[DEFAULT]" which are already initialized) */
9634     if (value != NULL && !strEqual(value, ARG_DEFAULT))
9635       *image_config_vars[i].value =
9636         get_token_parameter_value(image_config_vars[i].token, value);
9637   }
9638
9639   freeSetupFileHash(setup_file_hash);
9640 }
9641
9642 void LoadMenuDesignSettings()
9643 {
9644   char *filename_base = UNDEFINED_FILENAME, *filename_local;
9645
9646   InitMenuDesignSettings_Static();
9647   InitMenuDesignSettings_SpecialPreProcessing();
9648
9649 #if 1
9650   if (!GFX_OVERRIDE_ARTWORK(ARTWORK_TYPE_GRAPHICS))
9651 #else
9652   if (!SETUP_OVERRIDE_ARTWORK(setup, ARTWORK_TYPE_GRAPHICS))
9653 #endif
9654   {
9655     /* first look for special settings configured in level series config */
9656     filename_base = getCustomArtworkLevelConfigFilename(ARTWORK_TYPE_GRAPHICS);
9657
9658     if (fileExists(filename_base))
9659       LoadMenuDesignSettingsFromFilename(filename_base);
9660   }
9661
9662   filename_local = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
9663
9664   if (filename_local != NULL && !strEqual(filename_base, filename_local))
9665     LoadMenuDesignSettingsFromFilename(filename_local);
9666
9667   InitMenuDesignSettings_SpecialPostProcessing();
9668 }
9669
9670 void LoadUserDefinedEditorElementList(int **elements, int *num_elements)
9671 {
9672   char *filename = getEditorSetupFilename();
9673   SetupFileList *setup_file_list, *list;
9674   SetupFileHash *element_hash;
9675   int num_unknown_tokens = 0;
9676   int i;
9677
9678   if ((setup_file_list = loadSetupFileList(filename)) == NULL)
9679     return;
9680
9681   element_hash = newSetupFileHash();
9682
9683   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9684     setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
9685
9686   /* determined size may be larger than needed (due to unknown elements) */
9687   *num_elements = 0;
9688   for (list = setup_file_list; list != NULL; list = list->next)
9689     (*num_elements)++;
9690
9691   /* add space for up to 3 more elements for padding that may be needed */
9692   *num_elements += 3;
9693
9694   /* free memory for old list of elements, if needed */
9695   checked_free(*elements);
9696
9697   /* allocate memory for new list of elements */
9698   *elements = checked_malloc(*num_elements * sizeof(int));
9699
9700   *num_elements = 0;
9701   for (list = setup_file_list; list != NULL; list = list->next)
9702   {
9703     char *value = getHashEntry(element_hash, list->token);
9704
9705     if (value == NULL)          /* try to find obsolete token mapping */
9706     {
9707       char *mapped_token = get_mapped_token(list->token);
9708
9709       if (mapped_token != NULL)
9710       {
9711         value = getHashEntry(element_hash, mapped_token);
9712
9713         free(mapped_token);
9714       }
9715     }
9716
9717     if (value != NULL)
9718     {
9719       (*elements)[(*num_elements)++] = atoi(value);
9720     }
9721     else
9722     {
9723       if (num_unknown_tokens == 0)
9724       {
9725         Error(ERR_INFO_LINE, "-");
9726         Error(ERR_INFO, "warning: unknown token(s) found in config file:");
9727         Error(ERR_INFO, "- config file: '%s'", filename);
9728
9729         num_unknown_tokens++;
9730       }
9731
9732       Error(ERR_INFO, "- token: '%s'", list->token);
9733     }
9734   }
9735
9736   if (num_unknown_tokens > 0)
9737     Error(ERR_INFO_LINE, "-");
9738
9739   while (*num_elements % 4)     /* pad with empty elements, if needed */
9740     (*elements)[(*num_elements)++] = EL_EMPTY;
9741
9742   freeSetupFileList(setup_file_list);
9743   freeSetupFileHash(element_hash);
9744
9745 #if 0
9746   for (i = 0; i < *num_elements; i++)
9747     printf("editor: element '%s' [%d]\n",
9748            element_info[(*elements)[i]].token_name, (*elements)[i]);
9749 #endif
9750 }
9751
9752 static struct MusicFileInfo *get_music_file_info_ext(char *basename, int music,
9753                                                      boolean is_sound)
9754 {
9755   SetupFileHash *setup_file_hash = NULL;
9756   struct MusicFileInfo tmp_music_file_info, *new_music_file_info;
9757   char *filename_music, *filename_prefix, *filename_info;
9758   struct
9759   {
9760     char *token;
9761     char **value_ptr;
9762   }
9763   token_to_value_ptr[] =
9764   {
9765     { "title_header",   &tmp_music_file_info.title_header       },
9766     { "artist_header",  &tmp_music_file_info.artist_header      },
9767     { "album_header",   &tmp_music_file_info.album_header       },
9768     { "year_header",    &tmp_music_file_info.year_header        },
9769
9770     { "title",          &tmp_music_file_info.title              },
9771     { "artist",         &tmp_music_file_info.artist             },
9772     { "album",          &tmp_music_file_info.album              },
9773     { "year",           &tmp_music_file_info.year               },
9774
9775     { NULL,             NULL                                    },
9776   };
9777   int i;
9778
9779   filename_music = (is_sound ? getCustomSoundFilename(basename) :
9780                     getCustomMusicFilename(basename));
9781
9782   if (filename_music == NULL)
9783     return NULL;
9784
9785   /* ---------- try to replace file extension ---------- */
9786
9787   filename_prefix = getStringCopy(filename_music);
9788   if (strrchr(filename_prefix, '.') != NULL)
9789     *strrchr(filename_prefix, '.') = '\0';
9790   filename_info = getStringCat2(filename_prefix, ".txt");
9791
9792 #if 0
9793   printf("trying to load file '%s'...\n", filename_info);
9794 #endif
9795
9796   if (fileExists(filename_info))
9797     setup_file_hash = loadSetupFileHash(filename_info);
9798
9799   free(filename_prefix);
9800   free(filename_info);
9801
9802   if (setup_file_hash == NULL)
9803   {
9804     /* ---------- try to add file extension ---------- */
9805
9806     filename_prefix = getStringCopy(filename_music);
9807     filename_info = getStringCat2(filename_prefix, ".txt");
9808
9809 #if 0
9810     printf("trying to load file '%s'...\n", filename_info);
9811 #endif
9812
9813     if (fileExists(filename_info))
9814       setup_file_hash = loadSetupFileHash(filename_info);
9815
9816     free(filename_prefix);
9817     free(filename_info);
9818   }
9819
9820   if (setup_file_hash == NULL)
9821     return NULL;
9822
9823   /* ---------- music file info found ---------- */
9824
9825   clear_mem(&tmp_music_file_info, sizeof(struct MusicFileInfo));
9826
9827   for (i = 0; token_to_value_ptr[i].token != NULL; i++)
9828   {
9829     char *value = getHashEntry(setup_file_hash, token_to_value_ptr[i].token);
9830
9831     *token_to_value_ptr[i].value_ptr =
9832       getStringCopy(value != NULL && *value != '\0' ? value : UNKNOWN_NAME);
9833   }
9834
9835   tmp_music_file_info.basename = getStringCopy(basename);
9836   tmp_music_file_info.music = music;
9837   tmp_music_file_info.is_sound = is_sound;
9838
9839   new_music_file_info = checked_malloc(sizeof(struct MusicFileInfo));
9840   *new_music_file_info = tmp_music_file_info;
9841
9842   return new_music_file_info;
9843 }
9844
9845 static struct MusicFileInfo *get_music_file_info(char *basename, int music)
9846 {
9847   return get_music_file_info_ext(basename, music, FALSE);
9848 }
9849
9850 static struct MusicFileInfo *get_sound_file_info(char *basename, int sound)
9851 {
9852   return get_music_file_info_ext(basename, sound, TRUE);
9853 }
9854
9855 static boolean music_info_listed_ext(struct MusicFileInfo *list,
9856                                      char *basename, boolean is_sound)
9857 {
9858   for (; list != NULL; list = list->next)
9859     if (list->is_sound == is_sound && strEqual(list->basename, basename))
9860       return TRUE;
9861
9862   return FALSE;
9863 }
9864
9865 static boolean music_info_listed(struct MusicFileInfo *list, char *basename)
9866 {
9867   return music_info_listed_ext(list, basename, FALSE);
9868 }
9869
9870 static boolean sound_info_listed(struct MusicFileInfo *list, char *basename)
9871 {
9872   return music_info_listed_ext(list, basename, TRUE);
9873 }
9874
9875 void LoadMusicInfo()
9876 {
9877   char *music_directory = getCustomMusicDirectory();
9878   int num_music = getMusicListSize();
9879   int num_music_noconf = 0;
9880   int num_sounds = getSoundListSize();
9881   DIR *dir;
9882   struct dirent *dir_entry;
9883   struct FileInfo *music, *sound;
9884   struct MusicFileInfo *next, **new;
9885   int i;
9886
9887   while (music_file_info != NULL)
9888   {
9889     next = music_file_info->next;
9890
9891     checked_free(music_file_info->basename);
9892
9893     checked_free(music_file_info->title_header);
9894     checked_free(music_file_info->artist_header);
9895     checked_free(music_file_info->album_header);
9896     checked_free(music_file_info->year_header);
9897
9898     checked_free(music_file_info->title);
9899     checked_free(music_file_info->artist);
9900     checked_free(music_file_info->album);
9901     checked_free(music_file_info->year);
9902
9903     free(music_file_info);
9904
9905     music_file_info = next;
9906   }
9907
9908   new = &music_file_info;
9909
9910   for (i = 0; i < num_music; i++)
9911   {
9912     music = getMusicListEntry(i);
9913
9914     if (music->filename == NULL)
9915       continue;
9916
9917     if (strEqual(music->filename, UNDEFINED_FILENAME))
9918       continue;
9919
9920     /* a configured file may be not recognized as music */
9921     if (!FileIsMusic(music->filename))
9922       continue;
9923
9924 #if 0
9925     printf("::: -> '%s' (configured)\n", music->filename);
9926 #endif
9927
9928     if (!music_info_listed(music_file_info, music->filename))
9929     {
9930       *new = get_music_file_info(music->filename, i);
9931       if (*new != NULL)
9932         new = &(*new)->next;
9933     }
9934   }
9935
9936   if ((dir = opendir(music_directory)) == NULL)
9937   {
9938     Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
9939     return;
9940   }
9941
9942   while ((dir_entry = readdir(dir)) != NULL)    /* loop until last dir entry */
9943   {
9944     char *basename = dir_entry->d_name;
9945     boolean music_already_used = FALSE;
9946     int i;
9947
9948     /* skip all music files that are configured in music config file */
9949     for (i = 0; i < num_music; i++)
9950     {
9951       music = getMusicListEntry(i);
9952
9953       if (music->filename == NULL)
9954         continue;
9955
9956       if (strEqual(basename, music->filename))
9957       {
9958         music_already_used = TRUE;
9959         break;
9960       }
9961     }
9962
9963     if (music_already_used)
9964       continue;
9965
9966     if (!FileIsMusic(basename))
9967       continue;
9968
9969 #if 0
9970     printf("::: -> '%s' (found in directory)\n", basename);
9971 #endif
9972
9973     if (!music_info_listed(music_file_info, basename))
9974     {
9975       *new = get_music_file_info(basename, MAP_NOCONF_MUSIC(num_music_noconf));
9976       if (*new != NULL)
9977         new = &(*new)->next;
9978     }
9979
9980     num_music_noconf++;
9981   }
9982
9983   closedir(dir);
9984
9985   for (i = 0; i < num_sounds; i++)
9986   {
9987     sound = getSoundListEntry(i);
9988
9989     if (sound->filename == NULL)
9990       continue;
9991
9992     if (strEqual(sound->filename, UNDEFINED_FILENAME))
9993       continue;
9994
9995     /* a configured file may be not recognized as sound */
9996     if (!FileIsSound(sound->filename))
9997       continue;
9998
9999 #if 0
10000     printf("::: -> '%s' (configured)\n", sound->filename);
10001 #endif
10002
10003     if (!sound_info_listed(music_file_info, sound->filename))
10004     {
10005       *new = get_sound_file_info(sound->filename, i);
10006       if (*new != NULL)
10007         new = &(*new)->next;
10008     }
10009   }
10010
10011 #if 0
10012   for (next = music_file_info; next != NULL; next = next->next)
10013     printf("::: title == '%s'\n", next->title);
10014 #endif
10015 }
10016
10017 void add_helpanim_entry(int element, int action, int direction, int delay,
10018                         int *num_list_entries)
10019 {
10020   struct HelpAnimInfo *new_list_entry;
10021   (*num_list_entries)++;
10022
10023   helpanim_info =
10024     checked_realloc(helpanim_info,
10025                     *num_list_entries * sizeof(struct HelpAnimInfo));
10026   new_list_entry = &helpanim_info[*num_list_entries - 1];
10027
10028   new_list_entry->element = element;
10029   new_list_entry->action = action;
10030   new_list_entry->direction = direction;
10031   new_list_entry->delay = delay;
10032 }
10033
10034 void print_unknown_token(char *filename, char *token, int token_nr)
10035 {
10036   if (token_nr == 0)
10037   {
10038     Error(ERR_INFO_LINE, "-");
10039     Error(ERR_INFO, "warning: unknown token(s) found in config file:");
10040     Error(ERR_INFO, "- config file: '%s'", filename);
10041   }
10042
10043   Error(ERR_INFO, "- token: '%s'", token);
10044 }
10045
10046 void print_unknown_token_end(int token_nr)
10047 {
10048   if (token_nr > 0)
10049     Error(ERR_INFO_LINE, "-");
10050 }
10051
10052 void LoadHelpAnimInfo()
10053 {
10054   char *filename = getHelpAnimFilename();
10055   SetupFileList *setup_file_list = NULL, *list;
10056   SetupFileHash *element_hash, *action_hash, *direction_hash;
10057   int num_list_entries = 0;
10058   int num_unknown_tokens = 0;
10059   int i;
10060
10061   if (fileExists(filename))
10062     setup_file_list = loadSetupFileList(filename);
10063
10064   if (setup_file_list == NULL)
10065   {
10066     /* use reliable default values from static configuration */
10067     SetupFileList *insert_ptr;
10068
10069     insert_ptr = setup_file_list =
10070       newSetupFileList(helpanim_config[0].token,
10071                        helpanim_config[0].value);
10072
10073     for (i = 1; helpanim_config[i].token; i++)
10074       insert_ptr = addListEntry(insert_ptr,
10075                                 helpanim_config[i].token,
10076                                 helpanim_config[i].value);
10077   }
10078
10079   element_hash   = newSetupFileHash();
10080   action_hash    = newSetupFileHash();
10081   direction_hash = newSetupFileHash();
10082
10083   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
10084     setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
10085
10086   for (i = 0; i < NUM_ACTIONS; i++)
10087     setHashEntry(action_hash, element_action_info[i].suffix,
10088                  i_to_a(element_action_info[i].value));
10089
10090   /* do not store direction index (bit) here, but direction value! */
10091   for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
10092     setHashEntry(direction_hash, element_direction_info[i].suffix,
10093                  i_to_a(1 << element_direction_info[i].value));
10094
10095   for (list = setup_file_list; list != NULL; list = list->next)
10096   {
10097     char *element_token, *action_token, *direction_token;
10098     char *element_value, *action_value, *direction_value;
10099     int delay = atoi(list->value);
10100
10101     if (strEqual(list->token, "end"))
10102     {
10103       add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
10104
10105       continue;
10106     }
10107
10108     /* first try to break element into element/action/direction parts;
10109        if this does not work, also accept combined "element[.act][.dir]"
10110        elements (like "dynamite.active"), which are unique elements */
10111
10112     if (strchr(list->token, '.') == NULL)       /* token contains no '.' */
10113     {
10114       element_value = getHashEntry(element_hash, list->token);
10115       if (element_value != NULL)        /* element found */
10116         add_helpanim_entry(atoi(element_value), -1, -1, delay,
10117                            &num_list_entries);
10118       else
10119       {
10120         /* no further suffixes found -- this is not an element */
10121         print_unknown_token(filename, list->token, num_unknown_tokens++);
10122       }
10123
10124       continue;
10125     }
10126
10127     /* token has format "<prefix>.<something>" */
10128
10129     action_token = strchr(list->token, '.');    /* suffix may be action ... */
10130     direction_token = action_token;             /* ... or direction */
10131
10132     element_token = getStringCopy(list->token);
10133     *strchr(element_token, '.') = '\0';
10134
10135     element_value = getHashEntry(element_hash, element_token);
10136
10137     if (element_value == NULL)          /* this is no element */
10138     {
10139       element_value = getHashEntry(element_hash, list->token);
10140       if (element_value != NULL)        /* combined element found */
10141         add_helpanim_entry(atoi(element_value), -1, -1, delay,
10142                            &num_list_entries);
10143       else
10144         print_unknown_token(filename, list->token, num_unknown_tokens++);
10145
10146       free(element_token);
10147
10148       continue;
10149     }
10150
10151     action_value = getHashEntry(action_hash, action_token);
10152
10153     if (action_value != NULL)           /* action found */
10154     {
10155       add_helpanim_entry(atoi(element_value), atoi(action_value), -1, delay,
10156                     &num_list_entries);
10157
10158       free(element_token);
10159
10160       continue;
10161     }
10162
10163     direction_value = getHashEntry(direction_hash, direction_token);
10164
10165     if (direction_value != NULL)        /* direction found */
10166     {
10167       add_helpanim_entry(atoi(element_value), -1, atoi(direction_value), delay,
10168                          &num_list_entries);
10169
10170       free(element_token);
10171
10172       continue;
10173     }
10174
10175     if (strchr(action_token + 1, '.') == NULL)
10176     {
10177       /* no further suffixes found -- this is not an action nor direction */
10178
10179       element_value = getHashEntry(element_hash, list->token);
10180       if (element_value != NULL)        /* combined element found */
10181         add_helpanim_entry(atoi(element_value), -1, -1, delay,
10182                            &num_list_entries);
10183       else
10184         print_unknown_token(filename, list->token, num_unknown_tokens++);
10185
10186       free(element_token);
10187
10188       continue;
10189     }
10190
10191     /* token has format "<prefix>.<suffix>.<something>" */
10192
10193     direction_token = strchr(action_token + 1, '.');
10194
10195     action_token = getStringCopy(action_token);
10196     *strchr(action_token + 1, '.') = '\0';
10197
10198     action_value = getHashEntry(action_hash, action_token);
10199
10200     if (action_value == NULL)           /* this is no action */
10201     {
10202       element_value = getHashEntry(element_hash, list->token);
10203       if (element_value != NULL)        /* combined element found */
10204         add_helpanim_entry(atoi(element_value), -1, -1, delay,
10205                            &num_list_entries);
10206       else
10207         print_unknown_token(filename, list->token, num_unknown_tokens++);
10208
10209       free(element_token);
10210       free(action_token);
10211
10212       continue;
10213     }
10214
10215     direction_value = getHashEntry(direction_hash, direction_token);
10216
10217     if (direction_value != NULL)        /* direction found */
10218     {
10219       add_helpanim_entry(atoi(element_value), atoi(action_value),
10220                          atoi(direction_value), delay, &num_list_entries);
10221
10222       free(element_token);
10223       free(action_token);
10224
10225       continue;
10226     }
10227
10228     /* this is no direction */
10229
10230     element_value = getHashEntry(element_hash, list->token);
10231     if (element_value != NULL)          /* combined element found */
10232       add_helpanim_entry(atoi(element_value), -1, -1, delay,
10233                          &num_list_entries);
10234     else
10235       print_unknown_token(filename, list->token, num_unknown_tokens++);
10236
10237     free(element_token);
10238     free(action_token);
10239   }
10240
10241   print_unknown_token_end(num_unknown_tokens);
10242
10243   add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
10244   add_helpanim_entry(HELPANIM_LIST_END,  -1, -1, -1, &num_list_entries);
10245
10246   freeSetupFileList(setup_file_list);
10247   freeSetupFileHash(element_hash);
10248   freeSetupFileHash(action_hash);
10249   freeSetupFileHash(direction_hash);
10250
10251 #if 0
10252   for (i = 0; i < num_list_entries; i++)
10253     printf("::: '%s': %d, %d, %d => %d\n",
10254            EL_NAME(helpanim_info[i].element),
10255            helpanim_info[i].element,
10256            helpanim_info[i].action,
10257            helpanim_info[i].direction,
10258            helpanim_info[i].delay);
10259 #endif
10260 }
10261
10262 void LoadHelpTextInfo()
10263 {
10264   char *filename = getHelpTextFilename();
10265   int i;
10266
10267   if (helptext_info != NULL)
10268   {
10269     freeSetupFileHash(helptext_info);
10270     helptext_info = NULL;
10271   }
10272
10273   if (fileExists(filename))
10274     helptext_info = loadSetupFileHash(filename);
10275
10276   if (helptext_info == NULL)
10277   {
10278     /* use reliable default values from static configuration */
10279     helptext_info = newSetupFileHash();
10280
10281     for (i = 0; helptext_config[i].token; i++)
10282       setHashEntry(helptext_info,
10283                    helptext_config[i].token,
10284                    helptext_config[i].value);
10285   }
10286
10287 #if 0
10288   BEGIN_HASH_ITERATION(helptext_info, itr)
10289   {
10290     printf("::: '%s' => '%s'\n",
10291            HASH_ITERATION_TOKEN(itr), HASH_ITERATION_VALUE(itr));
10292   }
10293   END_HASH_ITERATION(hash, itr)
10294 #endif
10295 }
10296
10297
10298 /* ------------------------------------------------------------------------- */
10299 /* convert levels                                                            */
10300 /* ------------------------------------------------------------------------- */
10301
10302 #define MAX_NUM_CONVERT_LEVELS          1000
10303
10304 void ConvertLevels()
10305 {
10306   static LevelDirTree *convert_leveldir = NULL;
10307   static int convert_level_nr = -1;
10308   static int num_levels_handled = 0;
10309   static int num_levels_converted = 0;
10310   static boolean levels_failed[MAX_NUM_CONVERT_LEVELS];
10311   int i;
10312
10313   convert_leveldir = getTreeInfoFromIdentifier(leveldir_first,
10314                                                global.convert_leveldir);
10315
10316   if (convert_leveldir == NULL)
10317     Error(ERR_EXIT, "no such level identifier: '%s'",
10318           global.convert_leveldir);
10319
10320   leveldir_current = convert_leveldir;
10321
10322   if (global.convert_level_nr != -1)
10323   {
10324     convert_leveldir->first_level = global.convert_level_nr;
10325     convert_leveldir->last_level  = global.convert_level_nr;
10326   }
10327
10328   convert_level_nr = convert_leveldir->first_level;
10329
10330   printf_line("=", 79);
10331   printf("Converting levels\n");
10332   printf_line("-", 79);
10333   printf("Level series identifier: '%s'\n", convert_leveldir->identifier);
10334   printf("Level series name:       '%s'\n", convert_leveldir->name);
10335   printf("Level series author:     '%s'\n", convert_leveldir->author);
10336   printf("Number of levels:        %d\n",   convert_leveldir->levels);
10337   printf_line("=", 79);
10338   printf("\n");
10339
10340   for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++)
10341     levels_failed[i] = FALSE;
10342
10343   while (convert_level_nr <= convert_leveldir->last_level)
10344   {
10345     char *level_filename;
10346     boolean new_level;
10347
10348     level_nr = convert_level_nr++;
10349
10350     printf("Level %03d: ", level_nr);
10351
10352     LoadLevel(level_nr);
10353     if (level.no_valid_file)
10354     {
10355       printf("(no level)\n");
10356       continue;
10357     }
10358
10359     printf("converting level ... ");
10360
10361     level_filename = getDefaultLevelFilename(level_nr);
10362     new_level = !fileExists(level_filename);
10363
10364     if (new_level)
10365     {
10366       SaveLevel(level_nr);
10367
10368       num_levels_converted++;
10369
10370       printf("converted.\n");
10371     }
10372     else
10373     {
10374       if (level_nr >= 0 && level_nr < MAX_NUM_CONVERT_LEVELS)
10375         levels_failed[level_nr] = TRUE;
10376
10377       printf("NOT CONVERTED -- LEVEL ALREADY EXISTS.\n");
10378     }
10379
10380     num_levels_handled++;
10381   }
10382
10383   printf("\n");
10384   printf_line("=", 79);
10385   printf("Number of levels handled: %d\n", num_levels_handled);
10386   printf("Number of levels converted: %d (%d%%)\n", num_levels_converted,
10387          (num_levels_handled ?
10388           num_levels_converted * 100 / num_levels_handled : 0));
10389   printf_line("-", 79);
10390   printf("Summary (for automatic parsing by scripts):\n");
10391   printf("LEVELDIR '%s', CONVERTED %d/%d (%d%%)",
10392          convert_leveldir->identifier, num_levels_converted,
10393          num_levels_handled,
10394          (num_levels_handled ?
10395           num_levels_converted * 100 / num_levels_handled : 0));
10396
10397   if (num_levels_handled != num_levels_converted)
10398   {
10399     printf(", FAILED:");
10400     for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++)
10401       if (levels_failed[i])
10402         printf(" %03d", i);
10403   }
10404
10405   printf("\n");
10406   printf_line("=", 79);
10407
10408   CloseAllAndExit(0);
10409 }
10410
10411
10412 /* ------------------------------------------------------------------------- */
10413 /* create and save images for use in level sketches (raw BMP format)         */
10414 /* ------------------------------------------------------------------------- */
10415
10416 void CreateLevelSketchImages()
10417 {
10418 #if defined(TARGET_SDL)
10419   Bitmap *bitmap1;
10420   Bitmap *bitmap2;
10421   int i;
10422
10423   InitElementPropertiesGfxElement();
10424
10425   bitmap1 = CreateBitmap(TILEX, TILEY, DEFAULT_DEPTH);
10426   bitmap2 = CreateBitmap(MINI_TILEX, MINI_TILEY, DEFAULT_DEPTH);
10427
10428   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
10429   {
10430     Bitmap *src_bitmap;
10431     int src_x, src_y;
10432     int element = getMappedElement(i);
10433     int graphic = el2edimg(element);
10434     char basename1[16];
10435     char basename2[16];
10436     char *filename1;
10437     char *filename2;
10438
10439     sprintf(basename1, "%03d.bmp", i);
10440     sprintf(basename2, "%03ds.bmp", i);
10441
10442     filename1 = getPath2(global.create_images_dir, basename1);
10443     filename2 = getPath2(global.create_images_dir, basename2);
10444
10445     getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
10446     BlitBitmap(src_bitmap, bitmap1, src_x, src_y, TILEX, TILEY, 0, 0);
10447
10448     if (SDL_SaveBMP(bitmap1->surface, filename1) != 0)
10449       Error(ERR_EXIT, "cannot save level sketch image file '%s'", filename1);
10450
10451     getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
10452     BlitBitmap(src_bitmap, bitmap2, src_x, src_y, MINI_TILEX, MINI_TILEY, 0, 0);
10453
10454     if (SDL_SaveBMP(bitmap2->surface, filename2) != 0)
10455       Error(ERR_EXIT, "cannot save level sketch image file '%s'", filename2);
10456
10457     free(filename1);
10458     free(filename2);
10459
10460     if (options.debug)
10461       printf("%03d `%03d%c", i, i, (i % 10 < 9 ? ' ' : '\n'));
10462   }
10463
10464   FreeBitmap(bitmap1);
10465   FreeBitmap(bitmap2);
10466
10467   if (options.debug)
10468     printf("\n");
10469
10470   Error(ERR_INFO, "%d normal and small images created", NUM_FILE_ELEMENTS);
10471
10472   CloseAllAndExit(0);
10473 #endif
10474 }
10475
10476
10477 /* ------------------------------------------------------------------------- */
10478 /* create and save images for custom and group elements (raw BMP format)     */
10479 /* ------------------------------------------------------------------------- */
10480
10481 void CreateCustomElementImages()
10482 {
10483 #if defined(TARGET_SDL)
10484   char *filename = "graphics.classic/RocksCE.bmp";
10485   Bitmap *bitmap;
10486   Bitmap *src_bitmap;
10487   int dummy_graphic = IMG_CUSTOM_99;
10488   int yoffset_ce = 0;
10489   int yoffset_ge = (TILEY * NUM_CUSTOM_ELEMENTS / 16);
10490   int src_x, src_y;
10491   int i;
10492
10493   bitmap = CreateBitmap(TILEX * 16 * 2,
10494                         TILEY * (NUM_CUSTOM_ELEMENTS + NUM_GROUP_ELEMENTS) / 16,
10495                         DEFAULT_DEPTH);
10496
10497   getGraphicSource(dummy_graphic, 0, &src_bitmap, &src_x, &src_y);
10498
10499   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
10500   {
10501     int x = i % 16;
10502     int y = i / 16;
10503     int ii = i + 1;
10504     int j;
10505
10506     BlitBitmap(src_bitmap, bitmap, 0, 0, TILEX, TILEY,
10507                TILEX * x, TILEY * y + yoffset_ce);
10508
10509     BlitBitmap(src_bitmap, bitmap, 0, TILEY, TILEX, TILEY,
10510                TILEX * x + TILEX * 16, TILEY * y + yoffset_ce);
10511
10512     for (j = 2; j >= 0; j--)
10513     {
10514       int c = ii % 10;
10515
10516       BlitBitmap(src_bitmap, bitmap, TILEX + c * 7, 0, 6, 10,
10517                  TILEX * x + 6 + j * 7,
10518                  TILEY * y + 11 + yoffset_ce);
10519
10520       BlitBitmap(src_bitmap, bitmap, TILEX + c * 8, TILEY, 6, 10,
10521                  TILEX * 16 + TILEX * x + 6 + j * 8,
10522                  TILEY * y + 10 + yoffset_ce);
10523
10524       ii /= 10;
10525     }
10526   }
10527
10528   for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
10529   {
10530     int x = i % 16;
10531     int y = i / 16;
10532     int ii = i + 1;
10533     int j;
10534
10535     BlitBitmap(src_bitmap, bitmap, 0, 0, TILEX, TILEY,
10536                TILEX * x, TILEY * y + yoffset_ge);
10537
10538     BlitBitmap(src_bitmap, bitmap, 0, TILEY, TILEX, TILEY,
10539                TILEX * x + TILEX * 16, TILEY * y + yoffset_ge);
10540
10541     for (j = 1; j >= 0; j--)
10542     {
10543       int c = ii % 10;
10544
10545       BlitBitmap(src_bitmap, bitmap, TILEX + c * 10, 11, 10, 10,
10546                  TILEX * x + 6 + j * 10,
10547                  TILEY * y + 11 + yoffset_ge);
10548
10549       BlitBitmap(src_bitmap, bitmap, TILEX + c * 8, TILEY + 12, 6, 10,
10550                  TILEX * 16 + TILEX * x + 10 + j * 8,
10551                  TILEY * y + 10 + yoffset_ge);
10552
10553       ii /= 10;
10554     }
10555   }
10556
10557   if (SDL_SaveBMP(bitmap->surface, filename) != 0)
10558     Error(ERR_EXIT, "cannot save CE graphics file '%s'", filename);
10559
10560   FreeBitmap(bitmap);
10561
10562   CloseAllAndExit(0);
10563 #endif
10564 }
10565
10566 #if 0
10567 void CreateLevelSketchImages_TEST()
10568 {
10569   void CreateCustomElementImages()
10570 }
10571 #endif