0d4f895c34c050bd381c1df74a63ad641975b1f2
[rocksndiamonds.git] / src / files.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * files.c                                                  *
12 ***********************************************************/
13
14 #include <ctype.h>
15 #include <sys/stat.h>
16 #include <dirent.h>
17 #include <math.h>
18
19 #include "libgame/libgame.h"
20
21 #include "files.h"
22 #include "init.h"
23 #include "tools.h"
24 #include "tape.h"
25
26
27 #define CHUNK_ID_LEN            4       /* IFF style chunk id length  */
28 #define CHUNK_SIZE_UNDEFINED    0       /* undefined chunk size == 0  */
29 #define CHUNK_SIZE_NONE         -1      /* do not write chunk size    */
30 #define FILE_VERS_CHUNK_SIZE    8       /* size of file version chunk */
31 #define LEVEL_HEADER_SIZE       80      /* size of level file header  */
32 #define LEVEL_HEADER_UNUSED     0       /* unused level header bytes  */
33 #define LEVEL_CHUNK_CNT2_SIZE   160     /* size of level CNT2 chunk   */
34 #define LEVEL_CHUNK_CNT2_UNUSED 11      /* unused CNT2 chunk bytes    */
35 #define LEVEL_CHUNK_CNT3_HEADER 16      /* size of level CNT3 header  */
36 #define LEVEL_CHUNK_CNT3_UNUSED 10      /* unused CNT3 chunk bytes    */
37 #define LEVEL_CPART_CUS3_SIZE   134     /* size of CUS3 chunk part    */
38 #define LEVEL_CPART_CUS3_UNUSED 15      /* unused CUS3 bytes / part   */
39 #define LEVEL_CHUNK_GRP1_SIZE   74      /* size of level GRP1 chunk   */
40 #define TAPE_HEADER_SIZE        20      /* size of tape file header   */
41 #define TAPE_HEADER_UNUSED      3       /* unused tape header bytes   */
42
43 #define LEVEL_CHUNK_CNT3_SIZE(x)         (LEVEL_CHUNK_CNT3_HEADER + (x))
44 #define LEVEL_CHUNK_CUS3_SIZE(x)         (2 + (x) * LEVEL_CPART_CUS3_SIZE)
45 #define LEVEL_CHUNK_CUS4_SIZE(x)         (96 + (x) * 48)
46
47 /* file identifier strings */
48 #define LEVEL_COOKIE_TMPL               "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x"
49 #define TAPE_COOKIE_TMPL                "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
50 #define SCORE_COOKIE                    "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
51
52 /* values for "CONF" chunk */
53 #define CONF_MASK_1_BYTE                0x00
54 #define CONF_MASK_2_BYTE                0x40
55 #define CONF_MASK_4_BYTE                0x80
56 #define CONF_MASK_MULTI_BYTES           0xc0
57
58 #define CONF_MASK_BYTES                 0xc0
59 #define CONF_MASK_TOKEN                 0x3f
60
61 #define CONF_LAST_ENTRY                 (CONF_MASK_1_BYTE | 0)
62
63 #define CONF_VALUE_INTEGER_1            (CONF_MASK_1_BYTE | 1)
64 #define CONF_VALUE_INTEGER_2            (CONF_MASK_1_BYTE | 2)
65 #define CONF_VALUE_INTEGER_3            (CONF_MASK_1_BYTE | 3)
66 #define CONF_VALUE_INTEGER_4            (CONF_MASK_1_BYTE | 4)
67 #define CONF_VALUE_INTEGER_5            (CONF_MASK_1_BYTE | 5)
68 #define CONF_VALUE_INTEGER_6            (CONF_MASK_1_BYTE | 6)
69 #define CONF_VALUE_INTEGER_7            (CONF_MASK_1_BYTE | 7)
70 #define CONF_VALUE_INTEGER_8            (CONF_MASK_1_BYTE | 8)
71 #define CONF_VALUE_BOOLEAN_1            (CONF_MASK_1_BYTE | 9)
72 #define CONF_VALUE_BOOLEAN_2            (CONF_MASK_1_BYTE | 10)
73 #define CONF_VALUE_BOOLEAN_3            (CONF_MASK_1_BYTE | 11)
74 #define CONF_VALUE_BOOLEAN_4            (CONF_MASK_1_BYTE | 12)
75 #define CONF_VALUE_BOOLEAN_5            (CONF_MASK_1_BYTE | 13)
76 #define CONF_VALUE_BOOLEAN_6            (CONF_MASK_1_BYTE | 14)
77 #define CONF_VALUE_BOOLEAN_7            (CONF_MASK_1_BYTE | 15)
78 #define CONF_VALUE_BOOLEAN_8            (CONF_MASK_1_BYTE | 16)
79
80 #define CONF_VALUE_ELEMENT_1            (CONF_MASK_2_BYTE | 1)
81 #define CONF_VALUE_ELEMENT_2            (CONF_MASK_2_BYTE | 2)
82 #define CONF_VALUE_ELEMENT_3            (CONF_MASK_2_BYTE | 3)
83 #define CONF_VALUE_ELEMENT_4            (CONF_MASK_2_BYTE | 4)
84 #define CONF_VALUE_ELEMENT_5            (CONF_MASK_2_BYTE | 5)
85 #define CONF_VALUE_ELEMENT_6            (CONF_MASK_2_BYTE | 6)
86 #define CONF_VALUE_ELEMENT_7            (CONF_MASK_2_BYTE | 7)
87 #define CONF_VALUE_ELEMENT_8            (CONF_MASK_2_BYTE | 8)
88
89 #define CONF_VALUE_ELEMENTS             (CONF_MASK_MULTI_BYTES | 1)
90 #define CONF_VALUE_CONTENTS             (CONF_MASK_MULTI_BYTES | 2)
91
92 #define CONF_VALUE_INTEGER(x)           ((x) >= CONF_VALUE_INTEGER_1 && \
93                                          (x) <= CONF_VALUE_INTEGER_8)
94
95 #define CONF_VALUE_BOOLEAN(x)           ((x) >= CONF_VALUE_BOOLEAN_1 && \
96                                          (x) <= CONF_VALUE_BOOLEAN_8)
97
98 #define CONF_VALUE_NUM_BYTES(x)         ((x) == CONF_MASK_1_BYTE ? 1 :  \
99                                          (x) == CONF_MASK_2_BYTE ? 2 :  \
100                                          (x) == CONF_MASK_4_BYTE ? 4 : 0)
101
102 #define CONF_CONTENT_NUM_ELEMENTS       (3 * 3)
103 #define CONF_CONTENT_NUM_BYTES          (CONF_CONTENT_NUM_ELEMENTS * 2)
104 #define CONF_ELEMENT_NUM_BYTES          (2)
105
106 #define CONF_ENTITY_NUM_BYTES(t)        ((t) == CONF_VALUE_ELEMENTS ?   \
107                                          CONF_ELEMENT_NUM_BYTES :       \
108                                          (t) == CONF_VALUE_CONTENTS ?   \
109                                          CONF_CONTENT_NUM_BYTES : 1)
110
111 #define CONF_ELEMENT_BYTE_POS(i)        ((i) * CONF_ELEMENT_NUM_BYTES)
112 #define CONF_ELEMENTS_ELEMENT(b,i)     ((b[CONF_ELEMENT_BYTE_POS(i)] << 8) |  \
113                                         (b[CONF_ELEMENT_BYTE_POS(i) + 1]))
114
115 #define CONF_CONTENT_ELEMENT_POS(c,x,y) ((c) * CONF_CONTENT_NUM_ELEMENTS +    \
116                                          (y) * 3 + (x))
117 #define CONF_CONTENT_BYTE_POS(c,x,y)    (CONF_CONTENT_ELEMENT_POS(c,x,y) *    \
118                                          CONF_ELEMENT_NUM_BYTES)
119 #define CONF_CONTENTS_ELEMENT(b,c,x,y) ((b[CONF_CONTENT_BYTE_POS(c,x,y)]<< 8)|\
120                                         (b[CONF_CONTENT_BYTE_POS(c,x,y) + 1]))
121
122 #if 0
123 static void LoadLevel_InitPlayfield(struct LevelInfo *, char *);
124 #endif
125
126 static struct LevelInfo li;
127
128 static struct
129 {
130   int element;                  /* element for which data is to be stored */
131   int type;                     /* type of data to be stored */
132
133   /* (mandatory) */
134   void *value;                  /* variable that holds the data to be stored */
135   int default_value;            /* initial default value for this variable */
136
137   /* (optional) */
138   void *num_entities;           /* number of entities for multi-byte data */
139   int default_num_entities;     /* default number of entities for this data */
140   int max_num_entities;         /* maximal number of entities for this data */
141 } element_conf[] =
142 {
143   /* ---------- 1-byte values ---------------------------------------------- */
144
145   {
146     EL_EMC_ANDROID,                     CONF_VALUE_INTEGER_1,
147     &li.android_move_time,              10
148   },
149   {
150     EL_EMC_ANDROID,                     CONF_VALUE_INTEGER_2,
151     &li.android_clone_time,             10
152   },
153   {
154     EL_EMC_LENSES,                      CONF_VALUE_INTEGER_1,
155     &li.lenses_score,                   10
156   },
157   {
158     EL_EMC_LENSES,                      CONF_VALUE_INTEGER_2,
159     &li.lenses_time,                    10
160   },
161   {
162     EL_EMC_MAGNIFIER,                   CONF_VALUE_INTEGER_1,
163     &li.magnify_score,                  10
164   },
165   {
166     EL_EMC_MAGNIFIER,                   CONF_VALUE_INTEGER_2,
167     &li.magnify_time,                   10
168   },
169   {
170     EL_ROBOT,                           CONF_VALUE_INTEGER_1,
171     &li.slurp_score,                    10
172   },
173   {
174     EL_GAME_OF_LIFE,                    CONF_VALUE_INTEGER_1,
175     &li.game_of_life[0],                2
176   },
177   {
178     EL_GAME_OF_LIFE,                    CONF_VALUE_INTEGER_2,
179     &li.game_of_life[1],                3
180   },
181   {
182     EL_GAME_OF_LIFE,                    CONF_VALUE_INTEGER_3,
183     &li.game_of_life[2],                3
184   },
185   {
186     EL_GAME_OF_LIFE,                    CONF_VALUE_INTEGER_4,
187     &li.game_of_life[3],                3
188   },
189   {
190     EL_BIOMAZE,                         CONF_VALUE_INTEGER_1,
191     &li.biomaze[0],                     2
192   },
193   {
194     EL_BIOMAZE,                         CONF_VALUE_INTEGER_2,
195     &li.biomaze[1],                     3
196   },
197   {
198     EL_BIOMAZE,                         CONF_VALUE_INTEGER_3,
199     &li.biomaze[2],                     3
200   },
201   {
202     EL_BIOMAZE,                         CONF_VALUE_INTEGER_4,
203     &li.biomaze[3],                     3
204   },
205   {
206     EL_BALLOON,                         CONF_VALUE_INTEGER_1,
207     &li.wind_direction_initial,         MV_NONE
208   },
209   {
210     EL_TIMEGATE_SWITCH,                 CONF_VALUE_INTEGER_1,
211     &li.time_timegate,                  10
212   },
213   {
214     EL_LIGHT_SWITCH_ACTIVE,             CONF_VALUE_INTEGER_1,
215     &li.time_light,                     10
216   },
217   {
218     EL_SHIELD_NORMAL,                   CONF_VALUE_INTEGER_1,
219     &li.shield_normal_time,             10
220   },
221   {
222     EL_SHIELD_DEADLY,                   CONF_VALUE_INTEGER_1,
223     &li.shield_deadly_time,             10
224   },
225   {
226     EL_EXTRA_TIME,                      CONF_VALUE_INTEGER_1,
227     &li.extra_time,                     10
228   },
229   {
230     EL_EXTRA_TIME,                      CONF_VALUE_INTEGER_2,
231     &li.extra_time_score,               10
232   },
233   {
234     EL_TIME_ORB_FULL,                   CONF_VALUE_INTEGER_1,
235     &li.time_orb_time,                  10
236   },
237   {
238     EL_TIME_ORB_FULL,                   CONF_VALUE_BOOLEAN_1,
239     &li.use_time_orb_bug,               FALSE
240   },
241   {
242     EL_PLAYER_1,                        CONF_VALUE_BOOLEAN_1,
243     &li.block_snap_field,               TRUE
244   },
245   {
246     EL_PLAYER_1,                        CONF_VALUE_BOOLEAN_2,
247     &li.use_start_element[0],           FALSE
248   },
249   {
250     EL_PLAYER_2,                        CONF_VALUE_BOOLEAN_2,
251     &li.use_start_element[1],           FALSE
252   },
253   {
254     EL_PLAYER_3,                        CONF_VALUE_BOOLEAN_2,
255     &li.use_start_element[2],           FALSE
256   },
257   {
258     EL_PLAYER_4,                        CONF_VALUE_BOOLEAN_2,
259     &li.use_start_element[3],           FALSE
260   },
261   {
262     EL_PLAYER_1,                        CONF_VALUE_BOOLEAN_3,
263     &li.use_artwork_element[0],         FALSE
264   },
265   {
266     EL_PLAYER_2,                        CONF_VALUE_BOOLEAN_3,
267     &li.use_artwork_element[1],         FALSE
268   },
269   {
270     EL_PLAYER_3,                        CONF_VALUE_BOOLEAN_3,
271     &li.use_artwork_element[2],         FALSE
272   },
273   {
274     EL_PLAYER_4,                        CONF_VALUE_BOOLEAN_3,
275     &li.use_artwork_element[3],         FALSE
276   },
277   {
278     EL_PLAYER_1,                        CONF_VALUE_BOOLEAN_4,
279     &li.use_explosion_element[0],       FALSE
280   },
281   {
282     EL_PLAYER_2,                        CONF_VALUE_BOOLEAN_4,
283     &li.use_explosion_element[1],       FALSE
284   },
285   {
286     EL_PLAYER_3,                        CONF_VALUE_BOOLEAN_4,
287     &li.use_explosion_element[2],       FALSE
288   },
289   {
290     EL_PLAYER_4,                        CONF_VALUE_BOOLEAN_4,
291     &li.use_explosion_element[3],       FALSE
292   },
293   {
294     EL_PLAYER_1,                        CONF_VALUE_INTEGER_1,
295     &li.initial_player_stepsize,        STEPSIZE_NORMAL
296   },
297   {
298     EL_EMC_MAGIC_BALL,                  CONF_VALUE_INTEGER_1,
299     &li.ball_time,                      10
300   },
301   {
302     EL_EMC_MAGIC_BALL,                  CONF_VALUE_BOOLEAN_1,
303     &li.ball_random,                    FALSE
304   },
305   {
306     EL_EMC_MAGIC_BALL,                  CONF_VALUE_BOOLEAN_2,
307     &li.ball_state_initial,             FALSE
308   },
309
310   /* ---------- 2-byte values ---------------------------------------------- */
311
312   {
313     EL_PLAYER_1,                        CONF_VALUE_ELEMENT_1,
314     &li.start_element[0],               EL_PLAYER_1
315   },
316   {
317     EL_PLAYER_2,                        CONF_VALUE_ELEMENT_1,
318     &li.start_element[1],               EL_PLAYER_2
319   },
320   {
321     EL_PLAYER_3,                        CONF_VALUE_ELEMENT_1,
322     &li.start_element[2],               EL_PLAYER_3
323   },
324   {
325     EL_PLAYER_4,                        CONF_VALUE_ELEMENT_1,
326     &li.start_element[3],               EL_PLAYER_4
327   },
328   {
329     EL_PLAYER_1,                        CONF_VALUE_ELEMENT_2,
330     &li.artwork_element[0],             EL_PLAYER_1
331   },
332   {
333     EL_PLAYER_2,                        CONF_VALUE_ELEMENT_2,
334     &li.artwork_element[1],             EL_PLAYER_2
335   },
336   {
337     EL_PLAYER_3,                        CONF_VALUE_ELEMENT_2,
338     &li.artwork_element[2],             EL_PLAYER_3
339   },
340   {
341     EL_PLAYER_4,                        CONF_VALUE_ELEMENT_2,
342     &li.artwork_element[3],             EL_PLAYER_4
343   },
344   {
345     EL_PLAYER_1,                        CONF_VALUE_ELEMENT_3,
346     &li.explosion_element[0],           EL_PLAYER_1
347   },
348   {
349     EL_PLAYER_2,                        CONF_VALUE_ELEMENT_3,
350     &li.explosion_element[1],           EL_PLAYER_2
351   },
352   {
353     EL_PLAYER_3,                        CONF_VALUE_ELEMENT_3,
354     &li.explosion_element[2],           EL_PLAYER_3
355   },
356   {
357     EL_PLAYER_4,                        CONF_VALUE_ELEMENT_3,
358     &li.explosion_element[3],           EL_PLAYER_4
359   },
360
361   /* ---------- multi-byte values ------------------------------------------ */
362
363   {
364     EL_EMC_MAGIC_BALL,                  CONF_VALUE_CONTENTS,
365     &li.ball_content,                   EL_EMPTY,
366     &li.num_ball_contents,              4, MAX_ELEMENT_CONTENTS
367   },
368   {
369     EL_EMC_ANDROID,                     CONF_VALUE_ELEMENTS,
370     &li.android_clone_element[0],       EL_EMPTY,
371     &li.num_android_clone_elements,     1, MAX_ANDROID_ELEMENTS
372   },
373
374   {
375     -1,                                 -1,
376     NULL,                               -1,
377   },
378 };
379
380 static struct
381 {
382   int filetype;
383   char *id;
384 }
385 filetype_id_list[] =
386 {
387   { LEVEL_FILE_TYPE_RND,        "RND"   },
388   { LEVEL_FILE_TYPE_BD,         "BD"    },
389   { LEVEL_FILE_TYPE_EM,         "EM"    },
390   { LEVEL_FILE_TYPE_SP,         "SP"    },
391   { LEVEL_FILE_TYPE_DX,         "DX"    },
392   { LEVEL_FILE_TYPE_SB,         "SB"    },
393   { LEVEL_FILE_TYPE_DC,         "DC"    },
394   { -1,                         NULL    },
395 };
396
397
398 /* ========================================================================= */
399 /* level file functions                                                      */
400 /* ========================================================================= */
401
402 static void setLevelInfoToDefaultsFromConfigList(struct LevelInfo *level)
403 {
404   int i;
405
406   li = *level;          /* copy level information into temporary buffer */
407
408   for (i = 0; element_conf[i].element != -1; i++)
409   {
410     int default_value = element_conf[i].default_value;
411     int type = element_conf[i].type;
412     int bytes = type & CONF_MASK_BYTES;
413
414     if (bytes == CONF_MASK_MULTI_BYTES)
415     {
416       int default_num_entities = element_conf[i].default_num_entities;
417       int max_num_entities = element_conf[i].max_num_entities;
418
419       *(int *)(element_conf[i].num_entities) = default_num_entities;
420
421       if (type == CONF_VALUE_ELEMENTS)
422       {
423         int *element_array = (int *)(element_conf[i].value);
424         int j;
425
426         for (j = 0; j < max_num_entities; j++)
427           element_array[j] = default_value;
428       }
429       else if (type == CONF_VALUE_CONTENTS)
430       {
431         struct Content *content = (struct Content *)(element_conf[i].value);
432         int c, x, y;
433
434         for (c = 0; c < max_num_entities; c++)
435           for (y = 0; y < 3; y++)
436             for (x = 0; x < 3; x++)
437               content[c].e[x][y] = default_value;
438       }
439     }
440     else        /* constant size configuration data (1, 2 or 4 bytes) */
441     {
442       if (CONF_VALUE_BOOLEAN(type))
443         *(boolean *)(element_conf[i].value) = default_value;
444       else
445         *(int *)    (element_conf[i].value) = default_value;
446     }
447   }
448
449   *level = li;          /* copy temporary buffer back to level information */
450 }
451
452 void setElementChangePages(struct ElementInfo *ei, int change_pages)
453 {
454   int change_page_size = sizeof(struct ElementChangeInfo);
455
456   ei->num_change_pages = MAX(1, change_pages);
457
458   ei->change_page =
459     checked_realloc(ei->change_page, ei->num_change_pages * change_page_size);
460
461   if (ei->current_change_page >= ei->num_change_pages)
462     ei->current_change_page = ei->num_change_pages - 1;
463
464   ei->change = &ei->change_page[ei->current_change_page];
465 }
466
467 void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
468 {
469   int i, x, y;
470
471   change->can_change = FALSE;
472
473   for (i = 0; i < NUM_CHANGE_EVENTS; i++)
474     change->has_event[i] = FALSE;
475
476   change->trigger_player = CH_PLAYER_ANY;
477   change->trigger_side = CH_SIDE_ANY;
478   change->trigger_page = CH_PAGE_ANY;
479
480   change->target_element = EL_EMPTY_SPACE;
481
482   change->delay_fixed = 0;
483   change->delay_random = 0;
484   change->delay_frames = FRAMES_PER_SECOND;
485
486   change->trigger_element = EL_EMPTY_SPACE;
487
488   change->explode = FALSE;
489   change->use_target_content = FALSE;
490   change->only_if_complete = FALSE;
491   change->use_random_replace = FALSE;
492   change->random_percentage = 100;
493   change->replace_when = CP_WHEN_EMPTY;
494
495   change->has_action = FALSE;
496   change->action_type = CA_NO_ACTION;
497   change->action_mode = CA_MODE_UNDEFINED;
498   change->action_arg = CA_ARG_UNDEFINED;
499
500   for (x = 0; x < 3; x++)
501     for (y = 0; y < 3; y++)
502       change->target_content.e[x][y] = EL_EMPTY_SPACE;
503
504   change->direct_action = 0;
505   change->other_action = 0;
506
507   change->pre_change_function = NULL;
508   change->change_function = NULL;
509   change->post_change_function = NULL;
510 }
511
512 static void setLevelInfoToDefaults(struct LevelInfo *level)
513 {
514   static boolean clipboard_elements_initialized = FALSE;
515   int i, j, x, y;
516
517 #if 1
518   InitElementPropertiesStatic();
519 #endif
520
521   setLevelInfoToDefaultsFromConfigList(level);
522   setLevelInfoToDefaults_EM();
523
524   level->native_em_level = &native_em_level;
525
526   level->game_engine_type = GAME_ENGINE_TYPE_RND;
527
528   level->file_version = FILE_VERSION_ACTUAL;
529   level->game_version = GAME_VERSION_ACTUAL;
530
531   level->encoding_16bit_field  = FALSE; /* default: only 8-bit elements */
532   level->encoding_16bit_yamyam = FALSE; /* default: only 8-bit elements */
533   level->encoding_16bit_amoeba = FALSE; /* default: only 8-bit elements */
534
535   level->fieldx = STD_LEV_FIELDX;
536   level->fieldy = STD_LEV_FIELDY;
537
538   for (x = 0; x < MAX_LEV_FIELDX; x++)
539     for (y = 0; y < MAX_LEV_FIELDY; y++)
540       level->field[x][y] = EL_SAND;
541
542   level->time = 100;
543   level->gems_needed = 0;
544
545   level->amoeba_speed = 10;
546
547   level->time_magic_wall = 10;
548   level->time_wheel = 10;
549 #if 0
550   level->time_light = 10;
551   level->time_timegate = 10;
552 #endif
553
554   level->amoeba_content = EL_DIAMOND;
555
556   level->game_of_life[0] = 2;
557   level->game_of_life[1] = 3;
558   level->game_of_life[2] = 3;
559   level->game_of_life[3] = 3;
560
561   level->biomaze[0] = 2;
562   level->biomaze[1] = 3;
563   level->biomaze[2] = 3;
564   level->biomaze[3] = 3;
565
566 #if 0
567   level->double_speed = FALSE;
568 #endif
569   level->initial_gravity = FALSE;
570   level->em_slippery_gems = FALSE;
571   level->instant_relocation = FALSE;
572   level->can_pass_to_walkable = FALSE;
573   level->grow_into_diggable = TRUE;
574
575   level->block_snap_field = TRUE;
576
577   level->block_last_field = FALSE;      /* EM does not block by default */
578   level->sp_block_last_field = TRUE;    /* SP blocks the last field */
579
580   level->can_move_into_acid_bits = ~0;  /* everything can move into acid */
581   level->dont_collide_with_bits = ~0;   /* always deadly when colliding */
582
583   level->use_spring_bug = FALSE;
584   level->use_time_orb_bug = FALSE;
585
586   level->use_step_counter = FALSE;
587
588   /* values for the new EMC elements */
589 #if 0
590   level->android_move_time = 10;
591   level->android_clone_time = 10;
592   level->ball_time = 10;
593   level->lenses_score = 10;
594   level->lenses_time = 10;
595   level->magnify_score = 10;
596   level->magnify_time = 10;
597   level->slurp_score = 10;
598   level->wind_direction_initial = MV_NONE;
599   level->ball_random = FALSE;
600   level->ball_state_initial = FALSE;
601   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
602     for (x = 0; x < 3; x++)
603       for (y = 0; y < 3; y++)
604         level->ball_content[i].e[x][y] = EL_EMPTY;
605 #endif
606 #if 0
607   for (i = 0; i < 16; i++)
608     level->android_array[i] = FALSE;
609 #endif
610
611   level->use_custom_template = FALSE;
612
613   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
614     level->name[i] = '\0';
615   for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
616     level->author[i] = '\0';
617
618   strcpy(level->name, NAMELESS_LEVEL_NAME);
619   strcpy(level->author, ANONYMOUS_NAME);
620
621   for (i = 0; i < 4; i++)
622   {
623     level->envelope_text[i][0] = '\0';
624     level->envelope_xsize[i] = MAX_ENVELOPE_XSIZE;
625     level->envelope_ysize[i] = MAX_ENVELOPE_YSIZE;
626   }
627
628   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
629     level->score[i] = (i == SC_TIME_BONUS ? 1 : 10);
630
631   level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
632   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
633     for (x = 0; x < 3; x++)
634       for (y = 0; y < 3; y++)
635         level->yamyam_content[i].e[x][y] =
636           (i < STD_ELEMENT_CONTENTS ? EL_ROCK : EL_EMPTY);
637
638   level->field[0][0] = EL_PLAYER_1;
639   level->field[STD_LEV_FIELDX - 1][STD_LEV_FIELDY - 1] = EL_EXIT_CLOSED;
640
641   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
642   {
643     int element = i;
644     struct ElementInfo *ei = &element_info[element];
645
646     /* never initialize clipboard elements after the very first time */
647     if (IS_CLIPBOARD_ELEMENT(element) && clipboard_elements_initialized)
648       continue;
649
650     setElementChangePages(ei, 1);
651     setElementChangeInfoToDefaults(ei->change);
652
653     if (IS_CUSTOM_ELEMENT(element) ||
654         IS_GROUP_ELEMENT(element) ||
655         IS_INTERNAL_ELEMENT(element))
656     {
657       for (j = 0; j < MAX_ELEMENT_NAME_LEN + 1; j++)
658         ei->description[j] = '\0';
659
660       if (ei->custom_description != NULL)
661         strncpy(ei->description, ei->custom_description,MAX_ELEMENT_NAME_LEN);
662       else
663         strcpy(ei->description, ei->editor_description);
664
665       ei->use_gfx_element = FALSE;
666       ei->gfx_element = EL_EMPTY_SPACE;
667
668       ei->modified_settings = FALSE;
669     }
670
671     if (IS_CUSTOM_ELEMENT(element) ||
672         IS_INTERNAL_ELEMENT(element))
673     {
674       ei->access_direction = MV_ALL_DIRECTIONS;
675
676       ei->collect_score_initial = 10;   /* special default */
677       ei->collect_count_initial = 1;    /* special default */
678
679       ei->ce_value_fixed_initial = 0;
680       ei->ce_value_random_initial = 0;
681       ei->use_last_ce_value = FALSE;
682
683       ei->push_delay_fixed = -1;        /* initialize later */
684       ei->push_delay_random = -1;       /* initialize later */
685       ei->drop_delay_fixed = 0;
686       ei->drop_delay_random = 0;
687       ei->move_delay_fixed = 0;
688       ei->move_delay_random = 0;
689
690       ei->move_pattern = MV_ALL_DIRECTIONS;
691       ei->move_direction_initial = MV_START_AUTOMATIC;
692       ei->move_stepsize = TILEX / 8;
693
694       ei->move_enter_element = EL_EMPTY_SPACE;
695       ei->move_leave_element = EL_EMPTY_SPACE;
696       ei->move_leave_type = LEAVE_TYPE_UNLIMITED;
697
698       ei->slippery_type = SLIPPERY_ANY_RANDOM;
699
700       ei->explosion_type = EXPLODES_3X3;
701       ei->explosion_delay = 16;
702       ei->ignition_delay = 8;
703
704       for (x = 0; x < 3; x++)
705         for (y = 0; y < 3; y++)
706           ei->content.e[x][y] = EL_EMPTY_SPACE;
707
708       ei->access_type = 0;
709       ei->access_layer = 0;
710       ei->access_protected = 0;
711       ei->walk_to_action = 0;
712       ei->smash_targets = 0;
713       ei->deadliness = 0;
714
715       ei->can_explode_by_fire = FALSE;
716       ei->can_explode_smashed = FALSE;
717       ei->can_explode_impact = FALSE;
718
719       ei->current_change_page = 0;
720
721 #if 0
722       /* !!! now done in InitElementPropertiesStatic() (see above) !!! */
723       /* !!! (else properties set there will be overwritten here)  !!! */
724       /* start with no properties at all */
725 #if 1
726       for (j = 0; j < NUM_EP_BITFIELDS; j++)
727         ei->properties[j] = EP_BITMASK_DEFAULT;
728 #else
729       for (j = 0; j < NUM_EP_BITFIELDS; j++)
730         Properties[element][j] = EP_BITMASK_DEFAULT;
731 #endif
732 #endif
733
734       /* now set default properties */
735       SET_PROPERTY(element, EP_CAN_MOVE_INTO_ACID, TRUE);
736     }
737
738     if (IS_GROUP_ELEMENT(element) ||
739         IS_INTERNAL_ELEMENT(element))
740     {
741       struct ElementGroupInfo *group;
742
743       /* initialize memory for list of elements in group */
744       if (ei->group == NULL)
745         ei->group = checked_malloc(sizeof(struct ElementGroupInfo));
746
747       group = ei->group;
748
749       for (j = 0; j < MAX_ELEMENTS_IN_GROUP; j++)
750         group->element[j] = EL_EMPTY_SPACE;
751
752       /* default: only one element in group */
753       group->num_elements = 1;
754
755       group->choice_mode = ANIM_RANDOM;
756     }
757   }
758
759   clipboard_elements_initialized = TRUE;
760
761   BorderElement = EL_STEELWALL;
762
763   level->no_valid_file = FALSE;
764
765   level->changed = FALSE;
766
767   if (leveldir_current == NULL)         /* only when dumping level */
768     return;
769
770   /* try to determine better author name than 'anonymous' */
771   if (strcmp(leveldir_current->author, ANONYMOUS_NAME) != 0)
772   {
773     strncpy(level->author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN);
774     level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
775   }
776   else
777   {
778     switch (LEVELCLASS(leveldir_current))
779     {
780       case LEVELCLASS_TUTORIAL:
781         strcpy(level->author, PROGRAM_AUTHOR_STRING);
782         break;
783
784       case LEVELCLASS_CONTRIB:
785         strncpy(level->author, leveldir_current->name, MAX_LEVEL_AUTHOR_LEN);
786         level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
787         break;
788
789       case LEVELCLASS_PRIVATE:
790         strncpy(level->author, getRealName(), MAX_LEVEL_AUTHOR_LEN);
791         level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
792         break;
793
794       default:
795         /* keep default value */
796         break;
797     }
798   }
799 }
800
801 static void setFileInfoToDefaults(struct LevelFileInfo *level_file_info)
802 {
803   level_file_info->nr = 0;
804   level_file_info->type = LEVEL_FILE_TYPE_UNKNOWN;
805   level_file_info->packed = FALSE;
806   level_file_info->basename = NULL;
807   level_file_info->filename = NULL;
808 }
809
810 static void ActivateLevelTemplate()
811 {
812 #if 1
813   /* Currently there is no special action needed to activate the template
814      data, because 'element_info' property settings overwrite the original
815      level data, while all other variables do not change. */
816 #else
817   /* Currently there is no special action needed to activate the template
818      data, because 'element_info' and 'Properties' overwrite the original
819      level data, while all other variables do not change. */
820 #endif
821 }
822
823 static char *getLevelFilenameFromBasename(char *basename)
824 {
825   static char *filename = NULL;
826
827   checked_free(filename);
828
829   filename = getPath2(getCurrentLevelDir(), basename);
830
831   return filename;
832 }
833
834 static int getFileTypeFromBasename(char *basename)
835 {
836   static char *filename = NULL;
837   struct stat file_status;
838
839   /* ---------- try to determine file type from filename ---------- */
840
841   /* check for typical filename of a Supaplex level package file */
842   if (strlen(basename) == 10 && (strncmp(basename, "levels.d", 8) == 0 ||
843                                  strncmp(basename, "LEVELS.D", 8) == 0))
844     return LEVEL_FILE_TYPE_SP;
845
846   /* ---------- try to determine file type from filesize ---------- */
847
848   checked_free(filename);
849   filename = getPath2(getCurrentLevelDir(), basename);
850
851   if (stat(filename, &file_status) == 0)
852   {
853     /* check for typical filesize of a Supaplex level package file */
854     if (file_status.st_size == 170496)
855       return LEVEL_FILE_TYPE_SP;
856   }
857
858   return LEVEL_FILE_TYPE_UNKNOWN;
859 }
860
861 static char *getSingleLevelBasename(int nr)
862 {
863   static char basename[MAX_FILENAME_LEN];
864
865   if (nr < 0)
866     sprintf(basename, "template.%s", LEVELFILE_EXTENSION);
867   else
868     sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION);
869
870   return basename;
871 }
872
873 static char *getPackedLevelBasename(int type)
874 {
875   static char basename[MAX_FILENAME_LEN];
876   char *directory = getCurrentLevelDir();
877   DIR *dir;
878   struct dirent *dir_entry;
879
880   strcpy(basename, UNDEFINED_FILENAME);         /* default: undefined file */
881
882   if ((dir = opendir(directory)) == NULL)
883   {
884     Error(ERR_WARN, "cannot read current level directory '%s'", directory);
885
886     return basename;
887   }
888
889   while ((dir_entry = readdir(dir)) != NULL)    /* loop until last dir entry */
890   {
891     char *entry_basename = dir_entry->d_name;
892     int entry_type = getFileTypeFromBasename(entry_basename);
893
894     if (entry_type != LEVEL_FILE_TYPE_UNKNOWN)  /* found valid level package */
895     {
896       if (type == LEVEL_FILE_TYPE_UNKNOWN ||
897           type == entry_type)
898       {
899         strcpy(basename, entry_basename);
900
901         break;
902       }
903     }
904   }
905
906   closedir(dir);
907
908   return basename;
909 }
910
911 static char *getSingleLevelFilename(int nr)
912 {
913   return getLevelFilenameFromBasename(getSingleLevelBasename(nr));
914 }
915
916 #if 0
917 static char *getPackedLevelFilename(int type)
918 {
919   return getLevelFilenameFromBasename(getPackedLevelBasename(type));
920 }
921 #endif
922
923 char *getDefaultLevelFilename(int nr)
924 {
925   return getSingleLevelFilename(nr);
926 }
927
928 #if 0
929 static void setLevelFileInfo_SingleLevelFilename(struct LevelFileInfo *lfi,
930                                                  int type)
931 {
932   lfi->type = type;
933   lfi->packed = FALSE;
934   lfi->basename = getSingleLevelBasename(lfi->nr, lfi->type);
935   lfi->filename = getLevelFilenameFromBasename(lfi->basename);
936 }
937 #endif
938
939 static void setLevelFileInfo_FormatLevelFilename(struct LevelFileInfo *lfi,
940                                                  int type, char *format, ...)
941 {
942   static char basename[MAX_FILENAME_LEN];
943   va_list ap;
944
945   va_start(ap, format);
946   vsprintf(basename, format, ap);
947   va_end(ap);
948
949   lfi->type = type;
950   lfi->packed = FALSE;
951   lfi->basename = basename;
952   lfi->filename = getLevelFilenameFromBasename(lfi->basename);
953 }
954
955 static void setLevelFileInfo_PackedLevelFilename(struct LevelFileInfo *lfi,
956                                                  int type)
957 {
958   lfi->type = type;
959   lfi->packed = TRUE;
960   lfi->basename = getPackedLevelBasename(lfi->type);
961   lfi->filename = getLevelFilenameFromBasename(lfi->basename);
962 }
963
964 static int getFiletypeFromID(char *filetype_id)
965 {
966   char *filetype_id_lower;
967   int filetype = LEVEL_FILE_TYPE_UNKNOWN;
968   int i;
969
970   if (filetype_id == NULL)
971     return LEVEL_FILE_TYPE_UNKNOWN;
972
973   filetype_id_lower = getStringToLower(filetype_id);
974
975   for (i = 0; filetype_id_list[i].id != NULL; i++)
976   {
977     char *id_lower = getStringToLower(filetype_id_list[i].id);
978     
979     if (strcmp(filetype_id_lower, id_lower) == 0)
980       filetype = filetype_id_list[i].filetype;
981
982     free(id_lower);
983
984     if (filetype != LEVEL_FILE_TYPE_UNKNOWN)
985       break;
986   }
987
988   free(filetype_id_lower);
989
990   return filetype;
991 }
992
993 static void determineLevelFileInfo_Filename(struct LevelFileInfo *lfi)
994 {
995   int nr = lfi->nr;
996
997   /* special case: level number is negative => check for level template file */
998   if (nr < 0)
999   {
1000     setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
1001                                          "template.%s", LEVELFILE_EXTENSION);
1002
1003     /* no fallback if template file not existing */
1004     return;
1005   }
1006
1007   /* special case: check for file name/pattern specified in "levelinfo.conf" */
1008   if (leveldir_current->level_filename != NULL)
1009   {
1010     int filetype = getFiletypeFromID(leveldir_current->level_filetype);
1011
1012     setLevelFileInfo_FormatLevelFilename(lfi, filetype,
1013                                          leveldir_current->level_filename, nr);
1014     if (fileExists(lfi->filename))
1015       return;
1016   }
1017
1018   /* check for native Rocks'n'Diamonds level file */
1019   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
1020                                        "%03d.%s", nr, LEVELFILE_EXTENSION);
1021   if (fileExists(lfi->filename))
1022     return;
1023
1024   /* check for Emerald Mine level file (V1) */
1025   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "a%c%c",
1026                                        'a' + (nr / 10) % 26, '0' + nr % 10);
1027   if (fileExists(lfi->filename))
1028     return;
1029   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "A%c%c",
1030                                        'A' + (nr / 10) % 26, '0' + nr % 10);
1031   if (fileExists(lfi->filename))
1032     return;
1033
1034   /* check for Emerald Mine level file (V2 to V5) */
1035   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%d", nr);
1036   if (fileExists(lfi->filename))
1037     return;
1038
1039   /* check for Emerald Mine level file (V6 / single mode) */
1040   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02ds", nr);
1041   if (fileExists(lfi->filename))
1042     return;
1043   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dS", nr);
1044   if (fileExists(lfi->filename))
1045     return;
1046
1047   /* check for Emerald Mine level file (V6 / teamwork mode) */
1048   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dt", nr);
1049   if (fileExists(lfi->filename))
1050     return;
1051   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_EM, "%02dT", nr);
1052   if (fileExists(lfi->filename))
1053     return;
1054
1055   /* check for various packed level file formats */
1056   setLevelFileInfo_PackedLevelFilename(lfi, LEVEL_FILE_TYPE_UNKNOWN);
1057   if (fileExists(lfi->filename))
1058     return;
1059
1060   /* no known level file found -- use default values (and fail later) */
1061   setLevelFileInfo_FormatLevelFilename(lfi, LEVEL_FILE_TYPE_RND,
1062                                        "%03d.%s", nr, LEVELFILE_EXTENSION);
1063 }
1064
1065 static void determineLevelFileInfo_Filetype(struct LevelFileInfo *lfi)
1066 {
1067   if (lfi->type == LEVEL_FILE_TYPE_UNKNOWN)
1068     lfi->type = getFileTypeFromBasename(lfi->basename);
1069 }
1070
1071 static void setLevelFileInfo(struct LevelFileInfo *level_file_info, int nr)
1072 {
1073   /* always start with reliable default values */
1074   setFileInfoToDefaults(level_file_info);
1075
1076   level_file_info->nr = nr;     /* set requested level number */
1077
1078   determineLevelFileInfo_Filename(level_file_info);
1079   determineLevelFileInfo_Filetype(level_file_info);
1080 }
1081
1082 /* ------------------------------------------------------------------------- */
1083 /* functions for loading R'n'D level                                         */
1084 /* ------------------------------------------------------------------------- */
1085
1086 int getMappedElement(int element)
1087 {
1088   /* remap some (historic, now obsolete) elements */
1089
1090   switch (element)
1091   {
1092     case EL_PLAYER_OBSOLETE:
1093       element = EL_PLAYER_1;
1094       break;
1095
1096     case EL_KEY_OBSOLETE:
1097       element = EL_KEY_1;
1098
1099     case EL_EM_KEY_1_FILE_OBSOLETE:
1100       element = EL_EM_KEY_1;
1101       break;
1102
1103     case EL_EM_KEY_2_FILE_OBSOLETE:
1104       element = EL_EM_KEY_2;
1105       break;
1106
1107     case EL_EM_KEY_3_FILE_OBSOLETE:
1108       element = EL_EM_KEY_3;
1109       break;
1110
1111     case EL_EM_KEY_4_FILE_OBSOLETE:
1112       element = EL_EM_KEY_4;
1113       break;
1114
1115     case EL_ENVELOPE_OBSOLETE:
1116       element = EL_ENVELOPE_1;
1117       break;
1118
1119     case EL_SP_EMPTY:
1120       element = EL_EMPTY;
1121       break;
1122
1123     default:
1124       if (element >= NUM_FILE_ELEMENTS)
1125       {
1126         Error(ERR_WARN, "invalid level element %d", element);
1127
1128         element = EL_UNKNOWN;
1129       }
1130       break;
1131   }
1132
1133   return element;
1134 }
1135
1136 int getMappedElementByVersion(int element, int game_version)
1137 {
1138   /* remap some elements due to certain game version */
1139
1140   if (game_version <= VERSION_IDENT(2,2,0,0))
1141   {
1142     /* map game font elements */
1143     element = (element == EL_CHAR('[')  ? EL_CHAR_AUMLAUT :
1144                element == EL_CHAR('\\') ? EL_CHAR_OUMLAUT :
1145                element == EL_CHAR(']')  ? EL_CHAR_UUMLAUT :
1146                element == EL_CHAR('^')  ? EL_CHAR_COPYRIGHT : element);
1147   }
1148
1149   if (game_version < VERSION_IDENT(3,0,0,0))
1150   {
1151     /* map Supaplex gravity tube elements */
1152     element = (element == EL_SP_GRAVITY_PORT_LEFT  ? EL_SP_PORT_LEFT  :
1153                element == EL_SP_GRAVITY_PORT_RIGHT ? EL_SP_PORT_RIGHT :
1154                element == EL_SP_GRAVITY_PORT_UP    ? EL_SP_PORT_UP    :
1155                element == EL_SP_GRAVITY_PORT_DOWN  ? EL_SP_PORT_DOWN  :
1156                element);
1157   }
1158
1159   return element;
1160 }
1161
1162 static int LoadLevel_VERS(FILE *file, int chunk_size, struct LevelInfo *level)
1163 {
1164   level->file_version = getFileVersion(file);
1165   level->game_version = getFileVersion(file);
1166
1167   return chunk_size;
1168 }
1169
1170 static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
1171 {
1172   int i, x, y;
1173
1174   level->fieldx = getFile8Bit(file);
1175   level->fieldy = getFile8Bit(file);
1176
1177   level->time           = getFile16BitBE(file);
1178   level->gems_needed    = getFile16BitBE(file);
1179
1180   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
1181     level->name[i] = getFile8Bit(file);
1182   level->name[MAX_LEVEL_NAME_LEN] = 0;
1183
1184   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
1185     level->score[i] = getFile8Bit(file);
1186
1187   level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
1188   for (i = 0; i < STD_ELEMENT_CONTENTS; i++)
1189     for (y = 0; y < 3; y++)
1190       for (x = 0; x < 3; x++)
1191         level->yamyam_content[i].e[x][y] = getMappedElement(getFile8Bit(file));
1192
1193   level->amoeba_speed           = getFile8Bit(file);
1194   level->time_magic_wall        = getFile8Bit(file);
1195   level->time_wheel             = getFile8Bit(file);
1196   level->amoeba_content         = getMappedElement(getFile8Bit(file));
1197
1198   level->initial_player_stepsize = (getFile8Bit(file) == 1 ? STEPSIZE_FAST :
1199                                     STEPSIZE_NORMAL);
1200
1201   level->initial_gravity        = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1202   level->encoding_16bit_field   = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1203   level->em_slippery_gems       = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1204
1205   level->use_custom_template    = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1206
1207   level->block_last_field       = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1208   level->sp_block_last_field    = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1209   level->can_move_into_acid_bits = getFile32BitBE(file);
1210   level->dont_collide_with_bits = getFile8Bit(file);
1211
1212   level->use_spring_bug         = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1213   level->use_step_counter       = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1214
1215   level->instant_relocation     = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1216   level->can_pass_to_walkable   = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1217   level->grow_into_diggable     = (getFile8Bit(file) == 1 ? TRUE : FALSE);
1218
1219   level->game_engine_type       = getFile8Bit(file);
1220
1221   ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED);
1222
1223   return chunk_size;
1224 }
1225
1226 static int LoadLevel_AUTH(FILE *file, int chunk_size, struct LevelInfo *level)
1227 {
1228   int i;
1229
1230   for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
1231     level->author[i] = getFile8Bit(file);
1232   level->author[MAX_LEVEL_NAME_LEN] = 0;
1233
1234   return chunk_size;
1235 }
1236
1237 static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level)
1238 {
1239   int x, y;
1240   int chunk_size_expected = level->fieldx * level->fieldy;
1241
1242   /* Note: "chunk_size" was wrong before version 2.0 when elements are
1243      stored with 16-bit encoding (and should be twice as big then).
1244      Even worse, playfield data was stored 16-bit when only yamyam content
1245      contained 16-bit elements and vice versa. */
1246
1247   if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
1248     chunk_size_expected *= 2;
1249
1250   if (chunk_size_expected != chunk_size)
1251   {
1252     ReadUnusedBytesFromFile(file, chunk_size);
1253     return chunk_size_expected;
1254   }
1255
1256   for (y = 0; y < level->fieldy; y++)
1257     for (x = 0; x < level->fieldx; x++)
1258       level->field[x][y] =
1259         getMappedElement(level->encoding_16bit_field ? getFile16BitBE(file) :
1260                          getFile8Bit(file));
1261   return chunk_size;
1262 }
1263
1264 static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
1265 {
1266   int i, x, y;
1267   int header_size = 4;
1268   int content_size = MAX_ELEMENT_CONTENTS * 3 * 3;
1269   int chunk_size_expected = header_size + content_size;
1270
1271   /* Note: "chunk_size" was wrong before version 2.0 when elements are
1272      stored with 16-bit encoding (and should be twice as big then).
1273      Even worse, playfield data was stored 16-bit when only yamyam content
1274      contained 16-bit elements and vice versa. */
1275
1276   if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
1277     chunk_size_expected += content_size;
1278
1279   if (chunk_size_expected != chunk_size)
1280   {
1281     ReadUnusedBytesFromFile(file, chunk_size);
1282     return chunk_size_expected;
1283   }
1284
1285   getFile8Bit(file);
1286   level->num_yamyam_contents = getFile8Bit(file);
1287   getFile8Bit(file);
1288   getFile8Bit(file);
1289
1290   /* correct invalid number of content fields -- should never happen */
1291   if (level->num_yamyam_contents < 1 ||
1292       level->num_yamyam_contents > MAX_ELEMENT_CONTENTS)
1293     level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
1294
1295   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
1296     for (y = 0; y < 3; y++)
1297       for (x = 0; x < 3; x++)
1298         level->yamyam_content[i].e[x][y] =
1299           getMappedElement(level->encoding_16bit_field ?
1300                            getFile16BitBE(file) : getFile8Bit(file));
1301   return chunk_size;
1302 }
1303
1304 static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
1305 {
1306   int i, x, y;
1307   int element;
1308   int num_contents, content_xsize, content_ysize;
1309   int content_array[MAX_ELEMENT_CONTENTS][3][3];
1310
1311   element = getMappedElement(getFile16BitBE(file));
1312   num_contents = getFile8Bit(file);
1313   content_xsize = getFile8Bit(file);
1314   content_ysize = getFile8Bit(file);
1315
1316   ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED);
1317
1318   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
1319     for (y = 0; y < 3; y++)
1320       for (x = 0; x < 3; x++)
1321         content_array[i][x][y] = getMappedElement(getFile16BitBE(file));
1322
1323   /* correct invalid number of content fields -- should never happen */
1324   if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS)
1325     num_contents = STD_ELEMENT_CONTENTS;
1326
1327   if (element == EL_YAMYAM)
1328   {
1329     level->num_yamyam_contents = num_contents;
1330
1331     for (i = 0; i < num_contents; i++)
1332       for (y = 0; y < 3; y++)
1333         for (x = 0; x < 3; x++)
1334           level->yamyam_content[i].e[x][y] = content_array[i][x][y];
1335   }
1336   else if (element == EL_BD_AMOEBA)
1337   {
1338     level->amoeba_content = content_array[0][0][0];
1339   }
1340   else
1341   {
1342     Error(ERR_WARN, "cannot load content for element '%d'", element);
1343   }
1344
1345   return chunk_size;
1346 }
1347
1348 static int LoadLevel_CNT3(FILE *file, int chunk_size, struct LevelInfo *level)
1349 {
1350   int i;
1351   int element;
1352   int envelope_nr;
1353   int envelope_len;
1354   int chunk_size_expected;
1355
1356   element = getMappedElement(getFile16BitBE(file));
1357   if (!IS_ENVELOPE(element))
1358     element = EL_ENVELOPE_1;
1359
1360   envelope_nr = element - EL_ENVELOPE_1;
1361
1362   envelope_len = getFile16BitBE(file);
1363
1364   level->envelope_xsize[envelope_nr] = getFile8Bit(file);
1365   level->envelope_ysize[envelope_nr] = getFile8Bit(file);
1366
1367   ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT3_UNUSED);
1368
1369   chunk_size_expected = LEVEL_CHUNK_CNT3_SIZE(envelope_len);
1370   if (chunk_size_expected != chunk_size)
1371   {
1372     ReadUnusedBytesFromFile(file, chunk_size - LEVEL_CHUNK_CNT3_HEADER);
1373     return chunk_size_expected;
1374   }
1375
1376   for (i = 0; i < envelope_len; i++)
1377     level->envelope_text[envelope_nr][i] = getFile8Bit(file);
1378
1379   return chunk_size;
1380 }
1381
1382 static int LoadLevel_CUS1(FILE *file, int chunk_size, struct LevelInfo *level)
1383 {
1384   int num_changed_custom_elements = getFile16BitBE(file);
1385   int chunk_size_expected = 2 + num_changed_custom_elements * 6;
1386   int i;
1387
1388   if (chunk_size_expected != chunk_size)
1389   {
1390     ReadUnusedBytesFromFile(file, chunk_size - 2);
1391     return chunk_size_expected;
1392   }
1393
1394   for (i = 0; i < num_changed_custom_elements; i++)
1395   {
1396     int element = getFile16BitBE(file);
1397     int properties = getFile32BitBE(file);
1398
1399 #if 1
1400     if (IS_CUSTOM_ELEMENT(element))
1401       element_info[element].properties[EP_BITFIELD_BASE] = properties;
1402     else
1403       Error(ERR_WARN, "invalid custom element number %d", element);
1404 #else
1405     if (IS_CUSTOM_ELEMENT(element))
1406       Properties[element][EP_BITFIELD_BASE] = properties;
1407     else
1408       Error(ERR_WARN, "invalid custom element number %d", element);
1409 #endif
1410   }
1411
1412   return chunk_size;
1413 }
1414
1415 static int LoadLevel_CUS2(FILE *file, int chunk_size, struct LevelInfo *level)
1416 {
1417   int num_changed_custom_elements = getFile16BitBE(file);
1418   int chunk_size_expected = 2 + num_changed_custom_elements * 4;
1419   int i;
1420
1421   if (chunk_size_expected != chunk_size)
1422   {
1423     ReadUnusedBytesFromFile(file, chunk_size - 2);
1424     return chunk_size_expected;
1425   }
1426
1427   for (i = 0; i < num_changed_custom_elements; i++)
1428   {
1429     int element = getFile16BitBE(file);
1430     int custom_target_element = getFile16BitBE(file);
1431
1432     if (IS_CUSTOM_ELEMENT(element))
1433       element_info[element].change->target_element = custom_target_element;
1434     else
1435       Error(ERR_WARN, "invalid custom element number %d", element);
1436   }
1437
1438   return chunk_size;
1439 }
1440
1441 static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level)
1442 {
1443   int num_changed_custom_elements = getFile16BitBE(file);
1444   int chunk_size_expected = LEVEL_CHUNK_CUS3_SIZE(num_changed_custom_elements);
1445   int i, j, x, y;
1446
1447   if (chunk_size_expected != chunk_size)
1448   {
1449     ReadUnusedBytesFromFile(file, chunk_size - 2);
1450     return chunk_size_expected;
1451   }
1452
1453   for (i = 0; i < num_changed_custom_elements; i++)
1454   {
1455     int element = getFile16BitBE(file);
1456     struct ElementInfo *ei = &element_info[element];
1457     unsigned long event_bits;
1458
1459     if (!IS_CUSTOM_ELEMENT(element))
1460     {
1461       Error(ERR_WARN, "invalid custom element number %d", element);
1462
1463       element = EL_INTERNAL_DUMMY;
1464     }
1465
1466     for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++)
1467       ei->description[j] = getFile8Bit(file);
1468     ei->description[MAX_ELEMENT_NAME_LEN] = 0;
1469
1470 #if 1
1471     ei->properties[EP_BITFIELD_BASE] = getFile32BitBE(file);
1472 #else
1473     Properties[element][EP_BITFIELD_BASE] = getFile32BitBE(file);
1474 #endif
1475
1476     /* some free bytes for future properties and padding */
1477     ReadUnusedBytesFromFile(file, 7);
1478
1479     ei->use_gfx_element = getFile8Bit(file);
1480     ei->gfx_element = getMappedElement(getFile16BitBE(file));
1481
1482     ei->collect_score_initial = getFile8Bit(file);
1483     ei->collect_count_initial = getFile8Bit(file);
1484
1485     ei->push_delay_fixed = getFile16BitBE(file);
1486     ei->push_delay_random = getFile16BitBE(file);
1487     ei->move_delay_fixed = getFile16BitBE(file);
1488     ei->move_delay_random = getFile16BitBE(file);
1489
1490     ei->move_pattern = getFile16BitBE(file);
1491     ei->move_direction_initial = getFile8Bit(file);
1492     ei->move_stepsize = getFile8Bit(file);
1493
1494     for (y = 0; y < 3; y++)
1495       for (x = 0; x < 3; x++)
1496         ei->content.e[x][y] = getMappedElement(getFile16BitBE(file));
1497
1498     event_bits = getFile32BitBE(file);
1499     for (j = 0; j < NUM_CHANGE_EVENTS; j++)
1500       if (event_bits & (1 << j))
1501         ei->change->has_event[j] = TRUE;
1502
1503     ei->change->target_element = getMappedElement(getFile16BitBE(file));
1504
1505     ei->change->delay_fixed = getFile16BitBE(file);
1506     ei->change->delay_random = getFile16BitBE(file);
1507     ei->change->delay_frames = getFile16BitBE(file);
1508
1509     ei->change->trigger_element = getMappedElement(getFile16BitBE(file));
1510
1511     ei->change->explode = getFile8Bit(file);
1512     ei->change->use_target_content = getFile8Bit(file);
1513     ei->change->only_if_complete = getFile8Bit(file);
1514     ei->change->use_random_replace = getFile8Bit(file);
1515
1516     ei->change->random_percentage = getFile8Bit(file);
1517     ei->change->replace_when = getFile8Bit(file);
1518
1519     for (y = 0; y < 3; y++)
1520       for (x = 0; x < 3; x++)
1521         ei->change->target_content.e[x][y] =
1522           getMappedElement(getFile16BitBE(file));
1523
1524     ei->slippery_type = getFile8Bit(file);
1525
1526     /* some free bytes for future properties and padding */
1527     ReadUnusedBytesFromFile(file, LEVEL_CPART_CUS3_UNUSED);
1528
1529     /* mark that this custom element has been modified */
1530     ei->modified_settings = TRUE;
1531   }
1532
1533   return chunk_size;
1534 }
1535
1536 static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
1537 {
1538   struct ElementInfo *ei;
1539   int chunk_size_expected;
1540   int element;
1541   int i, j, x, y;
1542
1543   /* ---------- custom element base property values (96 bytes) ------------- */
1544
1545   element = getFile16BitBE(file);
1546
1547   if (!IS_CUSTOM_ELEMENT(element))
1548   {
1549     Error(ERR_WARN, "invalid custom element number %d", element);
1550
1551     ReadUnusedBytesFromFile(file, chunk_size - 2);
1552     return chunk_size;
1553   }
1554
1555   ei = &element_info[element];
1556
1557   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
1558     ei->description[i] = getFile8Bit(file);
1559   ei->description[MAX_ELEMENT_NAME_LEN] = 0;
1560
1561 #if 1
1562   ei->properties[EP_BITFIELD_BASE] = getFile32BitBE(file);
1563 #else
1564   Properties[element][EP_BITFIELD_BASE] = getFile32BitBE(file);
1565 #endif
1566   ReadUnusedBytesFromFile(file, 4);     /* reserved for more base properties */
1567
1568   ei->num_change_pages = getFile8Bit(file);
1569
1570   chunk_size_expected = LEVEL_CHUNK_CUS4_SIZE(ei->num_change_pages);
1571   if (chunk_size_expected != chunk_size)
1572   {
1573     ReadUnusedBytesFromFile(file, chunk_size - 43);
1574     return chunk_size_expected;
1575   }
1576
1577   ei->ce_value_fixed_initial = getFile16BitBE(file);
1578   ei->ce_value_random_initial = getFile16BitBE(file);
1579   ei->use_last_ce_value = getFile8Bit(file);
1580
1581   ei->use_gfx_element = getFile8Bit(file);
1582   ei->gfx_element = getMappedElement(getFile16BitBE(file));
1583
1584   ei->collect_score_initial = getFile8Bit(file);
1585   ei->collect_count_initial = getFile8Bit(file);
1586
1587   ei->drop_delay_fixed = getFile8Bit(file);
1588   ei->push_delay_fixed = getFile8Bit(file);
1589   ei->drop_delay_random = getFile8Bit(file);
1590   ei->push_delay_random = getFile8Bit(file);
1591   ei->move_delay_fixed = getFile16BitBE(file);
1592   ei->move_delay_random = getFile16BitBE(file);
1593
1594   /* bits 0 - 15 of "move_pattern" ... */
1595   ei->move_pattern = getFile16BitBE(file);
1596   ei->move_direction_initial = getFile8Bit(file);
1597   ei->move_stepsize = getFile8Bit(file);
1598
1599   ei->slippery_type = getFile8Bit(file);
1600
1601   for (y = 0; y < 3; y++)
1602     for (x = 0; x < 3; x++)
1603       ei->content.e[x][y] = getMappedElement(getFile16BitBE(file));
1604
1605   ei->move_enter_element = getMappedElement(getFile16BitBE(file));
1606   ei->move_leave_element = getMappedElement(getFile16BitBE(file));
1607   ei->move_leave_type = getFile8Bit(file);
1608
1609   /* ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible) */
1610   ei->move_pattern |= (getFile16BitBE(file) << 16);
1611
1612   ei->access_direction = getFile8Bit(file);
1613
1614   ei->explosion_delay = getFile8Bit(file);
1615   ei->ignition_delay = getFile8Bit(file);
1616   ei->explosion_type = getFile8Bit(file);
1617
1618   /* some free bytes for future custom property values and padding */
1619   ReadUnusedBytesFromFile(file, 1);
1620
1621   /* ---------- change page property values (48 bytes) --------------------- */
1622
1623   setElementChangePages(ei, ei->num_change_pages);
1624
1625   for (i = 0; i < ei->num_change_pages; i++)
1626   {
1627     struct ElementChangeInfo *change = &ei->change_page[i];
1628     unsigned long event_bits;
1629
1630     /* always start with reliable default values */
1631     setElementChangeInfoToDefaults(change);
1632
1633     /* bits 0 - 31 of "has_event[]" ... */
1634     event_bits = getFile32BitBE(file);
1635     for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
1636       if (event_bits & (1 << j))
1637         change->has_event[j] = TRUE;
1638
1639     change->target_element = getMappedElement(getFile16BitBE(file));
1640
1641     change->delay_fixed = getFile16BitBE(file);
1642     change->delay_random = getFile16BitBE(file);
1643     change->delay_frames = getFile16BitBE(file);
1644
1645     change->trigger_element = getMappedElement(getFile16BitBE(file));
1646
1647     change->explode = getFile8Bit(file);
1648     change->use_target_content = getFile8Bit(file);
1649     change->only_if_complete = getFile8Bit(file);
1650     change->use_random_replace = getFile8Bit(file);
1651
1652     change->random_percentage = getFile8Bit(file);
1653     change->replace_when = getFile8Bit(file);
1654
1655     for (y = 0; y < 3; y++)
1656       for (x = 0; x < 3; x++)
1657         change->target_content.e[x][y]= getMappedElement(getFile16BitBE(file));
1658
1659     change->can_change = getFile8Bit(file);
1660
1661     change->trigger_side = getFile8Bit(file);
1662
1663     change->trigger_player = getFile8Bit(file);
1664     change->trigger_page = getFile8Bit(file);
1665
1666     change->trigger_page = (change->trigger_page == CH_PAGE_ANY_FILE ?
1667                             CH_PAGE_ANY : (1 << change->trigger_page));
1668
1669     change->has_action = getFile8Bit(file);
1670     change->action_type = getFile8Bit(file);
1671     change->action_mode = getFile8Bit(file);
1672     change->action_arg = getFile16BitBE(file);
1673
1674     /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */
1675     event_bits = getFile8Bit(file);
1676     for (j = 32; j < NUM_CHANGE_EVENTS; j++)
1677       if (event_bits & (1 << (j - 32)))
1678         change->has_event[j] = TRUE;
1679   }
1680
1681   /* mark this custom element as modified */
1682   ei->modified_settings = TRUE;
1683
1684   return chunk_size;
1685 }
1686
1687 static int LoadLevel_GRP1(FILE *file, int chunk_size, struct LevelInfo *level)
1688 {
1689   struct ElementInfo *ei;
1690   struct ElementGroupInfo *group;
1691   int element;
1692   int i;
1693
1694   element = getFile16BitBE(file);
1695
1696   if (!IS_GROUP_ELEMENT(element))
1697   {
1698     Error(ERR_WARN, "invalid group element number %d", element);
1699
1700     ReadUnusedBytesFromFile(file, chunk_size - 2);
1701     return chunk_size;
1702   }
1703
1704   ei = &element_info[element];
1705
1706   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
1707     ei->description[i] = getFile8Bit(file);
1708   ei->description[MAX_ELEMENT_NAME_LEN] = 0;
1709
1710   group = element_info[element].group;
1711
1712   group->num_elements = getFile8Bit(file);
1713
1714   ei->use_gfx_element = getFile8Bit(file);
1715   ei->gfx_element = getMappedElement(getFile16BitBE(file));
1716
1717   group->choice_mode = getFile8Bit(file);
1718
1719   /* some free bytes for future values and padding */
1720   ReadUnusedBytesFromFile(file, 3);
1721
1722   for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
1723     group->element[i] = getMappedElement(getFile16BitBE(file));
1724
1725   /* mark this group element as modified */
1726   element_info[element].modified_settings = TRUE;
1727
1728   return chunk_size;
1729 }
1730
1731 static int LoadLevel_CONF(FILE *file, int chunk_size, struct LevelInfo *level)
1732 {
1733   int real_chunk_size = 0;
1734   int i;
1735
1736   while (!feof(file))
1737   {
1738     int element = getFile16BitBE(file);
1739     int type = getFile8Bit(file);
1740     int bytes = type & CONF_MASK_BYTES;
1741     boolean element_found = FALSE;
1742
1743     real_chunk_size += 3;
1744
1745     li = *level;        /* copy level information into temporary buffer */
1746
1747     if (bytes == CONF_MASK_MULTI_BYTES)
1748     {
1749       int num_bytes = getFile16BitBE(file);
1750       byte *buffer = checked_malloc(num_bytes);
1751
1752       ReadBytesFromFile(file, buffer, num_bytes);
1753
1754       for (i = 0; element_conf[i].element != -1; i++)
1755       {
1756         if (element_conf[i].element == element &&
1757             element_conf[i].type    == type)
1758         {
1759           int num_entities = num_bytes / CONF_ENTITY_NUM_BYTES(type);
1760           int max_num_entities = element_conf[i].max_num_entities;
1761
1762           if (num_entities > max_num_entities)
1763           {
1764             Error(ERR_WARN,
1765                   "truncating number of entities for element %d from %d to %d",
1766                   element, num_entities, max_num_entities);
1767
1768             num_entities = max_num_entities;
1769           }
1770
1771           *(int *)(element_conf[i].num_entities) = num_entities;
1772
1773           element_found = TRUE;
1774
1775           if (type == CONF_VALUE_ELEMENTS)
1776           {
1777             int *element_array = (int *)(element_conf[i].value);
1778             int j;
1779
1780             for (j = 0; j < num_entities; j++)
1781               element_array[j] =
1782                 getMappedElement(CONF_ELEMENTS_ELEMENT(buffer, j));
1783           }
1784           else if (type == CONF_VALUE_CONTENTS)
1785           {
1786             struct Content *content= (struct Content *)(element_conf[i].value);
1787             int c, x, y;
1788
1789             for (c = 0; c < num_entities; c++)
1790               for (y = 0; y < 3; y++)
1791                 for (x = 0; x < 3; x++)
1792                   content[c].e[x][y] =
1793                     getMappedElement(CONF_CONTENTS_ELEMENT(buffer, c, x, y));
1794           }
1795           else
1796             element_found = FALSE;
1797
1798           break;
1799         }
1800       }
1801
1802       checked_free(buffer);
1803
1804       real_chunk_size += 2 + num_bytes;
1805     }
1806     else        /* constant size configuration data (1, 2 or 4 bytes) */
1807     {
1808       int value = (bytes == CONF_MASK_1_BYTE ? getFile8Bit   (file) :
1809                    bytes == CONF_MASK_2_BYTE ? getFile16BitBE(file) :
1810                    bytes == CONF_MASK_4_BYTE ? getFile32BitBE(file) : 0);
1811
1812       for (i = 0; element_conf[i].element != -1; i++)
1813       {
1814         if (element_conf[i].element == element &&
1815             element_conf[i].type    == type)
1816         {
1817           if (CONF_VALUE_BOOLEAN(type))
1818             *(boolean *)(element_conf[i].value) = value;
1819           else
1820             *(int *)    (element_conf[i].value) = value;
1821
1822           element_found = TRUE;
1823
1824           break;
1825         }
1826       }
1827
1828       real_chunk_size += CONF_VALUE_NUM_BYTES(bytes);
1829     }
1830
1831     *level = li;        /* copy temporary buffer back to level information */
1832
1833     if (!element_found)
1834       Error(ERR_WARN, "cannot load CONF value for element %d", element);
1835
1836     if (type == CONF_LAST_ENTRY || real_chunk_size >= chunk_size)
1837       break;
1838   }
1839
1840   return real_chunk_size;
1841 }
1842
1843 static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
1844                                       struct LevelFileInfo *level_file_info)
1845 {
1846   char *filename = level_file_info->filename;
1847   char cookie[MAX_LINE_LEN];
1848   char chunk_name[CHUNK_ID_LEN + 1];
1849   int chunk_size;
1850   FILE *file;
1851
1852   if (!(file = fopen(filename, MODE_READ)))
1853   {
1854     level->no_valid_file = TRUE;
1855
1856     if (level != &level_template)
1857       Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
1858
1859     return;
1860   }
1861
1862   getFileChunkBE(file, chunk_name, NULL);
1863   if (strcmp(chunk_name, "RND1") == 0)
1864   {
1865     getFile32BitBE(file);               /* not used */
1866
1867     getFileChunkBE(file, chunk_name, NULL);
1868     if (strcmp(chunk_name, "CAVE") != 0)
1869     {
1870       level->no_valid_file = TRUE;
1871
1872       Error(ERR_WARN, "unknown format of level file '%s'", filename);
1873       fclose(file);
1874       return;
1875     }
1876   }
1877   else  /* check for pre-2.0 file format with cookie string */
1878   {
1879     strcpy(cookie, chunk_name);
1880     fgets(&cookie[4], MAX_LINE_LEN - 4, file);
1881     if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
1882       cookie[strlen(cookie) - 1] = '\0';
1883
1884     if (!checkCookieString(cookie, LEVEL_COOKIE_TMPL))
1885     {
1886       level->no_valid_file = TRUE;
1887
1888       Error(ERR_WARN, "unknown format of level file '%s'", filename);
1889       fclose(file);
1890       return;
1891     }
1892
1893     if ((level->file_version = getFileVersionFromCookieString(cookie)) == -1)
1894     {
1895       level->no_valid_file = TRUE;
1896
1897       Error(ERR_WARN, "unsupported version of level file '%s'", filename);
1898       fclose(file);
1899       return;
1900     }
1901
1902     /* pre-2.0 level files have no game version, so use file version here */
1903     level->game_version = level->file_version;
1904   }
1905
1906   if (level->file_version < FILE_VERSION_1_2)
1907   {
1908     /* level files from versions before 1.2.0 without chunk structure */
1909     LoadLevel_HEAD(file, LEVEL_HEADER_SIZE,             level);
1910     LoadLevel_BODY(file, level->fieldx * level->fieldy, level);
1911   }
1912   else
1913   {
1914     static struct
1915     {
1916       char *name;
1917       int size;
1918       int (*loader)(FILE *, int, struct LevelInfo *);
1919     }
1920     chunk_info[] =
1921     {
1922       { "VERS", FILE_VERS_CHUNK_SIZE,   LoadLevel_VERS },
1923       { "HEAD", LEVEL_HEADER_SIZE,      LoadLevel_HEAD },
1924       { "AUTH", MAX_LEVEL_AUTHOR_LEN,   LoadLevel_AUTH },
1925       { "BODY", -1,                     LoadLevel_BODY },
1926       { "CONT", -1,                     LoadLevel_CONT },
1927       { "CNT2", LEVEL_CHUNK_CNT2_SIZE,  LoadLevel_CNT2 },
1928       { "CNT3", -1,                     LoadLevel_CNT3 },
1929       { "CUS1", -1,                     LoadLevel_CUS1 },
1930       { "CUS2", -1,                     LoadLevel_CUS2 },
1931       { "CUS3", -1,                     LoadLevel_CUS3 },
1932       { "CUS4", -1,                     LoadLevel_CUS4 },
1933       { "GRP1", -1,                     LoadLevel_GRP1 },
1934       { "CONF", -1,                     LoadLevel_CONF },
1935
1936       {  NULL,  0,                      NULL }
1937     };
1938
1939     while (getFileChunkBE(file, chunk_name, &chunk_size))
1940     {
1941       int i = 0;
1942
1943       while (chunk_info[i].name != NULL &&
1944              strcmp(chunk_name, chunk_info[i].name) != 0)
1945         i++;
1946
1947       if (chunk_info[i].name == NULL)
1948       {
1949         Error(ERR_WARN, "unknown chunk '%s' in level file '%s'",
1950               chunk_name, filename);
1951         ReadUnusedBytesFromFile(file, chunk_size);
1952       }
1953       else if (chunk_info[i].size != -1 &&
1954                chunk_info[i].size != chunk_size)
1955       {
1956         Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
1957               chunk_size, chunk_name, filename);
1958         ReadUnusedBytesFromFile(file, chunk_size);
1959       }
1960       else
1961       {
1962         /* call function to load this level chunk */
1963         int chunk_size_expected =
1964           (chunk_info[i].loader)(file, chunk_size, level);
1965
1966         /* the size of some chunks cannot be checked before reading other
1967            chunks first (like "HEAD" and "BODY") that contain some header
1968            information, so check them here */
1969         if (chunk_size_expected != chunk_size)
1970         {
1971           Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
1972                 chunk_size, chunk_name, filename);
1973         }
1974       }
1975     }
1976   }
1977
1978   fclose(file);
1979 }
1980
1981 /* ------------------------------------------------------------------------- */
1982 /* functions for loading EM level                                            */
1983 /* ------------------------------------------------------------------------- */
1984
1985 #if 0
1986
1987 static int map_em_element_yam(int element)
1988 {
1989   switch (element)
1990   {
1991     case 0x00:  return EL_EMPTY;
1992     case 0x01:  return EL_EMERALD;
1993     case 0x02:  return EL_DIAMOND;
1994     case 0x03:  return EL_ROCK;
1995     case 0x04:  return EL_ROBOT;
1996     case 0x05:  return EL_SPACESHIP_UP;
1997     case 0x06:  return EL_BOMB;
1998     case 0x07:  return EL_BUG_UP;
1999     case 0x08:  return EL_AMOEBA_DROP;
2000     case 0x09:  return EL_NUT;
2001     case 0x0a:  return EL_YAMYAM;
2002     case 0x0b:  return EL_QUICKSAND_FULL;
2003     case 0x0c:  return EL_SAND;
2004     case 0x0d:  return EL_WALL_SLIPPERY;
2005     case 0x0e:  return EL_STEELWALL;
2006     case 0x0f:  return EL_WALL;
2007     case 0x10:  return EL_EM_KEY_1;
2008     case 0x11:  return EL_EM_KEY_2;
2009     case 0x12:  return EL_EM_KEY_4;
2010     case 0x13:  return EL_EM_KEY_3;
2011     case 0x14:  return EL_MAGIC_WALL;
2012     case 0x15:  return EL_ROBOT_WHEEL;
2013     case 0x16:  return EL_DYNAMITE;
2014
2015     case 0x17:  return EL_EM_KEY_1;                     /* EMC */
2016     case 0x18:  return EL_BUG_UP;                       /* EMC */
2017     case 0x1a:  return EL_DIAMOND;                      /* EMC */
2018     case 0x1b:  return EL_EMERALD;                      /* EMC */
2019     case 0x25:  return EL_NUT;                          /* EMC */
2020     case 0x80:  return EL_EMPTY;                        /* EMC */
2021     case 0x85:  return EL_EM_KEY_1;                     /* EMC */
2022     case 0x86:  return EL_EM_KEY_2;                     /* EMC */
2023     case 0x87:  return EL_EM_KEY_4;                     /* EMC */
2024     case 0x88:  return EL_EM_KEY_3;                     /* EMC */
2025     case 0x94:  return EL_QUICKSAND_EMPTY;              /* EMC */
2026     case 0x9a:  return EL_AMOEBA_WET;                   /* EMC */
2027     case 0xaf:  return EL_DYNAMITE;                     /* EMC */
2028     case 0xbd:  return EL_SAND;                         /* EMC */
2029
2030     default:
2031       Error(ERR_WARN, "invalid level element %d", element);
2032       return EL_UNKNOWN;
2033   }
2034 }
2035
2036 static int map_em_element_field(int element)
2037 {
2038   if (element >= 0xc8 && element <= 0xe1)
2039     return EL_CHAR_A + (element - 0xc8);
2040   else if (element >= 0xe2 && element <= 0xeb)
2041     return EL_CHAR_0 + (element - 0xe2);
2042
2043   switch (element)
2044   {
2045     case 0x00:  return EL_ROCK;
2046     case 0x01:  return EL_ROCK;                         /* EMC */
2047     case 0x02:  return EL_DIAMOND;
2048     case 0x03:  return EL_DIAMOND;
2049     case 0x04:  return EL_ROBOT;
2050     case 0x05:  return EL_ROBOT;                        /* EMC */
2051     case 0x06:  return EL_EMPTY_SPACE;                  /* EMC */
2052     case 0x07:  return EL_EMPTY_SPACE;                  /* EMC */
2053     case 0x08:  return EL_SPACESHIP_UP;
2054     case 0x09:  return EL_SPACESHIP_RIGHT;
2055     case 0x0a:  return EL_SPACESHIP_DOWN;
2056     case 0x0b:  return EL_SPACESHIP_LEFT;
2057     case 0x0c:  return EL_SPACESHIP_UP;
2058     case 0x0d:  return EL_SPACESHIP_RIGHT;
2059     case 0x0e:  return EL_SPACESHIP_DOWN;
2060     case 0x0f:  return EL_SPACESHIP_LEFT;
2061
2062     case 0x10:  return EL_BOMB;
2063     case 0x11:  return EL_BOMB;                         /* EMC */
2064     case 0x12:  return EL_EMERALD;
2065     case 0x13:  return EL_EMERALD;
2066     case 0x14:  return EL_BUG_UP;
2067     case 0x15:  return EL_BUG_RIGHT;
2068     case 0x16:  return EL_BUG_DOWN;
2069     case 0x17:  return EL_BUG_LEFT;
2070     case 0x18:  return EL_BUG_UP;
2071     case 0x19:  return EL_BUG_RIGHT;
2072     case 0x1a:  return EL_BUG_DOWN;
2073     case 0x1b:  return EL_BUG_LEFT;
2074     case 0x1c:  return EL_AMOEBA_DROP;
2075     case 0x1d:  return EL_AMOEBA_DROP;                  /* EMC */
2076     case 0x1e:  return EL_AMOEBA_DROP;                  /* EMC */
2077     case 0x1f:  return EL_AMOEBA_DROP;                  /* EMC */
2078
2079     case 0x20:  return EL_ROCK;
2080     case 0x21:  return EL_BOMB;                         /* EMC */
2081     case 0x22:  return EL_DIAMOND;                      /* EMC */
2082     case 0x23:  return EL_EMERALD;                      /* EMC */
2083     case 0x24:  return EL_MAGIC_WALL;
2084     case 0x25:  return EL_NUT;
2085     case 0x26:  return EL_NUT;                          /* EMC */
2086     case 0x27:  return EL_NUT;                          /* EMC */
2087
2088       /* looks like magic wheel, but is _always_ activated */
2089     case 0x28:  return EL_ROBOT_WHEEL;                  /* EMC */
2090
2091     case 0x29:  return EL_YAMYAM;       /* up */
2092     case 0x2a:  return EL_YAMYAM;       /* down */
2093     case 0x2b:  return EL_YAMYAM;       /* left */      /* EMC */
2094     case 0x2c:  return EL_YAMYAM;       /* right */     /* EMC */
2095     case 0x2d:  return EL_QUICKSAND_FULL;
2096     case 0x2e:  return EL_EMPTY_SPACE;                  /* EMC */
2097     case 0x2f:  return EL_EMPTY_SPACE;                  /* EMC */
2098
2099     case 0x30:  return EL_EMPTY_SPACE;                  /* EMC */
2100     case 0x31:  return EL_SAND;                         /* EMC */
2101     case 0x32:  return EL_SAND;                         /* EMC */
2102     case 0x33:  return EL_SAND;                         /* EMC */
2103     case 0x34:  return EL_QUICKSAND_FULL;               /* EMC */
2104     case 0x35:  return EL_QUICKSAND_FULL;               /* EMC */
2105     case 0x36:  return EL_QUICKSAND_FULL;               /* EMC */
2106     case 0x37:  return EL_SAND;                         /* EMC */
2107     case 0x38:  return EL_ROCK;                         /* EMC */
2108     case 0x39:  return EL_EXPANDABLE_WALL_HORIZONTAL;   /* EMC */
2109     case 0x3a:  return EL_EXPANDABLE_WALL_VERTICAL;     /* EMC */
2110     case 0x3b:  return EL_DYNAMITE_ACTIVE;      /* 1 */
2111     case 0x3c:  return EL_DYNAMITE_ACTIVE;      /* 2 */
2112     case 0x3d:  return EL_DYNAMITE_ACTIVE;      /* 3 */
2113     case 0x3e:  return EL_DYNAMITE_ACTIVE;      /* 4 */
2114     case 0x3f:  return EL_ACID_POOL_BOTTOM;
2115
2116     case 0x40:  return EL_EXIT_OPEN;    /* 1 */
2117     case 0x41:  return EL_EXIT_OPEN;    /* 2 */
2118     case 0x42:  return EL_EXIT_OPEN;    /* 3 */
2119     case 0x43:  return EL_BALLOON;                      /* EMC */
2120     case 0x44:  return EL_UNKNOWN;                      /* EMC ("plant") */
2121     case 0x45:  return EL_SPRING;                       /* EMC */
2122     case 0x46:  return EL_SPRING;       /* falling */   /* EMC */
2123     case 0x47:  return EL_SPRING;       /* left */      /* EMC */
2124     case 0x48:  return EL_SPRING;       /* right */     /* EMC */
2125     case 0x49:  return EL_UNKNOWN;                      /* EMC ("ball 1") */
2126     case 0x4a:  return EL_UNKNOWN;                      /* EMC ("ball 2") */
2127     case 0x4b:  return EL_UNKNOWN;                      /* EMC ("android") */
2128     case 0x4c:  return EL_EMPTY_SPACE;                  /* EMC */
2129     case 0x4d:  return EL_UNKNOWN;                      /* EMC ("android") */
2130     case 0x4e:  return EL_INVISIBLE_WALL;               /* EMC (? "android") */
2131     case 0x4f:  return EL_UNKNOWN;                      /* EMC ("android") */
2132
2133     case 0x50:  return EL_UNKNOWN;                      /* EMC ("android") */
2134     case 0x51:  return EL_UNKNOWN;                      /* EMC ("android") */
2135     case 0x52:  return EL_UNKNOWN;                      /* EMC ("android") */
2136     case 0x53:  return EL_UNKNOWN;                      /* EMC ("android") */
2137     case 0x54:  return EL_UNKNOWN;                      /* EMC ("android") */
2138     case 0x55:  return EL_EMPTY_SPACE;                  /* EMC */
2139     case 0x56:  return EL_EMPTY_SPACE;                  /* EMC */
2140     case 0x57:  return EL_EMPTY_SPACE;                  /* EMC */
2141     case 0x58:  return EL_EMPTY_SPACE;                  /* EMC */
2142     case 0x59:  return EL_EMPTY_SPACE;                  /* EMC */
2143     case 0x5a:  return EL_EMPTY_SPACE;                  /* EMC */
2144     case 0x5b:  return EL_EMPTY_SPACE;                  /* EMC */
2145     case 0x5c:  return EL_EMPTY_SPACE;                  /* EMC */
2146     case 0x5d:  return EL_EMPTY_SPACE;                  /* EMC */
2147     case 0x5e:  return EL_EMPTY_SPACE;                  /* EMC */
2148     case 0x5f:  return EL_EMPTY_SPACE;                  /* EMC */
2149
2150     case 0x60:  return EL_EMPTY_SPACE;                  /* EMC */
2151     case 0x61:  return EL_EMPTY_SPACE;                  /* EMC */
2152     case 0x62:  return EL_EMPTY_SPACE;                  /* EMC */
2153     case 0x63:  return EL_SPRING;       /* left */      /* EMC */
2154     case 0x64:  return EL_SPRING;       /* right */     /* EMC */
2155     case 0x65:  return EL_ACID;         /* 1 */         /* EMC */
2156     case 0x66:  return EL_ACID;         /* 2 */         /* EMC */
2157     case 0x67:  return EL_ACID;         /* 3 */         /* EMC */
2158     case 0x68:  return EL_ACID;         /* 4 */         /* EMC */
2159     case 0x69:  return EL_ACID;         /* 5 */         /* EMC */
2160     case 0x6a:  return EL_ACID;         /* 6 */         /* EMC */
2161     case 0x6b:  return EL_ACID;         /* 7 */         /* EMC */
2162     case 0x6c:  return EL_ACID;         /* 8 */         /* EMC */
2163     case 0x6d:  return EL_EMPTY_SPACE;                  /* EMC */
2164     case 0x6e:  return EL_EMPTY_SPACE;                  /* EMC */
2165     case 0x6f:  return EL_EMPTY_SPACE;                  /* EMC */
2166
2167     case 0x70:  return EL_EMPTY_SPACE;                  /* EMC */
2168     case 0x71:  return EL_EMPTY_SPACE;                  /* EMC */
2169     case 0x72:  return EL_NUT;          /* left */      /* EMC */
2170     case 0x73:  return EL_SAND;                         /* EMC (? "nut") */
2171     case 0x74:  return EL_STEELWALL;
2172     case 0x75:  return EL_EMPTY_SPACE;                  /* EMC */
2173     case 0x76:  return EL_EMPTY_SPACE;                  /* EMC */
2174     case 0x77:  return EL_BOMB;         /* left */      /* EMC */
2175     case 0x78:  return EL_BOMB;         /* right */     /* EMC */
2176     case 0x79:  return EL_ROCK;         /* left */      /* EMC */
2177     case 0x7a:  return EL_ROCK;         /* right */     /* EMC */
2178     case 0x7b:  return EL_ACID;                         /* (? EMC "blank") */
2179     case 0x7c:  return EL_EMPTY_SPACE;                  /* EMC */
2180     case 0x7d:  return EL_EMPTY_SPACE;                  /* EMC */
2181     case 0x7e:  return EL_EMPTY_SPACE;                  /* EMC */
2182     case 0x7f:  return EL_EMPTY_SPACE;                  /* EMC */
2183
2184     case 0x80:  return EL_EMPTY;
2185     case 0x81:  return EL_WALL_SLIPPERY;
2186     case 0x82:  return EL_SAND;
2187     case 0x83:  return EL_STEELWALL;
2188     case 0x84:  return EL_WALL;
2189     case 0x85:  return EL_EM_KEY_1;
2190     case 0x86:  return EL_EM_KEY_2;
2191     case 0x87:  return EL_EM_KEY_4;
2192     case 0x88:  return EL_EM_KEY_3;
2193     case 0x89:  return EL_EM_GATE_1;
2194     case 0x8a:  return EL_EM_GATE_2;
2195     case 0x8b:  return EL_EM_GATE_4;
2196     case 0x8c:  return EL_EM_GATE_3;
2197     case 0x8d:  return EL_INVISIBLE_WALL;               /* EMC (? "dripper") */
2198     case 0x8e:  return EL_EM_GATE_1_GRAY;
2199     case 0x8f:  return EL_EM_GATE_2_GRAY;
2200
2201     case 0x90:  return EL_EM_GATE_4_GRAY;
2202     case 0x91:  return EL_EM_GATE_3_GRAY;
2203     case 0x92:  return EL_MAGIC_WALL;
2204     case 0x93:  return EL_ROBOT_WHEEL;
2205     case 0x94:  return EL_QUICKSAND_EMPTY;              /* (? EMC "sand") */
2206     case 0x95:  return EL_ACID_POOL_TOPLEFT;
2207     case 0x96:  return EL_ACID_POOL_TOPRIGHT;
2208     case 0x97:  return EL_ACID_POOL_BOTTOMLEFT;
2209     case 0x98:  return EL_ACID_POOL_BOTTOMRIGHT;
2210     case 0x99:  return EL_ACID;                 /* (? EMC "fake blank") */
2211     case 0x9a:  return EL_AMOEBA_DEAD;          /* 1 */
2212     case 0x9b:  return EL_AMOEBA_DEAD;          /* 2 */
2213     case 0x9c:  return EL_AMOEBA_DEAD;          /* 3 */
2214     case 0x9d:  return EL_AMOEBA_DEAD;          /* 4 */
2215     case 0x9e:  return EL_EXIT_CLOSED;
2216     case 0x9f:  return EL_CHAR_LESS;            /* arrow left */
2217
2218       /* looks like normal sand, but behaves like wall */
2219     case 0xa0:  return EL_UNKNOWN;              /* EMC ("fake grass") */
2220     case 0xa1:  return EL_UNKNOWN;              /* EMC ("lenses") */
2221     case 0xa2:  return EL_UNKNOWN;              /* EMC ("magnify") */
2222     case 0xa3:  return EL_UNKNOWN;              /* EMC ("fake blank") */
2223     case 0xa4:  return EL_UNKNOWN;              /* EMC ("fake grass") */
2224     case 0xa5:  return EL_UNKNOWN;              /* EMC ("switch") */
2225     case 0xa6:  return EL_UNKNOWN;              /* EMC ("switch") */
2226     case 0xa7:  return EL_EMPTY_SPACE;                  /* EMC */
2227     case 0xa8:  return EL_EMC_WALL_1;                   /* EMC ("decor 8") */
2228     case 0xa9:  return EL_EMC_WALL_2;                   /* EMC ("decor 9") */
2229     case 0xaa:  return EL_EMC_WALL_3;                   /* EMC ("decor 10") */
2230     case 0xab:  return EL_EMC_WALL_7;                   /* EMC ("decor 5") */
2231     case 0xac:  return EL_CHAR_COMMA;                   /* EMC */
2232     case 0xad:  return EL_CHAR_QUOTEDBL;                /* EMC */
2233     case 0xae:  return EL_CHAR_MINUS;                   /* EMC */
2234     case 0xaf:  return EL_DYNAMITE;
2235
2236     case 0xb0:  return EL_EMC_STEELWALL_1;              /* EMC ("steel 3") */
2237     case 0xb1:  return EL_EMC_WALL_8;                   /* EMC ("decor 6") */
2238     case 0xb2:  return EL_UNKNOWN;                      /* EMC ("decor 7") */
2239     case 0xb3:  return EL_STEELWALL;            /* 2 */ /* EMC */
2240     case 0xb4:  return EL_WALL_SLIPPERY;        /* 2 */ /* EMC */
2241     case 0xb5:  return EL_EMC_WALL_6;                   /* EMC ("decor 2") */
2242     case 0xb6:  return EL_EMC_WALL_5;                   /* EMC ("decor 4") */
2243     case 0xb7:  return EL_EMC_WALL_4;                   /* EMC ("decor 3") */
2244     case 0xb8:  return EL_BALLOON_SWITCH_ANY;           /* EMC */
2245     case 0xb9:  return EL_BALLOON_SWITCH_RIGHT;         /* EMC */
2246     case 0xba:  return EL_BALLOON_SWITCH_DOWN;          /* EMC */
2247     case 0xbb:  return EL_BALLOON_SWITCH_LEFT;          /* EMC */
2248     case 0xbc:  return EL_BALLOON_SWITCH_UP;            /* EMC */
2249     case 0xbd:  return EL_SAND;                         /* EMC ("dirt") */
2250     case 0xbe:  return EL_UNKNOWN;                      /* EMC ("plant") */
2251     case 0xbf:  return EL_UNKNOWN;                      /* EMC ("key 5") */
2252
2253     case 0xc0:  return EL_UNKNOWN;                      /* EMC ("key 6") */
2254     case 0xc1:  return EL_UNKNOWN;                      /* EMC ("key 7") */
2255     case 0xc2:  return EL_UNKNOWN;                      /* EMC ("key 8") */
2256     case 0xc3:  return EL_UNKNOWN;                      /* EMC ("door 5") */
2257     case 0xc4:  return EL_UNKNOWN;                      /* EMC ("door 6") */
2258     case 0xc5:  return EL_UNKNOWN;                      /* EMC ("door 7") */
2259     case 0xc6:  return EL_UNKNOWN;                      /* EMC ("door 8") */
2260     case 0xc7:  return EL_UNKNOWN;                      /* EMC ("bumper") */
2261
2262       /* characters: see above */
2263
2264     case 0xec:  return EL_CHAR_PERIOD;
2265     case 0xed:  return EL_CHAR_EXCLAM;
2266     case 0xee:  return EL_CHAR_COLON;
2267     case 0xef:  return EL_CHAR_QUESTION;
2268
2269     case 0xf0:  return EL_CHAR_GREATER;                 /* arrow right */
2270     case 0xf1:  return EL_CHAR_COPYRIGHT;               /* EMC: "decor 1" */
2271     case 0xf2:  return EL_UNKNOWN;              /* EMC ("fake door 5") */
2272     case 0xf3:  return EL_UNKNOWN;              /* EMC ("fake door 6") */
2273     case 0xf4:  return EL_UNKNOWN;              /* EMC ("fake door 7") */
2274     case 0xf5:  return EL_UNKNOWN;              /* EMC ("fake door 8") */
2275     case 0xf6:  return EL_EMPTY_SPACE;                  /* EMC */
2276     case 0xf7:  return EL_EMPTY_SPACE;                  /* EMC */
2277
2278     case 0xf8:  return EL_EMPTY_SPACE;                  /* EMC */
2279     case 0xf9:  return EL_EMPTY_SPACE;                  /* EMC */
2280     case 0xfa:  return EL_EMPTY_SPACE;                  /* EMC */
2281     case 0xfb:  return EL_EMPTY_SPACE;                  /* EMC */
2282     case 0xfc:  return EL_EMPTY_SPACE;                  /* EMC */
2283     case 0xfd:  return EL_EMPTY_SPACE;                  /* EMC */
2284
2285     case 0xfe:  return EL_PLAYER_1;                     /* EMC: "blank" */
2286     case 0xff:  return EL_PLAYER_2;                     /* EMC: "blank" */
2287
2288     default:
2289       /* should never happen (all 8-bit value cases should be handled) */
2290       Error(ERR_WARN, "invalid level element %d", element);
2291       return EL_UNKNOWN;
2292   }
2293 }
2294
2295 #define EM_LEVEL_SIZE                   2106
2296 #define EM_LEVEL_XSIZE                  64
2297 #define EM_LEVEL_YSIZE                  32
2298
2299 static void OLD_LoadLevelFromFileInfo_EM(struct LevelInfo *level,
2300                                          struct LevelFileInfo *level_file_info)
2301 {
2302   char *filename = level_file_info->filename;
2303   FILE *file;
2304   unsigned char leveldata[EM_LEVEL_SIZE];
2305   unsigned char *header = &leveldata[EM_LEVEL_XSIZE * EM_LEVEL_YSIZE];
2306   int nr = level_file_info->nr;
2307   int i, x, y;
2308
2309   if (!(file = fopen(filename, MODE_READ)))
2310   {
2311     level->no_valid_file = TRUE;
2312
2313     Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
2314
2315     return;
2316   }
2317
2318   for (i = 0; i < EM_LEVEL_SIZE; i++)
2319     leveldata[i] = fgetc(file);
2320
2321   fclose(file);
2322
2323   /* check if level data is crypted by testing against known starting bytes
2324      of the few existing crypted level files (from Emerald Mine 1 + 2) */
2325
2326   if ((leveldata[0] == 0xf1 ||
2327        leveldata[0] == 0xf5) && leveldata[2] == 0xe7 && leveldata[3] == 0xee)
2328   {
2329     unsigned char code0 = 0x65;
2330     unsigned char code1 = 0x11;
2331
2332     if (leveldata[0] == 0xf5)   /* error in crypted Emerald Mine 2 levels */
2333       leveldata[0] = 0xf1;
2334
2335     /* decode crypted level data */
2336
2337     for (i = 0; i < EM_LEVEL_SIZE; i++)
2338     {
2339       leveldata[i] ^= code0;
2340       leveldata[i] -= code1;
2341
2342       code0 = (code0 + 7) & 0xff;
2343     }
2344   }
2345
2346   level->fieldx = EM_LEVEL_XSIZE;
2347   level->fieldy = EM_LEVEL_YSIZE;
2348
2349   level->time           = header[46] * 10;
2350   level->gems_needed    = header[47];
2351
2352   /* The original Emerald Mine levels have their level number stored
2353      at the second byte of the level file...
2354      Do not trust this information at other level files, e.g. EMC,
2355      but correct it anyway (normally the first row is completely
2356      steel wall, so the correction does not hurt anyway). */
2357
2358   if (leveldata[1] == nr)
2359     leveldata[1] = leveldata[2];        /* correct level number field */
2360
2361   sprintf(level->name, "Level %d", nr);         /* set level name */
2362
2363   level->score[SC_EMERALD]      = header[36];
2364   level->score[SC_DIAMOND]      = header[37];
2365   level->score[SC_ROBOT]        = header[38];
2366   level->score[SC_SPACESHIP]    = header[39];
2367   level->score[SC_BUG]          = header[40];
2368   level->score[SC_YAMYAM]       = header[41];
2369   level->score[SC_NUT]          = header[42];
2370   level->score[SC_DYNAMITE]     = header[43];
2371   level->score[SC_TIME_BONUS]   = header[44];
2372
2373   level->num_yamyam_contents = 4;
2374
2375   for (i = 0; i < level->num_yamyam_contents; i++)
2376     for (y = 0; y < 3; y++)
2377       for (x = 0; x < 3; x++)
2378         level->yamyam_content[i].e[x][y] =
2379           map_em_element_yam(header[i * 9 + y * 3 + x]);
2380
2381   level->amoeba_speed           = (header[52] * 256 + header[53]) % 256;
2382   level->time_magic_wall        = (header[54] * 256 + header[55]) * 16 / 100;
2383   level->time_wheel             = (header[56] * 256 + header[57]) * 16 / 100;
2384   level->amoeba_content         = EL_DIAMOND;
2385
2386   for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
2387   {
2388     int new_element = map_em_element_field(leveldata[y * EM_LEVEL_XSIZE + x]);
2389
2390     if (new_element == EL_AMOEBA_DEAD && level->amoeba_speed)
2391       new_element = EL_AMOEBA_WET;
2392
2393     level->field[x][y] = new_element;
2394   }
2395
2396   x = (header[48] * 256 + header[49]) % EM_LEVEL_XSIZE;
2397   y = (header[48] * 256 + header[49]) / EM_LEVEL_XSIZE;
2398   level->field[x][y] = EL_PLAYER_1;
2399
2400   x = (header[50] * 256 + header[51]) % EM_LEVEL_XSIZE;
2401   y = (header[50] * 256 + header[51]) / EM_LEVEL_XSIZE;
2402   level->field[x][y] = EL_PLAYER_2;
2403 }
2404
2405 #endif
2406
2407 void CopyNativeLevel_RND_to_EM(struct LevelInfo *level)
2408 {
2409   static int ball_xy[8][2] =
2410   {
2411     { 0, 0 },
2412     { 1, 0 },
2413     { 2, 0 },
2414     { 0, 1 },
2415     { 2, 1 },
2416     { 0, 2 },
2417     { 1, 2 },
2418     { 2, 2 },
2419   };
2420   struct LevelInfo_EM *level_em = level->native_em_level;
2421   struct LEVEL *lev = level_em->lev;
2422   struct PLAYER **ply = level_em->ply;
2423   int i, j, x, y;
2424
2425 #if 0
2426   printf("::: A\n");
2427   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
2428     for (j = 0; j < 8; j++)
2429       printf("::: ball %d, %d: %d\n", i, j,
2430              level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
2431 #endif
2432
2433   lev->width  = MIN(level->fieldx, EM_MAX_CAVE_WIDTH);
2434   lev->height = MIN(level->fieldy, EM_MAX_CAVE_HEIGHT);
2435
2436   lev->time_seconds     = level->time;
2437   lev->required_initial = level->gems_needed;
2438
2439   lev->emerald_score    = level->score[SC_EMERALD];
2440   lev->diamond_score    = level->score[SC_DIAMOND];
2441   lev->alien_score      = level->score[SC_ROBOT];
2442   lev->tank_score       = level->score[SC_SPACESHIP];
2443   lev->bug_score        = level->score[SC_BUG];
2444   lev->eater_score      = level->score[SC_YAMYAM];
2445   lev->nut_score        = level->score[SC_NUT];
2446   lev->dynamite_score   = level->score[SC_DYNAMITE];
2447   lev->key_score        = level->score[SC_KEY];
2448   lev->exit_score       = level->score[SC_TIME_BONUS];
2449
2450   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
2451     for (y = 0; y < 3; y++)
2452       for (x = 0; x < 3; x++)
2453         lev->eater_array[i][y * 3 + x] =
2454           map_element_RND_to_EM(level->yamyam_content[i].e[x][y]);
2455
2456   lev->amoeba_time              = level->amoeba_speed;
2457   lev->wonderwall_time_initial  = level->time_magic_wall;
2458   lev->wheel_time               = level->time_wheel;
2459
2460   lev->android_move_time        = level->android_move_time;
2461   lev->android_clone_time       = level->android_clone_time;
2462   lev->ball_random              = level->ball_random;
2463   lev->ball_state_initial       = level->ball_state_initial;
2464   lev->ball_time                = level->ball_time;
2465   lev->num_ball_arrays          = level->num_ball_contents;
2466
2467   lev->lenses_score             = level->lenses_score;
2468   lev->magnify_score            = level->magnify_score;
2469   lev->slurp_score              = level->slurp_score;
2470
2471   lev->lenses_time              = level->lenses_time;
2472   lev->magnify_time             = level->magnify_time;
2473
2474   lev->wind_direction_initial =
2475     map_direction_RND_to_EM(level->wind_direction_initial);
2476   lev->wind_cnt_initial = (level->wind_direction_initial != MV_NONE ?
2477                            lev->wind_time : 0);
2478
2479   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
2480     for (j = 0; j < 8; j++)
2481       lev->ball_array[i][j] =
2482         map_element_RND_to_EM(level->
2483                               ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
2484
2485 #if 0
2486   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
2487     for (j = 0; j < 8; j++)
2488       printf("::: ball %d, %d: %d\n", i, j,
2489              level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
2490 #endif
2491
2492   map_android_clone_elements_RND_to_EM(level);
2493
2494 #if 0
2495   for (i = 0; i < 16; i++)
2496     lev->android_array[i] = FALSE;      /* !!! YET TO COME !!! */
2497 #endif
2498
2499   /* first fill the complete playfield with the default border element */
2500   for (y = 0; y < EM_MAX_CAVE_HEIGHT; y++)
2501     for (x = 0; x < EM_MAX_CAVE_WIDTH; x++)
2502       level_em->cave[x][y] = ZBORDER;
2503
2504 #if 1
2505
2506 #if 0
2507 #if 1
2508   LoadLevel_InitPlayfield();
2509 #else
2510   lev_fieldx = lev->width;      /* !!! also in LoadLevel_InitPlayfield() !!! */
2511   lev_fieldy = lev->height;     /* !!! also in LoadLevel_InitPlayfield() !!! */
2512   SetBorderElement();           /* !!! also in LoadLevel_InitPlayfield() !!! */
2513 #endif
2514 #endif
2515
2516 #if 0
2517   printf("::: BorderElement == %d\n", BorderElement);
2518 #endif
2519
2520   if (BorderElement == EL_STEELWALL)
2521   {
2522     for (y = 0; y < lev->height + 2; y++)
2523       for (x = 0; x < lev->width + 2; x++)
2524         level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_STEELWALL);
2525   }
2526
2527   /* then copy the real level contents from level file into the playfield */
2528   for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
2529   {
2530     int new_element = map_element_RND_to_EM(level->field[x][y]);
2531     int offset = (BorderElement == EL_STEELWALL ? 1 : 0);
2532     int xx = x + 1 + offset;
2533     int yy = y + 1 + offset;
2534
2535     if (level->field[x][y] == EL_AMOEBA_DEAD)
2536       new_element = map_element_RND_to_EM(EL_AMOEBA_WET);
2537
2538     level_em->cave[xx][yy] = new_element;
2539   }
2540
2541 #else
2542
2543   /* then copy the real level contents from level file into the playfield */
2544   for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
2545   {
2546     int new_element = map_element_RND_to_EM(level->field[x][y]);
2547
2548     if (level->field[x][y] == EL_AMOEBA_DEAD)
2549       new_element = map_element_RND_to_EM(EL_AMOEBA_WET);
2550
2551     level_em->cave[x + 1][y + 1] = new_element;
2552   }
2553
2554 #endif
2555
2556 #if 1
2557
2558   for (i = 0; i < MAX_PLAYERS; i++)
2559   {
2560     ply[i]->x_initial = 0;
2561     ply[i]->y_initial = 0;
2562   }
2563
2564 #else
2565
2566   ply1->x_initial = 0;
2567   ply1->y_initial = 0;
2568
2569   ply2->x_initial = 0;
2570   ply2->y_initial = 0;
2571
2572 #endif
2573
2574   /* initialize player positions and delete players from the playfield */
2575   for (y = 0; y < lev->height; y++) for (x = 0; x < lev->width; x++)
2576   {
2577
2578 #if 1
2579     if (ELEM_IS_PLAYER(level->field[x][y]))
2580     {
2581       int player_nr = GET_PLAYER_NR(level->field[x][y]);
2582       int offset = (BorderElement == EL_STEELWALL ? 1 : 0);
2583       int xx = x + 1 + offset;
2584       int yy = y + 1 + offset;
2585
2586       ply[player_nr]->x_initial = xx;
2587       ply[player_nr]->y_initial = yy;
2588
2589       level_em->cave[xx][yy] = map_element_RND_to_EM(EL_EMPTY);
2590     }
2591
2592 #else
2593
2594 #if 1
2595     /* !!! CURRENTLY ONLY SUPPORT FOR ONE PLAYER !!! */
2596     if (ELEM_IS_PLAYER(level->field[x][y]))
2597     {
2598       ply1->x_initial = x + 1;
2599       ply1->y_initial = y + 1;
2600       level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_EMPTY);
2601     }
2602 #else
2603     /* !!! ADD SUPPORT FOR MORE THAN ONE PLAYER !!! */
2604     if (level->field[x][y] == EL_PLAYER_1)
2605     {
2606       ply1->x_initial = x + 1;
2607       ply1->y_initial = y + 1;
2608       level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_EMPTY);
2609     }
2610     else if (level->field[x][y] == EL_PLAYER_2)
2611     {
2612       ply2->x_initial = x + 1;
2613       ply2->y_initial = y + 1;
2614       level_em->cave[x + 1][y + 1] = map_element_RND_to_EM(EL_EMPTY);
2615     }
2616 #endif
2617
2618 #endif
2619
2620   }
2621
2622   if (BorderElement == EL_STEELWALL)
2623   {
2624 #if 1
2625     lev->width  += 2;
2626     lev->height += 2;
2627 #endif
2628   }
2629 }
2630
2631 void CopyNativeLevel_EM_to_RND(struct LevelInfo *level)
2632 {
2633   static int ball_xy[8][2] =
2634   {
2635     { 0, 0 },
2636     { 1, 0 },
2637     { 2, 0 },
2638     { 0, 1 },
2639     { 2, 1 },
2640     { 0, 2 },
2641     { 1, 2 },
2642     { 2, 2 },
2643   };
2644   struct LevelInfo_EM *level_em = level->native_em_level;
2645   struct LEVEL *lev = level_em->lev;
2646   struct PLAYER **ply = level_em->ply;
2647   int i, j, x, y;
2648
2649   level->fieldx = MIN(lev->width,  MAX_LEV_FIELDX);
2650   level->fieldy = MIN(lev->height, MAX_LEV_FIELDY);
2651
2652   level->time        = lev->time_seconds;
2653   level->gems_needed = lev->required_initial;
2654
2655   sprintf(level->name, "Level %d", level->file_info.nr);
2656
2657   level->score[SC_EMERALD]      = lev->emerald_score;
2658   level->score[SC_DIAMOND]      = lev->diamond_score;
2659   level->score[SC_ROBOT]        = lev->alien_score;
2660   level->score[SC_SPACESHIP]    = lev->tank_score;
2661   level->score[SC_BUG]          = lev->bug_score;
2662   level->score[SC_YAMYAM]       = lev->eater_score;
2663   level->score[SC_NUT]          = lev->nut_score;
2664   level->score[SC_DYNAMITE]     = lev->dynamite_score;
2665   level->score[SC_KEY]          = lev->key_score;
2666   level->score[SC_TIME_BONUS]   = lev->exit_score;
2667
2668   level->num_yamyam_contents = MAX_ELEMENT_CONTENTS;
2669
2670   for (i = 0; i < level->num_yamyam_contents; i++)
2671     for (y = 0; y < 3; y++)
2672       for (x = 0; x < 3; x++)
2673         level->yamyam_content[i].e[x][y] =
2674           map_element_EM_to_RND(lev->eater_array[i][y * 3 + x]);
2675
2676   level->amoeba_speed           = lev->amoeba_time;
2677   level->time_magic_wall        = lev->wonderwall_time_initial;
2678   level->time_wheel             = lev->wheel_time;
2679
2680   level->android_move_time      = lev->android_move_time;
2681   level->android_clone_time     = lev->android_clone_time;
2682   level->ball_random            = lev->ball_random;
2683   level->ball_state_initial     = lev->ball_state_initial;
2684   level->ball_time              = lev->ball_time;
2685   level->num_ball_contents      = lev->num_ball_arrays;
2686
2687   level->lenses_score           = lev->lenses_score;
2688   level->magnify_score          = lev->magnify_score;
2689   level->slurp_score            = lev->slurp_score;
2690
2691   level->lenses_time            = lev->lenses_time;
2692   level->magnify_time           = lev->magnify_time;
2693
2694   level->wind_direction_initial =
2695     map_direction_EM_to_RND(lev->wind_direction_initial);
2696
2697 #if 0
2698   printf("::: foo\n");
2699   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
2700     for (j = 0; j < 8; j++)
2701       printf("::: ball %d, %d: %d\n", i, j,
2702              level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
2703 #endif
2704
2705   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
2706     for (j = 0; j < 8; j++)
2707       level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]] =
2708         map_element_EM_to_RND(lev->ball_array[i][j]);
2709
2710 #if 0
2711   printf("::: bar\n");
2712   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
2713     for (j = 0; j < 8; j++)
2714       printf("::: ball %d, %d: %d\n", i, j,
2715              level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
2716 #endif
2717
2718   map_android_clone_elements_EM_to_RND(level);
2719
2720 #if 0
2721   for (i = 0; i < 16; i++)
2722     level->android_array[i] = FALSE;    /* !!! YET TO COME !!! */
2723 #endif
2724
2725   /* convert the playfield (some elements need special treatment) */
2726   for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
2727   {
2728     int new_element = map_element_EM_to_RND(level_em->cave[x + 1][y + 1]);
2729
2730     if (new_element == EL_AMOEBA_WET && level->amoeba_speed == 0)
2731       new_element = EL_AMOEBA_DEAD;
2732
2733     level->field[x][y] = new_element;
2734   }
2735
2736 #if 0
2737   printf("::: bar 0\n");
2738   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
2739     for (j = 0; j < 8; j++)
2740       printf("::: ball %d, %d: %d\n", i, j,
2741              level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
2742 #endif
2743
2744 #if 1
2745
2746   for (i = 0; i < MAX_PLAYERS; i++)
2747   {
2748     /* in case of all players set to the same field, use the first player */
2749     int nr = MAX_PLAYERS - i - 1;
2750     int jx = ply[nr]->x_initial - 1;
2751     int jy = ply[nr]->y_initial - 1;
2752
2753 #if 0
2754     printf("::: player %d: %d, %d\n", nr, jx, jy);
2755 #endif
2756
2757     if (jx != -1 && jy != -1)
2758       level->field[jx][jy] = EL_PLAYER_1 + nr;
2759   }
2760
2761 #else
2762
2763   /* in case of both players set to the same field, use the first player */
2764   level->field[ply2->x_initial - 1][ply2->y_initial - 1] = EL_PLAYER_2;
2765   level->field[ply1->x_initial - 1][ply1->y_initial - 1] = EL_PLAYER_1;
2766
2767 #endif
2768
2769 #if 0
2770   printf("::: native Emerald Mine file version: %d\n", level_em->file_version);
2771 #endif
2772
2773 #if 0
2774   printf("::: bar 2\n");
2775   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
2776     for (j = 0; j < 8; j++)
2777       printf("::: ball %d, %d: %d\n", i, j,
2778              level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
2779 #endif
2780 }
2781
2782 static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,
2783                                      struct LevelFileInfo *level_file_info)
2784 {
2785   if (!LoadNativeLevel_EM(level_file_info->filename))
2786     level->no_valid_file = TRUE;
2787 }
2788
2789 void CopyNativeLevel_RND_to_Native(struct LevelInfo *level)
2790 {
2791   if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
2792     CopyNativeLevel_RND_to_EM(level);
2793 }
2794
2795 void CopyNativeLevel_Native_to_RND(struct LevelInfo *level)
2796 {
2797
2798 #if 0
2799   {
2800     static int ball_xy[8][2] =
2801       {
2802         { 0, 0 },
2803         { 1, 0 },
2804         { 2, 0 },
2805         { 0, 1 },
2806         { 2, 1 },
2807         { 0, 2 },
2808         { 1, 2 },
2809         { 2, 2 },
2810       };
2811     int i, j;
2812
2813     printf("::: A6\n");
2814     for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
2815       for (j = 0; j < 8; j++)
2816         printf("::: ball %d, %d: %d\n", i, j,
2817                level->ball_content[i].e[ball_xy[j][0]][ball_xy[j][1]]);
2818   }
2819 #endif
2820
2821   if (level->game_engine_type == GAME_ENGINE_TYPE_EM)
2822     CopyNativeLevel_EM_to_RND(level);
2823 }
2824
2825
2826 /* ------------------------------------------------------------------------- */
2827 /* functions for loading SP level                                            */
2828 /* ------------------------------------------------------------------------- */
2829
2830 #define NUM_SUPAPLEX_LEVELS_PER_PACKAGE 111
2831 #define SP_LEVEL_SIZE                   1536
2832 #define SP_LEVEL_XSIZE                  60
2833 #define SP_LEVEL_YSIZE                  24
2834 #define SP_LEVEL_NAME_LEN               23
2835
2836 static void LoadLevelFromFileStream_SP(FILE *file, struct LevelInfo *level,
2837                                        int nr)
2838 {
2839   int num_special_ports;
2840   int i, x, y;
2841
2842   /* for details of the Supaplex level format, see Herman Perk's Supaplex
2843      documentation file "SPFIX63.DOC" from his Supaplex "SpeedFix" package */
2844
2845   /* read level body (width * height == 60 * 24 tiles == 1440 bytes) */
2846   for (y = 0; y < SP_LEVEL_YSIZE; y++)
2847   {
2848     for (x = 0; x < SP_LEVEL_XSIZE; x++)
2849     {
2850       int element_old = fgetc(file);
2851       int element_new;
2852
2853       if (element_old <= 0x27)
2854         element_new = getMappedElement(EL_SP_START + element_old);
2855       else if (element_old == 0x28)
2856         element_new = EL_INVISIBLE_WALL;
2857       else
2858       {
2859         Error(ERR_WARN, "in level %d, at position %d, %d:", nr, x, y);
2860         Error(ERR_WARN, "invalid level element %d", element_old);
2861
2862         element_new = EL_UNKNOWN;
2863       }
2864
2865       level->field[x][y] = element_new;
2866     }
2867   }
2868
2869   ReadUnusedBytesFromFile(file, 4);     /* (not used by Supaplex engine) */
2870
2871   /* initial gravity: 1 == "on", anything else (0) == "off" */
2872   level->initial_gravity = (fgetc(file) == 1 ? TRUE : FALSE);
2873
2874   ReadUnusedBytesFromFile(file, 1);     /* (not used by Supaplex engine) */
2875
2876   /* level title in uppercase letters, padded with dashes ("-") (23 bytes) */
2877   for (i = 0; i < SP_LEVEL_NAME_LEN; i++)
2878     level->name[i] = fgetc(file);
2879   level->name[SP_LEVEL_NAME_LEN] = '\0';
2880
2881   /* initial "freeze zonks": 2 == "on", anything else (0, 1) == "off" */
2882   ReadUnusedBytesFromFile(file, 1);     /* (not used by R'n'D engine) */
2883
2884   /* number of infotrons needed; 0 means that Supaplex will count the total
2885      amount of infotrons in the level and use the low byte of that number
2886      (a multiple of 256 infotrons will result in "0 infotrons needed"!) */
2887   level->gems_needed = fgetc(file);
2888
2889   /* number of special ("gravity") port entries below (maximum 10 allowed) */
2890   num_special_ports = fgetc(file);
2891
2892   /* database of properties of up to 10 special ports (6 bytes per port) */
2893   for (i = 0; i < 10; i++)
2894   {
2895     int port_location, port_x, port_y, port_element;
2896     int gravity;
2897
2898     /* high and low byte of the location of a special port; if (x, y) are the
2899        coordinates of a port in the field and (0, 0) is the top-left corner,
2900        the 16 bit value here calculates as 2 * (x + (y * 60)) (this is twice
2901        of what may be expected: Supaplex works with a game field in memory
2902        which is 2 bytes per tile) */
2903     port_location = getFile16BitBE(file);
2904
2905     /* change gravity: 1 == "turn on", anything else (0) == "turn off" */
2906     gravity = fgetc(file);
2907
2908     /* "freeze zonks": 2 == "turn on", anything else (0, 1) == "turn off" */
2909     ReadUnusedBytesFromFile(file, 1);   /* (not used by R'n'D engine) */
2910
2911     /* "freeze enemies": 1 == "turn on", anything else (0) == "turn off" */
2912     ReadUnusedBytesFromFile(file, 1);   /* (not used by R'n'D engine) */
2913
2914     ReadUnusedBytesFromFile(file, 1);   /* (not used by Supaplex engine) */
2915
2916     if (i >= num_special_ports)
2917       continue;
2918
2919     port_x = (port_location / 2) % SP_LEVEL_XSIZE;
2920     port_y = (port_location / 2) / SP_LEVEL_XSIZE;
2921
2922     if (port_x < 0 || port_x >= SP_LEVEL_XSIZE ||
2923         port_y < 0 || port_y >= SP_LEVEL_YSIZE)
2924     {
2925       Error(ERR_WARN, "special port position (%d, %d) out of bounds",
2926             port_x, port_y);
2927
2928       continue;
2929     }
2930
2931     port_element = level->field[port_x][port_y];
2932
2933     if (port_element < EL_SP_GRAVITY_PORT_RIGHT ||
2934         port_element > EL_SP_GRAVITY_PORT_UP)
2935     {
2936       Error(ERR_WARN, "no special port at position (%d, %d)", port_x, port_y);
2937
2938       continue;
2939     }
2940
2941     /* change previous (wrong) gravity inverting special port to either
2942        gravity enabling special port or gravity disabling special port */
2943     level->field[port_x][port_y] +=
2944       (gravity == 1 ? EL_SP_GRAVITY_ON_PORT_RIGHT :
2945        EL_SP_GRAVITY_OFF_PORT_RIGHT) - EL_SP_GRAVITY_PORT_RIGHT;
2946   }
2947
2948   ReadUnusedBytesFromFile(file, 4);     /* (not used by Supaplex engine) */
2949
2950   /* change special gravity ports without database entries to normal ports */
2951   for (y = 0; y < SP_LEVEL_YSIZE; y++)
2952     for (x = 0; x < SP_LEVEL_XSIZE; x++)
2953       if (level->field[x][y] >= EL_SP_GRAVITY_PORT_RIGHT &&
2954           level->field[x][y] <= EL_SP_GRAVITY_PORT_UP)
2955         level->field[x][y] += EL_SP_PORT_RIGHT - EL_SP_GRAVITY_PORT_RIGHT;
2956
2957   /* auto-determine number of infotrons if it was stored as "0" -- see above */
2958   if (level->gems_needed == 0)
2959   {
2960     for (y = 0; y < SP_LEVEL_YSIZE; y++)
2961       for (x = 0; x < SP_LEVEL_XSIZE; x++)
2962         if (level->field[x][y] == EL_SP_INFOTRON)
2963           level->gems_needed++;
2964
2965     level->gems_needed &= 0xff;         /* only use low byte -- see above */
2966   }
2967
2968   level->fieldx = SP_LEVEL_XSIZE;
2969   level->fieldy = SP_LEVEL_YSIZE;
2970
2971   level->time = 0;                      /* no time limit */
2972   level->amoeba_speed = 0;
2973   level->time_magic_wall = 0;
2974   level->time_wheel = 0;
2975   level->amoeba_content = EL_EMPTY;
2976
2977   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
2978     level->score[i] = 0;                /* !!! CORRECT THIS !!! */
2979
2980   /* there are no yamyams in supaplex levels */
2981   for (i = 0; i < level->num_yamyam_contents; i++)
2982     for (y = 0; y < 3; y++)
2983       for (x = 0; x < 3; x++)
2984         level->yamyam_content[i].e[x][y] = EL_EMPTY;
2985 }
2986
2987 static void LoadLevelFromFileInfo_SP(struct LevelInfo *level,
2988                                      struct LevelFileInfo *level_file_info)
2989 {
2990   char *filename = level_file_info->filename;
2991   FILE *file;
2992   int nr = level_file_info->nr - leveldir_current->first_level;
2993   int i, l, x, y;
2994   char name_first, name_last;
2995   struct LevelInfo multipart_level;
2996   int multipart_xpos, multipart_ypos;
2997   boolean is_multipart_level;
2998   boolean is_first_part;
2999   boolean reading_multipart_level = FALSE;
3000   boolean use_empty_level = FALSE;
3001
3002   if (!(file = fopen(filename, MODE_READ)))
3003   {
3004     level->no_valid_file = TRUE;
3005
3006     Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
3007
3008     return;
3009   }
3010
3011   /* position file stream to the requested level inside the level package */
3012   if (fseek(file, nr * SP_LEVEL_SIZE, SEEK_SET) != 0)
3013   {
3014     level->no_valid_file = TRUE;
3015
3016     Error(ERR_WARN, "cannot fseek level '%s' -- using empty level", filename);
3017
3018     return;
3019   }
3020
3021   /* there exist Supaplex level package files with multi-part levels which
3022      can be detected as follows: instead of leading and trailing dashes ('-')
3023      to pad the level name, they have leading and trailing numbers which are
3024      the x and y coordinations of the current part of the multi-part level;
3025      if there are '?' characters instead of numbers on the left or right side
3026      of the level name, the multi-part level consists of only horizontal or
3027      vertical parts */
3028
3029   for (l = nr; l < NUM_SUPAPLEX_LEVELS_PER_PACKAGE; l++)
3030   {
3031     LoadLevelFromFileStream_SP(file, level, l);
3032
3033     /* check if this level is a part of a bigger multi-part level */
3034
3035     name_first = level->name[0];
3036     name_last  = level->name[SP_LEVEL_NAME_LEN - 1];
3037
3038     is_multipart_level =
3039       ((name_first == '?' || (name_first >= '0' && name_first <= '9')) &&
3040        (name_last  == '?' || (name_last  >= '0' && name_last  <= '9')));
3041
3042     is_first_part =
3043       ((name_first == '?' || name_first == '1') &&
3044        (name_last  == '?' || name_last  == '1'));
3045
3046     /* correct leading multipart level meta information in level name */
3047     for (i = 0; i < SP_LEVEL_NAME_LEN && level->name[i] == name_first; i++)
3048       level->name[i] = '-';
3049
3050     /* correct trailing multipart level meta information in level name */
3051     for (i = SP_LEVEL_NAME_LEN - 1; i>=0 && level->name[i] == name_last; i--)
3052       level->name[i] = '-';
3053
3054     /* ---------- check for normal single level ---------- */
3055
3056     if (!reading_multipart_level && !is_multipart_level)
3057     {
3058       /* the current level is simply a normal single-part level, and we are
3059          not reading a multi-part level yet, so return the level as it is */
3060
3061       break;
3062     }
3063
3064     /* ---------- check for empty level (unused multi-part) ---------- */
3065
3066     if (!reading_multipart_level && is_multipart_level && !is_first_part)
3067     {
3068       /* this is a part of a multi-part level, but not the first part
3069          (and we are not already reading parts of a multi-part level);
3070          in this case, use an empty level instead of the single part */
3071
3072       use_empty_level = TRUE;
3073
3074       break;
3075     }
3076
3077     /* ---------- check for finished multi-part level ---------- */
3078
3079     if (reading_multipart_level &&
3080         (!is_multipart_level ||
3081          strcmp(level->name, multipart_level.name) != 0))
3082     {
3083       /* we are already reading parts of a multi-part level, but this level is
3084          either not a multi-part level, or a part of a different multi-part
3085          level; in both cases, the multi-part level seems to be complete */
3086
3087       break;
3088     }
3089
3090     /* ---------- here we have one part of a multi-part level ---------- */
3091
3092     reading_multipart_level = TRUE;
3093
3094     if (is_first_part)  /* start with first part of new multi-part level */
3095     {
3096       /* copy level info structure from first part */
3097       multipart_level = *level;
3098
3099       /* clear playfield of new multi-part level */
3100       for (y = 0; y < MAX_LEV_FIELDY; y++)
3101         for (x = 0; x < MAX_LEV_FIELDX; x++)
3102           multipart_level.field[x][y] = EL_EMPTY;
3103     }
3104
3105     if (name_first == '?')
3106       name_first = '1';
3107     if (name_last == '?')
3108       name_last = '1';
3109
3110     multipart_xpos = (int)(name_first - '0');
3111     multipart_ypos = (int)(name_last  - '0');
3112
3113 #if 0
3114     printf("----------> part (%d/%d) of multi-part level '%s'\n",
3115            multipart_xpos, multipart_ypos, multipart_level.name);
3116 #endif
3117
3118     if (multipart_xpos * SP_LEVEL_XSIZE > MAX_LEV_FIELDX ||
3119         multipart_ypos * SP_LEVEL_YSIZE > MAX_LEV_FIELDY)
3120     {
3121       Error(ERR_WARN, "multi-part level is too big -- ignoring part of it");
3122
3123       break;
3124     }
3125
3126     multipart_level.fieldx = MAX(multipart_level.fieldx,
3127                                  multipart_xpos * SP_LEVEL_XSIZE);
3128     multipart_level.fieldy = MAX(multipart_level.fieldy,
3129                                  multipart_ypos * SP_LEVEL_YSIZE);
3130
3131     /* copy level part at the right position of multi-part level */
3132     for (y = 0; y < SP_LEVEL_YSIZE; y++)
3133     {
3134       for (x = 0; x < SP_LEVEL_XSIZE; x++)
3135       {
3136         int start_x = (multipart_xpos - 1) * SP_LEVEL_XSIZE;
3137         int start_y = (multipart_ypos - 1) * SP_LEVEL_YSIZE;
3138
3139         multipart_level.field[start_x + x][start_y + y] = level->field[x][y];
3140       }
3141     }
3142   }
3143
3144   fclose(file);
3145
3146   if (use_empty_level)
3147   {
3148     setLevelInfoToDefaults(level);
3149
3150     level->fieldx = SP_LEVEL_XSIZE;
3151     level->fieldy = SP_LEVEL_YSIZE;
3152
3153     for (y = 0; y < SP_LEVEL_YSIZE; y++)
3154       for (x = 0; x < SP_LEVEL_XSIZE; x++)
3155         level->field[x][y] = EL_EMPTY;
3156
3157     strcpy(level->name, "-------- EMPTY --------");
3158
3159     Error(ERR_WARN, "single part of multi-part level -- using empty level");
3160   }
3161
3162   if (reading_multipart_level)
3163     *level = multipart_level;
3164 }
3165
3166 /* ------------------------------------------------------------------------- */
3167 /* functions for loading generic level                                       */
3168 /* ------------------------------------------------------------------------- */
3169
3170 void LoadLevelFromFileInfo(struct LevelInfo *level,
3171                            struct LevelFileInfo *level_file_info)
3172 {
3173   /* always start with reliable default values */
3174   setLevelInfoToDefaults(level);
3175
3176   switch (level_file_info->type)
3177   {
3178     case LEVEL_FILE_TYPE_RND:
3179       LoadLevelFromFileInfo_RND(level, level_file_info);
3180       break;
3181
3182     case LEVEL_FILE_TYPE_EM:
3183       LoadLevelFromFileInfo_EM(level, level_file_info);
3184       level->game_engine_type = GAME_ENGINE_TYPE_EM;
3185       break;
3186
3187     case LEVEL_FILE_TYPE_SP:
3188       LoadLevelFromFileInfo_SP(level, level_file_info);
3189       break;
3190
3191     default:
3192       LoadLevelFromFileInfo_RND(level, level_file_info);
3193       break;
3194   }
3195
3196   /* if level file is invalid, restore level structure to default values */
3197   if (level->no_valid_file)
3198     setLevelInfoToDefaults(level);
3199
3200   if (level->game_engine_type == GAME_ENGINE_TYPE_UNKNOWN)
3201     level->game_engine_type = GAME_ENGINE_TYPE_RND;
3202
3203 #if 1
3204   if (level_file_info->type != LEVEL_FILE_TYPE_RND)
3205     CopyNativeLevel_Native_to_RND(level);
3206 #else
3207   if (level_file_info->type == LEVEL_FILE_TYPE_RND)
3208     CopyNativeLevel_RND_to_Native(level);
3209   else
3210     CopyNativeLevel_Native_to_RND(level);
3211 #endif
3212 }
3213
3214 void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
3215 {
3216   static struct LevelFileInfo level_file_info;
3217
3218   /* always start with reliable default values */
3219   setFileInfoToDefaults(&level_file_info);
3220
3221   level_file_info.nr = 0;                       /* unknown level number */
3222   level_file_info.type = LEVEL_FILE_TYPE_RND;   /* no others supported yet */
3223   level_file_info.filename = filename;
3224
3225   LoadLevelFromFileInfo(level, &level_file_info);
3226 }
3227
3228 static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
3229 {
3230   if (leveldir_current == NULL)         /* only when dumping level */
3231     return;
3232
3233   /* all engine modifications also valid for levels which use latest engine */
3234 #if 1
3235   if (level->game_version < VERSION_IDENT(3,2,0,5))
3236   {
3237     /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */
3238     level->score[SC_TIME_BONUS] /= 10;
3239   }
3240 #endif
3241
3242   if (leveldir_current->latest_engine)
3243   {
3244     /* ---------- use latest game engine ----------------------------------- */
3245
3246     /* For all levels which are forced to use the latest game engine version
3247        (normally all but user contributed, private and undefined levels), set
3248        the game engine version to the actual version; this allows for actual
3249        corrections in the game engine to take effect for existing, converted
3250        levels (from "classic" or other existing games) to make the emulation
3251        of the corresponding game more accurate, while (hopefully) not breaking
3252        existing levels created from other players. */
3253
3254     level->game_version = GAME_VERSION_ACTUAL;
3255
3256     /* Set special EM style gems behaviour: EM style gems slip down from
3257        normal, steel and growing wall. As this is a more fundamental change,
3258        it seems better to set the default behaviour to "off" (as it is more
3259        natural) and make it configurable in the level editor (as a property
3260        of gem style elements). Already existing converted levels (neither
3261        private nor contributed levels) are changed to the new behaviour. */
3262
3263     if (level->file_version < FILE_VERSION_2_0)
3264       level->em_slippery_gems = TRUE;
3265
3266     return;
3267   }
3268
3269   /* ---------- use game engine the level was created with ----------------- */
3270
3271   /* For all levels which are not forced to use the latest game engine
3272      version (normally user contributed, private and undefined levels),
3273      use the version of the game engine the levels were created for.
3274
3275      Since 2.0.1, the game engine version is now directly stored
3276      in the level file (chunk "VERS"), so there is no need anymore
3277      to set the game version from the file version (except for old,
3278      pre-2.0 levels, where the game version is still taken from the
3279      file format version used to store the level -- see above). */
3280
3281   /* player was faster than enemies in 1.0.0 and before */
3282   if (level->file_version == FILE_VERSION_1_0)
3283     level->initial_player_stepsize = STEPSIZE_FAST;
3284
3285   /* default behaviour for EM style gems was "slippery" only in 2.0.1 */
3286   if (level->game_version == VERSION_IDENT(2,0,1,0))
3287     level->em_slippery_gems = TRUE;
3288
3289   /* springs could be pushed over pits before (pre-release version) 2.2.0 */
3290   if (level->game_version < VERSION_IDENT(2,2,0,0))
3291     level->use_spring_bug = TRUE;
3292
3293   if (level->game_version < VERSION_IDENT(3,2,0,5))
3294   {
3295     /* time orb caused limited time in endless time levels before 3.2.0-5 */
3296     level->use_time_orb_bug = TRUE;
3297
3298     /* default behaviour for snapping was "no snap delay" before 3.2.0-5 */
3299     level->block_snap_field = FALSE;
3300
3301     /* extra time score was same value as time left score before 3.2.0-5 */
3302     level->extra_time_score = level->score[SC_TIME_BONUS];
3303
3304 #if 0
3305     /* time bonus score was given for 10 s instead of 1 s before 3.2.0-5 */
3306     level->score[SC_TIME_BONUS] /= 10;
3307 #endif
3308   }
3309
3310   /* only few elements were able to actively move into acid before 3.1.0 */
3311   /* trigger settings did not exist before 3.1.0; set to default "any" */
3312   if (level->game_version < VERSION_IDENT(3,1,0,0))
3313   {
3314     int i, j;
3315
3316     /* correct "can move into acid" settings (all zero in old levels) */
3317
3318     level->can_move_into_acid_bits = 0; /* nothing can move into acid */
3319     level->dont_collide_with_bits = 0; /* nothing is deadly when colliding */
3320
3321     setMoveIntoAcidProperty(level, EL_ROBOT,     TRUE);
3322     setMoveIntoAcidProperty(level, EL_SATELLITE, TRUE);
3323     setMoveIntoAcidProperty(level, EL_PENGUIN,   TRUE);
3324     setMoveIntoAcidProperty(level, EL_BALLOON,   TRUE);
3325
3326     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3327       SET_PROPERTY(EL_CUSTOM_START + i, EP_CAN_MOVE_INTO_ACID, TRUE);
3328
3329     /* correct trigger settings (stored as zero == "none" in old levels) */
3330
3331     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3332     {
3333       int element = EL_CUSTOM_START + i;
3334       struct ElementInfo *ei = &element_info[element];
3335
3336       for (j = 0; j < ei->num_change_pages; j++)
3337       {
3338         struct ElementChangeInfo *change = &ei->change_page[j];
3339
3340         change->trigger_player = CH_PLAYER_ANY;
3341         change->trigger_page = CH_PAGE_ANY;
3342       }
3343     }
3344   }
3345 }
3346
3347 static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
3348 {
3349   int i, j, x, y;
3350
3351   /* map custom element change events that have changed in newer versions
3352      (these following values were accidentally changed in version 3.0.1)
3353      (this seems to be needed only for 'ab_levelset3' and 'ab_levelset4') */
3354   if (level->game_version <= VERSION_IDENT(3,0,0,0))
3355   {
3356     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3357     {
3358       int element = EL_CUSTOM_START + i;
3359
3360       /* order of checking and copying events to be mapped is important */
3361       for (j = CE_BY_OTHER_ACTION; j >= CE_VALUE_GETS_ZERO; j--)
3362       {
3363         if (HAS_CHANGE_EVENT(element, j - 2))
3364         {
3365           SET_CHANGE_EVENT(element, j - 2, FALSE);
3366           SET_CHANGE_EVENT(element, j, TRUE);
3367         }
3368       }
3369
3370       /* order of checking and copying events to be mapped is important */
3371       for (j = CE_PLAYER_COLLECTS_X; j >= CE_HITTING_SOMETHING; j--)
3372       {
3373         if (HAS_CHANGE_EVENT(element, j - 1))
3374         {
3375           SET_CHANGE_EVENT(element, j - 1, FALSE);
3376           SET_CHANGE_EVENT(element, j, TRUE);
3377         }
3378       }
3379     }
3380   }
3381
3382   /* initialize "can_change" field for old levels with only one change page */
3383   if (level->game_version <= VERSION_IDENT(3,0,2,0))
3384   {
3385     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3386     {
3387       int element = EL_CUSTOM_START + i;
3388
3389       if (CAN_CHANGE(element))
3390         element_info[element].change->can_change = TRUE;
3391     }
3392   }
3393
3394   /* correct custom element values (for old levels without these options) */
3395   if (level->game_version < VERSION_IDENT(3,1,1,0))
3396   {
3397     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3398     {
3399       int element = EL_CUSTOM_START + i;
3400       struct ElementInfo *ei = &element_info[element];
3401
3402       if (ei->access_direction == MV_NO_DIRECTION)
3403         ei->access_direction = MV_ALL_DIRECTIONS;
3404
3405 #if 0
3406       for (j = 0; j < ei->num_change_pages; j++)
3407       {
3408         struct ElementChangeInfo *change = &ei->change_page[j];
3409
3410         if (change->trigger_side == CH_SIDE_NONE)
3411           change->trigger_side = CH_SIDE_ANY;
3412       }
3413 #endif
3414     }
3415   }
3416
3417 #if 1
3418   /* correct custom element values (fix invalid values for all versions) */
3419   if (1)
3420   {
3421     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3422     {
3423       int element = EL_CUSTOM_START + i;
3424       struct ElementInfo *ei = &element_info[element];
3425
3426       for (j = 0; j < ei->num_change_pages; j++)
3427       {
3428         struct ElementChangeInfo *change = &ei->change_page[j];
3429
3430         if (change->trigger_player == CH_PLAYER_NONE)
3431           change->trigger_player = CH_PLAYER_ANY;
3432
3433         if (change->trigger_side == CH_SIDE_NONE)
3434           change->trigger_side = CH_SIDE_ANY;
3435       }
3436     }
3437   }
3438 #endif
3439
3440   /* initialize "can_explode" field for old levels which did not store this */
3441   /* !!! CHECK THIS -- "<= 3,1,0,0" IS PROBABLY WRONG !!! */
3442   if (level->game_version <= VERSION_IDENT(3,1,0,0))
3443   {
3444     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3445     {
3446       int element = EL_CUSTOM_START + i;
3447
3448       if (EXPLODES_1X1_OLD(element))
3449         element_info[element].explosion_type = EXPLODES_1X1;
3450
3451       SET_PROPERTY(element, EP_CAN_EXPLODE, (EXPLODES_BY_FIRE(element) ||
3452                                              EXPLODES_SMASHED(element) ||
3453                                              EXPLODES_IMPACT(element)));
3454     }
3455   }
3456
3457   /* correct previously hard-coded move delay values for maze runner style */
3458   if (level->game_version < VERSION_IDENT(3,1,1,0))
3459   {
3460     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3461     {
3462       int element = EL_CUSTOM_START + i;
3463
3464       if (element_info[element].move_pattern & MV_MAZE_RUNNER_STYLE)
3465       {
3466         /* previously hard-coded and therefore ignored */
3467         element_info[element].move_delay_fixed = 9;
3468         element_info[element].move_delay_random = 0;
3469       }
3470     }
3471   }
3472
3473   /* map elements that have changed in newer versions */
3474   level->amoeba_content = getMappedElementByVersion(level->amoeba_content,
3475                                                     level->game_version);
3476   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3477     for (x = 0; x < 3; x++)
3478       for (y = 0; y < 3; y++)
3479         level->yamyam_content[i].e[x][y] =
3480           getMappedElementByVersion(level->yamyam_content[i].e[x][y],
3481                                     level->game_version);
3482
3483   /* initialize element properties for level editor etc. */
3484   InitElementPropertiesEngine(level->game_version);
3485 }
3486
3487 static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
3488 {
3489   int x, y;
3490
3491   /* map elements that have changed in newer versions */
3492   for (y = 0; y < level->fieldy; y++)
3493     for (x = 0; x < level->fieldx; x++)
3494       level->field[x][y] = getMappedElementByVersion(level->field[x][y],
3495                                                      level->game_version);
3496
3497   /* copy elements to runtime playfield array */
3498   for (x = 0; x < MAX_LEV_FIELDX; x++)
3499     for (y = 0; y < MAX_LEV_FIELDY; y++)
3500       Feld[x][y] = level->field[x][y];
3501
3502   /* initialize level size variables for faster access */
3503   lev_fieldx = level->fieldx;
3504   lev_fieldy = level->fieldy;
3505
3506   /* determine border element for this level */
3507   SetBorderElement();
3508 }
3509
3510 static void LoadLevel_InitNativeEngines(struct LevelInfo *level,char *filename)
3511 {
3512   struct LevelFileInfo *level_file_info = &level->file_info;
3513
3514 #if 1
3515   if (level_file_info->type == LEVEL_FILE_TYPE_RND)
3516     CopyNativeLevel_RND_to_Native(level);
3517 #else
3518   if (level_file_info->type == LEVEL_FILE_TYPE_RND)
3519     CopyNativeLevel_RND_to_Native(level);
3520   else
3521     CopyNativeLevel_Native_to_RND(level);
3522 #endif
3523 }
3524
3525 void LoadLevelTemplate(int nr)
3526 {
3527   char *filename;
3528
3529   setLevelFileInfo(&level_template.file_info, nr);
3530   filename = level_template.file_info.filename;
3531
3532   LoadLevelFromFileInfo(&level_template, &level_template.file_info);
3533
3534   LoadLevel_InitVersion(&level_template, filename);
3535   LoadLevel_InitElements(&level_template, filename);
3536
3537   ActivateLevelTemplate();
3538 }
3539
3540 void LoadLevel(int nr)
3541 {
3542   char *filename;
3543
3544   setLevelFileInfo(&level.file_info, nr);
3545   filename = level.file_info.filename;
3546
3547   LoadLevelFromFileInfo(&level, &level.file_info);
3548
3549   if (level.use_custom_template)
3550     LoadLevelTemplate(-1);
3551
3552   LoadLevel_InitVersion(&level, filename);
3553   LoadLevel_InitElements(&level, filename);
3554   LoadLevel_InitPlayfield(&level, filename);
3555
3556   LoadLevel_InitNativeEngines(&level, filename);
3557 }
3558
3559 static void SaveLevel_VERS(FILE *file, struct LevelInfo *level)
3560 {
3561   putFileVersion(file, level->file_version);
3562   putFileVersion(file, level->game_version);
3563 }
3564
3565 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
3566 {
3567   int i, x, y;
3568
3569   putFile8Bit(file, level->fieldx);
3570   putFile8Bit(file, level->fieldy);
3571
3572   putFile16BitBE(file, level->time);
3573   putFile16BitBE(file, level->gems_needed);
3574
3575   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
3576     putFile8Bit(file, level->name[i]);
3577
3578   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
3579     putFile8Bit(file, level->score[i]);
3580
3581   for (i = 0; i < STD_ELEMENT_CONTENTS; i++)
3582     for (y = 0; y < 3; y++)
3583       for (x = 0; x < 3; x++)
3584         putFile8Bit(file, (level->encoding_16bit_yamyam ? EL_EMPTY :
3585                            level->yamyam_content[i].e[x][y]));
3586   putFile8Bit(file, level->amoeba_speed);
3587   putFile8Bit(file, level->time_magic_wall);
3588   putFile8Bit(file, level->time_wheel);
3589   putFile8Bit(file, (level->encoding_16bit_amoeba ? EL_EMPTY :
3590                      level->amoeba_content));
3591   putFile8Bit(file, (level->initial_player_stepsize == STEPSIZE_FAST ? 1 : 0));
3592   putFile8Bit(file, (level->initial_gravity ? 1 : 0));
3593   putFile8Bit(file, (level->encoding_16bit_field ? 1 : 0));
3594   putFile8Bit(file, (level->em_slippery_gems ? 1 : 0));
3595
3596   putFile8Bit(file, (level->use_custom_template ? 1 : 0));
3597
3598   putFile8Bit(file, (level->block_last_field ? 1 : 0));
3599   putFile8Bit(file, (level->sp_block_last_field ? 1 : 0));
3600   putFile32BitBE(file, level->can_move_into_acid_bits);
3601   putFile8Bit(file, level->dont_collide_with_bits);
3602
3603   putFile8Bit(file, (level->use_spring_bug ? 1 : 0));
3604   putFile8Bit(file, (level->use_step_counter ? 1 : 0));
3605
3606   putFile8Bit(file, (level->instant_relocation ? 1 : 0));
3607   putFile8Bit(file, (level->can_pass_to_walkable ? 1 : 0));
3608   putFile8Bit(file, (level->grow_into_diggable ? 1 : 0));
3609
3610   putFile8Bit(file, level->game_engine_type);
3611
3612   WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
3613 }
3614
3615 static void SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
3616 {
3617   int i;
3618
3619   for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
3620     putFile8Bit(file, level->author[i]);
3621 }
3622
3623 static void SaveLevel_BODY(FILE *file, struct LevelInfo *level)
3624 {
3625   int x, y;
3626
3627   for (y = 0; y < level->fieldy; y++) 
3628     for (x = 0; x < level->fieldx; x++) 
3629       if (level->encoding_16bit_field)
3630         putFile16BitBE(file, level->field[x][y]);
3631       else
3632         putFile8Bit(file, level->field[x][y]);
3633 }
3634
3635 #if 0
3636 static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
3637 {
3638   int i, x, y;
3639
3640   putFile8Bit(file, EL_YAMYAM);
3641   putFile8Bit(file, level->num_yamyam_contents);
3642   putFile8Bit(file, 0);
3643   putFile8Bit(file, 0);
3644
3645   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3646     for (y = 0; y < 3; y++)
3647       for (x = 0; x < 3; x++)
3648         if (level->encoding_16bit_field)
3649           putFile16BitBE(file, level->yamyam_content[i].e[x][y]);
3650         else
3651           putFile8Bit(file, level->yamyam_content[i].e[x][y]);
3652 }
3653 #endif
3654
3655 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
3656 {
3657   int i, x, y;
3658   int num_contents, content_xsize, content_ysize;
3659   int content_array[MAX_ELEMENT_CONTENTS][3][3];
3660
3661   if (element == EL_YAMYAM)
3662   {
3663     num_contents = level->num_yamyam_contents;
3664     content_xsize = 3;
3665     content_ysize = 3;
3666
3667     for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3668       for (y = 0; y < 3; y++)
3669         for (x = 0; x < 3; x++)
3670           content_array[i][x][y] = level->yamyam_content[i].e[x][y];
3671   }
3672   else if (element == EL_BD_AMOEBA)
3673   {
3674     num_contents = 1;
3675     content_xsize = 1;
3676     content_ysize = 1;
3677
3678     for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3679       for (y = 0; y < 3; y++)
3680         for (x = 0; x < 3; x++)
3681           content_array[i][x][y] = EL_EMPTY;
3682     content_array[0][0][0] = level->amoeba_content;
3683   }
3684   else
3685   {
3686     /* chunk header already written -- write empty chunk data */
3687     WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_SIZE);
3688
3689     Error(ERR_WARN, "cannot save content for element '%d'", element);
3690     return;
3691   }
3692
3693   putFile16BitBE(file, element);
3694   putFile8Bit(file, num_contents);
3695   putFile8Bit(file, content_xsize);
3696   putFile8Bit(file, content_ysize);
3697
3698   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED);
3699
3700   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
3701     for (y = 0; y < 3; y++)
3702       for (x = 0; x < 3; x++)
3703         putFile16BitBE(file, content_array[i][x][y]);
3704 }
3705
3706 static void SaveLevel_CNT3(FILE *file, struct LevelInfo *level, int element)
3707 {
3708   int i;
3709   int envelope_nr = element - EL_ENVELOPE_1;
3710   int envelope_len = strlen(level->envelope_text[envelope_nr]) + 1;
3711
3712   putFile16BitBE(file, element);
3713   putFile16BitBE(file, envelope_len);
3714   putFile8Bit(file, level->envelope_xsize[envelope_nr]);
3715   putFile8Bit(file, level->envelope_ysize[envelope_nr]);
3716
3717   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT3_UNUSED);
3718
3719   for (i = 0; i < envelope_len; i++)
3720     putFile8Bit(file, level->envelope_text[envelope_nr][i]);
3721 }
3722
3723 #if 0
3724 static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level,
3725                            int num_changed_custom_elements)
3726 {
3727   int i, check = 0;
3728
3729   putFile16BitBE(file, num_changed_custom_elements);
3730
3731   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3732   {
3733     int element = EL_CUSTOM_START + i;
3734
3735 #if 1
3736     struct ElementInfo *ei = &element_info[element];
3737
3738     if (ei->properties[EP_BITFIELD_BASE] != EP_BITMASK_DEFAULT)
3739     {
3740       if (check < num_changed_custom_elements)
3741       {
3742         putFile16BitBE(file, element);
3743         putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE]);
3744       }
3745
3746       check++;
3747     }
3748 #else
3749     if (Properties[element][EP_BITFIELD_BASE] != EP_BITMASK_DEFAULT)
3750     {
3751       if (check < num_changed_custom_elements)
3752       {
3753         putFile16BitBE(file, element);
3754         putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
3755       }
3756
3757       check++;
3758     }
3759 #endif
3760   }
3761
3762   if (check != num_changed_custom_elements)     /* should not happen */
3763     Error(ERR_WARN, "inconsistent number of custom element properties");
3764 }
3765 #endif
3766
3767 #if 0
3768 static void SaveLevel_CUS2(FILE *file, struct LevelInfo *level,
3769                            int num_changed_custom_elements)
3770 {
3771   int i, check = 0;
3772
3773   putFile16BitBE(file, num_changed_custom_elements);
3774
3775   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3776   {
3777     int element = EL_CUSTOM_START + i;
3778
3779     if (element_info[element].change->target_element != EL_EMPTY_SPACE)
3780     {
3781       if (check < num_changed_custom_elements)
3782       {
3783         putFile16BitBE(file, element);
3784         putFile16BitBE(file, element_info[element].change->target_element);
3785       }
3786
3787       check++;
3788     }
3789   }
3790
3791   if (check != num_changed_custom_elements)     /* should not happen */
3792     Error(ERR_WARN, "inconsistent number of custom target elements");
3793 }
3794 #endif
3795
3796 #if 0
3797 static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
3798                            int num_changed_custom_elements)
3799 {
3800   int i, j, x, y, check = 0;
3801
3802   putFile16BitBE(file, num_changed_custom_elements);
3803
3804   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
3805   {
3806     int element = EL_CUSTOM_START + i;
3807     struct ElementInfo *ei = &element_info[element];
3808
3809     if (ei->modified_settings)
3810     {
3811       if (check < num_changed_custom_elements)
3812       {
3813         putFile16BitBE(file, element);
3814
3815         for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++)
3816           putFile8Bit(file, ei->description[j]);
3817
3818 #if 1
3819         putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE]);
3820 #else
3821         putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
3822 #endif
3823
3824         /* some free bytes for future properties and padding */
3825         WriteUnusedBytesToFile(file, 7);
3826
3827         putFile8Bit(file, ei->use_gfx_element);
3828         putFile16BitBE(file, ei->gfx_element);
3829
3830         putFile8Bit(file, ei->collect_score_initial);
3831         putFile8Bit(file, ei->collect_count_initial);
3832
3833         putFile16BitBE(file, ei->push_delay_fixed);
3834         putFile16BitBE(file, ei->push_delay_random);
3835         putFile16BitBE(file, ei->move_delay_fixed);
3836         putFile16BitBE(file, ei->move_delay_random);
3837
3838         putFile16BitBE(file, ei->move_pattern);
3839         putFile8Bit(file, ei->move_direction_initial);
3840         putFile8Bit(file, ei->move_stepsize);
3841
3842         for (y = 0; y < 3; y++)
3843           for (x = 0; x < 3; x++)
3844             putFile16BitBE(file, ei->content.e[x][y]);
3845
3846         putFile32BitBE(file, ei->change->events);
3847
3848         putFile16BitBE(file, ei->change->target_element);
3849
3850         putFile16BitBE(file, ei->change->delay_fixed);
3851         putFile16BitBE(file, ei->change->delay_random);
3852         putFile16BitBE(file, ei->change->delay_frames);
3853
3854         putFile16BitBE(file, ei->change->trigger_element);
3855
3856         putFile8Bit(file, ei->change->explode);
3857         putFile8Bit(file, ei->change->use_target_content);
3858         putFile8Bit(file, ei->change->only_if_complete);
3859         putFile8Bit(file, ei->change->use_random_replace);
3860
3861         putFile8Bit(file, ei->change->random_percentage);
3862         putFile8Bit(file, ei->change->replace_when);
3863
3864         for (y = 0; y < 3; y++)
3865           for (x = 0; x < 3; x++)
3866             putFile16BitBE(file, ei->change->content.e[x][y]);
3867
3868         putFile8Bit(file, ei->slippery_type);
3869
3870         /* some free bytes for future properties and padding */
3871         WriteUnusedBytesToFile(file, LEVEL_CPART_CUS3_UNUSED);
3872       }
3873
3874       check++;
3875     }
3876   }
3877
3878   if (check != num_changed_custom_elements)     /* should not happen */
3879     Error(ERR_WARN, "inconsistent number of custom element properties");
3880 }
3881 #endif
3882
3883 static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
3884 {
3885   struct ElementInfo *ei = &element_info[element];
3886   int i, j, x, y;
3887
3888   /* ---------- custom element base property values (96 bytes) ------------- */
3889
3890   putFile16BitBE(file, element);
3891
3892   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
3893     putFile8Bit(file, ei->description[i]);
3894
3895 #if 1
3896   putFile32BitBE(file, ei->properties[EP_BITFIELD_BASE]);
3897 #else
3898   putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
3899 #endif
3900   WriteUnusedBytesToFile(file, 4);      /* reserved for more base properties */
3901
3902   putFile8Bit(file, ei->num_change_pages);
3903
3904   putFile16BitBE(file, ei->ce_value_fixed_initial);
3905   putFile16BitBE(file, ei->ce_value_random_initial);
3906   putFile8Bit(file, ei->use_last_ce_value);
3907
3908   putFile8Bit(file, ei->use_gfx_element);
3909   putFile16BitBE(file, ei->gfx_element);
3910
3911   putFile8Bit(file, ei->collect_score_initial);
3912   putFile8Bit(file, ei->collect_count_initial);
3913
3914   putFile8Bit(file, ei->drop_delay_fixed);
3915   putFile8Bit(file, ei->push_delay_fixed);
3916   putFile8Bit(file, ei->drop_delay_random);
3917   putFile8Bit(file, ei->push_delay_random);
3918   putFile16BitBE(file, ei->move_delay_fixed);
3919   putFile16BitBE(file, ei->move_delay_random);
3920
3921   /* bits 0 - 15 of "move_pattern" ... */
3922   putFile16BitBE(file, ei->move_pattern & 0xffff);
3923   putFile8Bit(file, ei->move_direction_initial);
3924   putFile8Bit(file, ei->move_stepsize);
3925
3926   putFile8Bit(file, ei->slippery_type);
3927
3928   for (y = 0; y < 3; y++)
3929     for (x = 0; x < 3; x++)
3930       putFile16BitBE(file, ei->content.e[x][y]);
3931
3932   putFile16BitBE(file, ei->move_enter_element);
3933   putFile16BitBE(file, ei->move_leave_element);
3934   putFile8Bit(file, ei->move_leave_type);
3935
3936   /* ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible) */
3937   putFile16BitBE(file, (ei->move_pattern >> 16) & 0xffff);
3938
3939   putFile8Bit(file, ei->access_direction);
3940
3941   putFile8Bit(file, ei->explosion_delay);
3942   putFile8Bit(file, ei->ignition_delay);
3943   putFile8Bit(file, ei->explosion_type);
3944
3945   /* some free bytes for future custom property values and padding */
3946   WriteUnusedBytesToFile(file, 1);
3947
3948   /* ---------- change page property values (48 bytes) --------------------- */
3949
3950   for (i = 0; i < ei->num_change_pages; i++)
3951   {
3952     struct ElementChangeInfo *change = &ei->change_page[i];
3953     unsigned long event_bits;
3954
3955     /* bits 0 - 31 of "has_event[]" ... */
3956     event_bits = 0;
3957     for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
3958       if (change->has_event[j])
3959         event_bits |= (1 << j);
3960     putFile32BitBE(file, event_bits);
3961
3962     putFile16BitBE(file, change->target_element);
3963
3964     putFile16BitBE(file, change->delay_fixed);
3965     putFile16BitBE(file, change->delay_random);
3966     putFile16BitBE(file, change->delay_frames);
3967
3968     putFile16BitBE(file, change->trigger_element);
3969
3970     putFile8Bit(file, change->explode);
3971     putFile8Bit(file, change->use_target_content);
3972     putFile8Bit(file, change->only_if_complete);
3973     putFile8Bit(file, change->use_random_replace);
3974
3975     putFile8Bit(file, change->random_percentage);
3976     putFile8Bit(file, change->replace_when);
3977
3978     for (y = 0; y < 3; y++)
3979       for (x = 0; x < 3; x++)
3980         putFile16BitBE(file, change->target_content.e[x][y]);
3981
3982     putFile8Bit(file, change->can_change);
3983
3984     putFile8Bit(file, change->trigger_side);
3985
3986     putFile8Bit(file, change->trigger_player);
3987     putFile8Bit(file, (change->trigger_page == CH_PAGE_ANY ? CH_PAGE_ANY_FILE :
3988                        log_2(change->trigger_page)));
3989
3990     putFile8Bit(file, change->has_action);
3991     putFile8Bit(file, change->action_type);
3992     putFile8Bit(file, change->action_mode);
3993     putFile16BitBE(file, change->action_arg);
3994
3995     /* ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible) */
3996     event_bits = 0;
3997     for (j = 32; j < NUM_CHANGE_EVENTS; j++)
3998       if (change->has_event[j])
3999         event_bits |= (1 << (j - 32));
4000     putFile8Bit(file, event_bits);
4001   }
4002 }
4003
4004 static void SaveLevel_GRP1(FILE *file, struct LevelInfo *level, int element)
4005 {
4006   struct ElementInfo *ei = &element_info[element];
4007   struct ElementGroupInfo *group = ei->group;
4008   int i;
4009
4010   putFile16BitBE(file, element);
4011
4012   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
4013     putFile8Bit(file, ei->description[i]);
4014
4015   putFile8Bit(file, group->num_elements);
4016
4017   putFile8Bit(file, ei->use_gfx_element);
4018   putFile16BitBE(file, ei->gfx_element);
4019
4020   putFile8Bit(file, group->choice_mode);
4021
4022   /* some free bytes for future values and padding */
4023   WriteUnusedBytesToFile(file, 3);
4024
4025   for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
4026     putFile16BitBE(file, group->element[i]);
4027 }
4028
4029 static int SaveLevel_CONF_Value(FILE *file, int pos)
4030 {
4031   int default_value = element_conf[pos].default_value;
4032   int element = element_conf[pos].element;
4033   int type = element_conf[pos].type;
4034   int bytes = type & CONF_MASK_BYTES;
4035   void *value_ptr = element_conf[pos].value;
4036   int value = (CONF_VALUE_BOOLEAN(type) ? *(boolean *)value_ptr :
4037                *(int *)value_ptr);
4038   int num_bytes = 0;
4039   boolean modified = FALSE;
4040
4041   /* check if any settings have been modified before saving them */
4042   if (value != default_value)
4043     modified = TRUE;
4044
4045   if (!modified)                /* do not save unmodified default settings */
4046     return 0;
4047
4048   if (bytes == CONF_MASK_MULTI_BYTES)
4049     Error(ERR_EXIT, "SaveLevel_CONF_Value: cannot save multi-byte values");
4050
4051   num_bytes += putFile16BitBE(file, element);
4052   num_bytes += putFile8Bit(file, type);
4053   num_bytes += (bytes == CONF_MASK_1_BYTE ? putFile8Bit   (file, value) :
4054                 bytes == CONF_MASK_2_BYTE ? putFile16BitBE(file, value) :
4055                 bytes == CONF_MASK_4_BYTE ? putFile32BitBE(file, value) : 0);
4056
4057   return num_bytes;
4058 }
4059
4060 static int SaveLevel_CONF_Elements(FILE *file, int pos)
4061 {
4062   int *element_array = (int *)(element_conf[pos].value);
4063   int num_elements = *(int *)element_conf[pos].num_entities;
4064   int default_value = element_conf[pos].default_value;
4065   int element = element_conf[pos].element;
4066   int type = element_conf[pos].type;
4067   int num_bytes = 0;
4068   boolean modified = FALSE;
4069   int i;
4070
4071   /* check if any settings have been modified before saving them */
4072   for (i = 0; i < num_elements; i++)
4073     if (element_array[i] != default_value)
4074       modified = TRUE;
4075
4076   if (!modified)                /* do not save unmodified default settings */
4077     return 0;
4078
4079   num_bytes += putFile16BitBE(file, element);
4080   num_bytes += putFile8Bit(file, type);
4081   num_bytes += putFile16BitBE(file, num_elements * CONF_ELEMENT_NUM_BYTES);
4082
4083   for (i = 0; i < num_elements; i++)
4084     num_bytes += putFile16BitBE(file, element_array[i]);
4085
4086   return num_bytes;
4087 }
4088
4089 static int SaveLevel_CONF_Contents(FILE *file, int pos)
4090 {
4091   struct Content *content = (struct Content *)(element_conf[pos].value);
4092   int num_contents = *(int *)element_conf[pos].num_entities;
4093   int default_value = element_conf[pos].default_value;
4094   int element = element_conf[pos].element;
4095   int type = element_conf[pos].type;
4096   int num_bytes = 0;
4097   boolean modified = FALSE;
4098   int i, x, y;
4099
4100   /* check if any settings have been modified before saving them */
4101   for (i = 0; i < num_contents; i++)
4102     for (y = 0; y < 3; y++)
4103       for (x = 0; x < 3; x++)
4104         if (content[i].e[x][y] != default_value)
4105           modified = TRUE;
4106
4107   if (!modified)                /* do not save unmodified default settings */
4108     return 0;
4109
4110   num_bytes += putFile16BitBE(file, element);
4111   num_bytes += putFile8Bit(file, type);
4112   num_bytes += putFile16BitBE(file, num_contents * CONF_CONTENT_NUM_BYTES);
4113
4114   for (i = 0; i < num_contents; i++)
4115     for (y = 0; y < 3; y++)
4116       for (x = 0; x < 3; x++)
4117         num_bytes += putFile16BitBE(file, content[i].e[x][y]);
4118
4119   return num_bytes;
4120 }
4121
4122 static int SaveLevel_CONF(FILE *file, struct LevelInfo *level)
4123 {
4124   int chunk_size = 0;
4125   int i;
4126
4127   li = *level;          /* copy level information into temporary buffer */
4128
4129   for (i = 0; element_conf[i].element != -1; i++)
4130   {
4131     int type = element_conf[i].type;
4132     int bytes = type & CONF_MASK_BYTES;
4133
4134     if (bytes != CONF_MASK_MULTI_BYTES)
4135       chunk_size += SaveLevel_CONF_Value(file, i);
4136     else if (type == CONF_VALUE_ELEMENTS)
4137       chunk_size += SaveLevel_CONF_Elements(file, i);
4138     else if (type == CONF_VALUE_CONTENTS)
4139       chunk_size += SaveLevel_CONF_Contents(file, i);
4140   }
4141
4142   return chunk_size;
4143 }
4144
4145 static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
4146 {
4147   int body_chunk_size, conf_chunk_size;
4148   int i, x, y;
4149   FILE *file;
4150
4151   if (!(file = fopen(filename, MODE_WRITE)))
4152   {
4153     Error(ERR_WARN, "cannot save level file '%s'", filename);
4154     return;
4155   }
4156
4157   level->file_version = FILE_VERSION_ACTUAL;
4158   level->game_version = GAME_VERSION_ACTUAL;
4159
4160   /* check level field for 16-bit elements */
4161   level->encoding_16bit_field = FALSE;
4162   for (y = 0; y < level->fieldy; y++) 
4163     for (x = 0; x < level->fieldx; x++) 
4164       if (level->field[x][y] > 255)
4165         level->encoding_16bit_field = TRUE;
4166
4167   /* check yamyam content for 16-bit elements */
4168   level->encoding_16bit_yamyam = FALSE;
4169   for (i = 0; i < level->num_yamyam_contents; i++)
4170     for (y = 0; y < 3; y++)
4171       for (x = 0; x < 3; x++)
4172         if (level->yamyam_content[i].e[x][y] > 255)
4173           level->encoding_16bit_yamyam = TRUE;
4174
4175   /* check amoeba content for 16-bit elements */
4176   level->encoding_16bit_amoeba = FALSE;
4177   if (level->amoeba_content > 255)
4178     level->encoding_16bit_amoeba = TRUE;
4179
4180   /* calculate size of "BODY" chunk */
4181   body_chunk_size =
4182     level->fieldx * level->fieldy * (level->encoding_16bit_field ? 2 : 1);
4183
4184   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
4185   putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
4186
4187   putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
4188   SaveLevel_VERS(file, level);
4189
4190   putFileChunkBE(file, "HEAD", LEVEL_HEADER_SIZE);
4191   SaveLevel_HEAD(file, level);
4192
4193   putFileChunkBE(file, "AUTH", MAX_LEVEL_AUTHOR_LEN);
4194   SaveLevel_AUTH(file, level);
4195
4196   putFileChunkBE(file, "BODY", body_chunk_size);
4197   SaveLevel_BODY(file, level);
4198
4199   if (level->encoding_16bit_yamyam ||
4200       level->num_yamyam_contents != STD_ELEMENT_CONTENTS)
4201   {
4202     putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
4203     SaveLevel_CNT2(file, level, EL_YAMYAM);
4204   }
4205
4206   if (level->encoding_16bit_amoeba)
4207   {
4208     putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
4209     SaveLevel_CNT2(file, level, EL_BD_AMOEBA);
4210   }
4211
4212   /* check for envelope content */
4213   for (i = 0; i < 4; i++)
4214   {
4215     if (strlen(level->envelope_text[i]) > 0)
4216     {
4217       int envelope_len = strlen(level->envelope_text[i]) + 1;
4218
4219       putFileChunkBE(file, "CNT3", LEVEL_CHUNK_CNT3_SIZE(envelope_len));
4220       SaveLevel_CNT3(file, level, EL_ENVELOPE_1 + i);
4221     }
4222   }
4223
4224   /* check for non-default custom elements (unless using template level) */
4225   if (!level->use_custom_template)
4226   {
4227     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
4228     {
4229       int element = EL_CUSTOM_START + i;
4230
4231       if (element_info[element].modified_settings)
4232       {
4233         int num_change_pages = element_info[element].num_change_pages;
4234
4235         putFileChunkBE(file, "CUS4", LEVEL_CHUNK_CUS4_SIZE(num_change_pages));
4236         SaveLevel_CUS4(file, level, element);
4237       }
4238     }
4239   }
4240
4241   /* check for non-default group elements (unless using template level) */
4242   if (!level->use_custom_template)
4243   {
4244     for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
4245     {
4246       int element = EL_GROUP_START + i;
4247
4248       if (element_info[element].modified_settings)
4249       {
4250         putFileChunkBE(file, "GRP1", LEVEL_CHUNK_GRP1_SIZE);
4251         SaveLevel_GRP1(file, level, element);
4252       }
4253     }
4254   }
4255
4256   conf_chunk_size = SaveLevel_CONF(NULL, level);        /* get chunk size */
4257
4258   /* check for non-default configuration settings to be saved in CONF chunk */
4259   if (conf_chunk_size > 0)
4260   {
4261     putFileChunkBE(file, "CONF", conf_chunk_size);
4262     SaveLevel_CONF(file, level);
4263   }
4264
4265   fclose(file);
4266
4267   SetFilePermissions(filename, PERMS_PRIVATE);
4268 }
4269
4270 void SaveLevel(int nr)
4271 {
4272   char *filename = getDefaultLevelFilename(nr);
4273
4274   SaveLevelFromFilename(&level, filename);
4275 }
4276
4277 void SaveLevelTemplate()
4278 {
4279   char *filename = getDefaultLevelFilename(-1);
4280
4281   SaveLevelFromFilename(&level, filename);
4282 }
4283
4284 void DumpLevel(struct LevelInfo *level)
4285 {
4286   if (level->no_valid_file)
4287   {
4288     Error(ERR_WARN, "cannot dump -- no valid level file found");
4289
4290     return;
4291   }
4292
4293   printf_line("-", 79);
4294   printf("Level xxx (file version %08d, game version %08d)\n",
4295          level->file_version, level->game_version);
4296   printf_line("-", 79);
4297
4298   printf("Level author: '%s'\n", level->author);
4299   printf("Level title:  '%s'\n", level->name);
4300   printf("\n");
4301   printf("Playfield size: %d x %d\n", level->fieldx, level->fieldy);
4302   printf("\n");
4303   printf("Level time:  %d seconds\n", level->time);
4304   printf("Gems needed: %d\n", level->gems_needed);
4305   printf("\n");
4306   printf("Time for magic wall: %d seconds\n", level->time_magic_wall);
4307   printf("Time for wheel:      %d seconds\n", level->time_wheel);
4308   printf("Time for light:      %d seconds\n", level->time_light);
4309   printf("Time for timegate:   %d seconds\n", level->time_timegate);
4310   printf("\n");
4311   printf("Amoeba speed: %d\n", level->amoeba_speed);
4312   printf("\n");
4313   printf("Initial gravity:             %s\n", (level->initial_gravity ? "yes" : "no"));
4314   printf("Initial player stepsize:     %d\n", level->initial_player_stepsize);
4315   printf("EM style slippery gems:      %s\n", (level->em_slippery_gems ? "yes" : "no"));
4316   printf("Player blocks last field:    %s\n", (level->block_last_field ? "yes" : "no"));
4317   printf("SP player blocks last field: %s\n", (level->sp_block_last_field ? "yes" : "no"));
4318   printf("use spring bug: %s\n", (level->use_spring_bug ? "yes" : "no"));
4319   printf("use step counter: %s\n", (level->use_step_counter ? "yes" : "no"));
4320
4321   printf_line("-", 79);
4322 }
4323
4324
4325 /* ========================================================================= */
4326 /* tape file functions                                                       */
4327 /* ========================================================================= */
4328
4329 static void setTapeInfoToDefaults()
4330 {
4331   int i;
4332
4333   /* always start with reliable default values (empty tape) */
4334   TapeErase();
4335
4336   /* default values (also for pre-1.2 tapes) with only the first player */
4337   tape.player_participates[0] = TRUE;
4338   for (i = 1; i < MAX_PLAYERS; i++)
4339     tape.player_participates[i] = FALSE;
4340
4341   /* at least one (default: the first) player participates in every tape */
4342   tape.num_participating_players = 1;
4343
4344   tape.level_nr = level_nr;
4345   tape.counter = 0;
4346   tape.changed = FALSE;
4347
4348   tape.recording = FALSE;
4349   tape.playing = FALSE;
4350   tape.pausing = FALSE;
4351
4352   tape.no_valid_file = FALSE;
4353 }
4354
4355 static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
4356 {
4357   tape->file_version = getFileVersion(file);
4358   tape->game_version = getFileVersion(file);
4359
4360   return chunk_size;
4361 }
4362
4363 static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
4364 {
4365   int i;
4366
4367   tape->random_seed = getFile32BitBE(file);
4368   tape->date        = getFile32BitBE(file);
4369   tape->length      = getFile32BitBE(file);
4370
4371   /* read header fields that are new since version 1.2 */
4372   if (tape->file_version >= FILE_VERSION_1_2)
4373   {
4374     byte store_participating_players = getFile8Bit(file);
4375     int engine_version;
4376
4377     /* since version 1.2, tapes store which players participate in the tape */
4378     tape->num_participating_players = 0;
4379     for (i = 0; i < MAX_PLAYERS; i++)
4380     {
4381       tape->player_participates[i] = FALSE;
4382
4383       if (store_participating_players & (1 << i))
4384       {
4385         tape->player_participates[i] = TRUE;
4386         tape->num_participating_players++;
4387       }
4388     }
4389
4390     ReadUnusedBytesFromFile(file, TAPE_HEADER_UNUSED);
4391
4392     engine_version = getFileVersion(file);
4393     if (engine_version > 0)
4394       tape->engine_version = engine_version;
4395     else
4396       tape->engine_version = tape->game_version;
4397   }
4398
4399   return chunk_size;
4400 }
4401
4402 static int LoadTape_INFO(FILE *file, int chunk_size, struct TapeInfo *tape)
4403 {
4404   int level_identifier_size;
4405   int i;
4406
4407   level_identifier_size = getFile16BitBE(file);
4408
4409   tape->level_identifier =
4410     checked_realloc(tape->level_identifier, level_identifier_size);
4411
4412   for (i = 0; i < level_identifier_size; i++)
4413     tape->level_identifier[i] = getFile8Bit(file);
4414
4415   tape->level_nr = getFile16BitBE(file);
4416
4417   chunk_size = 2 + level_identifier_size + 2;
4418
4419   return chunk_size;
4420 }
4421
4422 static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
4423 {
4424   int i, j;
4425   int chunk_size_expected =
4426     (tape->num_participating_players + 1) * tape->length;
4427
4428   if (chunk_size_expected != chunk_size)
4429   {
4430     ReadUnusedBytesFromFile(file, chunk_size);
4431     return chunk_size_expected;
4432   }
4433
4434   for (i = 0; i < tape->length; i++)
4435   {
4436     if (i >= MAX_TAPE_LEN)
4437       break;
4438
4439     for (j = 0; j < MAX_PLAYERS; j++)
4440     {
4441       tape->pos[i].action[j] = MV_NONE;
4442
4443       if (tape->player_participates[j])
4444         tape->pos[i].action[j] = getFile8Bit(file);
4445     }
4446
4447     tape->pos[i].delay = getFile8Bit(file);
4448
4449     if (tape->file_version == FILE_VERSION_1_0)
4450     {
4451       /* eliminate possible diagonal moves in old tapes */
4452       /* this is only for backward compatibility */
4453
4454       byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
4455       byte action = tape->pos[i].action[0];
4456       int k, num_moves = 0;
4457
4458       for (k = 0; k<4; k++)
4459       {
4460         if (action & joy_dir[k])
4461         {
4462           tape->pos[i + num_moves].action[0] = joy_dir[k];
4463           if (num_moves > 0)
4464             tape->pos[i + num_moves].delay = 0;
4465           num_moves++;
4466         }
4467       }
4468
4469       if (num_moves > 1)
4470       {
4471         num_moves--;
4472         i += num_moves;
4473         tape->length += num_moves;
4474       }
4475     }
4476     else if (tape->file_version < FILE_VERSION_2_0)
4477     {
4478       /* convert pre-2.0 tapes to new tape format */
4479
4480       if (tape->pos[i].delay > 1)
4481       {
4482         /* action part */
4483         tape->pos[i + 1] = tape->pos[i];
4484         tape->pos[i + 1].delay = 1;
4485
4486         /* delay part */
4487         for (j = 0; j < MAX_PLAYERS; j++)
4488           tape->pos[i].action[j] = MV_NONE;
4489         tape->pos[i].delay--;
4490
4491         i++;
4492         tape->length++;
4493       }
4494     }
4495
4496     if (feof(file))
4497       break;
4498   }
4499
4500   if (i != tape->length)
4501     chunk_size = (tape->num_participating_players + 1) * i;
4502
4503   return chunk_size;
4504 }
4505
4506 void LoadTapeFromFilename(char *filename)
4507 {
4508   char cookie[MAX_LINE_LEN];
4509   char chunk_name[CHUNK_ID_LEN + 1];
4510   FILE *file;
4511   int chunk_size;
4512
4513   /* always start with reliable default values */
4514   setTapeInfoToDefaults();
4515
4516   if (!(file = fopen(filename, MODE_READ)))
4517   {
4518     tape.no_valid_file = TRUE;
4519
4520     return;
4521   }
4522
4523   getFileChunkBE(file, chunk_name, NULL);
4524   if (strcmp(chunk_name, "RND1") == 0)
4525   {
4526     getFile32BitBE(file);               /* not used */
4527
4528     getFileChunkBE(file, chunk_name, NULL);
4529     if (strcmp(chunk_name, "TAPE") != 0)
4530     {
4531       tape.no_valid_file = TRUE;
4532
4533       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
4534       fclose(file);
4535       return;
4536     }
4537   }
4538   else  /* check for pre-2.0 file format with cookie string */
4539   {
4540     strcpy(cookie, chunk_name);
4541     fgets(&cookie[4], MAX_LINE_LEN - 4, file);
4542     if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
4543       cookie[strlen(cookie) - 1] = '\0';
4544
4545     if (!checkCookieString(cookie, TAPE_COOKIE_TMPL))
4546     {
4547       tape.no_valid_file = TRUE;
4548
4549       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
4550       fclose(file);
4551       return;
4552     }
4553
4554     if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1)
4555     {
4556       tape.no_valid_file = TRUE;
4557
4558       Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
4559       fclose(file);
4560       return;
4561     }
4562
4563     /* pre-2.0 tape files have no game version, so use file version here */
4564     tape.game_version = tape.file_version;
4565   }
4566
4567   if (tape.file_version < FILE_VERSION_1_2)
4568   {
4569     /* tape files from versions before 1.2.0 without chunk structure */
4570     LoadTape_HEAD(file, TAPE_HEADER_SIZE, &tape);
4571     LoadTape_BODY(file, 2 * tape.length,  &tape);
4572   }
4573   else
4574   {
4575     static struct
4576     {
4577       char *name;
4578       int size;
4579       int (*loader)(FILE *, int, struct TapeInfo *);
4580     }
4581     chunk_info[] =
4582     {
4583       { "VERS", FILE_VERS_CHUNK_SIZE,   LoadTape_VERS },
4584       { "HEAD", TAPE_HEADER_SIZE,       LoadTape_HEAD },
4585       { "INFO", -1,                     LoadTape_INFO },
4586       { "BODY", -1,                     LoadTape_BODY },
4587       {  NULL,  0,                      NULL }
4588     };
4589
4590     while (getFileChunkBE(file, chunk_name, &chunk_size))
4591     {
4592       int i = 0;
4593
4594       while (chunk_info[i].name != NULL &&
4595              strcmp(chunk_name, chunk_info[i].name) != 0)
4596         i++;
4597
4598       if (chunk_info[i].name == NULL)
4599       {
4600         Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'",
4601               chunk_name, filename);
4602         ReadUnusedBytesFromFile(file, chunk_size);
4603       }
4604       else if (chunk_info[i].size != -1 &&
4605                chunk_info[i].size != chunk_size)
4606       {
4607         Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
4608               chunk_size, chunk_name, filename);
4609         ReadUnusedBytesFromFile(file, chunk_size);
4610       }
4611       else
4612       {
4613         /* call function to load this tape chunk */
4614         int chunk_size_expected =
4615           (chunk_info[i].loader)(file, chunk_size, &tape);
4616
4617         /* the size of some chunks cannot be checked before reading other
4618            chunks first (like "HEAD" and "BODY") that contain some header
4619            information, so check them here */
4620         if (chunk_size_expected != chunk_size)
4621         {
4622           Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
4623                 chunk_size, chunk_name, filename);
4624         }
4625       }
4626     }
4627   }
4628
4629   fclose(file);
4630
4631   tape.length_seconds = GetTapeLength();
4632
4633 #if 0
4634   printf("::: tape game version: %d\n", tape.game_version);
4635   printf("::: tape engine version: %d\n", tape.engine_version);
4636 #endif
4637 }
4638
4639 void LoadTape(int nr)
4640 {
4641   char *filename = getTapeFilename(nr);
4642
4643   LoadTapeFromFilename(filename);
4644 }
4645
4646 void LoadSolutionTape(int nr)
4647 {
4648   char *filename = getSolutionTapeFilename(nr);
4649
4650   LoadTapeFromFilename(filename);
4651 }
4652
4653 static void SaveTape_VERS(FILE *file, struct TapeInfo *tape)
4654 {
4655   putFileVersion(file, tape->file_version);
4656   putFileVersion(file, tape->game_version);
4657 }
4658
4659 static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
4660 {
4661   int i;
4662   byte store_participating_players = 0;
4663
4664   /* set bits for participating players for compact storage */
4665   for (i = 0; i < MAX_PLAYERS; i++)
4666     if (tape->player_participates[i])
4667       store_participating_players |= (1 << i);
4668
4669   putFile32BitBE(file, tape->random_seed);
4670   putFile32BitBE(file, tape->date);
4671   putFile32BitBE(file, tape->length);
4672
4673   putFile8Bit(file, store_participating_players);
4674
4675   /* unused bytes not at the end here for 4-byte alignment of engine_version */
4676   WriteUnusedBytesToFile(file, TAPE_HEADER_UNUSED);
4677
4678   putFileVersion(file, tape->engine_version);
4679 }
4680
4681 static void SaveTape_INFO(FILE *file, struct TapeInfo *tape)
4682 {
4683   int level_identifier_size = strlen(tape->level_identifier) + 1;
4684   int i;
4685
4686   putFile16BitBE(file, level_identifier_size);
4687
4688   for (i = 0; i < level_identifier_size; i++)
4689     putFile8Bit(file, tape->level_identifier[i]);
4690
4691   putFile16BitBE(file, tape->level_nr);
4692 }
4693
4694 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
4695 {
4696   int i, j;
4697
4698   for (i = 0; i < tape->length; i++)
4699   {
4700     for (j = 0; j < MAX_PLAYERS; j++)
4701       if (tape->player_participates[j])
4702         putFile8Bit(file, tape->pos[i].action[j]);
4703
4704     putFile8Bit(file, tape->pos[i].delay);
4705   }
4706 }
4707
4708 void SaveTape(int nr)
4709 {
4710   char *filename = getTapeFilename(nr);
4711   FILE *file;
4712   boolean new_tape = TRUE;
4713   int num_participating_players = 0;
4714   int info_chunk_size;
4715   int body_chunk_size;
4716   int i;
4717
4718   InitTapeDirectory(leveldir_current->subdir);
4719
4720   /* if a tape still exists, ask to overwrite it */
4721   if (fileExists(filename))
4722   {
4723     new_tape = FALSE;
4724     if (!Request("Replace old tape ?", REQ_ASK))
4725       return;
4726   }
4727
4728   if (!(file = fopen(filename, MODE_WRITE)))
4729   {
4730     Error(ERR_WARN, "cannot save level recording file '%s'", filename);
4731     return;
4732   }
4733
4734   tape.file_version = FILE_VERSION_ACTUAL;
4735   tape.game_version = GAME_VERSION_ACTUAL;
4736
4737   /* count number of participating players  */
4738   for (i = 0; i < MAX_PLAYERS; i++)
4739     if (tape.player_participates[i])
4740       num_participating_players++;
4741
4742   info_chunk_size = 2 + (strlen(tape.level_identifier) + 1) + 2;
4743   body_chunk_size = (num_participating_players + 1) * tape.length;
4744
4745   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
4746   putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
4747
4748   putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
4749   SaveTape_VERS(file, &tape);
4750
4751   putFileChunkBE(file, "HEAD", TAPE_HEADER_SIZE);
4752   SaveTape_HEAD(file, &tape);
4753
4754   putFileChunkBE(file, "INFO", info_chunk_size);
4755   SaveTape_INFO(file, &tape);
4756
4757   putFileChunkBE(file, "BODY", body_chunk_size);
4758   SaveTape_BODY(file, &tape);
4759
4760   fclose(file);
4761
4762   SetFilePermissions(filename, PERMS_PRIVATE);
4763
4764   tape.changed = FALSE;
4765
4766   if (new_tape)
4767     Request("Tape saved !", REQ_CONFIRM);
4768 }
4769
4770 void DumpTape(struct TapeInfo *tape)
4771 {
4772   int tape_frame_counter;
4773   int i, j;
4774
4775   if (tape->no_valid_file)
4776   {
4777     Error(ERR_WARN, "cannot dump -- no valid tape file found");
4778
4779     return;
4780   }
4781
4782   printf_line("-", 79);
4783   printf("Tape of Level %03d (file version %08d, game version %08d)\n",
4784          tape->level_nr, tape->file_version, tape->game_version);
4785   printf("                  (effective engine version %08d)\n",
4786          tape->engine_version);
4787   printf("Level series identifier: '%s'\n", tape->level_identifier);
4788   printf_line("-", 79);
4789
4790   tape_frame_counter = 0;
4791
4792   for (i = 0; i < tape->length; i++)
4793   {
4794     if (i >= MAX_TAPE_LEN)
4795       break;
4796
4797     printf("%04d: ", i);
4798
4799     for (j = 0; j < MAX_PLAYERS; j++)
4800     {
4801       if (tape->player_participates[j])
4802       {
4803         int action = tape->pos[i].action[j];
4804
4805         printf("%d:%02x ", j, action);
4806         printf("[%c%c%c%c|%c%c] - ",
4807                (action & JOY_LEFT ? '<' : ' '),
4808                (action & JOY_RIGHT ? '>' : ' '),
4809                (action & JOY_UP ? '^' : ' '),
4810                (action & JOY_DOWN ? 'v' : ' '),
4811                (action & JOY_BUTTON_1 ? '1' : ' '),
4812                (action & JOY_BUTTON_2 ? '2' : ' '));
4813       }
4814     }
4815
4816     printf("(%03d) ", tape->pos[i].delay);
4817     printf("[%05d]\n", tape_frame_counter);
4818
4819     tape_frame_counter += tape->pos[i].delay;
4820   }
4821
4822   printf_line("-", 79);
4823 }
4824
4825
4826 /* ========================================================================= */
4827 /* score file functions                                                      */
4828 /* ========================================================================= */
4829
4830 void LoadScore(int nr)
4831 {
4832   int i;
4833   char *filename = getScoreFilename(nr);
4834   char cookie[MAX_LINE_LEN];
4835   char line[MAX_LINE_LEN];
4836   char *line_ptr;
4837   FILE *file;
4838
4839   /* always start with reliable default values */
4840   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
4841   {
4842     strcpy(highscore[i].Name, EMPTY_PLAYER_NAME);
4843     highscore[i].Score = 0;
4844   }
4845
4846   if (!(file = fopen(filename, MODE_READ)))
4847     return;
4848
4849   /* check file identifier */
4850   fgets(cookie, MAX_LINE_LEN, file);
4851   if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
4852     cookie[strlen(cookie) - 1] = '\0';
4853
4854   if (!checkCookieString(cookie, SCORE_COOKIE))
4855   {
4856     Error(ERR_WARN, "unknown format of score file '%s'", filename);
4857     fclose(file);
4858     return;
4859   }
4860
4861   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
4862   {
4863     fscanf(file, "%d", &highscore[i].Score);
4864     fgets(line, MAX_LINE_LEN, file);
4865
4866     if (line[strlen(line) - 1] == '\n')
4867       line[strlen(line) - 1] = '\0';
4868
4869     for (line_ptr = line; *line_ptr; line_ptr++)
4870     {
4871       if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
4872       {
4873         strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN);
4874         highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0';
4875         break;
4876       }
4877     }
4878   }
4879
4880   fclose(file);
4881 }
4882
4883 void SaveScore(int nr)
4884 {
4885   int i;
4886   char *filename = getScoreFilename(nr);
4887   FILE *file;
4888
4889   InitScoreDirectory(leveldir_current->subdir);
4890
4891   if (!(file = fopen(filename, MODE_WRITE)))
4892   {
4893     Error(ERR_WARN, "cannot save score for level %d", nr);
4894     return;
4895   }
4896
4897   fprintf(file, "%s\n\n", SCORE_COOKIE);
4898
4899   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
4900     fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name);
4901
4902   fclose(file);
4903
4904   SetFilePermissions(filename, PERMS_PUBLIC);
4905 }
4906
4907
4908 /* ========================================================================= */
4909 /* setup file functions                                                      */
4910 /* ========================================================================= */
4911
4912 #define TOKEN_STR_PLAYER_PREFIX                 "player_"
4913
4914 /* global setup */
4915 #define SETUP_TOKEN_PLAYER_NAME                 0
4916 #define SETUP_TOKEN_SOUND                       1
4917 #define SETUP_TOKEN_SOUND_LOOPS                 2
4918 #define SETUP_TOKEN_SOUND_MUSIC                 3
4919 #define SETUP_TOKEN_SOUND_SIMPLE                4
4920 #define SETUP_TOKEN_TOONS                       5
4921 #define SETUP_TOKEN_SCROLL_DELAY                6
4922 #define SETUP_TOKEN_SOFT_SCROLLING              7
4923 #define SETUP_TOKEN_FADING                      8
4924 #define SETUP_TOKEN_AUTORECORD                  9
4925 #define SETUP_TOKEN_QUICK_DOORS                 10
4926 #define SETUP_TOKEN_TEAM_MODE                   11
4927 #define SETUP_TOKEN_HANDICAP                    12
4928 #define SETUP_TOKEN_SKIP_LEVELS                 13
4929 #define SETUP_TOKEN_TIME_LIMIT                  14
4930 #define SETUP_TOKEN_FULLSCREEN                  15
4931 #define SETUP_TOKEN_ASK_ON_ESCAPE               16
4932 #define SETUP_TOKEN_QUICK_SWITCH                17
4933 #define SETUP_TOKEN_GRAPHICS_SET                18
4934 #define SETUP_TOKEN_SOUNDS_SET                  19
4935 #define SETUP_TOKEN_MUSIC_SET                   20
4936 #define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS     21
4937 #define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS       22
4938 #define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC        23
4939
4940 #define NUM_GLOBAL_SETUP_TOKENS                 24
4941
4942 /* editor setup */
4943 #define SETUP_TOKEN_EDITOR_EL_BOULDERDASH       0
4944 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE      1
4945 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE_CLUB 2
4946 #define SETUP_TOKEN_EDITOR_EL_MORE              3
4947 #define SETUP_TOKEN_EDITOR_EL_SOKOBAN           4
4948 #define SETUP_TOKEN_EDITOR_EL_SUPAPLEX          5
4949 #define SETUP_TOKEN_EDITOR_EL_DIAMOND_CAVES     6
4950 #define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH    7
4951 #define SETUP_TOKEN_EDITOR_EL_CHARS             8
4952 #define SETUP_TOKEN_EDITOR_EL_CUSTOM            9
4953 #define SETUP_TOKEN_EDITOR_EL_HEADLINES         10
4954 #define SETUP_TOKEN_EDITOR_EL_USER_DEFINED      11
4955 #define SETUP_TOKEN_EDITOR_EL_DYNAMIC           12
4956
4957 #define NUM_EDITOR_SETUP_TOKENS                 13
4958
4959 /* editor cascade setup */
4960 #define SETUP_TOKEN_EDITOR_CASCADE_BD           0
4961 #define SETUP_TOKEN_EDITOR_CASCADE_EM           1
4962 #define SETUP_TOKEN_EDITOR_CASCADE_EMC          2
4963 #define SETUP_TOKEN_EDITOR_CASCADE_RND          3
4964 #define SETUP_TOKEN_EDITOR_CASCADE_SB           4
4965 #define SETUP_TOKEN_EDITOR_CASCADE_SP           5
4966 #define SETUP_TOKEN_EDITOR_CASCADE_DC           6
4967 #define SETUP_TOKEN_EDITOR_CASCADE_DX           7
4968 #define SETUP_TOKEN_EDITOR_CASCADE_TEXT         8
4969 #define SETUP_TOKEN_EDITOR_CASCADE_CE           9
4970 #define SETUP_TOKEN_EDITOR_CASCADE_GE           10
4971 #define SETUP_TOKEN_EDITOR_CASCADE_USER         11
4972 #define SETUP_TOKEN_EDITOR_CASCADE_GENERIC      12
4973 #define SETUP_TOKEN_EDITOR_CASCADE_DYNAMIC      13
4974
4975 #define NUM_EDITOR_CASCADE_SETUP_TOKENS         14
4976
4977 /* shortcut setup */
4978 #define SETUP_TOKEN_SHORTCUT_SAVE_GAME          0
4979 #define SETUP_TOKEN_SHORTCUT_LOAD_GAME          1
4980 #define SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE       2
4981
4982 #define NUM_SHORTCUT_SETUP_TOKENS               3
4983
4984 /* player setup */
4985 #define SETUP_TOKEN_PLAYER_USE_JOYSTICK         0
4986 #define SETUP_TOKEN_PLAYER_JOY_DEVICE_NAME      1
4987 #define SETUP_TOKEN_PLAYER_JOY_XLEFT            2
4988 #define SETUP_TOKEN_PLAYER_JOY_XMIDDLE          3
4989 #define SETUP_TOKEN_PLAYER_JOY_XRIGHT           4
4990 #define SETUP_TOKEN_PLAYER_JOY_YUPPER           5
4991 #define SETUP_TOKEN_PLAYER_JOY_YMIDDLE          6
4992 #define SETUP_TOKEN_PLAYER_JOY_YLOWER           7
4993 #define SETUP_TOKEN_PLAYER_JOY_SNAP             8
4994 #define SETUP_TOKEN_PLAYER_JOY_DROP             9
4995 #define SETUP_TOKEN_PLAYER_KEY_LEFT             10
4996 #define SETUP_TOKEN_PLAYER_KEY_RIGHT            11
4997 #define SETUP_TOKEN_PLAYER_KEY_UP               12
4998 #define SETUP_TOKEN_PLAYER_KEY_DOWN             13
4999 #define SETUP_TOKEN_PLAYER_KEY_SNAP             14
5000 #define SETUP_TOKEN_PLAYER_KEY_DROP             15
5001
5002 #define NUM_PLAYER_SETUP_TOKENS                 16
5003
5004 /* system setup */
5005 #define SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER      0
5006 #define SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE  1
5007
5008 #define NUM_SYSTEM_SETUP_TOKENS                 2
5009
5010 /* options setup */
5011 #define SETUP_TOKEN_OPTIONS_VERBOSE             0
5012
5013 #define NUM_OPTIONS_SETUP_TOKENS                1
5014
5015
5016 static struct SetupInfo si;
5017 static struct SetupEditorInfo sei;
5018 static struct SetupEditorCascadeInfo seci;
5019 static struct SetupShortcutInfo ssi;
5020 static struct SetupInputInfo sii;
5021 static struct SetupSystemInfo syi;
5022 static struct OptionInfo soi;
5023
5024 static struct TokenInfo global_setup_tokens[] =
5025 {
5026   { TYPE_STRING, &si.player_name,       "player_name"                   },
5027   { TYPE_SWITCH, &si.sound,             "sound"                         },
5028   { TYPE_SWITCH, &si.sound_loops,       "repeating_sound_loops"         },
5029   { TYPE_SWITCH, &si.sound_music,       "background_music"              },
5030   { TYPE_SWITCH, &si.sound_simple,      "simple_sound_effects"          },
5031   { TYPE_SWITCH, &si.toons,             "toons"                         },
5032   { TYPE_SWITCH, &si.scroll_delay,      "scroll_delay"                  },
5033   { TYPE_SWITCH, &si.soft_scrolling,    "soft_scrolling"                },
5034   { TYPE_SWITCH, &si.fading,            "screen_fading"                 },
5035   { TYPE_SWITCH, &si.autorecord,        "automatic_tape_recording"      },
5036   { TYPE_SWITCH, &si.quick_doors,       "quick_doors"                   },
5037   { TYPE_SWITCH, &si.team_mode,         "team_mode"                     },
5038   { TYPE_SWITCH, &si.handicap,          "handicap"                      },
5039   { TYPE_SWITCH, &si.skip_levels,       "skip_levels"                   },
5040   { TYPE_SWITCH, &si.time_limit,        "time_limit"                    },
5041   { TYPE_SWITCH, &si.fullscreen,        "fullscreen"                    },
5042   { TYPE_SWITCH, &si.ask_on_escape,     "ask_on_escape"                 },
5043   { TYPE_SWITCH, &si.quick_switch,      "quick_player_switch"           },
5044   { TYPE_STRING, &si.graphics_set,      "graphics_set"                  },
5045   { TYPE_STRING, &si.sounds_set,        "sounds_set"                    },
5046   { TYPE_STRING, &si.music_set,         "music_set"                     },
5047   { TYPE_SWITCH, &si.override_level_graphics, "override_level_graphics" },
5048   { TYPE_SWITCH, &si.override_level_sounds,   "override_level_sounds"   },
5049   { TYPE_SWITCH, &si.override_level_music,    "override_level_music"    },
5050 };
5051
5052 static struct TokenInfo editor_setup_tokens[] =
5053 {
5054   { TYPE_SWITCH, &sei.el_boulderdash,   "editor.el_boulderdash"         },
5055   { TYPE_SWITCH, &sei.el_emerald_mine,  "editor.el_emerald_mine"        },
5056   { TYPE_SWITCH, &sei.el_emerald_mine_club,"editor.el_emerald_mine_club"},
5057   { TYPE_SWITCH, &sei.el_more,          "editor.el_more"                },
5058   { TYPE_SWITCH, &sei.el_sokoban,       "editor.el_sokoban"             },
5059   { TYPE_SWITCH, &sei.el_supaplex,      "editor.el_supaplex"            },
5060   { TYPE_SWITCH, &sei.el_diamond_caves, "editor.el_diamond_caves"       },
5061   { TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash"      },
5062   { TYPE_SWITCH, &sei.el_chars,         "editor.el_chars"               },
5063   { TYPE_SWITCH, &sei.el_custom,        "editor.el_custom"              },
5064   { TYPE_SWITCH, &sei.el_headlines,     "editor.el_headlines"           },
5065   { TYPE_SWITCH, &sei.el_user_defined,  "editor.el_user_defined"        },
5066   { TYPE_SWITCH, &sei.el_dynamic,       "editor.el_dynamic"             },
5067 };
5068
5069 static struct TokenInfo editor_cascade_setup_tokens[] =
5070 {
5071   { TYPE_SWITCH, &seci.el_bd,           "editor.cascade.el_bd"          },
5072   { TYPE_SWITCH, &seci.el_em,           "editor.cascade.el_em"          },
5073   { TYPE_SWITCH, &seci.el_emc,          "editor.cascade.el_emc"         },
5074   { TYPE_SWITCH, &seci.el_rnd,          "editor.cascade.el_rnd"         },
5075   { TYPE_SWITCH, &seci.el_sb,           "editor.cascade.el_sb"          },
5076   { TYPE_SWITCH, &seci.el_sp,           "editor.cascade.el_sp"          },
5077   { TYPE_SWITCH, &seci.el_dc,           "editor.cascade.el_dc"          },
5078   { TYPE_SWITCH, &seci.el_dx,           "editor.cascade.el_dx"          },
5079   { TYPE_SWITCH, &seci.el_chars,        "editor.cascade.el_chars"       },
5080   { TYPE_SWITCH, &seci.el_ce,           "editor.cascade.el_ce"          },
5081   { TYPE_SWITCH, &seci.el_ge,           "editor.cascade.el_ge"          },
5082   { TYPE_SWITCH, &seci.el_user,         "editor.cascade.el_user"        },
5083   { TYPE_SWITCH, &seci.el_generic,      "editor.cascade.el_generic"     },
5084   { TYPE_SWITCH, &seci.el_dynamic,      "editor.cascade.el_dynamic"     },
5085 };
5086
5087 static struct TokenInfo shortcut_setup_tokens[] =
5088 {
5089   { TYPE_KEY_X11, &ssi.save_game,       "shortcut.save_game"            },
5090   { TYPE_KEY_X11, &ssi.load_game,       "shortcut.load_game"            },
5091   { TYPE_KEY_X11, &ssi.toggle_pause,    "shortcut.toggle_pause"         }
5092 };
5093
5094 static struct TokenInfo player_setup_tokens[] =
5095 {
5096   { TYPE_BOOLEAN, &sii.use_joystick,    ".use_joystick"                 },
5097   { TYPE_STRING,  &sii.joy.device_name, ".joy.device_name"              },
5098   { TYPE_INTEGER, &sii.joy.xleft,       ".joy.xleft"                    },
5099   { TYPE_INTEGER, &sii.joy.xmiddle,     ".joy.xmiddle"                  },
5100   { TYPE_INTEGER, &sii.joy.xright,      ".joy.xright"                   },
5101   { TYPE_INTEGER, &sii.joy.yupper,      ".joy.yupper"                   },
5102   { TYPE_INTEGER, &sii.joy.ymiddle,     ".joy.ymiddle"                  },
5103   { TYPE_INTEGER, &sii.joy.ylower,      ".joy.ylower"                   },
5104   { TYPE_INTEGER, &sii.joy.snap,        ".joy.snap_field"               },
5105   { TYPE_INTEGER, &sii.joy.drop,        ".joy.place_bomb"               },
5106   { TYPE_KEY_X11, &sii.key.left,        ".key.move_left"                },
5107   { TYPE_KEY_X11, &sii.key.right,       ".key.move_right"               },
5108   { TYPE_KEY_X11, &sii.key.up,          ".key.move_up"                  },
5109   { TYPE_KEY_X11, &sii.key.down,        ".key.move_down"                },
5110   { TYPE_KEY_X11, &sii.key.snap,        ".key.snap_field"               },
5111   { TYPE_KEY_X11, &sii.key.drop,        ".key.place_bomb"               }
5112 };
5113
5114 static struct TokenInfo system_setup_tokens[] =
5115 {
5116   { TYPE_STRING,  &syi.sdl_audiodriver, "system.sdl_audiodriver"        },
5117   { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size" }
5118 };
5119
5120 static struct TokenInfo options_setup_tokens[] =
5121 {
5122   { TYPE_BOOLEAN, &soi.verbose,         "options.verbose"               }
5123 };
5124
5125 static char *get_corrected_login_name(char *login_name)
5126 {
5127   /* needed because player name must be a fixed length string */
5128   char *login_name_new = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
5129
5130   strncpy(login_name_new, login_name, MAX_PLAYER_NAME_LEN);
5131   login_name_new[MAX_PLAYER_NAME_LEN] = '\0';
5132
5133   if (strlen(login_name) > MAX_PLAYER_NAME_LEN)         /* name has been cut */
5134     if (strchr(login_name_new, ' '))
5135       *strchr(login_name_new, ' ') = '\0';
5136
5137   return login_name_new;
5138 }
5139
5140 static void setSetupInfoToDefaults(struct SetupInfo *si)
5141 {
5142   int i;
5143
5144   si->player_name = get_corrected_login_name(getLoginName());
5145
5146   si->sound = TRUE;
5147   si->sound_loops = TRUE;
5148   si->sound_music = TRUE;
5149   si->sound_simple = TRUE;
5150   si->toons = TRUE;
5151   si->double_buffering = TRUE;
5152   si->direct_draw = !si->double_buffering;
5153   si->scroll_delay = TRUE;
5154   si->soft_scrolling = TRUE;
5155   si->fading = FALSE;
5156   si->autorecord = TRUE;
5157   si->quick_doors = FALSE;
5158   si->team_mode = FALSE;
5159   si->handicap = TRUE;
5160   si->skip_levels = TRUE;
5161   si->time_limit = TRUE;
5162   si->fullscreen = FALSE;
5163   si->ask_on_escape = TRUE;
5164   si->quick_switch = FALSE;
5165
5166   si->graphics_set = getStringCopy(GFX_CLASSIC_SUBDIR);
5167   si->sounds_set = getStringCopy(SND_CLASSIC_SUBDIR);
5168   si->music_set = getStringCopy(MUS_CLASSIC_SUBDIR);
5169   si->override_level_graphics = FALSE;
5170   si->override_level_sounds = FALSE;
5171   si->override_level_music = FALSE;
5172
5173   si->editor.el_boulderdash       = TRUE;
5174   si->editor.el_emerald_mine      = TRUE;
5175   si->editor.el_emerald_mine_club = TRUE;
5176   si->editor.el_more              = TRUE;
5177   si->editor.el_sokoban           = TRUE;
5178   si->editor.el_supaplex          = TRUE;
5179   si->editor.el_diamond_caves     = TRUE;
5180   si->editor.el_dx_boulderdash    = TRUE;
5181   si->editor.el_chars             = TRUE;
5182   si->editor.el_custom            = TRUE;
5183
5184   si->editor.el_headlines = TRUE;
5185   si->editor.el_user_defined = FALSE;
5186   si->editor.el_dynamic = TRUE;
5187
5188   si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
5189   si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME;
5190   si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE;
5191
5192   for (i = 0; i < MAX_PLAYERS; i++)
5193   {
5194     si->input[i].use_joystick = FALSE;
5195     si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
5196     si->input[i].joy.xleft   = JOYSTICK_XLEFT;
5197     si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
5198     si->input[i].joy.xright  = JOYSTICK_XRIGHT;
5199     si->input[i].joy.yupper  = JOYSTICK_YUPPER;
5200     si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
5201     si->input[i].joy.ylower  = JOYSTICK_YLOWER;
5202     si->input[i].joy.snap  = (i == 0 ? JOY_BUTTON_1 : 0);
5203     si->input[i].joy.drop  = (i == 0 ? JOY_BUTTON_2 : 0);
5204     si->input[i].key.left  = (i == 0 ? DEFAULT_KEY_LEFT  : KSYM_UNDEFINED);
5205     si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
5206     si->input[i].key.up    = (i == 0 ? DEFAULT_KEY_UP    : KSYM_UNDEFINED);
5207     si->input[i].key.down  = (i == 0 ? DEFAULT_KEY_DOWN  : KSYM_UNDEFINED);
5208     si->input[i].key.snap  = (i == 0 ? DEFAULT_KEY_SNAP  : KSYM_UNDEFINED);
5209     si->input[i].key.drop  = (i == 0 ? DEFAULT_KEY_DROP  : KSYM_UNDEFINED);
5210   }
5211
5212   si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT);
5213   si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
5214
5215   si->options.verbose = FALSE;
5216 }
5217
5218 static void setSetupInfoToDefaults_EditorCascade(struct SetupInfo *si)
5219 {
5220   si->editor_cascade.el_bd      = TRUE;
5221   si->editor_cascade.el_em      = TRUE;
5222   si->editor_cascade.el_emc     = TRUE;
5223   si->editor_cascade.el_rnd     = TRUE;
5224   si->editor_cascade.el_sb      = TRUE;
5225   si->editor_cascade.el_sp      = TRUE;
5226   si->editor_cascade.el_dc      = TRUE;
5227   si->editor_cascade.el_dx      = TRUE;
5228
5229   si->editor_cascade.el_chars   = FALSE;
5230   si->editor_cascade.el_ce      = FALSE;
5231   si->editor_cascade.el_ge      = FALSE;
5232   si->editor_cascade.el_user    = FALSE;
5233   si->editor_cascade.el_generic = FALSE;
5234   si->editor_cascade.el_dynamic = FALSE;
5235 }
5236
5237 static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
5238 {
5239   int i, pnr;
5240
5241   if (!setup_file_hash)
5242     return;
5243
5244   /* global setup */
5245   si = setup;
5246   for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
5247     setSetupInfo(global_setup_tokens, i,
5248                  getHashEntry(setup_file_hash, global_setup_tokens[i].text));
5249   setup = si;
5250
5251   /* editor setup */
5252   sei = setup.editor;
5253   for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
5254     setSetupInfo(editor_setup_tokens, i,
5255                  getHashEntry(setup_file_hash,editor_setup_tokens[i].text));
5256   setup.editor = sei;
5257
5258   /* shortcut setup */
5259   ssi = setup.shortcut;
5260   for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
5261     setSetupInfo(shortcut_setup_tokens, i,
5262                  getHashEntry(setup_file_hash,shortcut_setup_tokens[i].text));
5263   setup.shortcut = ssi;
5264
5265   /* player setup */
5266   for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
5267   {
5268     char prefix[30];
5269
5270     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
5271
5272     sii = setup.input[pnr];
5273     for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
5274     {
5275       char full_token[100];
5276
5277       sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
5278       setSetupInfo(player_setup_tokens, i,
5279                    getHashEntry(setup_file_hash, full_token));
5280     }
5281     setup.input[pnr] = sii;
5282   }
5283
5284   /* system setup */
5285   syi = setup.system;
5286   for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
5287     setSetupInfo(system_setup_tokens, i,
5288                  getHashEntry(setup_file_hash, system_setup_tokens[i].text));
5289   setup.system = syi;
5290
5291   /* options setup */
5292   soi = setup.options;
5293   for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
5294     setSetupInfo(options_setup_tokens, i,
5295                  getHashEntry(setup_file_hash, options_setup_tokens[i].text));
5296   setup.options = soi;
5297 }
5298
5299 static void decodeSetupFileHash_EditorCascade(SetupFileHash *setup_file_hash)
5300 {
5301   int i;
5302
5303   if (!setup_file_hash)
5304     return;
5305
5306   /* editor cascade setup */
5307   seci = setup.editor_cascade;
5308   for (i = 0; i < NUM_EDITOR_CASCADE_SETUP_TOKENS; i++)
5309     setSetupInfo(editor_cascade_setup_tokens, i,
5310                  getHashEntry(setup_file_hash,
5311                               editor_cascade_setup_tokens[i].text));
5312   setup.editor_cascade = seci;
5313 }
5314
5315 void LoadSetup()
5316 {
5317   char *filename = getSetupFilename();
5318   SetupFileHash *setup_file_hash = NULL;
5319
5320   /* always start with reliable default values */
5321   setSetupInfoToDefaults(&setup);
5322
5323   setup_file_hash = loadSetupFileHash(filename);
5324
5325   if (setup_file_hash)
5326   {
5327     char *player_name_new;
5328
5329     checkSetupFileHashIdentifier(setup_file_hash, getCookie("SETUP"));
5330     decodeSetupFileHash(setup_file_hash);
5331
5332     setup.direct_draw = !setup.double_buffering;
5333
5334     freeSetupFileHash(setup_file_hash);
5335
5336     /* needed to work around problems with fixed length strings */
5337     player_name_new = get_corrected_login_name(setup.player_name);
5338     free(setup.player_name);
5339     setup.player_name = player_name_new;
5340   }
5341   else
5342     Error(ERR_WARN, "using default setup values");
5343 }
5344
5345 void LoadSetup_EditorCascade()
5346 {
5347   char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
5348   SetupFileHash *setup_file_hash = NULL;
5349
5350   /* always start with reliable default values */
5351   setSetupInfoToDefaults_EditorCascade(&setup);
5352
5353   setup_file_hash = loadSetupFileHash(filename);
5354
5355   if (setup_file_hash)
5356   {
5357     checkSetupFileHashIdentifier(setup_file_hash, getCookie("SETUP"));
5358     decodeSetupFileHash_EditorCascade(setup_file_hash);
5359
5360     freeSetupFileHash(setup_file_hash);
5361   }
5362
5363   free(filename);
5364 }
5365
5366 void SaveSetup()
5367 {
5368   char *filename = getSetupFilename();
5369   FILE *file;
5370   int i, pnr;
5371
5372   InitUserDataDirectory();
5373
5374   if (!(file = fopen(filename, MODE_WRITE)))
5375   {
5376     Error(ERR_WARN, "cannot write setup file '%s'", filename);
5377     return;
5378   }
5379
5380   fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
5381                                                getCookie("SETUP")));
5382   fprintf(file, "\n");
5383
5384   /* global setup */
5385   si = setup;
5386   for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
5387   {
5388     /* just to make things nicer :) */
5389     if (i == SETUP_TOKEN_PLAYER_NAME + 1 ||
5390         i == SETUP_TOKEN_GRAPHICS_SET)
5391       fprintf(file, "\n");
5392
5393     fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
5394   }
5395
5396   /* editor setup */
5397   sei = setup.editor;
5398   fprintf(file, "\n");
5399   for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
5400     fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i));
5401
5402   /* shortcut setup */
5403   ssi = setup.shortcut;
5404   fprintf(file, "\n");
5405   for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
5406     fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
5407
5408   /* player setup */
5409   for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
5410   {
5411     char prefix[30];
5412
5413     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
5414     fprintf(file, "\n");
5415
5416     sii = setup.input[pnr];
5417     for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
5418       fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
5419   }
5420
5421   /* system setup */
5422   syi = setup.system;
5423   fprintf(file, "\n");
5424   for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
5425     fprintf(file, "%s\n", getSetupLine(system_setup_tokens, "", i));
5426
5427   /* options setup */
5428   soi = setup.options;
5429   fprintf(file, "\n");
5430   for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
5431     fprintf(file, "%s\n", getSetupLine(options_setup_tokens, "", i));
5432
5433   fclose(file);
5434
5435   SetFilePermissions(filename, PERMS_PRIVATE);
5436 }
5437
5438 void SaveSetup_EditorCascade()
5439 {
5440   char *filename = getPath2(getSetupDir(), EDITORCASCADE_FILENAME);
5441   FILE *file;
5442   int i;
5443
5444   InitUserDataDirectory();
5445
5446   if (!(file = fopen(filename, MODE_WRITE)))
5447   {
5448     Error(ERR_WARN, "cannot write editor cascade state file '%s'", filename);
5449     free(filename);
5450     return;
5451   }
5452
5453   fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
5454                                                getCookie("SETUP")));
5455   fprintf(file, "\n");
5456
5457   seci = setup.editor_cascade;
5458   fprintf(file, "\n");
5459   for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
5460     fprintf(file, "%s\n", getSetupLine(editor_cascade_setup_tokens, "", i));
5461
5462   fclose(file);
5463
5464   SetFilePermissions(filename, PERMS_PRIVATE);
5465
5466   free(filename);
5467 }
5468
5469 void LoadCustomElementDescriptions()
5470 {
5471   char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
5472   SetupFileHash *setup_file_hash;
5473   int i;
5474
5475   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5476   {
5477     if (element_info[i].custom_description != NULL)
5478     {
5479       free(element_info[i].custom_description);
5480       element_info[i].custom_description = NULL;
5481     }
5482   }
5483
5484   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
5485     return;
5486
5487   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5488   {
5489     char *token = getStringCat2(element_info[i].token_name, ".name");
5490     char *value = getHashEntry(setup_file_hash, token);
5491
5492     if (value != NULL)
5493       element_info[i].custom_description = getStringCopy(value);
5494
5495     free(token);
5496   }
5497
5498   freeSetupFileHash(setup_file_hash);
5499 }
5500
5501 void LoadSpecialMenuDesignSettings()
5502 {
5503   char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
5504   SetupFileHash *setup_file_hash;
5505   int i, j;
5506
5507   /* always start with reliable default values from default config */
5508   for (i = 0; image_config_vars[i].token != NULL; i++)
5509     for (j = 0; image_config[j].token != NULL; j++)
5510       if (strcmp(image_config_vars[i].token, image_config[j].token) == 0)
5511         *image_config_vars[i].value =
5512           get_auto_parameter_value(image_config_vars[i].token,
5513                                    image_config[j].value);
5514
5515   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
5516     return;
5517
5518   /* special case: initialize with default values that may be overwritten */
5519   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
5520   {
5521     char *value_x = getHashEntry(setup_file_hash, "menu.draw_xoffset");
5522     char *value_y = getHashEntry(setup_file_hash, "menu.draw_yoffset");
5523     char *list_size = getHashEntry(setup_file_hash, "menu.list_size");
5524
5525     if (value_x != NULL)
5526       menu.draw_xoffset[i] = get_integer_from_string(value_x);
5527     if (value_y != NULL)
5528       menu.draw_yoffset[i] = get_integer_from_string(value_y);
5529     if (list_size != NULL)
5530       menu.list_size[i] = get_integer_from_string(list_size);
5531   }
5532
5533   /* read (and overwrite with) values that may be specified in config file */
5534   for (i = 0; image_config_vars[i].token != NULL; i++)
5535   {
5536     char *value = getHashEntry(setup_file_hash, image_config_vars[i].token);
5537
5538     if (value != NULL)
5539       *image_config_vars[i].value =
5540         get_auto_parameter_value(image_config_vars[i].token, value);
5541   }
5542
5543   freeSetupFileHash(setup_file_hash);
5544 }
5545
5546 void LoadUserDefinedEditorElementList(int **elements, int *num_elements)
5547 {
5548   char *filename = getEditorSetupFilename();
5549   SetupFileList *setup_file_list, *list;
5550   SetupFileHash *element_hash;
5551   int num_unknown_tokens = 0;
5552   int i;
5553
5554   if ((setup_file_list = loadSetupFileList(filename)) == NULL)
5555     return;
5556
5557   element_hash = newSetupFileHash();
5558
5559   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5560     setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
5561
5562   /* determined size may be larger than needed (due to unknown elements) */
5563   *num_elements = 0;
5564   for (list = setup_file_list; list != NULL; list = list->next)
5565     (*num_elements)++;
5566
5567   /* add space for up to 3 more elements for padding that may be needed */
5568   *num_elements += 3;
5569
5570   /* free memory for old list of elements, if needed */
5571   checked_free(*elements);
5572
5573   /* allocate memory for new list of elements */
5574   *elements = checked_malloc(*num_elements * sizeof(int));
5575
5576   *num_elements = 0;
5577   for (list = setup_file_list; list != NULL; list = list->next)
5578   {
5579     char *value = getHashEntry(element_hash, list->token);
5580
5581     if (value == NULL)          /* try to find obsolete token mapping */
5582     {
5583       char *mapped_token = get_mapped_token(list->token);
5584
5585       if (mapped_token != NULL)
5586       {
5587         value = getHashEntry(element_hash, mapped_token);
5588
5589         free(mapped_token);
5590       }
5591     }
5592
5593     if (value != NULL)
5594     {
5595       (*elements)[(*num_elements)++] = atoi(value);
5596     }
5597     else
5598     {
5599       if (num_unknown_tokens == 0)
5600       {
5601         Error(ERR_RETURN_LINE, "-");
5602         Error(ERR_RETURN, "warning: unknown token(s) found in config file:");
5603         Error(ERR_RETURN, "- config file: '%s'", filename);
5604
5605         num_unknown_tokens++;
5606       }
5607
5608       Error(ERR_RETURN, "- token: '%s'", list->token);
5609     }
5610   }
5611
5612   if (num_unknown_tokens > 0)
5613     Error(ERR_RETURN_LINE, "-");
5614
5615   while (*num_elements % 4)     /* pad with empty elements, if needed */
5616     (*elements)[(*num_elements)++] = EL_EMPTY;
5617
5618   freeSetupFileList(setup_file_list);
5619   freeSetupFileHash(element_hash);
5620
5621 #if 0
5622   for (i = 0; i < *num_elements; i++)
5623     printf("editor: element '%s' [%d]\n",
5624            element_info[(*elements)[i]].token_name, (*elements)[i]);
5625 #endif
5626 }
5627
5628 static struct MusicFileInfo *get_music_file_info_ext(char *basename, int music,
5629                                                      boolean is_sound)
5630 {
5631   SetupFileHash *setup_file_hash = NULL;
5632   struct MusicFileInfo tmp_music_file_info, *new_music_file_info;
5633   char *filename_music, *filename_prefix, *filename_info;
5634   struct
5635   {
5636     char *token;
5637     char **value_ptr;
5638   }
5639   token_to_value_ptr[] =
5640   {
5641     { "title_header",   &tmp_music_file_info.title_header       },
5642     { "artist_header",  &tmp_music_file_info.artist_header      },
5643     { "album_header",   &tmp_music_file_info.album_header       },
5644     { "year_header",    &tmp_music_file_info.year_header        },
5645
5646     { "title",          &tmp_music_file_info.title              },
5647     { "artist",         &tmp_music_file_info.artist             },
5648     { "album",          &tmp_music_file_info.album              },
5649     { "year",           &tmp_music_file_info.year               },
5650
5651     { NULL,             NULL                                    },
5652   };
5653   int i;
5654
5655   filename_music = (is_sound ? getCustomSoundFilename(basename) :
5656                     getCustomMusicFilename(basename));
5657
5658   if (filename_music == NULL)
5659     return NULL;
5660
5661   /* ---------- try to replace file extension ---------- */
5662
5663   filename_prefix = getStringCopy(filename_music);
5664   if (strrchr(filename_prefix, '.') != NULL)
5665     *strrchr(filename_prefix, '.') = '\0';
5666   filename_info = getStringCat2(filename_prefix, ".txt");
5667
5668 #if 0
5669   printf("trying to load file '%s'...\n", filename_info);
5670 #endif
5671
5672   if (fileExists(filename_info))
5673     setup_file_hash = loadSetupFileHash(filename_info);
5674
5675   free(filename_prefix);
5676   free(filename_info);
5677
5678   if (setup_file_hash == NULL)
5679   {
5680     /* ---------- try to add file extension ---------- */
5681
5682     filename_prefix = getStringCopy(filename_music);
5683     filename_info = getStringCat2(filename_prefix, ".txt");
5684
5685 #if 0
5686     printf("trying to load file '%s'...\n", filename_info);
5687 #endif
5688
5689     if (fileExists(filename_info))
5690       setup_file_hash = loadSetupFileHash(filename_info);
5691
5692     free(filename_prefix);
5693     free(filename_info);
5694   }
5695
5696   if (setup_file_hash == NULL)
5697     return NULL;
5698
5699   /* ---------- music file info found ---------- */
5700
5701   memset(&tmp_music_file_info, 0, sizeof(struct MusicFileInfo));
5702
5703   for (i = 0; token_to_value_ptr[i].token != NULL; i++)
5704   {
5705     char *value = getHashEntry(setup_file_hash, token_to_value_ptr[i].token);
5706
5707     *token_to_value_ptr[i].value_ptr =
5708       getStringCopy(value != NULL && *value != '\0' ? value : UNKNOWN_NAME);
5709   }
5710
5711   tmp_music_file_info.basename = getStringCopy(basename);
5712   tmp_music_file_info.music = music;
5713   tmp_music_file_info.is_sound = is_sound;
5714
5715   new_music_file_info = checked_malloc(sizeof(struct MusicFileInfo));
5716   *new_music_file_info = tmp_music_file_info;
5717
5718   return new_music_file_info;
5719 }
5720
5721 static struct MusicFileInfo *get_music_file_info(char *basename, int music)
5722 {
5723   return get_music_file_info_ext(basename, music, FALSE);
5724 }
5725
5726 static struct MusicFileInfo *get_sound_file_info(char *basename, int sound)
5727 {
5728   return get_music_file_info_ext(basename, sound, TRUE);
5729 }
5730
5731 static boolean music_info_listed_ext(struct MusicFileInfo *list,
5732                                      char *basename, boolean is_sound)
5733 {
5734   for (; list != NULL; list = list->next)
5735     if (list->is_sound == is_sound && strcmp(list->basename, basename) == 0)
5736       return TRUE;
5737
5738   return FALSE;
5739 }
5740
5741 static boolean music_info_listed(struct MusicFileInfo *list, char *basename)
5742 {
5743   return music_info_listed_ext(list, basename, FALSE);
5744 }
5745
5746 static boolean sound_info_listed(struct MusicFileInfo *list, char *basename)
5747 {
5748   return music_info_listed_ext(list, basename, TRUE);
5749 }
5750
5751 void LoadMusicInfo()
5752 {
5753   char *music_directory = getCustomMusicDirectory();
5754   int num_music = getMusicListSize();
5755   int num_music_noconf = 0;
5756   int num_sounds = getSoundListSize();
5757   DIR *dir;
5758   struct dirent *dir_entry;
5759   struct FileInfo *music, *sound;
5760   struct MusicFileInfo *next, **new;
5761   int i;
5762
5763   while (music_file_info != NULL)
5764   {
5765     next = music_file_info->next;
5766
5767     checked_free(music_file_info->basename);
5768
5769     checked_free(music_file_info->title_header);
5770     checked_free(music_file_info->artist_header);
5771     checked_free(music_file_info->album_header);
5772     checked_free(music_file_info->year_header);
5773
5774     checked_free(music_file_info->title);
5775     checked_free(music_file_info->artist);
5776     checked_free(music_file_info->album);
5777     checked_free(music_file_info->year);
5778
5779     free(music_file_info);
5780
5781     music_file_info = next;
5782   }
5783
5784   new = &music_file_info;
5785
5786   for (i = 0; i < num_music; i++)
5787   {
5788     music = getMusicListEntry(i);
5789
5790     if (music->filename == NULL)
5791       continue;
5792
5793     if (strcmp(music->filename, UNDEFINED_FILENAME) == 0)
5794       continue;
5795
5796     /* a configured file may be not recognized as music */
5797     if (!FileIsMusic(music->filename))
5798       continue;
5799
5800 #if 0
5801     printf("::: -> '%s' (configured)\n", music->filename);
5802 #endif
5803
5804     if (!music_info_listed(music_file_info, music->filename))
5805     {
5806       *new = get_music_file_info(music->filename, i);
5807       if (*new != NULL)
5808         new = &(*new)->next;
5809     }
5810   }
5811
5812   if ((dir = opendir(music_directory)) == NULL)
5813   {
5814     Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
5815     return;
5816   }
5817
5818   while ((dir_entry = readdir(dir)) != NULL)    /* loop until last dir entry */
5819   {
5820     char *basename = dir_entry->d_name;
5821     boolean music_already_used = FALSE;
5822     int i;
5823
5824     /* skip all music files that are configured in music config file */
5825     for (i = 0; i < num_music; i++)
5826     {
5827       music = getMusicListEntry(i);
5828
5829       if (music->filename == NULL)
5830         continue;
5831
5832       if (strcmp(basename, music->filename) == 0)
5833       {
5834         music_already_used = TRUE;
5835         break;
5836       }
5837     }
5838
5839     if (music_already_used)
5840       continue;
5841
5842     if (!FileIsMusic(basename))
5843       continue;
5844
5845 #if 0
5846     printf("::: -> '%s' (found in directory)\n", basename);
5847 #endif
5848
5849     if (!music_info_listed(music_file_info, basename))
5850     {
5851       *new = get_music_file_info(basename, MAP_NOCONF_MUSIC(num_music_noconf));
5852       if (*new != NULL)
5853         new = &(*new)->next;
5854     }
5855
5856     num_music_noconf++;
5857   }
5858
5859   closedir(dir);
5860
5861   for (i = 0; i < num_sounds; i++)
5862   {
5863     sound = getSoundListEntry(i);
5864
5865     if (sound->filename == NULL)
5866       continue;
5867
5868     if (strcmp(sound->filename, UNDEFINED_FILENAME) == 0)
5869       continue;
5870
5871     /* a configured file may be not recognized as sound */
5872     if (!FileIsSound(sound->filename))
5873       continue;
5874
5875 #if 0
5876     printf("::: -> '%s' (configured)\n", sound->filename);
5877 #endif
5878
5879     if (!sound_info_listed(music_file_info, sound->filename))
5880     {
5881       *new = get_sound_file_info(sound->filename, i);
5882       if (*new != NULL)
5883         new = &(*new)->next;
5884     }
5885   }
5886
5887 #if 0
5888   for (next = music_file_info; next != NULL; next = next->next)
5889     printf("::: title == '%s'\n", next->title);
5890 #endif
5891 }
5892
5893 void add_helpanim_entry(int element, int action, int direction, int delay,
5894                         int *num_list_entries)
5895 {
5896   struct HelpAnimInfo *new_list_entry;
5897   (*num_list_entries)++;
5898
5899   helpanim_info =
5900     checked_realloc(helpanim_info,
5901                     *num_list_entries * sizeof(struct HelpAnimInfo));
5902   new_list_entry = &helpanim_info[*num_list_entries - 1];
5903
5904   new_list_entry->element = element;
5905   new_list_entry->action = action;
5906   new_list_entry->direction = direction;
5907   new_list_entry->delay = delay;
5908 }
5909
5910 void print_unknown_token(char *filename, char *token, int token_nr)
5911 {
5912   if (token_nr == 0)
5913   {
5914     Error(ERR_RETURN_LINE, "-");
5915     Error(ERR_RETURN, "warning: unknown token(s) found in config file:");
5916     Error(ERR_RETURN, "- config file: '%s'", filename);
5917   }
5918
5919   Error(ERR_RETURN, "- token: '%s'", token);
5920 }
5921
5922 void print_unknown_token_end(int token_nr)
5923 {
5924   if (token_nr > 0)
5925     Error(ERR_RETURN_LINE, "-");
5926 }
5927
5928 void LoadHelpAnimInfo()
5929 {
5930   char *filename = getHelpAnimFilename();
5931   SetupFileList *setup_file_list = NULL, *list;
5932   SetupFileHash *element_hash, *action_hash, *direction_hash;
5933   int num_list_entries = 0;
5934   int num_unknown_tokens = 0;
5935   int i;
5936
5937   if (fileExists(filename))
5938     setup_file_list = loadSetupFileList(filename);
5939
5940   if (setup_file_list == NULL)
5941   {
5942     /* use reliable default values from static configuration */
5943     SetupFileList *insert_ptr;
5944
5945     insert_ptr = setup_file_list =
5946       newSetupFileList(helpanim_config[0].token,
5947                        helpanim_config[0].value);
5948
5949     for (i = 1; helpanim_config[i].token; i++)
5950       insert_ptr = addListEntry(insert_ptr,
5951                                 helpanim_config[i].token,
5952                                 helpanim_config[i].value);
5953   }
5954
5955   element_hash   = newSetupFileHash();
5956   action_hash    = newSetupFileHash();
5957   direction_hash = newSetupFileHash();
5958
5959   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
5960     setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
5961
5962   for (i = 0; i < NUM_ACTIONS; i++)
5963     setHashEntry(action_hash, element_action_info[i].suffix,
5964                  i_to_a(element_action_info[i].value));
5965
5966   /* do not store direction index (bit) here, but direction value! */
5967   for (i = 0; i < NUM_DIRECTIONS_FULL; i++)
5968     setHashEntry(direction_hash, element_direction_info[i].suffix,
5969                  i_to_a(1 << element_direction_info[i].value));
5970
5971   for (list = setup_file_list; list != NULL; list = list->next)
5972   {
5973     char *element_token, *action_token, *direction_token;
5974     char *element_value, *action_value, *direction_value;
5975     int delay = atoi(list->value);
5976
5977     if (strcmp(list->token, "end") == 0)
5978     {
5979       add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
5980
5981       continue;
5982     }
5983
5984     /* first try to break element into element/action/direction parts;
5985        if this does not work, also accept combined "element[.act][.dir]"
5986        elements (like "dynamite.active"), which are unique elements */
5987
5988     if (strchr(list->token, '.') == NULL)       /* token contains no '.' */
5989     {
5990       element_value = getHashEntry(element_hash, list->token);
5991       if (element_value != NULL)        /* element found */
5992         add_helpanim_entry(atoi(element_value), -1, -1, delay,
5993                            &num_list_entries);
5994       else
5995       {
5996         /* no further suffixes found -- this is not an element */
5997         print_unknown_token(filename, list->token, num_unknown_tokens++);
5998       }
5999
6000       continue;
6001     }
6002
6003     /* token has format "<prefix>.<something>" */
6004
6005     action_token = strchr(list->token, '.');    /* suffix may be action ... */
6006     direction_token = action_token;             /* ... or direction */
6007
6008     element_token = getStringCopy(list->token);
6009     *strchr(element_token, '.') = '\0';
6010
6011     element_value = getHashEntry(element_hash, element_token);
6012
6013     if (element_value == NULL)          /* this is no element */
6014     {
6015       element_value = getHashEntry(element_hash, list->token);
6016       if (element_value != NULL)        /* combined element found */
6017         add_helpanim_entry(atoi(element_value), -1, -1, delay,
6018                            &num_list_entries);
6019       else
6020         print_unknown_token(filename, list->token, num_unknown_tokens++);
6021
6022       free(element_token);
6023
6024       continue;
6025     }
6026
6027     action_value = getHashEntry(action_hash, action_token);
6028
6029     if (action_value != NULL)           /* action found */
6030     {
6031       add_helpanim_entry(atoi(element_value), atoi(action_value), -1, delay,
6032                     &num_list_entries);
6033
6034       free(element_token);
6035
6036       continue;
6037     }
6038
6039     direction_value = getHashEntry(direction_hash, direction_token);
6040
6041     if (direction_value != NULL)        /* direction found */
6042     {
6043       add_helpanim_entry(atoi(element_value), -1, atoi(direction_value), delay,
6044                          &num_list_entries);
6045
6046       free(element_token);
6047
6048       continue;
6049     }
6050
6051     if (strchr(action_token + 1, '.') == NULL)
6052     {
6053       /* no further suffixes found -- this is not an action nor direction */
6054
6055       element_value = getHashEntry(element_hash, list->token);
6056       if (element_value != NULL)        /* combined element found */
6057         add_helpanim_entry(atoi(element_value), -1, -1, delay,
6058                            &num_list_entries);
6059       else
6060         print_unknown_token(filename, list->token, num_unknown_tokens++);
6061
6062       free(element_token);
6063
6064       continue;
6065     }
6066
6067     /* token has format "<prefix>.<suffix>.<something>" */
6068
6069     direction_token = strchr(action_token + 1, '.');
6070
6071     action_token = getStringCopy(action_token);
6072     *strchr(action_token + 1, '.') = '\0';
6073
6074     action_value = getHashEntry(action_hash, action_token);
6075
6076     if (action_value == NULL)           /* this is no action */
6077     {
6078       element_value = getHashEntry(element_hash, list->token);
6079       if (element_value != NULL)        /* combined element found */
6080         add_helpanim_entry(atoi(element_value), -1, -1, delay,
6081                            &num_list_entries);
6082       else
6083         print_unknown_token(filename, list->token, num_unknown_tokens++);
6084
6085       free(element_token);
6086       free(action_token);
6087
6088       continue;
6089     }
6090
6091     direction_value = getHashEntry(direction_hash, direction_token);
6092
6093     if (direction_value != NULL)        /* direction found */
6094     {
6095       add_helpanim_entry(atoi(element_value), atoi(action_value),
6096                          atoi(direction_value), delay, &num_list_entries);
6097
6098       free(element_token);
6099       free(action_token);
6100
6101       continue;
6102     }
6103
6104     /* this is no direction */
6105
6106     element_value = getHashEntry(element_hash, list->token);
6107     if (element_value != NULL)          /* combined element found */
6108       add_helpanim_entry(atoi(element_value), -1, -1, delay,
6109                          &num_list_entries);
6110     else
6111       print_unknown_token(filename, list->token, num_unknown_tokens++);
6112
6113     free(element_token);
6114     free(action_token);
6115   }
6116
6117   print_unknown_token_end(num_unknown_tokens);
6118
6119   add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
6120   add_helpanim_entry(HELPANIM_LIST_END,  -1, -1, -1, &num_list_entries);
6121
6122   freeSetupFileList(setup_file_list);
6123   freeSetupFileHash(element_hash);
6124   freeSetupFileHash(action_hash);
6125   freeSetupFileHash(direction_hash);
6126
6127 #if 0
6128   for (i = 0; i < num_list_entries; i++)
6129     printf("::: '%s': %d, %d, %d => %d\n",
6130            EL_NAME(helpanim_info[i].element),
6131            helpanim_info[i].element,
6132            helpanim_info[i].action,
6133            helpanim_info[i].direction,
6134            helpanim_info[i].delay);
6135 #endif
6136 }
6137
6138 void LoadHelpTextInfo()
6139 {
6140   char *filename = getHelpTextFilename();
6141   int i;
6142
6143   if (helptext_info != NULL)
6144   {
6145     freeSetupFileHash(helptext_info);
6146     helptext_info = NULL;
6147   }
6148
6149   if (fileExists(filename))
6150     helptext_info = loadSetupFileHash(filename);
6151
6152   if (helptext_info == NULL)
6153   {
6154     /* use reliable default values from static configuration */
6155     helptext_info = newSetupFileHash();
6156
6157     for (i = 0; helptext_config[i].token; i++)
6158       setHashEntry(helptext_info,
6159                    helptext_config[i].token,
6160                    helptext_config[i].value);
6161   }
6162
6163 #if 0
6164   BEGIN_HASH_ITERATION(helptext_info, itr)
6165   {
6166     printf("::: '%s' => '%s'\n",
6167            HASH_ITERATION_TOKEN(itr), HASH_ITERATION_VALUE(itr));
6168   }
6169   END_HASH_ITERATION(hash, itr)
6170 #endif
6171 }
6172
6173
6174 /* ------------------------------------------------------------------------- *
6175  * convert levels
6176  * ------------------------------------------------------------------------- */
6177
6178 #define MAX_NUM_CONVERT_LEVELS          1000
6179
6180 void ConvertLevels()
6181 {
6182   static LevelDirTree *convert_leveldir = NULL;
6183   static int convert_level_nr = -1;
6184   static int num_levels_handled = 0;
6185   static int num_levels_converted = 0;
6186   static boolean levels_failed[MAX_NUM_CONVERT_LEVELS];
6187   int i;
6188
6189   convert_leveldir = getTreeInfoFromIdentifier(leveldir_first,
6190                                                global.convert_leveldir);
6191
6192   if (convert_leveldir == NULL)
6193     Error(ERR_EXIT, "no such level identifier: '%s'",
6194           global.convert_leveldir);
6195
6196   leveldir_current = convert_leveldir;
6197
6198   if (global.convert_level_nr != -1)
6199   {
6200     convert_leveldir->first_level = global.convert_level_nr;
6201     convert_leveldir->last_level  = global.convert_level_nr;
6202   }
6203
6204   convert_level_nr = convert_leveldir->first_level;
6205
6206   printf_line("=", 79);
6207   printf("Converting levels\n");
6208   printf_line("-", 79);
6209   printf("Level series identifier: '%s'\n", convert_leveldir->identifier);
6210   printf("Level series name:       '%s'\n", convert_leveldir->name);
6211   printf("Level series author:     '%s'\n", convert_leveldir->author);
6212   printf("Number of levels:        %d\n",   convert_leveldir->levels);
6213   printf_line("=", 79);
6214   printf("\n");
6215
6216   for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++)
6217     levels_failed[i] = FALSE;
6218
6219   while (convert_level_nr <= convert_leveldir->last_level)
6220   {
6221     char *level_filename;
6222     boolean new_level;
6223
6224     level_nr = convert_level_nr++;
6225
6226     printf("Level %03d: ", level_nr);
6227
6228     LoadLevel(level_nr);
6229     if (level.no_valid_file)
6230     {
6231       printf("(no level)\n");
6232       continue;
6233     }
6234
6235     printf("converting level ... ");
6236
6237     level_filename = getDefaultLevelFilename(level_nr);
6238     new_level = !fileExists(level_filename);
6239
6240     if (new_level)
6241     {
6242       SaveLevel(level_nr);
6243
6244       num_levels_converted++;
6245
6246       printf("converted.\n");
6247     }
6248     else
6249     {
6250       if (level_nr >= 0 && level_nr < MAX_NUM_CONVERT_LEVELS)
6251         levels_failed[level_nr] = TRUE;
6252
6253       printf("NOT CONVERTED -- LEVEL ALREADY EXISTS.\n");
6254     }
6255
6256     num_levels_handled++;
6257   }
6258
6259   printf("\n");
6260   printf_line("=", 79);
6261   printf("Number of levels handled: %d\n", num_levels_handled);
6262   printf("Number of levels converted: %d (%d%%)\n", num_levels_converted,
6263          (num_levels_handled ?
6264           num_levels_converted * 100 / num_levels_handled : 0));
6265   printf_line("-", 79);
6266   printf("Summary (for automatic parsing by scripts):\n");
6267   printf("LEVELDIR '%s', CONVERTED %d/%d (%d%%)",
6268          convert_leveldir->identifier, num_levels_converted,
6269          num_levels_handled,
6270          (num_levels_handled ?
6271           num_levels_converted * 100 / num_levels_handled : 0));
6272
6273   if (num_levels_handled != num_levels_converted)
6274   {
6275     printf(", FAILED:");
6276     for (i = 0; i < MAX_NUM_CONVERT_LEVELS; i++)
6277       if (levels_failed[i])
6278         printf(" %03d", i);
6279   }
6280
6281   printf("\n");
6282   printf_line("=", 79);
6283
6284   CloseAllAndExit(0);
6285 }