rnd-20040130-1-src
[rocksndiamonds.git] / src / files.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * files.c                                                  *
12 ***********************************************************/
13
14 #include <ctype.h>
15 #include <sys/stat.h>
16 #include <dirent.h>
17 #include <math.h>
18
19 #include "libgame/libgame.h"
20
21 #include "files.h"
22 #include "init.h"
23 #include "tools.h"
24 #include "tape.h"
25
26
27 #define CHUNK_ID_LEN            4       /* IFF style chunk id length  */
28 #define CHUNK_SIZE_UNDEFINED    0       /* undefined chunk size == 0  */
29 #define CHUNK_SIZE_NONE         -1      /* do not write chunk size    */
30 #define FILE_VERS_CHUNK_SIZE    8       /* size of file version chunk */
31 #define LEVEL_HEADER_SIZE       80      /* size of level file header  */
32 #define LEVEL_HEADER_UNUSED     11      /* 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) (48 + 48 + (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 level file type identifier */
53 #define LEVEL_FILE_TYPE_UNKNOWN         0
54 #define LEVEL_FILE_TYPE_RND             1
55 #define LEVEL_FILE_TYPE_BD              2
56 #define LEVEL_FILE_TYPE_EM              3
57 #define LEVEL_FILE_TYPE_SP              4
58 #define LEVEL_FILE_TYPE_DX              5
59 #define LEVEL_FILE_TYPE_SB              6
60 #define LEVEL_FILE_TYPE_DC              7
61
62 #define LEVEL_FILE_TYPE_RND_PACKED      (10 + LEVEL_FILE_TYPE_RND)
63 #define LEVEL_FILE_TYPE_EM_PACKED       (10 + LEVEL_FILE_TYPE_EM)
64
65 #define IS_SINGLE_LEVEL_FILE(x)         (x < 10)
66 #define IS_PACKED_LEVEL_FILE(x)         (x > 10)
67
68
69 /* ========================================================================= */
70 /* level file functions                                                      */
71 /* ========================================================================= */
72
73 void setElementChangePages(struct ElementInfo *ei, int change_pages)
74 {
75   int change_page_size = sizeof(struct ElementChangeInfo);
76
77   ei->num_change_pages = MAX(1, change_pages);
78
79   ei->change_page =
80     checked_realloc(ei->change_page, ei->num_change_pages * change_page_size);
81
82   if (ei->current_change_page >= ei->num_change_pages)
83     ei->current_change_page = ei->num_change_pages - 1;
84
85   ei->change = &ei->change_page[ei->current_change_page];
86 }
87
88 void setElementChangeInfoToDefaults(struct ElementChangeInfo *change)
89 {
90   int x, y;
91
92   change->can_change = FALSE;
93
94   change->events = CE_BITMASK_DEFAULT;
95   change->sides = CH_SIDE_ANY;
96
97   change->target_element = EL_EMPTY_SPACE;
98
99   change->delay_fixed = 0;
100   change->delay_random = 0;
101   change->delay_frames = 1;
102
103   change->trigger_element = EL_EMPTY_SPACE;
104
105   change->explode = FALSE;
106   change->use_content = FALSE;
107   change->only_complete = FALSE;
108   change->use_random_change = FALSE;
109   change->random = 100;
110   change->power = CP_NON_DESTRUCTIVE;
111
112   for (x = 0; x < 3; x++)
113     for (y = 0; y < 3; y++)
114       change->content[x][y] = EL_EMPTY_SPACE;
115
116   change->direct_action = 0;
117   change->other_action = 0;
118
119   change->pre_change_function = NULL;
120   change->change_function = NULL;
121   change->post_change_function = NULL;
122 }
123
124 static void setLevelInfoToDefaults(struct LevelInfo *level)
125 {
126   int i, j, x, y;
127
128   level->file_version = FILE_VERSION_ACTUAL;
129   level->game_version = GAME_VERSION_ACTUAL;
130
131   level->encoding_16bit_field  = FALSE; /* default: only 8-bit elements */
132   level->encoding_16bit_yamyam = FALSE; /* default: only 8-bit elements */
133   level->encoding_16bit_amoeba = FALSE; /* default: only 8-bit elements */
134
135   level->fieldx = STD_LEV_FIELDX;
136   level->fieldy = STD_LEV_FIELDY;
137
138   for (x = 0; x < MAX_LEV_FIELDX; x++)
139     for (y = 0; y < MAX_LEV_FIELDY; y++)
140       level->field[x][y] = EL_SAND;
141
142   level->time = 100;
143   level->gems_needed = 0;
144   level->amoeba_speed = 10;
145   level->time_magic_wall = 10;
146   level->time_wheel = 10;
147   level->time_light = 10;
148   level->time_timegate = 10;
149   level->amoeba_content = EL_DIAMOND;
150   level->double_speed = FALSE;
151   level->initial_gravity = FALSE;
152   level->em_slippery_gems = FALSE;
153   level->block_last_field = FALSE;
154   level->sp_block_last_field = TRUE;
155
156   level->use_custom_template = FALSE;
157
158   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
159     level->name[i] = '\0';
160   for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
161     level->author[i] = '\0';
162
163   strcpy(level->name, NAMELESS_LEVEL_NAME);
164   strcpy(level->author, ANONYMOUS_NAME);
165
166   for (i = 0; i < 4; i++)
167   {
168     level->envelope_text[i][0] = '\0';
169     level->envelope_xsize[i] = MAX_ENVELOPE_XSIZE;
170     level->envelope_ysize[i] = MAX_ENVELOPE_YSIZE;
171   }
172
173   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
174     level->score[i] = 10;
175
176   level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
177   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
178     for (x = 0; x < 3; x++)
179       for (y = 0; y < 3; y++)
180         level->yamyam_content[i][x][y] =
181           (i < STD_ELEMENT_CONTENTS ? EL_ROCK : EL_EMPTY);
182
183   level->field[0][0] = EL_PLAYER_1;
184   level->field[STD_LEV_FIELDX - 1][STD_LEV_FIELDY - 1] = EL_EXIT_CLOSED;
185
186   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
187   {
188     int element = i;
189
190     setElementChangePages(&element_info[element], 1);
191     setElementChangeInfoToDefaults(element_info[element].change);
192
193     if (IS_CUSTOM_ELEMENT(element) || IS_GROUP_ELEMENT(element))
194     {
195       for (j = 0; j < MAX_ELEMENT_NAME_LEN + 1; j++)
196         element_info[element].description[j] = '\0';
197
198       if (element_info[element].custom_description != NULL)
199         strncpy(element_info[element].description,
200                 element_info[element].custom_description,MAX_ELEMENT_NAME_LEN);
201       else
202         strcpy(element_info[element].description,
203                element_info[element].editor_description);
204
205       element_info[element].use_gfx_element = FALSE;
206       element_info[element].gfx_element = EL_EMPTY_SPACE;
207     }
208
209     if (IS_CUSTOM_ELEMENT(element))
210     {
211       element_info[element].collect_score = 10;         /* special default */
212       element_info[element].collect_count = 1;          /* special default */
213
214       element_info[element].push_delay_fixed = -1;      /* initialize later */
215       element_info[element].push_delay_random = -1;     /* initialize later */
216       element_info[element].move_delay_fixed = 0;
217       element_info[element].move_delay_random = 0;
218
219       element_info[element].move_pattern = MV_ALL_DIRECTIONS;
220       element_info[element].move_direction_initial = MV_AUTOMATIC;
221       element_info[element].move_stepsize = TILEX / 8;
222       element_info[element].move_enter_element = EL_EMPTY_SPACE;
223       element_info[element].move_leave_element = EL_EMPTY_SPACE;
224       element_info[element].move_leave_type = LEAVE_TYPE_UNLIMITED;
225
226       element_info[element].slippery_type = SLIPPERY_ANY_RANDOM;
227
228       for (x = 0; x < 3; x++)
229         for (y = 0; y < 3; y++)
230           element_info[element].content[x][y] = EL_EMPTY_SPACE;
231
232       element_info[element].access_type = 0;
233       element_info[element].access_layer = 0;
234       element_info[element].walk_to_action = 0;
235       element_info[element].smash_targets = 0;
236       element_info[element].deadliness = 0;
237       element_info[element].consistency = 0;
238
239       element_info[element].can_explode_by_fire = FALSE;
240       element_info[element].can_explode_smashed = FALSE;
241       element_info[element].can_explode_impact = FALSE;
242
243       element_info[element].current_change_page = 0;
244
245       /* start with no properties at all */
246       for (j = 0; j < NUM_EP_BITFIELDS; j++)
247         Properties[element][j] = EP_BITMASK_DEFAULT;
248
249       element_info[element].modified_settings = FALSE;
250     }
251     else if (IS_GROUP_ELEMENT(element) || element == EL_INTERNAL_EDITOR)
252     {
253       /* initialize memory for list of elements in group */
254       if (element_info[element].group == NULL)
255         element_info[element].group =
256           checked_malloc(sizeof(struct ElementGroupInfo));
257
258       for (j = 0; j < MAX_ELEMENTS_IN_GROUP; j++)
259         element_info[element].group->element[j] = EL_EMPTY_SPACE;
260
261       /* default: only one element in group */
262       element_info[element].group->num_elements = 1;
263
264       element_info[element].group->choice_mode = ANIM_RANDOM;
265     }
266   }
267
268   BorderElement = EL_STEELWALL;
269
270   level->no_level_file = FALSE;
271
272   if (leveldir_current == NULL)         /* only when dumping level */
273     return;
274
275   /* try to determine better author name than 'anonymous' */
276   if (strcmp(leveldir_current->author, ANONYMOUS_NAME) != 0)
277   {
278     strncpy(level->author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN);
279     level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
280   }
281   else
282   {
283     switch (LEVELCLASS(leveldir_current))
284     {
285       case LEVELCLASS_TUTORIAL:
286         strcpy(level->author, PROGRAM_AUTHOR_STRING);
287         break;
288
289       case LEVELCLASS_CONTRIB:
290         strncpy(level->author, leveldir_current->name, MAX_LEVEL_AUTHOR_LEN);
291         level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
292         break;
293
294       case LEVELCLASS_PRIVATE:
295         strncpy(level->author, getRealName(), MAX_LEVEL_AUTHOR_LEN);
296         level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
297         break;
298
299       default:
300         /* keep default value */
301         break;
302     }
303   }
304 }
305
306 static void setFileInfoToDefaults(struct LevelFileInfo *level_file_info)
307 {
308   level_file_info->nr = 0;
309   level_file_info->type = LEVEL_FILE_TYPE_UNKNOWN;
310   level_file_info->packed = FALSE;
311   level_file_info->basename = NULL;
312   level_file_info->filename = NULL;
313 }
314
315 static void ActivateLevelTemplate()
316 {
317   /* Currently there is no special action needed to activate the template
318      data, because 'element_info' and 'Properties' overwrite the original
319      level data, while all other variables do not change. */
320 }
321
322 static char *getLevelFilenameFromBasename(char *basename)
323 {
324   static char *filename = NULL;
325
326   checked_free(filename);
327
328   filename = getPath2(getCurrentLevelDir(), basename);
329
330   return filename;
331 }
332
333 static int getFileTypeFromBasename(char *basename)
334 {
335   static char *filename = NULL;
336   struct stat file_status;
337
338   /* ---------- try to determine file type from filename ---------- */
339
340   /* check for typical filename of a Supaplex level package file */
341   if (strlen(basename) == 10 && (strncmp(basename, "levels.d", 8) == 0 ||
342                                  strncmp(basename, "LEVELS.D", 8) == 0))
343     return LEVEL_FILE_TYPE_SP;
344
345   /* ---------- try to determine file type from filesize ---------- */
346
347   checked_free(filename);
348   filename = getPath2(getCurrentLevelDir(), basename);
349
350   if (stat(filename, &file_status) == 0)
351   {
352     /* check for typical filesize of a Supaplex level package file */
353     if (file_status.st_size == 170496)
354       return LEVEL_FILE_TYPE_SP;
355   }
356
357   return LEVEL_FILE_TYPE_UNKNOWN;
358 }
359
360 static char *getSingleLevelBasename(int nr, int type)
361 {
362   static char basename[MAX_FILENAME_LEN];
363   char *level_filename = getStringCopy(leveldir_current->level_filename);
364
365   if (level_filename == NULL)
366     level_filename = getStringCat2("%03d.", LEVELFILE_EXTENSION);
367
368   switch (type)
369   {
370     case LEVEL_FILE_TYPE_RND:
371       if (nr < 0)
372         sprintf(basename, "template.%s", LEVELFILE_EXTENSION);
373       else
374         sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION);
375       break;
376
377     case LEVEL_FILE_TYPE_EM:
378       sprintf(basename, "%d", nr);
379       break;
380
381     case LEVEL_FILE_TYPE_UNKNOWN:
382     default:
383       sprintf(basename, level_filename, nr);
384       break;
385   }
386
387   free(level_filename);
388
389   return basename;
390 }
391
392 static char *getPackedLevelBasename(int type)
393 {
394   static char basename[MAX_FILENAME_LEN];
395   char *directory = getCurrentLevelDir();
396   DIR *dir;
397   struct dirent *dir_entry;
398
399   strcpy(basename, UNDEFINED_FILENAME);         /* default: undefined file */
400
401   if ((dir = opendir(directory)) == NULL)
402   {
403     Error(ERR_WARN, "cannot read current level directory '%s'", directory);
404
405     return basename;
406   }
407
408   while ((dir_entry = readdir(dir)) != NULL)    /* loop until last dir entry */
409   {
410     char *entry_basename = dir_entry->d_name;
411     int entry_type = getFileTypeFromBasename(entry_basename);
412
413     if (entry_type != LEVEL_FILE_TYPE_UNKNOWN)  /* found valid level package */
414     {
415       if (type == LEVEL_FILE_TYPE_UNKNOWN ||
416           type == entry_type)
417       {
418         strcpy(basename, entry_basename);
419
420         break;
421       }
422     }
423   }
424
425   closedir(dir);
426
427   return basename;
428 }
429
430 static char *getSingleLevelFilename(int nr, int type)
431 {
432   return getLevelFilenameFromBasename(getSingleLevelBasename(nr, type));
433 }
434
435 #if 0
436 static char *getPackedLevelFilename(int type)
437 {
438   return getLevelFilenameFromBasename(getPackedLevelBasename(type));
439 }
440 #endif
441
442 char *getDefaultLevelFilename(int nr)
443 {
444   return getSingleLevelFilename(nr, LEVEL_FILE_TYPE_RND);
445 }
446
447 static void setLevelFileInfo_SingleLevelFilename(struct LevelFileInfo *lfi,
448                                                  int type)
449 {
450   lfi->type = type;
451   lfi->packed = FALSE;
452   lfi->basename = getSingleLevelBasename(lfi->nr, lfi->type);
453   lfi->filename = getLevelFilenameFromBasename(lfi->basename);
454 }
455
456 static void setLevelFileInfo_PackedLevelFilename(struct LevelFileInfo *lfi,
457                                                  int type)
458 {
459   lfi->type = type;
460   lfi->packed = TRUE;
461   lfi->basename = getPackedLevelBasename(lfi->type);
462   lfi->filename = getLevelFilenameFromBasename(lfi->basename);
463 }
464
465 static void determineLevelFileInfo_Filename(struct LevelFileInfo *lfi)
466 {
467   /* special case: level number is negative => check for level template file */
468   if (lfi->nr < 0)
469   {
470     setLevelFileInfo_SingleLevelFilename(lfi, LEVEL_FILE_TYPE_RND);
471
472     return;
473   }
474
475   if (leveldir_current->level_filename != NULL)
476   {
477     /* check for file name/pattern specified in "levelinfo.conf" */
478     setLevelFileInfo_SingleLevelFilename(lfi, LEVEL_FILE_TYPE_UNKNOWN);
479     if (fileExists(lfi->filename))
480       return;
481   }
482
483   /* check for native Rocks'n'Diamonds level file */
484   setLevelFileInfo_SingleLevelFilename(lfi, LEVEL_FILE_TYPE_RND);
485   if (fileExists(lfi->filename))
486     return;
487
488   /* check for classic Emerald Mine level file */
489   setLevelFileInfo_SingleLevelFilename(lfi, LEVEL_FILE_TYPE_EM);
490   if (fileExists(lfi->filename))
491     return;
492
493   /* check for various packed level file formats */
494   setLevelFileInfo_PackedLevelFilename(lfi, LEVEL_FILE_TYPE_UNKNOWN);
495   if (fileExists(lfi->filename))
496     return;
497
498   /* no known level file found -- try to use default values */
499   setLevelFileInfo_SingleLevelFilename(lfi, LEVEL_FILE_TYPE_UNKNOWN);
500 }
501
502 static void determineLevelFileInfo_Filetype(struct LevelFileInfo *lfi)
503 {
504   if (lfi->type == LEVEL_FILE_TYPE_UNKNOWN)
505     lfi->type = getFileTypeFromBasename(lfi->basename);
506 }
507
508 static struct LevelFileInfo *getLevelFileInfo(int nr)
509 {
510   static struct LevelFileInfo level_file_info;
511
512   /* always start with reliable default values */
513   setFileInfoToDefaults(&level_file_info);
514
515   level_file_info.nr = nr;      /* set requested level number */
516
517   determineLevelFileInfo_Filename(&level_file_info);
518   determineLevelFileInfo_Filetype(&level_file_info);
519
520   return &level_file_info;
521 }
522
523
524 /* ------------------------------------------------------------------------- */
525 /* functions for loading R'n'D level                                         */
526 /* ------------------------------------------------------------------------- */
527
528 int getMappedElement(int element)
529 {
530   /* map some (historic, now obsolete) elements */
531
532 #if 1
533   switch (element)
534   {
535     case EL_PLAYER_OBSOLETE:
536       element = EL_PLAYER_1;
537       break;
538
539     case EL_KEY_OBSOLETE:
540       element = EL_KEY_1;
541
542     case EL_EM_KEY_1_FILE_OBSOLETE:
543       element = EL_EM_KEY_1;
544       break;
545
546     case EL_EM_KEY_2_FILE_OBSOLETE:
547       element = EL_EM_KEY_2;
548       break;
549
550     case EL_EM_KEY_3_FILE_OBSOLETE:
551       element = EL_EM_KEY_3;
552       break;
553
554     case EL_EM_KEY_4_FILE_OBSOLETE:
555       element = EL_EM_KEY_4;
556       break;
557
558     case EL_ENVELOPE_OBSOLETE:
559       element = EL_ENVELOPE_1;
560       break;
561
562     case EL_SP_EMPTY:
563       element = EL_EMPTY;
564       break;
565
566     default:
567       if (element >= NUM_FILE_ELEMENTS)
568       {
569         Error(ERR_WARN, "invalid level element %d", element);
570
571         element = EL_CHAR_QUESTION;
572       }
573       break;
574   }
575 #else
576   if (element >= NUM_FILE_ELEMENTS)
577   {
578     Error(ERR_WARN, "invalid level element %d", element);
579
580     element = EL_CHAR_QUESTION;
581   }
582   else if (element == EL_PLAYER_OBSOLETE)
583     element = EL_PLAYER_1;
584   else if (element == EL_KEY_OBSOLETE)
585     element = EL_KEY_1;
586 #endif
587
588   return element;
589 }
590
591 static int LoadLevel_VERS(FILE *file, int chunk_size, struct LevelInfo *level)
592 {
593   level->file_version = getFileVersion(file);
594   level->game_version = getFileVersion(file);
595
596   return chunk_size;
597 }
598
599 static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
600 {
601   int i, x, y;
602
603   level->fieldx = getFile8Bit(file);
604   level->fieldy = getFile8Bit(file);
605
606   level->time           = getFile16BitBE(file);
607   level->gems_needed    = getFile16BitBE(file);
608
609   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
610     level->name[i] = getFile8Bit(file);
611   level->name[MAX_LEVEL_NAME_LEN] = 0;
612
613   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
614     level->score[i] = getFile8Bit(file);
615
616   level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
617   for (i = 0; i < STD_ELEMENT_CONTENTS; i++)
618     for (y = 0; y < 3; y++)
619       for (x = 0; x < 3; x++)
620         level->yamyam_content[i][x][y] = getMappedElement(getFile8Bit(file));
621
622   level->amoeba_speed           = getFile8Bit(file);
623   level->time_magic_wall        = getFile8Bit(file);
624   level->time_wheel             = getFile8Bit(file);
625   level->amoeba_content         = getMappedElement(getFile8Bit(file));
626   level->double_speed           = (getFile8Bit(file) == 1 ? TRUE : FALSE);
627   level->initial_gravity        = (getFile8Bit(file) == 1 ? TRUE : FALSE);
628   level->encoding_16bit_field   = (getFile8Bit(file) == 1 ? TRUE : FALSE);
629   level->em_slippery_gems       = (getFile8Bit(file) == 1 ? TRUE : FALSE);
630   level->block_last_field       = (getFile8Bit(file) == 1 ? TRUE : FALSE);
631   level->sp_block_last_field    = (getFile8Bit(file) == 1 ? TRUE : FALSE);
632
633   level->use_custom_template    = (getFile8Bit(file) == 1 ? TRUE : FALSE);
634
635   ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED);
636
637   return chunk_size;
638 }
639
640 static int LoadLevel_AUTH(FILE *file, int chunk_size, struct LevelInfo *level)
641 {
642   int i;
643
644   for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
645     level->author[i] = getFile8Bit(file);
646   level->author[MAX_LEVEL_NAME_LEN] = 0;
647
648   return chunk_size;
649 }
650
651 static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level)
652 {
653   int x, y;
654   int chunk_size_expected = level->fieldx * level->fieldy;
655
656   /* Note: "chunk_size" was wrong before version 2.0 when elements are
657      stored with 16-bit encoding (and should be twice as big then).
658      Even worse, playfield data was stored 16-bit when only yamyam content
659      contained 16-bit elements and vice versa. */
660
661   if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
662     chunk_size_expected *= 2;
663
664   if (chunk_size_expected != chunk_size)
665   {
666     ReadUnusedBytesFromFile(file, chunk_size);
667     return chunk_size_expected;
668   }
669
670   for (y = 0; y < level->fieldy; y++)
671     for (x = 0; x < level->fieldx; x++)
672       level->field[x][y] =
673         getMappedElement(level->encoding_16bit_field ? getFile16BitBE(file) :
674                          getFile8Bit(file));
675   return chunk_size;
676 }
677
678 static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
679 {
680   int i, x, y;
681   int header_size = 4;
682   int content_size = MAX_ELEMENT_CONTENTS * 3 * 3;
683   int chunk_size_expected = header_size + content_size;
684
685   /* Note: "chunk_size" was wrong before version 2.0 when elements are
686      stored with 16-bit encoding (and should be twice as big then).
687      Even worse, playfield data was stored 16-bit when only yamyam content
688      contained 16-bit elements and vice versa. */
689
690   if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
691     chunk_size_expected += content_size;
692
693   if (chunk_size_expected != chunk_size)
694   {
695     ReadUnusedBytesFromFile(file, chunk_size);
696     return chunk_size_expected;
697   }
698
699   getFile8Bit(file);
700   level->num_yamyam_contents = getFile8Bit(file);
701   getFile8Bit(file);
702   getFile8Bit(file);
703
704   /* correct invalid number of content fields -- should never happen */
705   if (level->num_yamyam_contents < 1 ||
706       level->num_yamyam_contents > MAX_ELEMENT_CONTENTS)
707     level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
708
709   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
710     for (y = 0; y < 3; y++)
711       for (x = 0; x < 3; x++)
712         level->yamyam_content[i][x][y] =
713           getMappedElement(level->encoding_16bit_field ?
714                            getFile16BitBE(file) : getFile8Bit(file));
715   return chunk_size;
716 }
717
718 static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
719 {
720   int i, x, y;
721   int element;
722   int num_contents, content_xsize, content_ysize;
723   int content_array[MAX_ELEMENT_CONTENTS][3][3];
724
725   element = getMappedElement(getFile16BitBE(file));
726   num_contents = getFile8Bit(file);
727   content_xsize = getFile8Bit(file);
728   content_ysize = getFile8Bit(file);
729
730   ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED);
731
732   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
733     for (y = 0; y < 3; y++)
734       for (x = 0; x < 3; x++)
735         content_array[i][x][y] = getMappedElement(getFile16BitBE(file));
736
737   /* correct invalid number of content fields -- should never happen */
738   if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS)
739     num_contents = STD_ELEMENT_CONTENTS;
740
741   if (element == EL_YAMYAM)
742   {
743     level->num_yamyam_contents = num_contents;
744
745     for (i = 0; i < num_contents; i++)
746       for (y = 0; y < 3; y++)
747         for (x = 0; x < 3; x++)
748           level->yamyam_content[i][x][y] = content_array[i][x][y];
749   }
750   else if (element == EL_BD_AMOEBA)
751   {
752     level->amoeba_content = content_array[0][0][0];
753   }
754   else
755   {
756     Error(ERR_WARN, "cannot load content for element '%d'", element);
757   }
758
759   return chunk_size;
760 }
761
762 static int LoadLevel_CNT3(FILE *file, int chunk_size, struct LevelInfo *level)
763 {
764   int i;
765   int element;
766   int envelope_nr;
767   int envelope_len;
768   int chunk_size_expected;
769
770   element = getMappedElement(getFile16BitBE(file));
771   if (!IS_ENVELOPE(element))
772     element = EL_ENVELOPE_1;
773
774   envelope_nr = element - EL_ENVELOPE_1;
775
776   envelope_len = getFile16BitBE(file);
777
778   level->envelope_xsize[envelope_nr] = getFile8Bit(file);
779   level->envelope_ysize[envelope_nr] = getFile8Bit(file);
780
781   ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT3_UNUSED);
782
783   chunk_size_expected = LEVEL_CHUNK_CNT3_SIZE(envelope_len);
784   if (chunk_size_expected != chunk_size)
785   {
786     ReadUnusedBytesFromFile(file, chunk_size - LEVEL_CHUNK_CNT3_HEADER);
787     return chunk_size_expected;
788   }
789
790   for (i = 0; i < envelope_len; i++)
791     level->envelope_text[envelope_nr][i] = getFile8Bit(file);
792
793   return chunk_size;
794 }
795
796 static int LoadLevel_CUS1(FILE *file, int chunk_size, struct LevelInfo *level)
797 {
798   int num_changed_custom_elements = getFile16BitBE(file);
799   int chunk_size_expected = 2 + num_changed_custom_elements * 6;
800   int i;
801
802   if (chunk_size_expected != chunk_size)
803   {
804     ReadUnusedBytesFromFile(file, chunk_size - 2);
805     return chunk_size_expected;
806   }
807
808   for (i = 0; i < num_changed_custom_elements; i++)
809   {
810     int element = getFile16BitBE(file);
811     int properties = getFile32BitBE(file);
812
813     if (IS_CUSTOM_ELEMENT(element))
814       Properties[element][EP_BITFIELD_BASE] = properties;
815     else
816       Error(ERR_WARN, "invalid custom element number %d", element);
817   }
818
819   return chunk_size;
820 }
821
822 static int LoadLevel_CUS2(FILE *file, int chunk_size, struct LevelInfo *level)
823 {
824   int num_changed_custom_elements = getFile16BitBE(file);
825   int chunk_size_expected = 2 + num_changed_custom_elements * 4;
826   int i;
827
828   if (chunk_size_expected != chunk_size)
829   {
830     ReadUnusedBytesFromFile(file, chunk_size - 2);
831     return chunk_size_expected;
832   }
833
834   for (i = 0; i < num_changed_custom_elements; i++)
835   {
836     int element = getFile16BitBE(file);
837     int custom_target_element = getFile16BitBE(file);
838
839     if (IS_CUSTOM_ELEMENT(element))
840       element_info[element].change->target_element = custom_target_element;
841     else
842       Error(ERR_WARN, "invalid custom element number %d", element);
843   }
844
845   return chunk_size;
846 }
847
848 static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level)
849 {
850   int num_changed_custom_elements = getFile16BitBE(file);
851   int chunk_size_expected = LEVEL_CHUNK_CUS3_SIZE(num_changed_custom_elements);
852   int i, j, x, y;
853
854   if (chunk_size_expected != chunk_size)
855   {
856     ReadUnusedBytesFromFile(file, chunk_size - 2);
857     return chunk_size_expected;
858   }
859
860   for (i = 0; i < num_changed_custom_elements; i++)
861   {
862     int element = getFile16BitBE(file);
863
864     if (!IS_CUSTOM_ELEMENT(element))
865     {
866       Error(ERR_WARN, "invalid custom element number %d", element);
867
868       element = EL_INTERNAL_DUMMY;
869     }
870
871     for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++)
872       element_info[element].description[j] = getFile8Bit(file);
873     element_info[element].description[MAX_ELEMENT_NAME_LEN] = 0;
874
875     Properties[element][EP_BITFIELD_BASE] = getFile32BitBE(file);
876
877     /* some free bytes for future properties and padding */
878     ReadUnusedBytesFromFile(file, 7);
879
880     element_info[element].use_gfx_element = getFile8Bit(file);
881     element_info[element].gfx_element =
882       getMappedElement(getFile16BitBE(file));
883
884     element_info[element].collect_score = getFile8Bit(file);
885     element_info[element].collect_count = getFile8Bit(file);
886
887     element_info[element].push_delay_fixed = getFile16BitBE(file);
888     element_info[element].push_delay_random = getFile16BitBE(file);
889     element_info[element].move_delay_fixed = getFile16BitBE(file);
890     element_info[element].move_delay_random = getFile16BitBE(file);
891
892     element_info[element].move_pattern = getFile16BitBE(file);
893     element_info[element].move_direction_initial = getFile8Bit(file);
894     element_info[element].move_stepsize = getFile8Bit(file);
895
896     for (y = 0; y < 3; y++)
897       for (x = 0; x < 3; x++)
898         element_info[element].content[x][y] =
899           getMappedElement(getFile16BitBE(file));
900
901     element_info[element].change->events = getFile32BitBE(file);
902
903     element_info[element].change->target_element =
904       getMappedElement(getFile16BitBE(file));
905
906     element_info[element].change->delay_fixed = getFile16BitBE(file);
907     element_info[element].change->delay_random = getFile16BitBE(file);
908     element_info[element].change->delay_frames = getFile16BitBE(file);
909
910     element_info[element].change->trigger_element =
911       getMappedElement(getFile16BitBE(file));
912
913     element_info[element].change->explode = getFile8Bit(file);
914     element_info[element].change->use_content = getFile8Bit(file);
915     element_info[element].change->only_complete = getFile8Bit(file);
916     element_info[element].change->use_random_change = getFile8Bit(file);
917
918     element_info[element].change->random = getFile8Bit(file);
919     element_info[element].change->power = getFile8Bit(file);
920
921     for (y = 0; y < 3; y++)
922       for (x = 0; x < 3; x++)
923         element_info[element].change->content[x][y] =
924           getMappedElement(getFile16BitBE(file));
925
926     element_info[element].slippery_type = getFile8Bit(file);
927
928     /* some free bytes for future properties and padding */
929     ReadUnusedBytesFromFile(file, LEVEL_CPART_CUS3_UNUSED);
930
931     /* mark that this custom element has been modified */
932     element_info[element].modified_settings = TRUE;
933   }
934
935   return chunk_size;
936 }
937
938 static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level)
939 {
940   struct ElementInfo *ei;
941   int chunk_size_expected;
942   int element;
943   int i, x, y;
944
945   element = getFile16BitBE(file);
946
947   if (!IS_CUSTOM_ELEMENT(element))
948   {
949     Error(ERR_WARN, "invalid custom element number %d", element);
950
951     ReadUnusedBytesFromFile(file, chunk_size - 2);
952     return chunk_size;
953   }
954
955   ei = &element_info[element];
956
957   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
958     ei->description[i] = getFile8Bit(file);
959   ei->description[MAX_ELEMENT_NAME_LEN] = 0;
960
961   Properties[element][EP_BITFIELD_BASE] = getFile32BitBE(file);
962   ReadUnusedBytesFromFile(file, 4);     /* reserved for more base properties */
963
964   ei->num_change_pages = getFile8Bit(file);
965
966   /* some free bytes for future base property values and padding */
967   ReadUnusedBytesFromFile(file, 5);
968
969   chunk_size_expected = LEVEL_CHUNK_CUS4_SIZE(ei->num_change_pages);
970   if (chunk_size_expected != chunk_size)
971   {
972     ReadUnusedBytesFromFile(file, chunk_size - 48);
973     return chunk_size_expected;
974   }
975
976   /* read custom property values */
977
978   ei->use_gfx_element = getFile8Bit(file);
979   ei->gfx_element = getMappedElement(getFile16BitBE(file));
980
981   ei->collect_score = getFile8Bit(file);
982   ei->collect_count = getFile8Bit(file);
983
984   ei->push_delay_fixed = getFile16BitBE(file);
985   ei->push_delay_random = getFile16BitBE(file);
986   ei->move_delay_fixed = getFile16BitBE(file);
987   ei->move_delay_random = getFile16BitBE(file);
988
989   ei->move_pattern = getFile16BitBE(file);
990   ei->move_direction_initial = getFile8Bit(file);
991   ei->move_stepsize = getFile8Bit(file);
992
993   ei->slippery_type = getFile8Bit(file);
994
995   for (y = 0; y < 3; y++)
996     for (x = 0; x < 3; x++)
997       ei->content[x][y] = getMappedElement(getFile16BitBE(file));
998
999   ei->move_enter_element = getMappedElement(getFile16BitBE(file));
1000   ei->move_leave_element = getMappedElement(getFile16BitBE(file));
1001   ei->move_leave_type = getFile8Bit(file);
1002
1003   /* some free bytes for future custom property values and padding */
1004   ReadUnusedBytesFromFile(file, 7);
1005
1006   /* read change property values */
1007
1008   setElementChangePages(ei, ei->num_change_pages);
1009
1010   for (i = 0; i < ei->num_change_pages; i++)
1011   {
1012     struct ElementChangeInfo *change = &ei->change_page[i];
1013
1014     /* always start with reliable default values */
1015     setElementChangeInfoToDefaults(change);
1016
1017     change->events = getFile32BitBE(file);
1018
1019     change->target_element = getMappedElement(getFile16BitBE(file));
1020
1021     change->delay_fixed = getFile16BitBE(file);
1022     change->delay_random = getFile16BitBE(file);
1023     change->delay_frames = getFile16BitBE(file);
1024
1025     change->trigger_element = getMappedElement(getFile16BitBE(file));
1026
1027     change->explode = getFile8Bit(file);
1028     change->use_content = getFile8Bit(file);
1029     change->only_complete = getFile8Bit(file);
1030     change->use_random_change = getFile8Bit(file);
1031
1032     change->random = getFile8Bit(file);
1033     change->power = getFile8Bit(file);
1034
1035     for (y = 0; y < 3; y++)
1036       for (x = 0; x < 3; x++)
1037         change->content[x][y] = getMappedElement(getFile16BitBE(file));
1038
1039     change->can_change = getFile8Bit(file);
1040
1041     change->sides = getFile8Bit(file);
1042
1043     if (change->sides == CH_SIDE_NONE)  /* correct empty sides field */
1044       change->sides = CH_SIDE_ANY;
1045
1046     /* some free bytes for future change property values and padding */
1047     ReadUnusedBytesFromFile(file, 8);
1048   }
1049
1050   /* mark this custom element as modified */
1051   ei->modified_settings = TRUE;
1052
1053   return chunk_size;
1054 }
1055
1056 static int LoadLevel_GRP1(FILE *file, int chunk_size, struct LevelInfo *level)
1057 {
1058   struct ElementInfo *ei;
1059   struct ElementGroupInfo *group;
1060   int element;
1061   int i;
1062
1063   element = getFile16BitBE(file);
1064
1065   if (!IS_GROUP_ELEMENT(element))
1066   {
1067     Error(ERR_WARN, "invalid group element number %d", element);
1068
1069     ReadUnusedBytesFromFile(file, chunk_size - 2);
1070     return chunk_size;
1071   }
1072
1073   ei = &element_info[element];
1074
1075   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
1076     ei->description[i] = getFile8Bit(file);
1077   ei->description[MAX_ELEMENT_NAME_LEN] = 0;
1078
1079   group = element_info[element].group;
1080
1081   group->num_elements = getFile8Bit(file);
1082
1083   ei->use_gfx_element = getFile8Bit(file);
1084   ei->gfx_element = getMappedElement(getFile16BitBE(file));
1085
1086   group->choice_mode = getFile8Bit(file);
1087
1088   /* some free bytes for future values and padding */
1089   ReadUnusedBytesFromFile(file, 3);
1090
1091   for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
1092     group->element[i] = getMappedElement(getFile16BitBE(file));
1093
1094   /* mark this group element as modified */
1095   element_info[element].modified_settings = TRUE;
1096
1097   return chunk_size;
1098 }
1099
1100 static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
1101                                       struct LevelFileInfo *level_file_info)
1102 {
1103   char *filename = level_file_info->filename;
1104   char cookie[MAX_LINE_LEN];
1105   char chunk_name[CHUNK_ID_LEN + 1];
1106   int chunk_size;
1107   FILE *file;
1108
1109   if (!(file = fopen(filename, MODE_READ)))
1110   {
1111     level->no_level_file = TRUE;
1112
1113     if (level != &level_template)
1114       Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
1115
1116     return;
1117   }
1118
1119   getFileChunkBE(file, chunk_name, NULL);
1120   if (strcmp(chunk_name, "RND1") == 0)
1121   {
1122     getFile32BitBE(file);               /* not used */
1123
1124     getFileChunkBE(file, chunk_name, NULL);
1125     if (strcmp(chunk_name, "CAVE") != 0)
1126     {
1127       Error(ERR_WARN, "unknown format of level file '%s'", filename);
1128       fclose(file);
1129       return;
1130     }
1131   }
1132   else  /* check for pre-2.0 file format with cookie string */
1133   {
1134     strcpy(cookie, chunk_name);
1135     fgets(&cookie[4], MAX_LINE_LEN - 4, file);
1136     if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
1137       cookie[strlen(cookie) - 1] = '\0';
1138
1139     if (!checkCookieString(cookie, LEVEL_COOKIE_TMPL))
1140     {
1141       Error(ERR_WARN, "unknown format of level file '%s'", filename);
1142       fclose(file);
1143       return;
1144     }
1145
1146     if ((level->file_version = getFileVersionFromCookieString(cookie)) == -1)
1147     {
1148       Error(ERR_WARN, "unsupported version of level file '%s'", filename);
1149       fclose(file);
1150       return;
1151     }
1152
1153     /* pre-2.0 level files have no game version, so use file version here */
1154     level->game_version = level->file_version;
1155   }
1156
1157   if (level->file_version < FILE_VERSION_1_2)
1158   {
1159     /* level files from versions before 1.2.0 without chunk structure */
1160     LoadLevel_HEAD(file, LEVEL_HEADER_SIZE,             level);
1161     LoadLevel_BODY(file, level->fieldx * level->fieldy, level);
1162   }
1163   else
1164   {
1165     static struct
1166     {
1167       char *name;
1168       int size;
1169       int (*loader)(FILE *, int, struct LevelInfo *);
1170     }
1171     chunk_info[] =
1172     {
1173       { "VERS", FILE_VERS_CHUNK_SIZE,   LoadLevel_VERS },
1174       { "HEAD", LEVEL_HEADER_SIZE,      LoadLevel_HEAD },
1175       { "AUTH", MAX_LEVEL_AUTHOR_LEN,   LoadLevel_AUTH },
1176       { "BODY", -1,                     LoadLevel_BODY },
1177       { "CONT", -1,                     LoadLevel_CONT },
1178       { "CNT2", LEVEL_CHUNK_CNT2_SIZE,  LoadLevel_CNT2 },
1179       { "CNT3", -1,                     LoadLevel_CNT3 },
1180       { "CUS1", -1,                     LoadLevel_CUS1 },
1181       { "CUS2", -1,                     LoadLevel_CUS2 },
1182       { "CUS3", -1,                     LoadLevel_CUS3 },
1183       { "CUS4", -1,                     LoadLevel_CUS4 },
1184       { "GRP1", -1,                     LoadLevel_GRP1 },
1185       {  NULL,  0,                      NULL }
1186     };
1187
1188     while (getFileChunkBE(file, chunk_name, &chunk_size))
1189     {
1190       int i = 0;
1191
1192       while (chunk_info[i].name != NULL &&
1193              strcmp(chunk_name, chunk_info[i].name) != 0)
1194         i++;
1195
1196       if (chunk_info[i].name == NULL)
1197       {
1198         Error(ERR_WARN, "unknown chunk '%s' in level file '%s'",
1199               chunk_name, filename);
1200         ReadUnusedBytesFromFile(file, chunk_size);
1201       }
1202       else if (chunk_info[i].size != -1 &&
1203                chunk_info[i].size != chunk_size)
1204       {
1205         Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
1206               chunk_size, chunk_name, filename);
1207         ReadUnusedBytesFromFile(file, chunk_size);
1208       }
1209       else
1210       {
1211         /* call function to load this level chunk */
1212         int chunk_size_expected =
1213           (chunk_info[i].loader)(file, chunk_size, level);
1214
1215         /* the size of some chunks cannot be checked before reading other
1216            chunks first (like "HEAD" and "BODY") that contain some header
1217            information, so check them here */
1218         if (chunk_size_expected != chunk_size)
1219         {
1220           Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
1221                 chunk_size, chunk_name, filename);
1222         }
1223       }
1224     }
1225   }
1226
1227   fclose(file);
1228 }
1229
1230 /* ------------------------------------------------------------------------- */
1231 /* functions for loading EM level                                            */
1232 /* ------------------------------------------------------------------------- */
1233
1234 static int map_em_element_yam(int element)
1235 {
1236   switch (element)
1237   {
1238     case 0x00:  return EL_EMPTY;
1239     case 0x01:  return EL_EMERALD;
1240     case 0x02:  return EL_DIAMOND;
1241     case 0x03:  return EL_ROCK;
1242     case 0x04:  return EL_ROBOT;
1243     case 0x05:  return EL_SPACESHIP_UP;
1244     case 0x06:  return EL_BOMB;
1245     case 0x07:  return EL_BUG_UP;
1246     case 0x08:  return EL_AMOEBA_DROP;
1247     case 0x09:  return EL_NUT;
1248     case 0x0a:  return EL_YAMYAM;
1249     case 0x0b:  return EL_QUICKSAND_FULL;
1250     case 0x0c:  return EL_SAND;
1251     case 0x0d:  return EL_WALL_SLIPPERY;
1252     case 0x0e:  return EL_STEELWALL;
1253     case 0x0f:  return EL_WALL;
1254     case 0x10:  return EL_EM_KEY_1;
1255     case 0x11:  return EL_EM_KEY_2;
1256     case 0x12:  return EL_EM_KEY_4;
1257     case 0x13:  return EL_EM_KEY_3;
1258     case 0x14:  return EL_MAGIC_WALL;
1259     case 0x15:  return EL_ROBOT_WHEEL;
1260     case 0x16:  return EL_DYNAMITE;
1261
1262     case 0x17:  return EL_EM_KEY_1;                     /* EMC */
1263     case 0x18:  return EL_BUG_UP;                       /* EMC */
1264     case 0x1a:  return EL_DIAMOND;                      /* EMC */
1265     case 0x1b:  return EL_EMERALD;                      /* EMC */
1266     case 0x25:  return EL_NUT;                          /* EMC */
1267     case 0x80:  return EL_EMPTY;                        /* EMC */
1268     case 0x85:  return EL_EM_KEY_1;                     /* EMC */
1269     case 0x86:  return EL_EM_KEY_2;                     /* EMC */
1270     case 0x87:  return EL_EM_KEY_4;                     /* EMC */
1271     case 0x88:  return EL_EM_KEY_3;                     /* EMC */
1272     case 0x94:  return EL_QUICKSAND_EMPTY;              /* EMC */
1273     case 0x9a:  return EL_AMOEBA_WET;                   /* EMC */
1274     case 0xaf:  return EL_DYNAMITE;                     /* EMC */
1275     case 0xbd:  return EL_SAND;                         /* EMC */
1276
1277     default:
1278       Error(ERR_WARN, "invalid level element %d", element);
1279       return EL_CHAR_QUESTION;
1280   }
1281 }
1282
1283 static int map_em_element_field(int element)
1284 {
1285   if (element >= 0xc8 && element <= 0xe1)
1286     return EL_CHAR_A + (element - 0xc8);
1287   else if (element >= 0xe2 && element <= 0xeb)
1288     return EL_CHAR_0 + (element - 0xe2);
1289
1290   switch (element)
1291   {
1292     case 0x00:  return EL_ROCK;
1293     case 0x02:  return EL_DIAMOND;
1294     case 0x03:  return EL_DIAMOND;
1295     case 0x04:  return EL_ROBOT;
1296     case 0x05:  return EL_ROBOT;                        /* EMC */
1297     case 0x08:  return EL_SPACESHIP_UP;
1298     case 0x09:  return EL_SPACESHIP_RIGHT;
1299     case 0x0a:  return EL_SPACESHIP_DOWN;
1300     case 0x0b:  return EL_SPACESHIP_LEFT;
1301     case 0x0c:  return EL_SPACESHIP_UP;
1302     case 0x0d:  return EL_SPACESHIP_RIGHT;
1303     case 0x0e:  return EL_SPACESHIP_DOWN;
1304     case 0x0f:  return EL_SPACESHIP_LEFT;
1305     case 0x10:  return EL_BOMB;
1306     case 0x12:  return EL_EMERALD;
1307     case 0x13:  return EL_EMERALD;
1308     case 0x14:  return EL_BUG_UP;
1309     case 0x15:  return EL_BUG_RIGHT;
1310     case 0x16:  return EL_BUG_DOWN;
1311     case 0x17:  return EL_BUG_LEFT;
1312     case 0x18:  return EL_BUG_UP;
1313     case 0x19:  return EL_BUG_RIGHT;
1314     case 0x1a:  return EL_BUG_DOWN;
1315     case 0x1b:  return EL_BUG_LEFT;
1316     case 0x1c:  return EL_AMOEBA_DROP;
1317     case 0x20:  return EL_ROCK;
1318     case 0x24:  return EL_MAGIC_WALL;
1319     case 0x25:  return EL_NUT;
1320
1321       /* looks like magic wheel, but is _always_ activated */
1322     case 0x28:  return EL_ROBOT_WHEEL;                  /* EMC */
1323
1324     case 0x29:  return EL_YAMYAM;
1325     case 0x2a:  return EL_YAMYAM;
1326     case 0x2b:  return EL_YAMYAM;                       /* EMC */
1327     case 0x2c:  return EL_YAMYAM;                       /* EMC */
1328     case 0x2d:  return EL_QUICKSAND_FULL;
1329     case 0x39:  return EL_EXPANDABLE_WALL_HORIZONTAL;   /* EMC */
1330     case 0x3a:  return EL_EXPANDABLE_WALL_VERTICAL;     /* EMC */
1331     case 0x3b:  return EL_DYNAMITE_ACTIVE;
1332     case 0x3c:  return EL_DYNAMITE_ACTIVE;
1333     case 0x3d:  return EL_DYNAMITE_ACTIVE;
1334     case 0x3e:  return EL_DYNAMITE_ACTIVE;
1335     case 0x3f:  return EL_ACID_POOL_BOTTOM;
1336     case 0x40:  return EL_EXIT_OPEN;
1337     case 0x41:  return EL_EXIT_OPEN;
1338     case 0x42:  return EL_EXIT_OPEN;
1339     case 0x43:  return EL_BALLOON;
1340     case 0x4e:  return EL_INVISIBLE_WALL;
1341     case 0x65:  return EL_ACID;                         /* EMC */
1342     case 0x73:  return EL_SAND;                         /* EMC */
1343     case 0x74:  return EL_STEELWALL;
1344     case 0x7b:  return EL_ACID;
1345     case 0x80:  return EL_EMPTY;
1346     case 0x81:  return EL_WALL_SLIPPERY;
1347     case 0x82:  return EL_SAND;
1348     case 0x83:  return EL_STEELWALL;
1349     case 0x84:  return EL_WALL;
1350     case 0x85:  return EL_EM_KEY_1;
1351     case 0x86:  return EL_EM_KEY_2;
1352     case 0x87:  return EL_EM_KEY_4;
1353     case 0x88:  return EL_EM_KEY_3;
1354     case 0x89:  return EL_EM_GATE_1;
1355     case 0x8a:  return EL_EM_GATE_2;
1356     case 0x8b:  return EL_EM_GATE_4;
1357     case 0x8c:  return EL_EM_GATE_3;
1358     case 0x8d:  return EL_INVISIBLE_WALL;               /* EMC */
1359     case 0x8e:  return EL_EM_GATE_1_GRAY;
1360     case 0x8f:  return EL_EM_GATE_2_GRAY;
1361     case 0x90:  return EL_EM_GATE_4_GRAY;
1362     case 0x91:  return EL_EM_GATE_3_GRAY;
1363     case 0x92:  return EL_MAGIC_WALL;
1364     case 0x94:  return EL_QUICKSAND_EMPTY;
1365     case 0x95:  return EL_ACID_POOL_TOPLEFT;
1366     case 0x96:  return EL_ACID_POOL_TOPRIGHT;
1367     case 0x97:  return EL_ACID_POOL_BOTTOMLEFT;
1368     case 0x98:  return EL_ACID_POOL_BOTTOMRIGHT;
1369     case 0x99:  return EL_ACID;
1370     case 0x9a:  return EL_AMOEBA_DEAD;
1371     case 0x9b:  return EL_AMOEBA_DEAD;
1372     case 0x9c:  return EL_AMOEBA_DEAD;
1373     case 0x9d:  return EL_AMOEBA_DEAD;
1374     case 0x9e:  return EL_EXIT_CLOSED;
1375     case 0x9f:  return EL_CHAR_LESS;                    /* EMC */
1376     case 0x93:  return EL_ROBOT_WHEEL;
1377
1378       /* looks like normal dust, but behaves like wall */
1379     case 0xa0:  return EL_WALL;                         /* EMC */
1380
1381     case 0xa8:  return EL_EMC_WALL_1;                   /* EMC */
1382     case 0xa9:  return EL_EMC_WALL_2;                   /* EMC */
1383     case 0xaa:  return EL_EMC_WALL_3;                   /* EMC */
1384     case 0xab:  return EL_EMC_WALL_7;                   /* EMC */
1385     case 0xae:  return EL_CHAR_MINUS;                   /* EMC */
1386     case 0xaf:  return EL_DYNAMITE;
1387     case 0xb0:  return EL_EMC_STEELWALL_1;              /* EMC */
1388     case 0xb1:  return EL_EMC_WALL_8;                   /* EMC */
1389
1390       /* (exact steel wall) */
1391     case 0xb3:  return EL_STEELWALL;                    /* EMC */
1392
1393     case 0xb4:  return EL_WALL_SLIPPERY;                /* EMC */
1394     case 0xb5:  return EL_EMC_WALL_6;                   /* EMC */
1395     case 0xb6:  return EL_EMC_WALL_5;                   /* EMC */
1396     case 0xb7:  return EL_EMC_WALL_4;                   /* EMC */
1397     case 0xb8:  return EL_BALLOON_SWITCH_ANY;           /* EMC */
1398     case 0xb9:  return EL_BALLOON_SWITCH_RIGHT;         /* EMC */
1399     case 0xba:  return EL_BALLOON_SWITCH_DOWN;          /* EMC */
1400     case 0xbb:  return EL_BALLOON_SWITCH_LEFT;          /* EMC */
1401     case 0xbc:  return EL_BALLOON_SWITCH_UP;            /* EMC */
1402     case 0xbd:  return EL_SAND;                         /* EMC */
1403     case 0xec:  return EL_CHAR_PERIOD;
1404     case 0xed:  return EL_CHAR_EXCLAM;
1405     case 0xee:  return EL_CHAR_COLON;
1406     case 0xef:  return EL_CHAR_QUESTION;
1407     case 0xf0:  return EL_CHAR_GREATER;
1408     case 0xf1:  return EL_CHAR_COPYRIGHT;
1409     case 0xfe:  return EL_PLAYER_1;
1410     case 0xff:  return EL_PLAYER_2;
1411
1412     default:
1413       Error(ERR_WARN, "invalid level element %d", element);
1414       return EL_CHAR_QUESTION;
1415   }
1416 }
1417
1418 #define EM_LEVEL_SIZE                   2106
1419 #define EM_LEVEL_XSIZE                  64
1420 #define EM_LEVEL_YSIZE                  32
1421
1422 static void LoadLevelFromFileInfo_EM(struct LevelInfo *level,
1423                                      struct LevelFileInfo *level_file_info)
1424 {
1425   char *filename = level_file_info->filename;
1426   FILE *file;
1427   unsigned char leveldata[EM_LEVEL_SIZE];
1428   unsigned char *header = &leveldata[EM_LEVEL_XSIZE * EM_LEVEL_YSIZE];
1429   unsigned char code0 = 0x65;
1430   unsigned char code1 = 0x11;
1431   boolean level_is_crypted = FALSE;
1432   int nr = level_file_info->nr;
1433   int i, x, y;
1434
1435   if (!(file = fopen(filename, MODE_READ)))
1436   {
1437     level->no_level_file = TRUE;
1438
1439     Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
1440
1441     return;
1442   }
1443
1444   for(i = 0; i < EM_LEVEL_SIZE; i++)
1445     leveldata[i] = fgetc(file);
1446
1447   fclose(file);
1448
1449   /* check if level data is crypted by testing against known starting bytes
1450      of the few existing crypted level files (from Emerald Mine 1 + 2) */
1451
1452   if ((leveldata[0] == 0xf1 ||
1453        leveldata[0] == 0xf5) && leveldata[2] == 0xe7 && leveldata[3] == 0xee)
1454   {
1455     level_is_crypted = TRUE;
1456
1457     if (leveldata[0] == 0xf5)   /* error in crypted Emerald Mine 2 levels */
1458       leveldata[0] = 0xf1;
1459   }
1460
1461   if (level_is_crypted)         /* decode crypted level data */
1462   {
1463     for(i = 0; i < EM_LEVEL_SIZE; i++)
1464     {
1465       leveldata[i] ^= code0;
1466       leveldata[i] -= code1;
1467
1468       code0  = (code0 + 7) & 0xff;
1469     }
1470   }
1471
1472   level->fieldx = EM_LEVEL_XSIZE;
1473   level->fieldy = EM_LEVEL_YSIZE;
1474
1475   level->time           = header[46] * 10;
1476   level->gems_needed    = header[47];
1477
1478   /* The original Emerald Mine levels have their level number stored
1479      at the second byte of the level file...
1480      Do not trust this information at other level files, e.g. EMC,
1481      but correct it anyway (normally the first row is completely
1482      steel wall, so the correction does not hurt anyway). */
1483
1484   if (leveldata[1] == nr)
1485     leveldata[1] = leveldata[2];        /* correct level number field */
1486
1487   sprintf(level->name, "Level %d", nr);         /* set level name */
1488
1489   level->score[SC_EMERALD]      = header[36];
1490   level->score[SC_DIAMOND]      = header[37];
1491   level->score[SC_ROBOT]        = header[38];
1492   level->score[SC_SPACESHIP]    = header[39];
1493   level->score[SC_BUG]          = header[40];
1494   level->score[SC_YAMYAM]       = header[41];
1495   level->score[SC_NUT]          = header[42];
1496   level->score[SC_DYNAMITE]     = header[43];
1497   level->score[SC_TIME_BONUS]   = header[44];
1498
1499   level->num_yamyam_contents = 4;
1500
1501   for(i = 0; i < level->num_yamyam_contents; i++)
1502     for(y = 0; y < 3; y++)
1503       for(x = 0; x < 3; x++)
1504         level->yamyam_content[i][x][y] =
1505           map_em_element_yam(header[i * 9 + y * 3 + x]);
1506
1507   level->amoeba_speed           = (header[52] * 256 + header[53]) % 256;
1508   level->time_magic_wall        = (header[54] * 256 + header[55]) * 16 / 100;
1509   level->time_wheel             = (header[56] * 256 + header[57]) * 16 / 100;
1510   level->amoeba_content         = EL_DIAMOND;
1511
1512   for (y = 0; y < level->fieldy; y++) for (x = 0; x < level->fieldx; x++)
1513   {
1514     int new_element = map_em_element_field(leveldata[y * EM_LEVEL_XSIZE + x]);
1515
1516     if (new_element == EL_AMOEBA_DEAD && level->amoeba_speed)
1517       new_element = EL_AMOEBA_WET;
1518
1519     level->field[x][y] = new_element;
1520   }
1521
1522   x = (header[48] * 256 + header[49]) % EM_LEVEL_XSIZE;
1523   y = (header[48] * 256 + header[49]) / EM_LEVEL_XSIZE;
1524   level->field[x][y] = EL_PLAYER_1;
1525
1526   x = (header[50] * 256 + header[51]) % EM_LEVEL_XSIZE;
1527   y = (header[50] * 256 + header[51]) / EM_LEVEL_XSIZE;
1528   level->field[x][y] = EL_PLAYER_2;
1529 }
1530
1531 /* ------------------------------------------------------------------------- */
1532 /* functions for loading SP level                                            */
1533 /* ------------------------------------------------------------------------- */
1534
1535 #define NUM_SUPAPLEX_LEVELS_PER_PACKAGE 111
1536 #define SP_LEVEL_SIZE                   1536
1537 #define SP_LEVEL_XSIZE                  60
1538 #define SP_LEVEL_YSIZE                  24
1539 #define SP_LEVEL_NAME_LEN               23
1540
1541 static void LoadLevelFromFileStream_SP(FILE *file, struct LevelInfo *level,
1542                                        int nr)
1543 {
1544   int i, x, y;
1545
1546   /* read level body (width * height == 60 * 24 tiles == 1440 bytes) */
1547   for (y = 0; y < SP_LEVEL_YSIZE; y++)
1548   {
1549     for (x = 0; x < SP_LEVEL_XSIZE; x++)
1550     {
1551       int element_old = fgetc(file);
1552       int element_new;
1553
1554       if (element_old <= 0x27)
1555         element_new = getMappedElement(EL_SP_START + element_old);
1556       else if (element_old == 0x28)
1557         element_new = EL_INVISIBLE_WALL;
1558       else
1559       {
1560         Error(ERR_WARN, "in level %d, at position %d, %d:", nr, x, y);
1561         Error(ERR_WARN, "invalid level element %d", element_old);
1562
1563         element_new = EL_CHAR_QUESTION;
1564       }
1565
1566       level->field[x][y] = element_new;
1567     }
1568   }
1569
1570   ReadUnusedBytesFromFile(file, 4);
1571
1572   /* Initial gravitation: 1 == "on", anything else (0) == "off" */
1573   level->initial_gravity = (fgetc(file) == 1 ? TRUE : FALSE);
1574
1575   ReadUnusedBytesFromFile(file, 1);
1576
1577   /* level title in uppercase letters, padded with dashes ("-") (23 bytes) */
1578   for (i = 0; i < SP_LEVEL_NAME_LEN; i++)
1579     level->name[i] = fgetc(file);
1580   level->name[SP_LEVEL_NAME_LEN] = '\0';
1581
1582   /* initial "freeze zonks": 2 == "on", anything else (0) == "off" */
1583   ReadUnusedBytesFromFile(file, 1);     /* !!! NOT SUPPORTED YET !!! */
1584
1585   /* number of infotrons needed; 0 means that Supaplex will count the total
1586      amount of infotrons in the level and use the low byte of that number.
1587      (a multiple of 256 infotrons will result in "0 infotrons needed"!) */
1588   level->gems_needed = fgetc(file);
1589
1590   /* information about special gravity port entries */
1591   ReadUnusedBytesFromFile(file, 65);    /* !!! NOT SUPPORTED YET !!! */
1592
1593   level->fieldx = SP_LEVEL_XSIZE;
1594   level->fieldy = SP_LEVEL_YSIZE;
1595
1596   level->time = 0;                      /* no time limit */
1597   level->amoeba_speed = 0;
1598   level->time_magic_wall = 0;
1599   level->time_wheel = 0;
1600   level->amoeba_content = EL_EMPTY;
1601
1602   for(i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
1603     level->score[i] = 0;                /* !!! CORRECT THIS !!! */
1604
1605   /* there are no yamyams in supaplex levels */
1606   for(i = 0; i < level->num_yamyam_contents; i++)
1607     for(y = 0; y < 3; y++)
1608       for(x = 0; x < 3; x++)
1609         level->yamyam_content[i][x][y] = EL_EMPTY;
1610 }
1611
1612 static void LoadLevelFromFileInfo_SP(struct LevelInfo *level,
1613                                      struct LevelFileInfo *level_file_info)
1614 {
1615   char *filename = level_file_info->filename;
1616   FILE *file;
1617   int nr = level_file_info->nr - leveldir_current->first_level;
1618   int i, l, x, y;
1619   char name_first, name_last;
1620   struct LevelInfo multipart_level;
1621   int multipart_xpos, multipart_ypos;
1622   boolean is_multipart_level;
1623   boolean is_first_part;
1624   boolean reading_multipart_level = FALSE;
1625   boolean use_empty_level = FALSE;
1626
1627   if (!(file = fopen(filename, MODE_READ)))
1628   {
1629     level->no_level_file = TRUE;
1630
1631     Error(ERR_WARN, "cannot read level '%s' -- using empty level", filename);
1632
1633     return;
1634   }
1635
1636   /* position file stream to the requested level inside the level package */
1637   if (fseek(file, nr * SP_LEVEL_SIZE, SEEK_SET) != 0)
1638   {
1639     level->no_level_file = TRUE;
1640
1641     Error(ERR_WARN, "cannot fseek level '%s' -- using empty level", filename);
1642
1643     return;
1644   }
1645
1646   /* there exist Supaplex level package files with multi-part levels which
1647      can be detected as follows: instead of leading and trailing dashes ('-')
1648      to pad the level name, they have leading and trailing numbers which are
1649      the x and y coordinations of the current part of the multi-part level;
1650      if there are '?' characters instead of numbers on the left or right side
1651      of the level name, the multi-part level consists of only horizontal or
1652      vertical parts */
1653
1654   for (l = nr; l < NUM_SUPAPLEX_LEVELS_PER_PACKAGE; l++)
1655   {
1656     LoadLevelFromFileStream_SP(file, level, l);
1657
1658     /* check if this level is a part of a bigger multi-part level */
1659
1660     name_first = level->name[0];
1661     name_last  = level->name[SP_LEVEL_NAME_LEN - 1];
1662
1663     is_multipart_level =
1664       ((name_first == '?' || (name_first >= '0' && name_first <= '9')) &&
1665        (name_last  == '?' || (name_last  >= '0' && name_last  <= '9')));
1666
1667     is_first_part =
1668       ((name_first == '?' || name_first == '1') &&
1669        (name_last  == '?' || name_last  == '1'));
1670
1671     /* correct leading multipart level meta information in level name */
1672     for (i = 0; i < SP_LEVEL_NAME_LEN && level->name[i] == name_first; i++)
1673       level->name[i] = '-';
1674
1675     /* correct trailing multipart level meta information in level name */
1676     for (i = SP_LEVEL_NAME_LEN - 1; i>=0 && level->name[i] == name_last; i--)
1677       level->name[i] = '-';
1678
1679     /* ---------- check for normal single level ---------- */
1680
1681     if (!reading_multipart_level && !is_multipart_level)
1682     {
1683       /* the current level is simply a normal single-part level, and we are
1684          not reading a multi-part level yet, so return the level as it is */
1685
1686       break;
1687     }
1688
1689     /* ---------- check for empty level (unused multi-part) ---------- */
1690
1691     if (!reading_multipart_level && is_multipart_level && !is_first_part)
1692     {
1693       /* this is a part of a multi-part level, but not the first part
1694          (and we are not already reading parts of a multi-part level);
1695          in this case, use an empty level instead of the single part */
1696
1697       use_empty_level = TRUE;
1698
1699       break;
1700     }
1701
1702     /* ---------- check for finished multi-part level ---------- */
1703
1704     if (reading_multipart_level &&
1705         (!is_multipart_level ||
1706          strcmp(level->name, multipart_level.name) != 0))
1707     {
1708       /* we are already reading parts of a multi-part level, but this level is
1709          either not a multi-part level, or a part of a different multi-part
1710          level; in both cases, the multi-part level seems to be complete */
1711
1712       break;
1713     }
1714
1715     /* ---------- here we have one part of a multi-part level ---------- */
1716
1717     reading_multipart_level = TRUE;
1718
1719     if (is_first_part)  /* start with first part of new multi-part level */
1720     {
1721       /* copy level info structure from first part */
1722       multipart_level = *level;
1723
1724       /* clear playfield of new multi-part level */
1725       for (y = 0; y < MAX_LEV_FIELDY; y++)
1726         for (x = 0; x < MAX_LEV_FIELDX; x++)
1727           multipart_level.field[x][y] = EL_EMPTY;
1728     }
1729
1730     if (name_first == '?')
1731       name_first = '1';
1732     if (name_last == '?')
1733       name_last = '1';
1734
1735     multipart_xpos = (int)(name_first - '0');
1736     multipart_ypos = (int)(name_last  - '0');
1737
1738 #if 0
1739     printf("----------> part (%d/%d) of multi-part level '%s'\n",
1740            multipart_xpos, multipart_ypos, multipart_level.name);
1741 #endif
1742
1743     if (multipart_xpos * SP_LEVEL_XSIZE > MAX_LEV_FIELDX ||
1744         multipart_ypos * SP_LEVEL_YSIZE > MAX_LEV_FIELDY)
1745     {
1746       Error(ERR_WARN, "multi-part level is too big -- ignoring part of it");
1747
1748       break;
1749     }
1750
1751     multipart_level.fieldx = MAX(multipart_level.fieldx,
1752                                  multipart_xpos * SP_LEVEL_XSIZE);
1753     multipart_level.fieldy = MAX(multipart_level.fieldy,
1754                                  multipart_ypos * SP_LEVEL_YSIZE);
1755
1756     /* copy level part at the right position of multi-part level */
1757     for (y = 0; y < SP_LEVEL_YSIZE; y++)
1758     {
1759       for (x = 0; x < SP_LEVEL_XSIZE; x++)
1760       {
1761         int start_x = (multipart_xpos - 1) * SP_LEVEL_XSIZE;
1762         int start_y = (multipart_ypos - 1) * SP_LEVEL_YSIZE;
1763
1764         multipart_level.field[start_x + x][start_y + y] = level->field[x][y];
1765       }
1766     }
1767   }
1768
1769   fclose(file);
1770
1771   if (use_empty_level)
1772   {
1773     setLevelInfoToDefaults(level);
1774
1775     level->fieldx = SP_LEVEL_XSIZE;
1776     level->fieldy = SP_LEVEL_YSIZE;
1777
1778     for (y = 0; y < SP_LEVEL_YSIZE; y++)
1779       for (x = 0; x < SP_LEVEL_XSIZE; x++)
1780         level->field[x][y] = EL_EMPTY;
1781
1782     strcpy(level->name, "-------- EMPTY --------");
1783
1784     Error(ERR_WARN, "single part of multi-part level -- using empty level");
1785   }
1786
1787   if (reading_multipart_level)
1788     *level = multipart_level;
1789 }
1790
1791 /* ------------------------------------------------------------------------- */
1792 /* functions for loading generic level                                       */
1793 /* ------------------------------------------------------------------------- */
1794
1795 void LoadLevelFromFileInfo(struct LevelInfo *level,
1796                            struct LevelFileInfo *level_file_info)
1797 {
1798   /* always start with reliable default values */
1799   setLevelInfoToDefaults(level);
1800
1801   switch (level_file_info->type)
1802   {
1803     case LEVEL_FILE_TYPE_RND:
1804       LoadLevelFromFileInfo_RND(level, level_file_info);
1805       break;
1806
1807     case LEVEL_FILE_TYPE_EM:
1808       LoadLevelFromFileInfo_EM(level, level_file_info);
1809       break;
1810
1811     case LEVEL_FILE_TYPE_SP:
1812       LoadLevelFromFileInfo_SP(level, level_file_info);
1813       break;
1814
1815     default:
1816       LoadLevelFromFileInfo_RND(level, level_file_info);
1817       break;
1818   }
1819 }
1820
1821 void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
1822 {
1823   static struct LevelFileInfo level_file_info;
1824
1825   /* always start with reliable default values */
1826   setFileInfoToDefaults(&level_file_info);
1827
1828   level_file_info.nr = 0;                       /* unknown level number */
1829   level_file_info.type = LEVEL_FILE_TYPE_RND;   /* no others supported yet */
1830   level_file_info.filename = filename;
1831
1832   LoadLevelFromFileInfo(level, &level_file_info);
1833 }
1834
1835 static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename)
1836 {
1837   if (leveldir_current == NULL)         /* only when dumping level */
1838     return;
1839
1840 #if 0
1841   printf("::: sort_priority: %d\n", leveldir_current->sort_priority);
1842 #endif
1843
1844   /* determine correct game engine version of current level */
1845 #if 1
1846   if (!leveldir_current->latest_engine)
1847 #else
1848   if (IS_LEVELCLASS_CONTRIB(leveldir_current) ||
1849       IS_LEVELCLASS_PRIVATE(leveldir_current) ||
1850       IS_LEVELCLASS_UNDEFINED(leveldir_current))
1851 #endif
1852   {
1853 #if 0
1854     printf("\n::: This level is private or contributed: '%s'\n", filename);
1855 #endif
1856
1857 #if 0
1858     printf("\n::: Use the stored game engine version for this level\n");
1859 #endif
1860
1861     /* For all levels which are not forced to use the latest game engine
1862        version (normally user contributed, private and undefined levels),
1863        use the version of the game engine the levels were created for.
1864
1865        Since 2.0.1, the game engine version is now directly stored
1866        in the level file (chunk "VERS"), so there is no need anymore
1867        to set the game version from the file version (except for old,
1868        pre-2.0 levels, where the game version is still taken from the
1869        file format version used to store the level -- see above). */
1870
1871     /* do some special adjustments to support older level versions */
1872     if (level->file_version == FILE_VERSION_1_0)
1873     {
1874       Error(ERR_WARN, "level file '%s' has version number 1.0", filename);
1875       Error(ERR_WARN, "using high speed movement for player");
1876
1877       /* player was faster than monsters in (pre-)1.0 levels */
1878       level->double_speed = TRUE;
1879     }
1880
1881     /* Default behaviour for EM style gems was "slippery" only in 2.0.1 */
1882     if (level->game_version == VERSION_IDENT(2,0,1,0))
1883       level->em_slippery_gems = TRUE;
1884   }
1885   else
1886   {
1887 #if 0
1888     printf("\n::: ALWAYS USE LATEST ENGINE FOR THIS LEVEL: [%d] '%s'\n",
1889            leveldir_current->sort_priority, filename);
1890 #endif
1891
1892 #if 0
1893     printf("\n::: Use latest game engine version for this level.\n");
1894 #endif
1895
1896     /* For all levels which are forced to use the latest game engine version
1897        (normally all but user contributed, private and undefined levels), set
1898        the game engine version to the actual version; this allows for actual
1899        corrections in the game engine to take effect for existing, converted
1900        levels (from "classic" or other existing games) to make the emulation
1901        of the corresponding game more accurate, while (hopefully) not breaking
1902        existing levels created from other players. */
1903
1904 #if 0
1905     printf("::: changing engine from %d to %d\n",
1906            level->game_version, GAME_VERSION_ACTUAL);
1907 #endif
1908
1909     level->game_version = GAME_VERSION_ACTUAL;
1910
1911     /* Set special EM style gems behaviour: EM style gems slip down from
1912        normal, steel and growing wall. As this is a more fundamental change,
1913        it seems better to set the default behaviour to "off" (as it is more
1914        natural) and make it configurable in the level editor (as a property
1915        of gem style elements). Already existing converted levels (neither
1916        private nor contributed levels) are changed to the new behaviour. */
1917
1918     if (level->file_version < FILE_VERSION_2_0)
1919       level->em_slippery_gems = TRUE;
1920   }
1921
1922 #if 0
1923   printf("::: => %d\n", level->game_version);
1924 #endif
1925 }
1926
1927 static void LoadLevel_InitElements(struct LevelInfo *level, char *filename)
1928 {
1929   int i, j;
1930
1931   /* map custom element change events that have changed in newer versions
1932      (these following values were accidentally changed in version 3.0.1) */
1933   if (level->game_version <= VERSION_IDENT(3,0,0,0))
1934   {
1935     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
1936     {
1937       int element = EL_CUSTOM_START + i;
1938
1939       /* order of checking and copying events to be mapped is important */
1940       for (j = CE_BY_OTHER_ACTION; j >= CE_BY_PLAYER_OBSOLETE; j--)
1941       {
1942         if (HAS_CHANGE_EVENT(element, j - 2))
1943         {
1944           SET_CHANGE_EVENT(element, j - 2, FALSE);
1945           SET_CHANGE_EVENT(element, j, TRUE);
1946         }
1947       }
1948
1949       /* order of checking and copying events to be mapped is important */
1950       for (j = CE_OTHER_GETS_COLLECTED; j >= CE_HITTING_SOMETHING; j--)
1951       {
1952         if (HAS_CHANGE_EVENT(element, j - 1))
1953         {
1954           SET_CHANGE_EVENT(element, j - 1, FALSE);
1955           SET_CHANGE_EVENT(element, j, TRUE);
1956         }
1957       }
1958     }
1959   }
1960
1961   /* some custom element change events get mapped since version 3.0.3 */
1962   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
1963   {
1964     int element = EL_CUSTOM_START + i;
1965
1966     if (HAS_CHANGE_EVENT(element, CE_BY_PLAYER_OBSOLETE) ||
1967         HAS_CHANGE_EVENT(element, CE_BY_COLLISION_OBSOLETE))
1968     {
1969       SET_CHANGE_EVENT(element, CE_BY_PLAYER_OBSOLETE, FALSE);
1970       SET_CHANGE_EVENT(element, CE_BY_COLLISION_OBSOLETE, FALSE);
1971
1972       SET_CHANGE_EVENT(element, CE_BY_DIRECT_ACTION, TRUE);
1973     }
1974   }
1975
1976   /* initialize "can_change" field for old levels with only one change page */
1977   if (level->game_version <= VERSION_IDENT(3,0,2,0))
1978   {
1979     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
1980     {
1981       int element = EL_CUSTOM_START + i;
1982
1983       if (CAN_CHANGE(element))
1984         element_info[element].change->can_change = TRUE;
1985     }
1986   }
1987
1988 #if 0
1989   /* set default push delay values (corrected since version 3.0.7-1) */
1990   if (level->game_version < VERSION_IDENT(3,0,7,1))
1991   {
1992     game.default_push_delay_fixed = 2;
1993     game.default_push_delay_random = 8;
1994   }
1995   else
1996   {
1997     game.default_push_delay_fixed = 8;
1998     game.default_push_delay_random = 8;
1999   }
2000
2001   /* set uninitialized push delay values of custom elements in older levels */
2002   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
2003   {
2004     int element = EL_CUSTOM_START + i;
2005
2006     if (element_info[element].push_delay_fixed == -1)
2007       element_info[element].push_delay_fixed = game.default_push_delay_fixed;
2008     if (element_info[element].push_delay_random == -1)
2009       element_info[element].push_delay_random = game.default_push_delay_random;
2010   }
2011 #endif
2012
2013   /* initialize element properties for level editor etc. */
2014   InitElementPropertiesEngine(level->game_version);
2015 }
2016
2017 static void LoadLevel_InitPlayfield(struct LevelInfo *level, char *filename)
2018 {
2019   int x, y;
2020
2021   /* map elements that have changed in newer versions */
2022   for (y = 0; y < level->fieldy; y++)
2023   {
2024     for (x = 0; x < level->fieldx; x++)
2025     {
2026       int element = level->field[x][y];
2027
2028       if (level->game_version <= VERSION_IDENT(2,2,0,0))
2029       {
2030         /* map game font elements */
2031         element = (element == EL_CHAR('[')  ? EL_CHAR_AUMLAUT :
2032                    element == EL_CHAR('\\') ? EL_CHAR_OUMLAUT :
2033                    element == EL_CHAR(']')  ? EL_CHAR_UUMLAUT :
2034                    element == EL_CHAR('^')  ? EL_CHAR_COPYRIGHT : element);
2035       }
2036
2037       if (level->game_version < VERSION_IDENT(3,0,0,0))
2038       {
2039         /* map Supaplex gravity tube elements */
2040         element = (element == EL_SP_GRAVITY_PORT_LEFT  ? EL_SP_PORT_LEFT  :
2041                    element == EL_SP_GRAVITY_PORT_RIGHT ? EL_SP_PORT_RIGHT :
2042                    element == EL_SP_GRAVITY_PORT_UP    ? EL_SP_PORT_UP    :
2043                    element == EL_SP_GRAVITY_PORT_DOWN  ? EL_SP_PORT_DOWN  :
2044                    element);
2045       }
2046
2047       level->field[x][y] = element;
2048     }
2049   }
2050
2051   /* copy elements to runtime playfield array */
2052   for (x = 0; x < MAX_LEV_FIELDX; x++)
2053     for (y = 0; y < MAX_LEV_FIELDY; y++)
2054       Feld[x][y] = level->field[x][y];
2055
2056   /* initialize level size variables for faster access */
2057   lev_fieldx = level->fieldx;
2058   lev_fieldy = level->fieldy;
2059
2060   /* determine border element for this level */
2061   SetBorderElement();
2062 }
2063
2064 void LoadLevelTemplate(int nr)
2065 {
2066 #if 1
2067   struct LevelFileInfo *level_file_info = getLevelFileInfo(nr);
2068   char *filename = level_file_info->filename;
2069
2070   LoadLevelFromFileInfo(&level_template, level_file_info);
2071 #else
2072   char *filename = getDefaultLevelFilename(nr);
2073
2074   LoadLevelFromFilename_RND(&level_template, filename);
2075 #endif
2076
2077   LoadLevel_InitVersion(&level, filename);
2078   LoadLevel_InitElements(&level, filename);
2079
2080   ActivateLevelTemplate();
2081 }
2082
2083 void LoadLevel(int nr)
2084 {
2085 #if 1
2086   struct LevelFileInfo *level_file_info = getLevelFileInfo(nr);
2087   char *filename = level_file_info->filename;
2088
2089   LoadLevelFromFileInfo(&level, level_file_info);
2090 #else
2091   char *filename = getLevelFilename(nr);
2092
2093   LoadLevelFromFilename_RND(&level, filename);
2094 #endif
2095
2096   if (level.use_custom_template)
2097     LoadLevelTemplate(-1);
2098
2099 #if 1
2100   LoadLevel_InitVersion(&level, filename);
2101   LoadLevel_InitElements(&level, filename);
2102   LoadLevel_InitPlayfield(&level, filename);
2103 #else
2104   LoadLevel_InitLevel(&level, filename);
2105 #endif
2106 }
2107
2108 static void SaveLevel_VERS(FILE *file, struct LevelInfo *level)
2109 {
2110   putFileVersion(file, level->file_version);
2111   putFileVersion(file, level->game_version);
2112 }
2113
2114 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
2115 {
2116   int i, x, y;
2117
2118   putFile8Bit(file, level->fieldx);
2119   putFile8Bit(file, level->fieldy);
2120
2121   putFile16BitBE(file, level->time);
2122   putFile16BitBE(file, level->gems_needed);
2123
2124   for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
2125     putFile8Bit(file, level->name[i]);
2126
2127   for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
2128     putFile8Bit(file, level->score[i]);
2129
2130   for (i = 0; i < STD_ELEMENT_CONTENTS; i++)
2131     for (y = 0; y < 3; y++)
2132       for (x = 0; x < 3; x++)
2133         putFile8Bit(file, (level->encoding_16bit_yamyam ? EL_EMPTY :
2134                            level->yamyam_content[i][x][y]));
2135   putFile8Bit(file, level->amoeba_speed);
2136   putFile8Bit(file, level->time_magic_wall);
2137   putFile8Bit(file, level->time_wheel);
2138   putFile8Bit(file, (level->encoding_16bit_amoeba ? EL_EMPTY :
2139                      level->amoeba_content));
2140   putFile8Bit(file, (level->double_speed ? 1 : 0));
2141   putFile8Bit(file, (level->initial_gravity ? 1 : 0));
2142   putFile8Bit(file, (level->encoding_16bit_field ? 1 : 0));
2143   putFile8Bit(file, (level->em_slippery_gems ? 1 : 0));
2144   putFile8Bit(file, (level->block_last_field ? 1 : 0));
2145   putFile8Bit(file, (level->sp_block_last_field ? 1 : 0));
2146
2147   putFile8Bit(file, (level->use_custom_template ? 1 : 0));
2148
2149   WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
2150 }
2151
2152 static void SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
2153 {
2154   int i;
2155
2156   for (i = 0; i < MAX_LEVEL_AUTHOR_LEN; i++)
2157     putFile8Bit(file, level->author[i]);
2158 }
2159
2160 static void SaveLevel_BODY(FILE *file, struct LevelInfo *level)
2161 {
2162   int x, y;
2163
2164   for (y = 0; y < level->fieldy; y++) 
2165     for (x = 0; x < level->fieldx; x++) 
2166       if (level->encoding_16bit_field)
2167         putFile16BitBE(file, level->field[x][y]);
2168       else
2169         putFile8Bit(file, level->field[x][y]);
2170 }
2171
2172 #if 0
2173 static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
2174 {
2175   int i, x, y;
2176
2177   putFile8Bit(file, EL_YAMYAM);
2178   putFile8Bit(file, level->num_yamyam_contents);
2179   putFile8Bit(file, 0);
2180   putFile8Bit(file, 0);
2181
2182   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
2183     for (y = 0; y < 3; y++)
2184       for (x = 0; x < 3; x++)
2185         if (level->encoding_16bit_field)
2186           putFile16BitBE(file, level->yamyam_content[i][x][y]);
2187         else
2188           putFile8Bit(file, level->yamyam_content[i][x][y]);
2189 }
2190 #endif
2191
2192 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
2193 {
2194   int i, x, y;
2195   int num_contents, content_xsize, content_ysize;
2196   int content_array[MAX_ELEMENT_CONTENTS][3][3];
2197
2198   if (element == EL_YAMYAM)
2199   {
2200     num_contents = level->num_yamyam_contents;
2201     content_xsize = 3;
2202     content_ysize = 3;
2203
2204     for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
2205       for (y = 0; y < 3; y++)
2206         for (x = 0; x < 3; x++)
2207           content_array[i][x][y] = level->yamyam_content[i][x][y];
2208   }
2209   else if (element == EL_BD_AMOEBA)
2210   {
2211     num_contents = 1;
2212     content_xsize = 1;
2213     content_ysize = 1;
2214
2215     for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
2216       for (y = 0; y < 3; y++)
2217         for (x = 0; x < 3; x++)
2218           content_array[i][x][y] = EL_EMPTY;
2219     content_array[0][0][0] = level->amoeba_content;
2220   }
2221   else
2222   {
2223     /* chunk header already written -- write empty chunk data */
2224     WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_SIZE);
2225
2226     Error(ERR_WARN, "cannot save content for element '%d'", element);
2227     return;
2228   }
2229
2230   putFile16BitBE(file, element);
2231   putFile8Bit(file, num_contents);
2232   putFile8Bit(file, content_xsize);
2233   putFile8Bit(file, content_ysize);
2234
2235   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED);
2236
2237   for (i = 0; i < MAX_ELEMENT_CONTENTS; i++)
2238     for (y = 0; y < 3; y++)
2239       for (x = 0; x < 3; x++)
2240         putFile16BitBE(file, content_array[i][x][y]);
2241 }
2242
2243 static void SaveLevel_CNT3(FILE *file, struct LevelInfo *level, int element)
2244 {
2245   int i;
2246   int envelope_nr = element - EL_ENVELOPE_1;
2247   int envelope_len = strlen(level->envelope_text[envelope_nr]) + 1;
2248
2249   putFile16BitBE(file, element);
2250   putFile16BitBE(file, envelope_len);
2251   putFile8Bit(file, level->envelope_xsize[envelope_nr]);
2252   putFile8Bit(file, level->envelope_ysize[envelope_nr]);
2253
2254   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT3_UNUSED);
2255
2256   for (i = 0; i < envelope_len; i++)
2257     putFile8Bit(file, level->envelope_text[envelope_nr][i]);
2258 }
2259
2260 #if 0
2261 static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level,
2262                            int num_changed_custom_elements)
2263 {
2264   int i, check = 0;
2265
2266   putFile16BitBE(file, num_changed_custom_elements);
2267
2268   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
2269   {
2270     int element = EL_CUSTOM_START + i;
2271
2272     if (Properties[element][EP_BITFIELD_BASE] != EP_BITMASK_DEFAULT)
2273     {
2274       if (check < num_changed_custom_elements)
2275       {
2276         putFile16BitBE(file, element);
2277         putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
2278       }
2279
2280       check++;
2281     }
2282   }
2283
2284   if (check != num_changed_custom_elements)     /* should not happen */
2285     Error(ERR_WARN, "inconsistent number of custom element properties");
2286 }
2287 #endif
2288
2289 #if 0
2290 static void SaveLevel_CUS2(FILE *file, struct LevelInfo *level,
2291                            int num_changed_custom_elements)
2292 {
2293   int i, check = 0;
2294
2295   putFile16BitBE(file, num_changed_custom_elements);
2296
2297   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
2298   {
2299     int element = EL_CUSTOM_START + i;
2300
2301     if (element_info[element].change->target_element != EL_EMPTY_SPACE)
2302     {
2303       if (check < num_changed_custom_elements)
2304       {
2305         putFile16BitBE(file, element);
2306         putFile16BitBE(file, element_info[element].change->target_element);
2307       }
2308
2309       check++;
2310     }
2311   }
2312
2313   if (check != num_changed_custom_elements)     /* should not happen */
2314     Error(ERR_WARN, "inconsistent number of custom target elements");
2315 }
2316 #endif
2317
2318 #if 0
2319 static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
2320                            int num_changed_custom_elements)
2321 {
2322   int i, j, x, y, check = 0;
2323
2324   putFile16BitBE(file, num_changed_custom_elements);
2325
2326   for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
2327   {
2328     int element = EL_CUSTOM_START + i;
2329
2330     if (element_info[element].modified_settings)
2331     {
2332       if (check < num_changed_custom_elements)
2333       {
2334         putFile16BitBE(file, element);
2335
2336         for (j = 0; j < MAX_ELEMENT_NAME_LEN; j++)
2337           putFile8Bit(file, element_info[element].description[j]);
2338
2339         putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
2340
2341         /* some free bytes for future properties and padding */
2342         WriteUnusedBytesToFile(file, 7);
2343
2344         putFile8Bit(file, element_info[element].use_gfx_element);
2345         putFile16BitBE(file, element_info[element].gfx_element);
2346
2347         putFile8Bit(file, element_info[element].collect_score);
2348         putFile8Bit(file, element_info[element].collect_count);
2349
2350         putFile16BitBE(file, element_info[element].push_delay_fixed);
2351         putFile16BitBE(file, element_info[element].push_delay_random);
2352         putFile16BitBE(file, element_info[element].move_delay_fixed);
2353         putFile16BitBE(file, element_info[element].move_delay_random);
2354
2355         putFile16BitBE(file, element_info[element].move_pattern);
2356         putFile8Bit(file, element_info[element].move_direction_initial);
2357         putFile8Bit(file, element_info[element].move_stepsize);
2358
2359         for (y = 0; y < 3; y++)
2360           for (x = 0; x < 3; x++)
2361             putFile16BitBE(file, element_info[element].content[x][y]);
2362
2363         putFile32BitBE(file, element_info[element].change->events);
2364
2365         putFile16BitBE(file, element_info[element].change->target_element);
2366
2367         putFile16BitBE(file, element_info[element].change->delay_fixed);
2368         putFile16BitBE(file, element_info[element].change->delay_random);
2369         putFile16BitBE(file, element_info[element].change->delay_frames);
2370
2371         putFile16BitBE(file, element_info[element].change->trigger_element);
2372
2373         putFile8Bit(file, element_info[element].change->explode);
2374         putFile8Bit(file, element_info[element].change->use_content);
2375         putFile8Bit(file, element_info[element].change->only_complete);
2376         putFile8Bit(file, element_info[element].change->use_random_change);
2377
2378         putFile8Bit(file, element_info[element].change->random);
2379         putFile8Bit(file, element_info[element].change->power);
2380
2381         for (y = 0; y < 3; y++)
2382           for (x = 0; x < 3; x++)
2383             putFile16BitBE(file, element_info[element].change->content[x][y]);
2384
2385         putFile8Bit(file, element_info[element].slippery_type);
2386
2387         /* some free bytes for future properties and padding */
2388         WriteUnusedBytesToFile(file, LEVEL_CPART_CUS3_UNUSED);
2389       }
2390
2391       check++;
2392     }
2393   }
2394
2395   if (check != num_changed_custom_elements)     /* should not happen */
2396     Error(ERR_WARN, "inconsistent number of custom element properties");
2397 }
2398 #endif
2399
2400 static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
2401 {
2402   struct ElementInfo *ei = &element_info[element];
2403   int i, x, y;
2404
2405   putFile16BitBE(file, element);
2406
2407   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
2408     putFile8Bit(file, ei->description[i]);
2409
2410   putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
2411   WriteUnusedBytesToFile(file, 4);      /* reserved for more base properties */
2412
2413   putFile8Bit(file, ei->num_change_pages);
2414
2415   /* some free bytes for future base property values and padding */
2416   WriteUnusedBytesToFile(file, 5);
2417
2418   /* write custom property values */
2419
2420   putFile8Bit(file, ei->use_gfx_element);
2421   putFile16BitBE(file, ei->gfx_element);
2422
2423   putFile8Bit(file, ei->collect_score);
2424   putFile8Bit(file, ei->collect_count);
2425
2426   putFile16BitBE(file, ei->push_delay_fixed);
2427   putFile16BitBE(file, ei->push_delay_random);
2428   putFile16BitBE(file, ei->move_delay_fixed);
2429   putFile16BitBE(file, ei->move_delay_random);
2430
2431   putFile16BitBE(file, ei->move_pattern);
2432   putFile8Bit(file, ei->move_direction_initial);
2433   putFile8Bit(file, ei->move_stepsize);
2434
2435   putFile8Bit(file, ei->slippery_type);
2436
2437   for (y = 0; y < 3; y++)
2438     for (x = 0; x < 3; x++)
2439       putFile16BitBE(file, ei->content[x][y]);
2440
2441   putFile16BitBE(file, ei->move_enter_element);
2442   putFile16BitBE(file, ei->move_leave_element);
2443   putFile8Bit(file, ei->move_leave_type);
2444
2445   /* some free bytes for future custom property values and padding */
2446   WriteUnusedBytesToFile(file, 7);
2447
2448   /* write change property values */
2449
2450   for (i = 0; i < ei->num_change_pages; i++)
2451   {
2452     struct ElementChangeInfo *change = &ei->change_page[i];
2453
2454     putFile32BitBE(file, change->events);
2455
2456     putFile16BitBE(file, change->target_element);
2457
2458     putFile16BitBE(file, change->delay_fixed);
2459     putFile16BitBE(file, change->delay_random);
2460     putFile16BitBE(file, change->delay_frames);
2461
2462     putFile16BitBE(file, change->trigger_element);
2463
2464     putFile8Bit(file, change->explode);
2465     putFile8Bit(file, change->use_content);
2466     putFile8Bit(file, change->only_complete);
2467     putFile8Bit(file, change->use_random_change);
2468
2469     putFile8Bit(file, change->random);
2470     putFile8Bit(file, change->power);
2471
2472     for (y = 0; y < 3; y++)
2473       for (x = 0; x < 3; x++)
2474         putFile16BitBE(file, change->content[x][y]);
2475
2476     putFile8Bit(file, change->can_change);
2477
2478     putFile8Bit(file, change->sides);
2479
2480     /* some free bytes for future change property values and padding */
2481     WriteUnusedBytesToFile(file, 8);
2482   }
2483 }
2484
2485 static void SaveLevel_GRP1(FILE *file, struct LevelInfo *level, int element)
2486 {
2487   struct ElementInfo *ei = &element_info[element];
2488   struct ElementGroupInfo *group = ei->group;
2489   int i;
2490
2491   putFile16BitBE(file, element);
2492
2493   for (i = 0; i < MAX_ELEMENT_NAME_LEN; i++)
2494     putFile8Bit(file, ei->description[i]);
2495
2496   putFile8Bit(file, group->num_elements);
2497
2498   putFile8Bit(file, ei->use_gfx_element);
2499   putFile16BitBE(file, ei->gfx_element);
2500
2501   putFile8Bit(file, group->choice_mode);
2502
2503   /* some free bytes for future values and padding */
2504   WriteUnusedBytesToFile(file, 3);
2505
2506   for (i = 0; i < MAX_ELEMENTS_IN_GROUP; i++)
2507     putFile16BitBE(file, group->element[i]);
2508 }
2509
2510 static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
2511 {
2512   int body_chunk_size;
2513   int i, x, y;
2514   FILE *file;
2515
2516   if (!(file = fopen(filename, MODE_WRITE)))
2517   {
2518     Error(ERR_WARN, "cannot save level file '%s'", filename);
2519     return;
2520   }
2521
2522   level->file_version = FILE_VERSION_ACTUAL;
2523   level->game_version = GAME_VERSION_ACTUAL;
2524
2525   /* check level field for 16-bit elements */
2526   level->encoding_16bit_field = FALSE;
2527   for (y = 0; y < level->fieldy; y++) 
2528     for (x = 0; x < level->fieldx; x++) 
2529       if (level->field[x][y] > 255)
2530         level->encoding_16bit_field = TRUE;
2531
2532   /* check yamyam content for 16-bit elements */
2533   level->encoding_16bit_yamyam = FALSE;
2534   for (i = 0; i < level->num_yamyam_contents; i++)
2535     for (y = 0; y < 3; y++)
2536       for (x = 0; x < 3; x++)
2537         if (level->yamyam_content[i][x][y] > 255)
2538           level->encoding_16bit_yamyam = TRUE;
2539
2540   /* check amoeba content for 16-bit elements */
2541   level->encoding_16bit_amoeba = FALSE;
2542   if (level->amoeba_content > 255)
2543     level->encoding_16bit_amoeba = TRUE;
2544
2545   /* calculate size of "BODY" chunk */
2546   body_chunk_size =
2547     level->fieldx * level->fieldy * (level->encoding_16bit_field ? 2 : 1);
2548
2549   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
2550   putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
2551
2552   putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
2553   SaveLevel_VERS(file, level);
2554
2555   putFileChunkBE(file, "HEAD", LEVEL_HEADER_SIZE);
2556   SaveLevel_HEAD(file, level);
2557
2558   putFileChunkBE(file, "AUTH", MAX_LEVEL_AUTHOR_LEN);
2559   SaveLevel_AUTH(file, level);
2560
2561   putFileChunkBE(file, "BODY", body_chunk_size);
2562   SaveLevel_BODY(file, level);
2563
2564   if (level->encoding_16bit_yamyam ||
2565       level->num_yamyam_contents != STD_ELEMENT_CONTENTS)
2566   {
2567     putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
2568     SaveLevel_CNT2(file, level, EL_YAMYAM);
2569   }
2570
2571   if (level->encoding_16bit_amoeba)
2572   {
2573     putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
2574     SaveLevel_CNT2(file, level, EL_BD_AMOEBA);
2575   }
2576
2577   /* check for envelope content */
2578   for (i = 0; i < 4; i++)
2579   {
2580     if (strlen(level->envelope_text[i]) > 0)
2581     {
2582       int envelope_len = strlen(level->envelope_text[i]) + 1;
2583
2584       putFileChunkBE(file, "CNT3", LEVEL_CHUNK_CNT3_SIZE(envelope_len));
2585       SaveLevel_CNT3(file, level, EL_ENVELOPE_1 + i);
2586     }
2587   }
2588
2589   /* check for non-default custom elements (unless using template level) */
2590   if (!level->use_custom_template)
2591   {
2592     for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
2593     {
2594       int element = EL_CUSTOM_START + i;
2595
2596       if (element_info[element].modified_settings)
2597       {
2598         int num_change_pages = element_info[element].num_change_pages;
2599
2600         putFileChunkBE(file, "CUS4", LEVEL_CHUNK_CUS4_SIZE(num_change_pages));
2601         SaveLevel_CUS4(file, level, element);
2602       }
2603     }
2604   }
2605
2606   /* check for non-default group elements (unless using template level) */
2607   if (!level->use_custom_template)
2608   {
2609     for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
2610     {
2611       int element = EL_GROUP_START + i;
2612
2613       if (element_info[element].modified_settings)
2614       {
2615         putFileChunkBE(file, "GRP1", LEVEL_CHUNK_GRP1_SIZE);
2616         SaveLevel_GRP1(file, level, element);
2617       }
2618     }
2619   }
2620
2621   fclose(file);
2622
2623   SetFilePermissions(filename, PERMS_PRIVATE);
2624 }
2625
2626 void SaveLevel(int nr)
2627 {
2628   char *filename = getDefaultLevelFilename(nr);
2629
2630   SaveLevelFromFilename(&level, filename);
2631 }
2632
2633 void SaveLevelTemplate()
2634 {
2635   char *filename = getDefaultLevelFilename(-1);
2636
2637   SaveLevelFromFilename(&level, filename);
2638 }
2639
2640 void DumpLevel(struct LevelInfo *level)
2641 {
2642   printf_line("-", 79);
2643   printf("Level xxx (file version %08d, game version %08d)\n",
2644          level->file_version, level->game_version);
2645   printf_line("-", 79);
2646
2647   printf("Level author: '%s'\n", level->author);
2648   printf("Level title:  '%s'\n", level->name);
2649   printf("\n");
2650   printf("Playfield size: %d x %d\n", level->fieldx, level->fieldy);
2651   printf("\n");
2652   printf("Level time:  %d seconds\n", level->time);
2653   printf("Gems needed: %d\n", level->gems_needed);
2654   printf("\n");
2655   printf("Time for magic wall: %d seconds\n", level->time_magic_wall);
2656   printf("Time for wheel:      %d seconds\n", level->time_wheel);
2657   printf("Time for light:      %d seconds\n", level->time_light);
2658   printf("Time for timegate:   %d seconds\n", level->time_timegate);
2659   printf("\n");
2660   printf("Amoeba speed: %d\n", level->amoeba_speed);
2661   printf("\n");
2662   printf("Initial gravity:             %s\n", (level->initial_gravity ? "yes" : "no"));
2663   printf("Double speed movement:       %s\n", (level->double_speed ? "yes" : "no"));
2664   printf("EM style slippery gems:      %s\n", (level->em_slippery_gems ? "yes" : "no"));
2665   printf("Player blocks last field:    %s\n", (level->block_last_field ? "yes" : "no"));
2666   printf("SP player blocks last field: %s\n", (level->sp_block_last_field ? "yes" : "no"));
2667
2668   printf_line("-", 79);
2669 }
2670
2671
2672 /* ========================================================================= */
2673 /* tape file functions                                                       */
2674 /* ========================================================================= */
2675
2676 static void setTapeInfoToDefaults()
2677 {
2678   int i;
2679
2680   /* always start with reliable default values (empty tape) */
2681   TapeErase();
2682
2683   /* default values (also for pre-1.2 tapes) with only the first player */
2684   tape.player_participates[0] = TRUE;
2685   for (i = 1; i < MAX_PLAYERS; i++)
2686     tape.player_participates[i] = FALSE;
2687
2688   /* at least one (default: the first) player participates in every tape */
2689   tape.num_participating_players = 1;
2690
2691   tape.level_nr = level_nr;
2692   tape.counter = 0;
2693   tape.changed = FALSE;
2694
2695   tape.recording = FALSE;
2696   tape.playing = FALSE;
2697   tape.pausing = FALSE;
2698 }
2699
2700 static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
2701 {
2702   tape->file_version = getFileVersion(file);
2703   tape->game_version = getFileVersion(file);
2704
2705   return chunk_size;
2706 }
2707
2708 static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
2709 {
2710   int i;
2711
2712   tape->random_seed = getFile32BitBE(file);
2713   tape->date        = getFile32BitBE(file);
2714   tape->length      = getFile32BitBE(file);
2715
2716   /* read header fields that are new since version 1.2 */
2717   if (tape->file_version >= FILE_VERSION_1_2)
2718   {
2719     byte store_participating_players = getFile8Bit(file);
2720     int engine_version;
2721
2722     /* since version 1.2, tapes store which players participate in the tape */
2723     tape->num_participating_players = 0;
2724     for (i = 0; i < MAX_PLAYERS; i++)
2725     {
2726       tape->player_participates[i] = FALSE;
2727
2728       if (store_participating_players & (1 << i))
2729       {
2730         tape->player_participates[i] = TRUE;
2731         tape->num_participating_players++;
2732       }
2733     }
2734
2735     ReadUnusedBytesFromFile(file, TAPE_HEADER_UNUSED);
2736
2737     engine_version = getFileVersion(file);
2738     if (engine_version > 0)
2739       tape->engine_version = engine_version;
2740     else
2741       tape->engine_version = tape->game_version;
2742   }
2743
2744   return chunk_size;
2745 }
2746
2747 static int LoadTape_INFO(FILE *file, int chunk_size, struct TapeInfo *tape)
2748 {
2749   int level_identifier_size;
2750   int i;
2751
2752   level_identifier_size = getFile16BitBE(file);
2753
2754   tape->level_identifier =
2755     checked_realloc(tape->level_identifier, level_identifier_size);
2756
2757   for (i = 0; i < level_identifier_size; i++)
2758     tape->level_identifier[i] = getFile8Bit(file);
2759
2760   tape->level_nr = getFile16BitBE(file);
2761
2762   chunk_size = 2 + level_identifier_size + 2;
2763
2764   return chunk_size;
2765 }
2766
2767 static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
2768 {
2769   int i, j;
2770   int chunk_size_expected =
2771     (tape->num_participating_players + 1) * tape->length;
2772
2773   if (chunk_size_expected != chunk_size)
2774   {
2775     ReadUnusedBytesFromFile(file, chunk_size);
2776     return chunk_size_expected;
2777   }
2778
2779   for (i = 0; i < tape->length; i++)
2780   {
2781     if (i >= MAX_TAPELEN)
2782       break;
2783
2784     for (j = 0; j < MAX_PLAYERS; j++)
2785     {
2786       tape->pos[i].action[j] = MV_NO_MOVING;
2787
2788       if (tape->player_participates[j])
2789         tape->pos[i].action[j] = getFile8Bit(file);
2790     }
2791
2792     tape->pos[i].delay = getFile8Bit(file);
2793
2794     if (tape->file_version == FILE_VERSION_1_0)
2795     {
2796       /* eliminate possible diagonal moves in old tapes */
2797       /* this is only for backward compatibility */
2798
2799       byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
2800       byte action = tape->pos[i].action[0];
2801       int k, num_moves = 0;
2802
2803       for (k = 0; k<4; k++)
2804       {
2805         if (action & joy_dir[k])
2806         {
2807           tape->pos[i + num_moves].action[0] = joy_dir[k];
2808           if (num_moves > 0)
2809             tape->pos[i + num_moves].delay = 0;
2810           num_moves++;
2811         }
2812       }
2813
2814       if (num_moves > 1)
2815       {
2816         num_moves--;
2817         i += num_moves;
2818         tape->length += num_moves;
2819       }
2820     }
2821     else if (tape->file_version < FILE_VERSION_2_0)
2822     {
2823       /* convert pre-2.0 tapes to new tape format */
2824
2825       if (tape->pos[i].delay > 1)
2826       {
2827         /* action part */
2828         tape->pos[i + 1] = tape->pos[i];
2829         tape->pos[i + 1].delay = 1;
2830
2831         /* delay part */
2832         for (j = 0; j < MAX_PLAYERS; j++)
2833           tape->pos[i].action[j] = MV_NO_MOVING;
2834         tape->pos[i].delay--;
2835
2836         i++;
2837         tape->length++;
2838       }
2839     }
2840
2841     if (feof(file))
2842       break;
2843   }
2844
2845   if (i != tape->length)
2846     chunk_size = (tape->num_participating_players + 1) * i;
2847
2848   return chunk_size;
2849 }
2850
2851 void LoadTapeFromFilename(char *filename)
2852 {
2853   char cookie[MAX_LINE_LEN];
2854   char chunk_name[CHUNK_ID_LEN + 1];
2855   FILE *file;
2856   int chunk_size;
2857
2858   /* always start with reliable default values */
2859   setTapeInfoToDefaults();
2860
2861   if (!(file = fopen(filename, MODE_READ)))
2862     return;
2863
2864   getFileChunkBE(file, chunk_name, NULL);
2865   if (strcmp(chunk_name, "RND1") == 0)
2866   {
2867     getFile32BitBE(file);               /* not used */
2868
2869     getFileChunkBE(file, chunk_name, NULL);
2870     if (strcmp(chunk_name, "TAPE") != 0)
2871     {
2872       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
2873       fclose(file);
2874       return;
2875     }
2876   }
2877   else  /* check for pre-2.0 file format with cookie string */
2878   {
2879     strcpy(cookie, chunk_name);
2880     fgets(&cookie[4], MAX_LINE_LEN - 4, file);
2881     if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
2882       cookie[strlen(cookie) - 1] = '\0';
2883
2884     if (!checkCookieString(cookie, TAPE_COOKIE_TMPL))
2885     {
2886       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
2887       fclose(file);
2888       return;
2889     }
2890
2891     if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1)
2892     {
2893       Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
2894       fclose(file);
2895       return;
2896     }
2897
2898     /* pre-2.0 tape files have no game version, so use file version here */
2899     tape.game_version = tape.file_version;
2900   }
2901
2902   if (tape.file_version < FILE_VERSION_1_2)
2903   {
2904     /* tape files from versions before 1.2.0 without chunk structure */
2905     LoadTape_HEAD(file, TAPE_HEADER_SIZE, &tape);
2906     LoadTape_BODY(file, 2 * tape.length,  &tape);
2907   }
2908   else
2909   {
2910     static struct
2911     {
2912       char *name;
2913       int size;
2914       int (*loader)(FILE *, int, struct TapeInfo *);
2915     }
2916     chunk_info[] =
2917     {
2918       { "VERS", FILE_VERS_CHUNK_SIZE,   LoadTape_VERS },
2919       { "HEAD", TAPE_HEADER_SIZE,       LoadTape_HEAD },
2920       { "INFO", -1,                     LoadTape_INFO },
2921       { "BODY", -1,                     LoadTape_BODY },
2922       {  NULL,  0,                      NULL }
2923     };
2924
2925     while (getFileChunkBE(file, chunk_name, &chunk_size))
2926     {
2927       int i = 0;
2928
2929       while (chunk_info[i].name != NULL &&
2930              strcmp(chunk_name, chunk_info[i].name) != 0)
2931         i++;
2932
2933       if (chunk_info[i].name == NULL)
2934       {
2935         Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'",
2936               chunk_name, filename);
2937         ReadUnusedBytesFromFile(file, chunk_size);
2938       }
2939       else if (chunk_info[i].size != -1 &&
2940                chunk_info[i].size != chunk_size)
2941       {
2942         Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
2943               chunk_size, chunk_name, filename);
2944         ReadUnusedBytesFromFile(file, chunk_size);
2945       }
2946       else
2947       {
2948         /* call function to load this tape chunk */
2949         int chunk_size_expected =
2950           (chunk_info[i].loader)(file, chunk_size, &tape);
2951
2952         /* the size of some chunks cannot be checked before reading other
2953            chunks first (like "HEAD" and "BODY") that contain some header
2954            information, so check them here */
2955         if (chunk_size_expected != chunk_size)
2956         {
2957           Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
2958                 chunk_size, chunk_name, filename);
2959         }
2960       }
2961     }
2962   }
2963
2964   fclose(file);
2965
2966   tape.length_seconds = GetTapeLength();
2967
2968 #if 0
2969   printf("::: tape game version: %d\n", tape.game_version);
2970   printf("::: tape engine version: %d\n", tape.engine_version);
2971 #endif
2972 }
2973
2974 void LoadTape(int nr)
2975 {
2976   char *filename = getTapeFilename(nr);
2977
2978   LoadTapeFromFilename(filename);
2979 }
2980
2981 void LoadSolutionTape(int nr)
2982 {
2983   char *filename = getSolutionTapeFilename(nr);
2984
2985   LoadTapeFromFilename(filename);
2986 }
2987
2988 static void SaveTape_VERS(FILE *file, struct TapeInfo *tape)
2989 {
2990   putFileVersion(file, tape->file_version);
2991   putFileVersion(file, tape->game_version);
2992 }
2993
2994 static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
2995 {
2996   int i;
2997   byte store_participating_players = 0;
2998
2999   /* set bits for participating players for compact storage */
3000   for (i = 0; i < MAX_PLAYERS; i++)
3001     if (tape->player_participates[i])
3002       store_participating_players |= (1 << i);
3003
3004   putFile32BitBE(file, tape->random_seed);
3005   putFile32BitBE(file, tape->date);
3006   putFile32BitBE(file, tape->length);
3007
3008   putFile8Bit(file, store_participating_players);
3009
3010   /* unused bytes not at the end here for 4-byte alignment of engine_version */
3011   WriteUnusedBytesToFile(file, TAPE_HEADER_UNUSED);
3012
3013   putFileVersion(file, tape->engine_version);
3014 }
3015
3016 static void SaveTape_INFO(FILE *file, struct TapeInfo *tape)
3017 {
3018   int level_identifier_size = strlen(tape->level_identifier) + 1;
3019   int i;
3020
3021   putFile16BitBE(file, level_identifier_size);
3022
3023   for (i = 0; i < level_identifier_size; i++)
3024     putFile8Bit(file, tape->level_identifier[i]);
3025
3026   putFile16BitBE(file, tape->level_nr);
3027 }
3028
3029 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
3030 {
3031   int i, j;
3032
3033   for (i = 0; i < tape->length; i++)
3034   {
3035     for (j = 0; j < MAX_PLAYERS; j++)
3036       if (tape->player_participates[j])
3037         putFile8Bit(file, tape->pos[i].action[j]);
3038
3039     putFile8Bit(file, tape->pos[i].delay);
3040   }
3041 }
3042
3043 void SaveTape(int nr)
3044 {
3045   char *filename = getTapeFilename(nr);
3046   FILE *file;
3047   boolean new_tape = TRUE;
3048   int num_participating_players = 0;
3049   int info_chunk_size;
3050   int body_chunk_size;
3051   int i;
3052
3053   InitTapeDirectory(leveldir_current->subdir);
3054
3055   /* if a tape still exists, ask to overwrite it */
3056   if (access(filename, F_OK) == 0)
3057   {
3058     new_tape = FALSE;
3059     if (!Request("Replace old tape ?", REQ_ASK))
3060       return;
3061   }
3062
3063   if (!(file = fopen(filename, MODE_WRITE)))
3064   {
3065     Error(ERR_WARN, "cannot save level recording file '%s'", filename);
3066     return;
3067   }
3068
3069   tape.file_version = FILE_VERSION_ACTUAL;
3070   tape.game_version = GAME_VERSION_ACTUAL;
3071
3072   /* count number of participating players  */
3073   for (i = 0; i < MAX_PLAYERS; i++)
3074     if (tape.player_participates[i])
3075       num_participating_players++;
3076
3077   info_chunk_size = 2 + (strlen(tape.level_identifier) + 1) + 2;
3078   body_chunk_size = (num_participating_players + 1) * tape.length;
3079
3080   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
3081   putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
3082
3083   putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
3084   SaveTape_VERS(file, &tape);
3085
3086   putFileChunkBE(file, "HEAD", TAPE_HEADER_SIZE);
3087   SaveTape_HEAD(file, &tape);
3088
3089   putFileChunkBE(file, "INFO", info_chunk_size);
3090   SaveTape_INFO(file, &tape);
3091
3092   putFileChunkBE(file, "BODY", body_chunk_size);
3093   SaveTape_BODY(file, &tape);
3094
3095   fclose(file);
3096
3097   SetFilePermissions(filename, PERMS_PRIVATE);
3098
3099   tape.changed = FALSE;
3100
3101   if (new_tape)
3102     Request("tape saved !", REQ_CONFIRM);
3103 }
3104
3105 void DumpTape(struct TapeInfo *tape)
3106 {
3107   int i, j;
3108
3109   if (TAPE_IS_EMPTY(*tape))
3110   {
3111     Error(ERR_WARN, "no tape available for level %d", tape->level_nr);
3112     return;
3113   }
3114
3115   printf_line("-", 79);
3116   printf("Tape of Level %03d (file version %08d, game version %08d)\n",
3117          tape->level_nr, tape->file_version, tape->game_version);
3118   printf("Level series identifier: '%s'\n", tape->level_identifier);
3119   printf_line("-", 79);
3120
3121   for (i = 0; i < tape->length; i++)
3122   {
3123     if (i >= MAX_TAPELEN)
3124       break;
3125
3126     printf("%03d: ", i);
3127
3128     for (j = 0; j < MAX_PLAYERS; j++)
3129     {
3130       if (tape->player_participates[j])
3131       {
3132         int action = tape->pos[i].action[j];
3133
3134         printf("%d:%02x ", j, action);
3135         printf("[%c%c%c%c|%c%c] - ",
3136                (action & JOY_LEFT ? '<' : ' '),
3137                (action & JOY_RIGHT ? '>' : ' '),
3138                (action & JOY_UP ? '^' : ' '),
3139                (action & JOY_DOWN ? 'v' : ' '),
3140                (action & JOY_BUTTON_1 ? '1' : ' '),
3141                (action & JOY_BUTTON_2 ? '2' : ' '));
3142       }
3143     }
3144
3145     printf("(%03d)\n", tape->pos[i].delay);
3146   }
3147
3148   printf_line("-", 79);
3149 }
3150
3151
3152 /* ========================================================================= */
3153 /* score file functions                                                      */
3154 /* ========================================================================= */
3155
3156 void LoadScore(int nr)
3157 {
3158   int i;
3159   char *filename = getScoreFilename(nr);
3160   char cookie[MAX_LINE_LEN];
3161   char line[MAX_LINE_LEN];
3162   char *line_ptr;
3163   FILE *file;
3164
3165   /* always start with reliable default values */
3166   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
3167   {
3168     strcpy(highscore[i].Name, EMPTY_PLAYER_NAME);
3169     highscore[i].Score = 0;
3170   }
3171
3172   if (!(file = fopen(filename, MODE_READ)))
3173     return;
3174
3175   /* check file identifier */
3176   fgets(cookie, MAX_LINE_LEN, file);
3177   if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
3178     cookie[strlen(cookie) - 1] = '\0';
3179
3180   if (!checkCookieString(cookie, SCORE_COOKIE))
3181   {
3182     Error(ERR_WARN, "unknown format of score file '%s'", filename);
3183     fclose(file);
3184     return;
3185   }
3186
3187   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
3188   {
3189     fscanf(file, "%d", &highscore[i].Score);
3190     fgets(line, MAX_LINE_LEN, file);
3191
3192     if (line[strlen(line) - 1] == '\n')
3193       line[strlen(line) - 1] = '\0';
3194
3195     for (line_ptr = line; *line_ptr; line_ptr++)
3196     {
3197       if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
3198       {
3199         strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN);
3200         highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0';
3201         break;
3202       }
3203     }
3204   }
3205
3206   fclose(file);
3207 }
3208
3209 void SaveScore(int nr)
3210 {
3211   int i;
3212   char *filename = getScoreFilename(nr);
3213   FILE *file;
3214
3215   InitScoreDirectory(leveldir_current->subdir);
3216
3217   if (!(file = fopen(filename, MODE_WRITE)))
3218   {
3219     Error(ERR_WARN, "cannot save score for level %d", nr);
3220     return;
3221   }
3222
3223   fprintf(file, "%s\n\n", SCORE_COOKIE);
3224
3225   for (i = 0; i < MAX_SCORE_ENTRIES; i++)
3226     fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name);
3227
3228   fclose(file);
3229
3230   SetFilePermissions(filename, PERMS_PUBLIC);
3231 }
3232
3233
3234 /* ========================================================================= */
3235 /* setup file functions                                                      */
3236 /* ========================================================================= */
3237
3238 #define TOKEN_STR_PLAYER_PREFIX                 "player_"
3239
3240 /* global setup */
3241 #define SETUP_TOKEN_PLAYER_NAME                 0
3242 #define SETUP_TOKEN_SOUND                       1
3243 #define SETUP_TOKEN_SOUND_LOOPS                 2
3244 #define SETUP_TOKEN_SOUND_MUSIC                 3
3245 #define SETUP_TOKEN_SOUND_SIMPLE                4
3246 #define SETUP_TOKEN_TOONS                       5
3247 #define SETUP_TOKEN_SCROLL_DELAY                6
3248 #define SETUP_TOKEN_SOFT_SCROLLING              7
3249 #define SETUP_TOKEN_FADING                      8
3250 #define SETUP_TOKEN_AUTORECORD                  9
3251 #define SETUP_TOKEN_QUICK_DOORS                 10
3252 #define SETUP_TOKEN_TEAM_MODE                   11
3253 #define SETUP_TOKEN_HANDICAP                    12
3254 #define SETUP_TOKEN_TIME_LIMIT                  13
3255 #define SETUP_TOKEN_FULLSCREEN                  14
3256 #define SETUP_TOKEN_ASK_ON_ESCAPE               15
3257 #define SETUP_TOKEN_GRAPHICS_SET                16
3258 #define SETUP_TOKEN_SOUNDS_SET                  17
3259 #define SETUP_TOKEN_MUSIC_SET                   18
3260 #define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS     19
3261 #define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS       20
3262 #define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC        21
3263
3264 #define NUM_GLOBAL_SETUP_TOKENS                 22
3265
3266 /* editor setup */
3267 #define SETUP_TOKEN_EDITOR_EL_BOULDERDASH       0
3268 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE      1
3269 #define SETUP_TOKEN_EDITOR_EL_MORE              2
3270 #define SETUP_TOKEN_EDITOR_EL_SOKOBAN           3
3271 #define SETUP_TOKEN_EDITOR_EL_SUPAPLEX          4
3272 #define SETUP_TOKEN_EDITOR_EL_DIAMOND_CAVES     5
3273 #define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH    6
3274 #define SETUP_TOKEN_EDITOR_EL_CHARS             7
3275 #define SETUP_TOKEN_EDITOR_EL_CUSTOM            8
3276 #define SETUP_TOKEN_EDITOR_EL_CUSTOM_MORE       9
3277 #define SETUP_TOKEN_EDITOR_EL_HEADLINES         10
3278 #define SETUP_TOKEN_EDITOR_EL_USER_DEFINED      11
3279
3280 #define NUM_EDITOR_SETUP_TOKENS                 12
3281
3282 /* shortcut setup */
3283 #define SETUP_TOKEN_SHORTCUT_SAVE_GAME          0
3284 #define SETUP_TOKEN_SHORTCUT_LOAD_GAME          1
3285 #define SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE       2
3286
3287 #define NUM_SHORTCUT_SETUP_TOKENS               3
3288
3289 /* player setup */
3290 #define SETUP_TOKEN_PLAYER_USE_JOYSTICK         0
3291 #define SETUP_TOKEN_PLAYER_JOY_DEVICE_NAME      1
3292 #define SETUP_TOKEN_PLAYER_JOY_XLEFT            2
3293 #define SETUP_TOKEN_PLAYER_JOY_XMIDDLE          3
3294 #define SETUP_TOKEN_PLAYER_JOY_XRIGHT           4
3295 #define SETUP_TOKEN_PLAYER_JOY_YUPPER           5
3296 #define SETUP_TOKEN_PLAYER_JOY_YMIDDLE          6
3297 #define SETUP_TOKEN_PLAYER_JOY_YLOWER           7
3298 #define SETUP_TOKEN_PLAYER_JOY_SNAP             8
3299 #define SETUP_TOKEN_PLAYER_JOY_DROP             9
3300 #define SETUP_TOKEN_PLAYER_KEY_LEFT             10
3301 #define SETUP_TOKEN_PLAYER_KEY_RIGHT            11
3302 #define SETUP_TOKEN_PLAYER_KEY_UP               12
3303 #define SETUP_TOKEN_PLAYER_KEY_DOWN             13
3304 #define SETUP_TOKEN_PLAYER_KEY_SNAP             14
3305 #define SETUP_TOKEN_PLAYER_KEY_DROP             15
3306
3307 #define NUM_PLAYER_SETUP_TOKENS                 16
3308
3309 /* system setup */
3310 #define SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER      0
3311 #define SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE  1
3312
3313 #define NUM_SYSTEM_SETUP_TOKENS                 2
3314
3315 /* options setup */
3316 #define SETUP_TOKEN_OPTIONS_VERBOSE             0
3317
3318 #define NUM_OPTIONS_SETUP_TOKENS                1
3319
3320
3321 static struct SetupInfo si;
3322 static struct SetupEditorInfo sei;
3323 static struct SetupShortcutInfo ssi;
3324 static struct SetupInputInfo sii;
3325 static struct SetupSystemInfo syi;
3326 static struct OptionInfo soi;
3327
3328 static struct TokenInfo global_setup_tokens[] =
3329 {
3330   { TYPE_STRING, &si.player_name,       "player_name"                   },
3331   { TYPE_SWITCH, &si.sound,             "sound"                         },
3332   { TYPE_SWITCH, &si.sound_loops,       "repeating_sound_loops"         },
3333   { TYPE_SWITCH, &si.sound_music,       "background_music"              },
3334   { TYPE_SWITCH, &si.sound_simple,      "simple_sound_effects"          },
3335   { TYPE_SWITCH, &si.toons,             "toons"                         },
3336   { TYPE_SWITCH, &si.scroll_delay,      "scroll_delay"                  },
3337   { TYPE_SWITCH, &si.soft_scrolling,    "soft_scrolling"                },
3338   { TYPE_SWITCH, &si.fading,            "screen_fading"                 },
3339   { TYPE_SWITCH, &si.autorecord,        "automatic_tape_recording"      },
3340   { TYPE_SWITCH, &si.quick_doors,       "quick_doors"                   },
3341   { TYPE_SWITCH, &si.team_mode,         "team_mode"                     },
3342   { TYPE_SWITCH, &si.handicap,          "handicap"                      },
3343   { TYPE_SWITCH, &si.time_limit,        "time_limit"                    },
3344   { TYPE_SWITCH, &si.fullscreen,        "fullscreen"                    },
3345   { TYPE_SWITCH, &si.ask_on_escape,     "ask_on_escape"                 },
3346   { TYPE_STRING, &si.graphics_set,      "graphics_set"                  },
3347   { TYPE_STRING, &si.sounds_set,        "sounds_set"                    },
3348   { TYPE_STRING, &si.music_set,         "music_set"                     },
3349   { TYPE_SWITCH, &si.override_level_graphics, "override_level_graphics" },
3350   { TYPE_SWITCH, &si.override_level_sounds,   "override_level_sounds"   },
3351   { TYPE_SWITCH, &si.override_level_music,    "override_level_music"    },
3352 };
3353
3354 static struct TokenInfo editor_setup_tokens[] =
3355 {
3356   { TYPE_SWITCH, &sei.el_boulderdash,   "editor.el_boulderdash"         },
3357   { TYPE_SWITCH, &sei.el_emerald_mine,  "editor.el_emerald_mine"        },
3358   { TYPE_SWITCH, &sei.el_more,          "editor.el_more"                },
3359   { TYPE_SWITCH, &sei.el_sokoban,       "editor.el_sokoban"             },
3360   { TYPE_SWITCH, &sei.el_supaplex,      "editor.el_supaplex"            },
3361   { TYPE_SWITCH, &sei.el_diamond_caves, "editor.el_diamond_caves"       },
3362   { TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash"      },
3363   { TYPE_SWITCH, &sei.el_chars,         "editor.el_chars"               },
3364   { TYPE_SWITCH, &sei.el_custom,        "editor.el_custom"              },
3365   { TYPE_SWITCH, &sei.el_custom_more,   "editor.el_custom_more"         },
3366   { TYPE_SWITCH, &sei.el_headlines,     "editor.el_headlines"           },
3367   { TYPE_SWITCH, &sei.el_user_defined,  "editor.el_user_defined"        },
3368 };
3369
3370 static struct TokenInfo shortcut_setup_tokens[] =
3371 {
3372   { TYPE_KEY_X11, &ssi.save_game,       "shortcut.save_game"            },
3373   { TYPE_KEY_X11, &ssi.load_game,       "shortcut.load_game"            },
3374   { TYPE_KEY_X11, &ssi.toggle_pause,    "shortcut.toggle_pause"         }
3375 };
3376
3377 static struct TokenInfo player_setup_tokens[] =
3378 {
3379   { TYPE_BOOLEAN, &sii.use_joystick,    ".use_joystick"                 },
3380   { TYPE_STRING,  &sii.joy.device_name, ".joy.device_name"              },
3381   { TYPE_INTEGER, &sii.joy.xleft,       ".joy.xleft"                    },
3382   { TYPE_INTEGER, &sii.joy.xmiddle,     ".joy.xmiddle"                  },
3383   { TYPE_INTEGER, &sii.joy.xright,      ".joy.xright"                   },
3384   { TYPE_INTEGER, &sii.joy.yupper,      ".joy.yupper"                   },
3385   { TYPE_INTEGER, &sii.joy.ymiddle,     ".joy.ymiddle"                  },
3386   { TYPE_INTEGER, &sii.joy.ylower,      ".joy.ylower"                   },
3387   { TYPE_INTEGER, &sii.joy.snap,        ".joy.snap_field"               },
3388   { TYPE_INTEGER, &sii.joy.drop,        ".joy.place_bomb"               },
3389   { TYPE_KEY_X11, &sii.key.left,        ".key.move_left"                },
3390   { TYPE_KEY_X11, &sii.key.right,       ".key.move_right"               },
3391   { TYPE_KEY_X11, &sii.key.up,          ".key.move_up"                  },
3392   { TYPE_KEY_X11, &sii.key.down,        ".key.move_down"                },
3393   { TYPE_KEY_X11, &sii.key.snap,        ".key.snap_field"               },
3394   { TYPE_KEY_X11, &sii.key.drop,        ".key.place_bomb"               }
3395 };
3396
3397 static struct TokenInfo system_setup_tokens[] =
3398 {
3399   { TYPE_STRING,  &syi.sdl_audiodriver, "system.sdl_audiodriver"        },
3400   { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size" }
3401 };
3402
3403 static struct TokenInfo options_setup_tokens[] =
3404 {
3405   { TYPE_BOOLEAN, &soi.verbose,         "options.verbose"               }
3406 };
3407
3408 static char *get_corrected_login_name(char *login_name)
3409 {
3410   /* needed because player name must be a fixed length string */
3411   char *login_name_new = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
3412
3413   strncpy(login_name_new, login_name, MAX_PLAYER_NAME_LEN);
3414   login_name_new[MAX_PLAYER_NAME_LEN] = '\0';
3415
3416   if (strlen(login_name) > MAX_PLAYER_NAME_LEN)         /* name has been cut */
3417     if (strchr(login_name_new, ' '))
3418       *strchr(login_name_new, ' ') = '\0';
3419
3420   return login_name_new;
3421 }
3422
3423 static void setSetupInfoToDefaults(struct SetupInfo *si)
3424 {
3425   int i;
3426
3427   si->player_name = get_corrected_login_name(getLoginName());
3428
3429   si->sound = TRUE;
3430   si->sound_loops = TRUE;
3431   si->sound_music = TRUE;
3432   si->sound_simple = TRUE;
3433   si->toons = TRUE;
3434   si->double_buffering = TRUE;
3435   si->direct_draw = !si->double_buffering;
3436   si->scroll_delay = TRUE;
3437   si->soft_scrolling = TRUE;
3438   si->fading = FALSE;
3439   si->autorecord = TRUE;
3440   si->quick_doors = FALSE;
3441   si->team_mode = FALSE;
3442   si->handicap = TRUE;
3443   si->time_limit = TRUE;
3444   si->fullscreen = FALSE;
3445   si->ask_on_escape = TRUE;
3446
3447   si->graphics_set = getStringCopy(GFX_CLASSIC_SUBDIR);
3448   si->sounds_set = getStringCopy(SND_CLASSIC_SUBDIR);
3449   si->music_set = getStringCopy(MUS_CLASSIC_SUBDIR);
3450   si->override_level_graphics = FALSE;
3451   si->override_level_sounds = FALSE;
3452   si->override_level_music = FALSE;
3453
3454   si->editor.el_boulderdash = TRUE;
3455   si->editor.el_emerald_mine = TRUE;
3456   si->editor.el_more = TRUE;
3457   si->editor.el_sokoban = TRUE;
3458   si->editor.el_supaplex = TRUE;
3459   si->editor.el_diamond_caves = TRUE;
3460   si->editor.el_dx_boulderdash = TRUE;
3461   si->editor.el_chars = TRUE;
3462   si->editor.el_custom = TRUE;
3463   si->editor.el_custom_more = FALSE;
3464
3465   si->editor.el_headlines = TRUE;
3466   si->editor.el_user_defined = FALSE;
3467
3468   si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
3469   si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME;
3470   si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE;
3471
3472   for (i = 0; i < MAX_PLAYERS; i++)
3473   {
3474     si->input[i].use_joystick = FALSE;
3475     si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
3476     si->input[i].joy.xleft   = JOYSTICK_XLEFT;
3477     si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
3478     si->input[i].joy.xright  = JOYSTICK_XRIGHT;
3479     si->input[i].joy.yupper  = JOYSTICK_YUPPER;
3480     si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
3481     si->input[i].joy.ylower  = JOYSTICK_YLOWER;
3482     si->input[i].joy.snap  = (i == 0 ? JOY_BUTTON_1 : 0);
3483     si->input[i].joy.drop  = (i == 0 ? JOY_BUTTON_2 : 0);
3484     si->input[i].key.left  = (i == 0 ? DEFAULT_KEY_LEFT  : KSYM_UNDEFINED);
3485     si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
3486     si->input[i].key.up    = (i == 0 ? DEFAULT_KEY_UP    : KSYM_UNDEFINED);
3487     si->input[i].key.down  = (i == 0 ? DEFAULT_KEY_DOWN  : KSYM_UNDEFINED);
3488     si->input[i].key.snap  = (i == 0 ? DEFAULT_KEY_SNAP  : KSYM_UNDEFINED);
3489     si->input[i].key.drop  = (i == 0 ? DEFAULT_KEY_DROP  : KSYM_UNDEFINED);
3490   }
3491
3492   si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT);
3493   si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
3494
3495   si->options.verbose = FALSE;
3496 }
3497
3498 static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
3499 {
3500   int i, pnr;
3501
3502   if (!setup_file_hash)
3503     return;
3504
3505   /* global setup */
3506   si = setup;
3507   for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
3508     setSetupInfo(global_setup_tokens, i,
3509                  getHashEntry(setup_file_hash, global_setup_tokens[i].text));
3510   setup = si;
3511
3512   /* editor setup */
3513   sei = setup.editor;
3514   for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
3515     setSetupInfo(editor_setup_tokens, i,
3516                  getHashEntry(setup_file_hash,editor_setup_tokens[i].text));
3517   setup.editor = sei;
3518
3519   /* shortcut setup */
3520   ssi = setup.shortcut;
3521   for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
3522     setSetupInfo(shortcut_setup_tokens, i,
3523                  getHashEntry(setup_file_hash,shortcut_setup_tokens[i].text));
3524   setup.shortcut = ssi;
3525
3526   /* player setup */
3527   for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
3528   {
3529     char prefix[30];
3530
3531     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
3532
3533     sii = setup.input[pnr];
3534     for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
3535     {
3536       char full_token[100];
3537
3538       sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
3539       setSetupInfo(player_setup_tokens, i,
3540                    getHashEntry(setup_file_hash, full_token));
3541     }
3542     setup.input[pnr] = sii;
3543   }
3544
3545   /* system setup */
3546   syi = setup.system;
3547   for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
3548     setSetupInfo(system_setup_tokens, i,
3549                  getHashEntry(setup_file_hash, system_setup_tokens[i].text));
3550   setup.system = syi;
3551
3552   /* options setup */
3553   soi = setup.options;
3554   for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
3555     setSetupInfo(options_setup_tokens, i,
3556                  getHashEntry(setup_file_hash, options_setup_tokens[i].text));
3557   setup.options = soi;
3558 }
3559
3560 void LoadSetup()
3561 {
3562   char *filename = getSetupFilename();
3563   SetupFileHash *setup_file_hash = NULL;
3564
3565   /* always start with reliable default values */
3566   setSetupInfoToDefaults(&setup);
3567
3568   setup_file_hash = loadSetupFileHash(filename);
3569
3570   if (setup_file_hash)
3571   {
3572     char *player_name_new;
3573
3574     checkSetupFileHashIdentifier(setup_file_hash, getCookie("SETUP"));
3575     decodeSetupFileHash(setup_file_hash);
3576
3577     setup.direct_draw = !setup.double_buffering;
3578
3579     freeSetupFileHash(setup_file_hash);
3580
3581     /* needed to work around problems with fixed length strings */
3582     player_name_new = get_corrected_login_name(setup.player_name);
3583     free(setup.player_name);
3584     setup.player_name = player_name_new;
3585   }
3586   else
3587     Error(ERR_WARN, "using default setup values");
3588 }
3589
3590 void SaveSetup()
3591 {
3592   char *filename = getSetupFilename();
3593   FILE *file;
3594   int i, pnr;
3595
3596   InitUserDataDirectory();
3597
3598   if (!(file = fopen(filename, MODE_WRITE)))
3599   {
3600     Error(ERR_WARN, "cannot write setup file '%s'", filename);
3601     return;
3602   }
3603
3604   fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
3605                                                getCookie("SETUP")));
3606   fprintf(file, "\n");
3607
3608   /* global setup */
3609   si = setup;
3610   for (i = 0; i < NUM_GLOBAL_SETUP_TOKENS; i++)
3611   {
3612     /* just to make things nicer :) */
3613     if (i == SETUP_TOKEN_PLAYER_NAME + 1 ||
3614         i == SETUP_TOKEN_GRAPHICS_SET)
3615       fprintf(file, "\n");
3616
3617     fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
3618   }
3619
3620   /* editor setup */
3621   sei = setup.editor;
3622   fprintf(file, "\n");
3623   for (i = 0; i < NUM_EDITOR_SETUP_TOKENS; i++)
3624     fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i));
3625
3626   /* shortcut setup */
3627   ssi = setup.shortcut;
3628   fprintf(file, "\n");
3629   for (i = 0; i < NUM_SHORTCUT_SETUP_TOKENS; i++)
3630     fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
3631
3632   /* player setup */
3633   for (pnr = 0; pnr < MAX_PLAYERS; pnr++)
3634   {
3635     char prefix[30];
3636
3637     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
3638     fprintf(file, "\n");
3639
3640     sii = setup.input[pnr];
3641     for (i = 0; i < NUM_PLAYER_SETUP_TOKENS; i++)
3642       fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
3643   }
3644
3645   /* system setup */
3646   syi = setup.system;
3647   fprintf(file, "\n");
3648   for (i = 0; i < NUM_SYSTEM_SETUP_TOKENS; i++)
3649     fprintf(file, "%s\n", getSetupLine(system_setup_tokens, "", i));
3650
3651   /* options setup */
3652   soi = setup.options;
3653   fprintf(file, "\n");
3654   for (i = 0; i < NUM_OPTIONS_SETUP_TOKENS; i++)
3655     fprintf(file, "%s\n", getSetupLine(options_setup_tokens, "", i));
3656
3657   fclose(file);
3658
3659   SetFilePermissions(filename, PERMS_PRIVATE);
3660 }
3661
3662 void LoadCustomElementDescriptions()
3663 {
3664   char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
3665   SetupFileHash *setup_file_hash;
3666   int i;
3667
3668   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
3669   {
3670     if (element_info[i].custom_description != NULL)
3671     {
3672       free(element_info[i].custom_description);
3673       element_info[i].custom_description = NULL;
3674     }
3675   }
3676
3677   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
3678     return;
3679
3680   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
3681   {
3682     char *token = getStringCat2(element_info[i].token_name, ".name");
3683     char *value = getHashEntry(setup_file_hash, token);
3684
3685     if (value != NULL)
3686       element_info[i].custom_description = getStringCopy(value);
3687
3688     free(token);
3689   }
3690
3691   freeSetupFileHash(setup_file_hash);
3692 }
3693
3694 void LoadSpecialMenuDesignSettings()
3695 {
3696   char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
3697   SetupFileHash *setup_file_hash;
3698   int i, j;
3699
3700   /* always start with reliable default values from default config */
3701   for (i = 0; image_config_vars[i].token != NULL; i++)
3702     for (j = 0; image_config[j].token != NULL; j++)
3703       if (strcmp(image_config_vars[i].token, image_config[j].token) == 0)
3704         *image_config_vars[i].value =
3705           get_auto_parameter_value(image_config_vars[i].token,
3706                                    image_config[j].value);
3707
3708   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
3709     return;
3710
3711   /* special case: initialize with default values that may be overwritten */
3712   for (i = 0; i < NUM_SPECIAL_GFX_ARGS; i++)
3713   {
3714     char *value_x = getHashEntry(setup_file_hash, "menu.draw_xoffset");
3715     char *value_y = getHashEntry(setup_file_hash, "menu.draw_yoffset");
3716     char *list_size = getHashEntry(setup_file_hash, "menu.list_size");
3717
3718     if (value_x != NULL)
3719       menu.draw_xoffset[i] = get_integer_from_string(value_x);
3720     if (value_y != NULL)
3721       menu.draw_yoffset[i] = get_integer_from_string(value_y);
3722     if (list_size != NULL)
3723       menu.list_size[i] = get_integer_from_string(list_size);
3724   }
3725
3726   /* read (and overwrite with) values that may be specified in config file */
3727   for (i = 0; image_config_vars[i].token != NULL; i++)
3728   {
3729     char *value = getHashEntry(setup_file_hash, image_config_vars[i].token);
3730
3731     if (value != NULL)
3732       *image_config_vars[i].value =
3733         get_auto_parameter_value(image_config_vars[i].token, value);
3734   }
3735
3736   freeSetupFileHash(setup_file_hash);
3737 }
3738
3739 void LoadUserDefinedEditorElementList(int **elements, int *num_elements)
3740 {
3741   char *filename = getEditorSetupFilename();
3742   SetupFileList *setup_file_list, *list;
3743   SetupFileHash *element_hash;
3744   int num_unknown_tokens = 0;
3745   int i;
3746
3747   if ((setup_file_list = loadSetupFileList(filename)) == NULL)
3748     return;
3749
3750   element_hash = newSetupFileHash();
3751
3752   for (i = 0; i < NUM_FILE_ELEMENTS; i++)
3753     setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
3754
3755   /* determined size may be larger than needed (due to unknown elements) */
3756   *num_elements = 0;
3757   for (list = setup_file_list; list != NULL; list = list->next)
3758     (*num_elements)++;
3759
3760   /* add space for up to 3 more elements for padding that may be needed */
3761   *num_elements += 3;
3762
3763   *elements = checked_malloc(*num_elements * sizeof(int));
3764
3765   *num_elements = 0;
3766   for (list = setup_file_list; list != NULL; list = list->next)
3767   {
3768     char *value = getHashEntry(element_hash, list->token);
3769
3770     if (value)
3771     {
3772       (*elements)[(*num_elements)++] = atoi(value);
3773     }
3774     else
3775     {
3776       if (num_unknown_tokens == 0)
3777       {
3778         Error(ERR_RETURN_LINE, "-");
3779         Error(ERR_RETURN, "warning: unknown token(s) found in config file:");
3780         Error(ERR_RETURN, "- config file: '%s'", filename);
3781
3782         num_unknown_tokens++;
3783       }
3784
3785       Error(ERR_RETURN, "- token: '%s'", list->token);
3786     }
3787   }
3788
3789   if (num_unknown_tokens > 0)
3790     Error(ERR_RETURN_LINE, "-");
3791
3792   while (*num_elements % 4)     /* pad with empty elements, if needed */
3793     (*elements)[(*num_elements)++] = EL_EMPTY;
3794
3795   freeSetupFileList(setup_file_list);
3796   freeSetupFileHash(element_hash);
3797
3798 #if 0
3799   /* TEST-ONLY */
3800   for (i = 0; i < *num_elements; i++)
3801     printf("editor: element '%s' [%d]\n",
3802            element_info[(*elements)[i]].token_name, (*elements)[i]);
3803 #endif
3804 }
3805
3806 static struct MusicFileInfo *get_music_file_info_ext(char *basename, int music,
3807                                                      boolean is_sound)
3808 {
3809   SetupFileHash *setup_file_hash = NULL;
3810   struct MusicFileInfo tmp_music_file_info, *new_music_file_info;
3811   char *filename_music, *filename_prefix, *filename_info;
3812   struct
3813   {
3814     char *token;
3815     char **value_ptr;
3816   }
3817   token_to_value_ptr[] =
3818   {
3819     { "title_header",   &tmp_music_file_info.title_header       },
3820     { "artist_header",  &tmp_music_file_info.artist_header      },
3821     { "album_header",   &tmp_music_file_info.album_header       },
3822     { "year_header",    &tmp_music_file_info.year_header        },
3823
3824     { "title",          &tmp_music_file_info.title              },
3825     { "artist",         &tmp_music_file_info.artist             },
3826     { "album",          &tmp_music_file_info.album              },
3827     { "year",           &tmp_music_file_info.year               },
3828
3829     { NULL,             NULL                                    },
3830   };
3831   int i;
3832
3833   filename_music = (is_sound ? getCustomSoundFilename(basename) :
3834                     getCustomMusicFilename(basename));
3835
3836   if (filename_music == NULL)
3837     return NULL;
3838
3839   /* ---------- try to replace file extension ---------- */
3840
3841   filename_prefix = getStringCopy(filename_music);
3842   if (strrchr(filename_prefix, '.') != NULL)
3843     *strrchr(filename_prefix, '.') = '\0';
3844   filename_info = getStringCat2(filename_prefix, ".txt");
3845
3846 #if 0
3847   printf("trying to load file '%s'...\n", filename_info);
3848 #endif
3849
3850   if (fileExists(filename_info))
3851     setup_file_hash = loadSetupFileHash(filename_info);
3852
3853   free(filename_prefix);
3854   free(filename_info);
3855
3856   if (setup_file_hash == NULL)
3857   {
3858     /* ---------- try to add file extension ---------- */
3859
3860     filename_prefix = getStringCopy(filename_music);
3861     filename_info = getStringCat2(filename_prefix, ".txt");
3862
3863 #if 0
3864     printf("trying to load file '%s'...\n", filename_info);
3865 #endif
3866
3867     if (fileExists(filename_info))
3868       setup_file_hash = loadSetupFileHash(filename_info);
3869
3870     free(filename_prefix);
3871     free(filename_info);
3872   }
3873
3874   if (setup_file_hash == NULL)
3875     return NULL;
3876
3877   /* ---------- music file info found ---------- */
3878
3879   memset(&tmp_music_file_info, 0, sizeof(struct MusicFileInfo));
3880
3881   for (i = 0; token_to_value_ptr[i].token != NULL; i++)
3882   {
3883     char *value = getHashEntry(setup_file_hash, token_to_value_ptr[i].token);
3884
3885     *token_to_value_ptr[i].value_ptr =
3886       getStringCopy(value != NULL && *value != '\0' ? value : UNKNOWN_NAME);
3887   }
3888
3889   tmp_music_file_info.basename = getStringCopy(basename);
3890   tmp_music_file_info.music = music;
3891   tmp_music_file_info.is_sound = is_sound;
3892
3893   new_music_file_info = checked_malloc(sizeof(struct MusicFileInfo));
3894   *new_music_file_info = tmp_music_file_info;
3895
3896   return new_music_file_info;
3897 }
3898
3899 static struct MusicFileInfo *get_music_file_info(char *basename, int music)
3900 {
3901   return get_music_file_info_ext(basename, music, FALSE);
3902 }
3903
3904 static struct MusicFileInfo *get_sound_file_info(char *basename, int sound)
3905 {
3906   return get_music_file_info_ext(basename, sound, TRUE);
3907 }
3908
3909 static boolean music_info_listed_ext(struct MusicFileInfo *list,
3910                                      char *basename, boolean is_sound)
3911 {
3912   for (; list != NULL; list = list->next)
3913     if (list->is_sound == is_sound && strcmp(list->basename, basename) == 0)
3914       return TRUE;
3915
3916   return FALSE;
3917 }
3918
3919 static boolean music_info_listed(struct MusicFileInfo *list, char *basename)
3920 {
3921   return music_info_listed_ext(list, basename, FALSE);
3922 }
3923
3924 static boolean sound_info_listed(struct MusicFileInfo *list, char *basename)
3925 {
3926   return music_info_listed_ext(list, basename, TRUE);
3927 }
3928
3929 void LoadMusicInfo()
3930 {
3931   char *music_directory = getCustomMusicDirectory();
3932   int num_music = getMusicListSize();
3933   int num_music_noconf = 0;
3934   int num_sounds = getSoundListSize();
3935   DIR *dir;
3936   struct dirent *dir_entry;
3937   struct FileInfo *music, *sound;
3938   struct MusicFileInfo *next, **new;
3939   int i;
3940
3941   while (music_file_info != NULL)
3942   {
3943     next = music_file_info->next;
3944
3945     checked_free(music_file_info->basename);
3946
3947     checked_free(music_file_info->title_header);
3948     checked_free(music_file_info->artist_header);
3949     checked_free(music_file_info->album_header);
3950     checked_free(music_file_info->year_header);
3951
3952     checked_free(music_file_info->title);
3953     checked_free(music_file_info->artist);
3954     checked_free(music_file_info->album);
3955     checked_free(music_file_info->year);
3956
3957     free(music_file_info);
3958
3959     music_file_info = next;
3960   }
3961
3962   new = &music_file_info;
3963
3964 #if 0
3965   printf("::: num_music == %d\n", num_music);
3966 #endif
3967
3968   for (i = 0; i < num_music; i++)
3969   {
3970     music = getMusicListEntry(i);
3971
3972 #if 0
3973     printf("::: %d [%08x]\n", i, music->filename);
3974 #endif
3975
3976     if (music->filename == NULL)
3977       continue;
3978
3979     if (strcmp(music->filename, UNDEFINED_FILENAME) == 0)
3980       continue;
3981
3982     /* a configured file may be not recognized as music */
3983     if (!FileIsMusic(music->filename))
3984       continue;
3985
3986 #if 0
3987     printf("::: -> '%s' (configured)\n", music->filename);
3988 #endif
3989
3990     if (!music_info_listed(music_file_info, music->filename))
3991     {
3992       *new = get_music_file_info(music->filename, i);
3993       if (*new != NULL)
3994         new = &(*new)->next;
3995     }
3996   }
3997
3998   if ((dir = opendir(music_directory)) == NULL)
3999   {
4000     Error(ERR_WARN, "cannot read music directory '%s'", music_directory);
4001     return;
4002   }
4003
4004   while ((dir_entry = readdir(dir)) != NULL)    /* loop until last dir entry */
4005   {
4006     char *basename = dir_entry->d_name;
4007     boolean music_already_used = FALSE;
4008     int i;
4009
4010     /* skip all music files that are configured in music config file */
4011     for (i = 0; i < num_music; i++)
4012     {
4013       music = getMusicListEntry(i);
4014
4015       if (music->filename == NULL)
4016         continue;
4017
4018       if (strcmp(basename, music->filename) == 0)
4019       {
4020         music_already_used = TRUE;
4021         break;
4022       }
4023     }
4024
4025     if (music_already_used)
4026       continue;
4027
4028     if (!FileIsMusic(basename))
4029       continue;
4030
4031 #if 0
4032     printf("::: -> '%s' (found in directory)\n", basename);
4033 #endif
4034
4035     if (!music_info_listed(music_file_info, basename))
4036     {
4037       *new = get_music_file_info(basename, MAP_NOCONF_MUSIC(num_music_noconf));
4038       if (*new != NULL)
4039         new = &(*new)->next;
4040     }
4041
4042     num_music_noconf++;
4043   }
4044
4045   closedir(dir);
4046
4047   for (i = 0; i < num_sounds; i++)
4048   {
4049     sound = getSoundListEntry(i);
4050
4051     if (sound->filename == NULL)
4052       continue;
4053
4054     if (strcmp(sound->filename, UNDEFINED_FILENAME) == 0)
4055       continue;
4056
4057     /* a configured file may be not recognized as sound */
4058     if (!FileIsSound(sound->filename))
4059       continue;
4060
4061 #if 0
4062     printf("::: -> '%s' (configured)\n", sound->filename);
4063 #endif
4064
4065     if (!sound_info_listed(music_file_info, sound->filename))
4066     {
4067       *new = get_sound_file_info(sound->filename, i);
4068       if (*new != NULL)
4069         new = &(*new)->next;
4070     }
4071   }
4072
4073 #if 0
4074   /* TEST-ONLY */
4075   for (next = music_file_info; next != NULL; next = next->next)
4076     printf("::: title == '%s'\n", next->title);
4077 #endif
4078 }
4079
4080 void add_helpanim_entry(int element, int action, int direction, int delay,
4081                         int *num_list_entries)
4082 {
4083   struct HelpAnimInfo *new_list_entry;
4084   (*num_list_entries)++;
4085
4086   helpanim_info =
4087     checked_realloc(helpanim_info,
4088                     *num_list_entries * sizeof(struct HelpAnimInfo));
4089   new_list_entry = &helpanim_info[*num_list_entries - 1];
4090
4091   new_list_entry->element = element;
4092   new_list_entry->action = action;
4093   new_list_entry->direction = direction;
4094   new_list_entry->delay = delay;
4095 }
4096
4097 void print_unknown_token(char *filename, char *token, int token_nr)
4098 {
4099   if (token_nr == 0)
4100   {
4101     Error(ERR_RETURN_LINE, "-");
4102     Error(ERR_RETURN, "warning: unknown token(s) found in config file:");
4103     Error(ERR_RETURN, "- config file: '%s'", filename);
4104   }
4105
4106   Error(ERR_RETURN, "- token: '%s'", token);
4107 }
4108
4109 void print_unknown_token_end(int token_nr)
4110 {
4111   if (token_nr > 0)
4112     Error(ERR_RETURN_LINE, "-");
4113 }
4114
4115 void LoadHelpAnimInfo()
4116 {
4117   char *filename = getHelpAnimFilename();
4118   SetupFileList *setup_file_list = NULL, *list;
4119   SetupFileHash *element_hash, *action_hash, *direction_hash;
4120   int num_list_entries = 0;
4121   int num_unknown_tokens = 0;
4122   int i;
4123
4124   if (fileExists(filename))
4125     setup_file_list = loadSetupFileList(filename);
4126
4127   if (setup_file_list == NULL)
4128   {
4129     /* use reliable default values from static configuration */
4130     SetupFileList *insert_ptr;
4131
4132     insert_ptr = setup_file_list =
4133       newSetupFileList(helpanim_config[0].token,
4134                        helpanim_config[0].value);
4135
4136     for (i = 1; helpanim_config[i].token; i++)
4137       insert_ptr = addListEntry(insert_ptr,
4138                                 helpanim_config[i].token,
4139                                 helpanim_config[i].value);
4140   }
4141
4142   element_hash   = newSetupFileHash();
4143   action_hash    = newSetupFileHash();
4144   direction_hash = newSetupFileHash();
4145
4146   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
4147     setHashEntry(element_hash, element_info[i].token_name, i_to_a(i));
4148
4149   for (i = 0; i < NUM_ACTIONS; i++)
4150     setHashEntry(action_hash, element_action_info[i].suffix,
4151                  i_to_a(element_action_info[i].value));
4152
4153   /* do not store direction index (bit) here, but direction value! */
4154   for (i = 0; i < NUM_DIRECTIONS; i++)
4155     setHashEntry(direction_hash, element_direction_info[i].suffix,
4156                  i_to_a(1 << element_direction_info[i].value));
4157
4158   for (list = setup_file_list; list != NULL; list = list->next)
4159   {
4160     char *element_token, *action_token, *direction_token;
4161     char *element_value, *action_value, *direction_value;
4162     int delay = atoi(list->value);
4163
4164     if (strcmp(list->token, "end") == 0)
4165     {
4166       add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
4167
4168       continue;
4169     }
4170
4171     /* first try to break element into element/action/direction parts;
4172        if this does not work, also accept combined "element[.act][.dir]"
4173        elements (like "dynamite.active"), which are unique elements */
4174
4175     if (strchr(list->token, '.') == NULL)       /* token contains no '.' */
4176     {
4177       element_value = getHashEntry(element_hash, list->token);
4178       if (element_value != NULL)        /* element found */
4179         add_helpanim_entry(atoi(element_value), -1, -1, delay,
4180                            &num_list_entries);
4181       else
4182       {
4183         /* no further suffixes found -- this is not an element */
4184         print_unknown_token(filename, list->token, num_unknown_tokens++);
4185       }
4186
4187       continue;
4188     }
4189
4190     /* token has format "<prefix>.<something>" */
4191
4192     action_token = strchr(list->token, '.');    /* suffix may be action ... */
4193     direction_token = action_token;             /* ... or direction */
4194
4195     element_token = getStringCopy(list->token);
4196     *strchr(element_token, '.') = '\0';
4197
4198     element_value = getHashEntry(element_hash, element_token);
4199
4200     if (element_value == NULL)          /* this is no element */
4201     {
4202       element_value = getHashEntry(element_hash, list->token);
4203       if (element_value != NULL)        /* combined element found */
4204         add_helpanim_entry(atoi(element_value), -1, -1, delay,
4205                            &num_list_entries);
4206       else
4207         print_unknown_token(filename, list->token, num_unknown_tokens++);
4208
4209       free(element_token);
4210
4211       continue;
4212     }
4213
4214     action_value = getHashEntry(action_hash, action_token);
4215
4216     if (action_value != NULL)           /* action found */
4217     {
4218       add_helpanim_entry(atoi(element_value), atoi(action_value), -1, delay,
4219                     &num_list_entries);
4220
4221       free(element_token);
4222
4223       continue;
4224     }
4225
4226     direction_value = getHashEntry(direction_hash, direction_token);
4227
4228     if (direction_value != NULL)        /* direction found */
4229     {
4230       add_helpanim_entry(atoi(element_value), -1, atoi(direction_value), delay,
4231                          &num_list_entries);
4232
4233       free(element_token);
4234
4235       continue;
4236     }
4237
4238     if (strchr(action_token + 1, '.') == NULL)
4239     {
4240       /* no further suffixes found -- this is not an action nor direction */
4241
4242       element_value = getHashEntry(element_hash, list->token);
4243       if (element_value != NULL)        /* combined element found */
4244         add_helpanim_entry(atoi(element_value), -1, -1, delay,
4245                            &num_list_entries);
4246       else
4247         print_unknown_token(filename, list->token, num_unknown_tokens++);
4248
4249       free(element_token);
4250
4251       continue;
4252     }
4253
4254     /* token has format "<prefix>.<suffix>.<something>" */
4255
4256     direction_token = strchr(action_token + 1, '.');
4257
4258     action_token = getStringCopy(action_token);
4259     *strchr(action_token + 1, '.') = '\0';
4260
4261     action_value = getHashEntry(action_hash, action_token);
4262
4263     if (action_value == NULL)           /* this is no action */
4264     {
4265       element_value = getHashEntry(element_hash, list->token);
4266       if (element_value != NULL)        /* combined element found */
4267         add_helpanim_entry(atoi(element_value), -1, -1, delay,
4268                            &num_list_entries);
4269       else
4270         print_unknown_token(filename, list->token, num_unknown_tokens++);
4271
4272       free(element_token);
4273       free(action_token);
4274
4275       continue;
4276     }
4277
4278     direction_value = getHashEntry(direction_hash, direction_token);
4279
4280     if (direction_value != NULL)        /* direction found */
4281     {
4282       add_helpanim_entry(atoi(element_value), atoi(action_value),
4283                          atoi(direction_value), delay, &num_list_entries);
4284
4285       free(element_token);
4286       free(action_token);
4287
4288       continue;
4289     }
4290
4291     /* this is no direction */
4292
4293     element_value = getHashEntry(element_hash, list->token);
4294     if (element_value != NULL)          /* combined element found */
4295       add_helpanim_entry(atoi(element_value), -1, -1, delay,
4296                          &num_list_entries);
4297     else
4298       print_unknown_token(filename, list->token, num_unknown_tokens++);
4299
4300     free(element_token);
4301     free(action_token);
4302   }
4303
4304   print_unknown_token_end(num_unknown_tokens);
4305
4306   add_helpanim_entry(HELPANIM_LIST_NEXT, -1, -1, -1, &num_list_entries);
4307   add_helpanim_entry(HELPANIM_LIST_END,  -1, -1, -1, &num_list_entries);
4308
4309   freeSetupFileList(setup_file_list);
4310   freeSetupFileHash(element_hash);
4311   freeSetupFileHash(action_hash);
4312   freeSetupFileHash(direction_hash);
4313
4314 #if 0
4315   /* TEST ONLY */
4316   for (i = 0; i < num_list_entries; i++)
4317     printf("::: %d, %d, %d => %d\n",
4318            helpanim_info[i].element,
4319            helpanim_info[i].action,
4320            helpanim_info[i].direction,
4321            helpanim_info[i].delay);
4322 #endif
4323 }
4324
4325 void LoadHelpTextInfo()
4326 {
4327   char *filename = getHelpTextFilename();
4328   int i;
4329
4330   if (helptext_info != NULL)
4331   {
4332     freeSetupFileHash(helptext_info);
4333     helptext_info = NULL;
4334   }
4335
4336   if (fileExists(filename))
4337     helptext_info = loadSetupFileHash(filename);
4338
4339   if (helptext_info == NULL)
4340   {
4341     /* use reliable default values from static configuration */
4342     helptext_info = newSetupFileHash();
4343
4344     for (i = 0; helptext_config[i].token; i++)
4345       setHashEntry(helptext_info,
4346                    helptext_config[i].token,
4347                    helptext_config[i].value);
4348   }
4349
4350 #if 0
4351   /* TEST ONLY */
4352   BEGIN_HASH_ITERATION(helptext_info, itr)
4353   {
4354     printf("::: '%s' => '%s'\n",
4355            HASH_ITERATION_TOKEN(itr), HASH_ITERATION_VALUE(itr));
4356   }
4357   END_HASH_ITERATION(hash, itr)
4358 #endif
4359 }