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