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