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