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