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