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