rnd-20030703-3-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
17 #include "libgame/libgame.h"
18
19 #include "files.h"
20 #include "init.h"
21 #include "tools.h"
22 #include "tape.h"
23
24
25 #define CHUNK_ID_LEN            4       /* IFF style chunk id length  */
26 #define CHUNK_SIZE_UNDEFINED    0       /* undefined chunk size == 0  */
27 #define CHUNK_SIZE_NONE         -1      /* do not write chunk size    */
28 #define FILE_VERS_CHUNK_SIZE    8       /* size of file version chunk */
29 #define LEVEL_HEADER_SIZE       80      /* size of level file header  */
30 #define LEVEL_HEADER_UNUSED     13      /* unused level header bytes  */
31 #define LEVEL_CHUNK_CNT2_SIZE   160     /* size of level CNT2 chunk   */
32 #define LEVEL_CHUNK_CNT2_UNUSED 11      /* unused CNT2 chunk bytes    */
33 #define LEVEL_CPART_CUS3_SIZE   134     /* size of CUS3 chunk part    */
34 #define LEVEL_CPART_CUS3_UNUSED 16      /* unused CUS3 bytes / part   */
35 #define TAPE_HEADER_SIZE        20      /* size of tape file header   */
36 #define TAPE_HEADER_UNUSED      3       /* unused tape header bytes   */
37
38 #define LEVEL_CHUNK_CUS3_SIZE(x) (2 + x * LEVEL_CPART_CUS3_SIZE)
39
40 /* file identifier strings */
41 #define LEVEL_COOKIE_TMPL       "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x"
42 #define TAPE_COOKIE_TMPL        "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
43 #define SCORE_COOKIE            "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
44
45
46 /* ========================================================================= */
47 /* level file functions                                                      */
48 /* ========================================================================= */
49
50 static void setLevelInfoToDefaults()
51 {
52   int i, j, x, y;
53
54   level.file_version = FILE_VERSION_ACTUAL;
55   level.game_version = GAME_VERSION_ACTUAL;
56
57   level.encoding_16bit_field = FALSE;   /* default: only 8-bit elements */
58   level.encoding_16bit_yamyam = FALSE;  /* default: only 8-bit elements */
59   level.encoding_16bit_amoeba = FALSE;  /* default: only 8-bit elements */
60
61   lev_fieldx = level.fieldx = STD_LEV_FIELDX;
62   lev_fieldy = level.fieldy = STD_LEV_FIELDY;
63
64   for(x=0; x<MAX_LEV_FIELDX; x++)
65     for(y=0; y<MAX_LEV_FIELDY; y++)
66       Feld[x][y] = Ur[x][y] = EL_SAND;
67
68   level.time = 100;
69   level.gems_needed = 0;
70   level.amoeba_speed = 10;
71   level.time_magic_wall = 10;
72   level.time_wheel = 10;
73   level.time_light = 10;
74   level.time_timegate = 10;
75   level.amoeba_content = EL_DIAMOND;
76   level.double_speed = FALSE;
77   level.gravity = FALSE;
78   level.em_slippery_gems = FALSE;
79
80   level.use_custom_template = FALSE;
81
82   for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
83     level.name[i] = '\0';
84   for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
85     level.author[i] = '\0';
86
87   strcpy(level.name, NAMELESS_LEVEL_NAME);
88   strcpy(level.author, ANONYMOUS_NAME);
89
90   for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
91     level.score[i] = 10;
92
93   level.num_yamyam_contents = STD_ELEMENT_CONTENTS;
94   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
95     for(x=0; x<3; x++)
96       for(y=0; y<3; y++)
97         level.yamyam_content[i][x][y] =
98           (i < STD_ELEMENT_CONTENTS ? EL_ROCK : EL_EMPTY);
99
100   Feld[0][0] = Ur[0][0] = EL_PLAYER_1;
101   Feld[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] =
102     Ur[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] = EL_EXIT_CLOSED;
103
104   for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
105   {
106     int element = EL_CUSTOM_START + i;
107
108     for(j=0; j<MAX_ELEMENT_NAME_LEN; j++)
109       element_info[element].description[j] = '\0';
110     strcpy(element_info[element].description,
111            element_info[element].editor_description);
112
113     element_info[element].use_gfx_element = FALSE;
114     element_info[element].gfx_element = EL_EMPTY_SPACE;
115
116     element_info[element].score = 0;
117     element_info[element].gem_count = 0;
118
119     element_info[element].push_delay_fixed = 2;         /* special default */
120     element_info[element].push_delay_random = 8;        /* special default */
121     element_info[element].move_delay_fixed = 0;
122     element_info[element].move_delay_random = 0;
123
124     element_info[element].move_pattern = MV_ALL_DIRECTIONS;
125     element_info[element].move_direction_initial = MV_NO_MOVING;
126     element_info[element].move_stepsize = TILEX / 8;
127
128     for(x=0; x<3; x++)
129       for(y=0; y<3; y++)
130         element_info[element].content[x][y] = EL_EMPTY_SPACE;
131
132     element_info[element].change.events = CE_BITMASK_DEFAULT;
133     element_info[element].change.target_element = EL_EMPTY_SPACE;
134
135     element_info[element].change.delay_fixed = 0;
136     element_info[element].change.delay_random = 0;
137     element_info[element].change.delay_frames = -1;     /* use default */
138
139     element_info[element].change.trigger_element = EL_EMPTY_SPACE;
140
141     element_info[element].change.explode = FALSE;
142     element_info[element].change.use_content = FALSE;
143     element_info[element].change.only_complete = FALSE;
144     element_info[element].change.use_random_change = FALSE;
145     element_info[element].change.random = 0;
146     element_info[element].change.power = CP_NON_DESTRUCTIVE;
147
148     for(x=0; x<3; x++)
149       for(y=0; y<3; y++)
150         element_info[element].change.content[x][y] = EL_EMPTY_SPACE;
151
152     element_info[element].access_type = 0;
153     element_info[element].access_layer = 0;
154     element_info[element].walk_to_action = 0;
155     element_info[element].smash_targets = 0;
156     element_info[element].deadliness = 0;
157     element_info[element].consistency = 0;
158     element_info[element].change_player_action = 0;
159     element_info[element].change_collide_action = 0;
160     element_info[element].change_other_action = 0;
161
162     element_info[element].can_explode_by_fire = FALSE;
163     element_info[element].can_explode_smashed = FALSE;
164     element_info[element].can_explode_impact = FALSE;
165
166     /* start with no properties at all */
167     for (j=0; j < NUM_EP_BITFIELDS; j++)
168       Properties[element][j] = EP_BITMASK_DEFAULT;
169   }
170
171   BorderElement = EL_STEELWALL;
172
173   level.no_level_file = FALSE;
174
175   if (leveldir_current == NULL)         /* only when dumping level */
176     return;
177
178   /* try to determine better author name than 'anonymous' */
179   if (strcmp(leveldir_current->author, ANONYMOUS_NAME) != 0)
180   {
181     strncpy(level.author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN);
182     level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
183   }
184   else
185   {
186     switch (LEVELCLASS(leveldir_current))
187     {
188       case LEVELCLASS_TUTORIAL:
189         strcpy(level.author, PROGRAM_AUTHOR_STRING);
190         break;
191
192       case LEVELCLASS_CONTRIBUTION:
193         strncpy(level.author, leveldir_current->name,MAX_LEVEL_AUTHOR_LEN);
194         level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
195         break;
196
197       case LEVELCLASS_USER:
198         strncpy(level.author, getRealName(), MAX_LEVEL_AUTHOR_LEN);
199         level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
200         break;
201
202       default:
203         /* keep default value */
204         break;
205     }
206   }
207 }
208
209 static int checkLevelElement(int element)
210 {
211   if (element >= NUM_FILE_ELEMENTS)
212   {
213     Error(ERR_WARN, "invalid level element %d", element);
214     element = EL_CHAR_QUESTION;
215   }
216   else if (element == EL_PLAYER_OBSOLETE)
217     element = EL_PLAYER_1;
218   else if (element == EL_KEY_OBSOLETE)
219     element = EL_KEY_1;
220
221   return element;
222 }
223
224 static int LoadLevel_VERS(FILE *file, int chunk_size, struct LevelInfo *level)
225 {
226   level->file_version = getFileVersion(file);
227   level->game_version = getFileVersion(file);
228
229   return chunk_size;
230 }
231
232 static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
233 {
234   int i, x, y;
235
236   lev_fieldx = level->fieldx = fgetc(file);
237   lev_fieldy = level->fieldy = fgetc(file);
238
239   level->time           = getFile16BitBE(file);
240   level->gems_needed    = getFile16BitBE(file);
241
242   for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
243     level->name[i] = fgetc(file);
244   level->name[MAX_LEVEL_NAME_LEN] = 0;
245
246   for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
247     level->score[i] = fgetc(file);
248
249   level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
250   for(i=0; i<STD_ELEMENT_CONTENTS; i++)
251     for(y=0; y<3; y++)
252       for(x=0; x<3; x++)
253         level->yamyam_content[i][x][y] = checkLevelElement(fgetc(file));
254
255   level->amoeba_speed           = fgetc(file);
256   level->time_magic_wall        = fgetc(file);
257   level->time_wheel             = fgetc(file);
258   level->amoeba_content         = checkLevelElement(fgetc(file));
259   level->double_speed           = (fgetc(file) == 1 ? TRUE : FALSE);
260   level->gravity                = (fgetc(file) == 1 ? TRUE : FALSE);
261   level->encoding_16bit_field   = (fgetc(file) == 1 ? TRUE : FALSE);
262   level->em_slippery_gems       = (fgetc(file) == 1 ? TRUE : FALSE);
263
264   level->use_custom_template    = (fgetc(file) == 1 ? TRUE : FALSE);
265
266   ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED);
267
268   return chunk_size;
269 }
270
271 static int LoadLevel_AUTH(FILE *file, int chunk_size, struct LevelInfo *level)
272 {
273   int i;
274
275   for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
276     level->author[i] = fgetc(file);
277   level->author[MAX_LEVEL_NAME_LEN] = 0;
278
279   return chunk_size;
280 }
281
282 static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level)
283 {
284   int x, y;
285   int chunk_size_expected = level->fieldx * level->fieldy;
286
287   /* Note: "chunk_size" was wrong before version 2.0 when elements are
288      stored with 16-bit encoding (and should be twice as big then).
289      Even worse, playfield data was stored 16-bit when only yamyam content
290      contained 16-bit elements and vice versa. */
291
292   if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
293     chunk_size_expected *= 2;
294
295   if (chunk_size_expected != chunk_size)
296   {
297     ReadUnusedBytesFromFile(file, chunk_size);
298     return chunk_size_expected;
299   }
300
301   for(y=0; y<level->fieldy; y++)
302     for(x=0; x<level->fieldx; x++)
303       Feld[x][y] = Ur[x][y] =
304         checkLevelElement(level->encoding_16bit_field ?
305                           getFile16BitBE(file) : fgetc(file));
306   return chunk_size;
307 }
308
309 static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
310 {
311   int i, x, y;
312   int header_size = 4;
313   int content_size = MAX_ELEMENT_CONTENTS * 3 * 3;
314   int chunk_size_expected = header_size + content_size;
315
316   /* Note: "chunk_size" was wrong before version 2.0 when elements are
317      stored with 16-bit encoding (and should be twice as big then).
318      Even worse, playfield data was stored 16-bit when only yamyam content
319      contained 16-bit elements and vice versa. */
320
321   if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
322     chunk_size_expected += content_size;
323
324   if (chunk_size_expected != chunk_size)
325   {
326     ReadUnusedBytesFromFile(file, chunk_size);
327     return chunk_size_expected;
328   }
329
330   fgetc(file);
331   level->num_yamyam_contents = fgetc(file);
332   fgetc(file);
333   fgetc(file);
334
335   /* correct invalid number of content fields -- should never happen */
336   if (level->num_yamyam_contents < 1 ||
337       level->num_yamyam_contents > MAX_ELEMENT_CONTENTS)
338     level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
339
340   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
341     for(y=0; y<3; y++)
342       for(x=0; x<3; x++)
343         level->yamyam_content[i][x][y] =
344           checkLevelElement(level->encoding_16bit_field ?
345                             getFile16BitBE(file) : fgetc(file));
346   return chunk_size;
347 }
348
349 static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
350 {
351   int i, x, y;
352   int element;
353   int num_contents, content_xsize, content_ysize;
354   int content_array[MAX_ELEMENT_CONTENTS][3][3];
355
356   element = checkLevelElement(getFile16BitBE(file));
357   num_contents = fgetc(file);
358   content_xsize = fgetc(file);
359   content_ysize = fgetc(file);
360   ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED);
361
362   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
363     for(y=0; y<3; y++)
364       for(x=0; x<3; x++)
365         content_array[i][x][y] = checkLevelElement(getFile16BitBE(file));
366
367   /* correct invalid number of content fields -- should never happen */
368   if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS)
369     num_contents = STD_ELEMENT_CONTENTS;
370
371   if (element == EL_YAMYAM)
372   {
373     level->num_yamyam_contents = num_contents;
374
375     for(i=0; i<num_contents; i++)
376       for(y=0; y<3; y++)
377         for(x=0; x<3; x++)
378           level->yamyam_content[i][x][y] = content_array[i][x][y];
379   }
380   else if (element == EL_BD_AMOEBA)
381   {
382     level->amoeba_content = content_array[0][0][0];
383   }
384   else
385   {
386     Error(ERR_WARN, "cannot load content for element '%d'", element);
387   }
388
389   return chunk_size;
390 }
391
392 static int LoadLevel_CUS1(FILE *file, int chunk_size, struct LevelInfo *level)
393 {
394   int num_changed_custom_elements = getFile16BitBE(file);
395   int chunk_size_expected = 2 + num_changed_custom_elements * 6;
396   int i;
397
398   if (chunk_size_expected != chunk_size)
399   {
400     ReadUnusedBytesFromFile(file, chunk_size - 2);
401     return chunk_size_expected;
402   }
403
404   for (i=0; i < num_changed_custom_elements; i++)
405   {
406     int element = getFile16BitBE(file);
407     int properties = getFile32BitBE(file);
408
409     if (IS_CUSTOM_ELEMENT(element))
410       Properties[element][EP_BITFIELD_BASE] = properties;
411     else
412       Error(ERR_WARN, "invalid custom element number %d", element);
413   }
414
415   return chunk_size;
416 }
417
418 static int LoadLevel_CUS2(FILE *file, int chunk_size, struct LevelInfo *level)
419 {
420   int num_changed_custom_elements = getFile16BitBE(file);
421   int chunk_size_expected = 2 + num_changed_custom_elements * 4;
422   int i;
423
424   if (chunk_size_expected != chunk_size)
425   {
426     ReadUnusedBytesFromFile(file, chunk_size - 2);
427     return chunk_size_expected;
428   }
429
430   for (i=0; i < num_changed_custom_elements; i++)
431   {
432     int element = getFile16BitBE(file);
433     int custom_target_element = getFile16BitBE(file);
434
435     if (IS_CUSTOM_ELEMENT(element))
436       element_info[element].change.target_element = custom_target_element;
437     else
438       Error(ERR_WARN, "invalid custom element number %d", element);
439   }
440
441   return chunk_size;
442 }
443
444 static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level)
445 {
446   int num_changed_custom_elements = getFile16BitBE(file);
447   int chunk_size_expected = LEVEL_CHUNK_CUS3_SIZE(num_changed_custom_elements);
448   int i, j, x, y;
449
450   if (chunk_size_expected != chunk_size)
451   {
452     ReadUnusedBytesFromFile(file, chunk_size - 2);
453     return chunk_size_expected;
454   }
455
456   for (i=0; i < num_changed_custom_elements; i++)
457   {
458     int element = getFile16BitBE(file);
459
460     if (!IS_CUSTOM_ELEMENT(element))
461     {
462       Error(ERR_WARN, "invalid custom element number %d", element);
463
464       element = EL_DEFAULT;     /* dummy element used for artwork config */
465     }
466
467     for(j=0; j<MAX_ELEMENT_NAME_LEN; j++)
468       element_info[element].description[j] = getFile8Bit(file);
469     element_info[element].description[MAX_ELEMENT_NAME_LEN] = 0;
470
471     Properties[element][EP_BITFIELD_BASE] = getFile32BitBE(file);
472
473     /* some free bytes for future properties and padding */
474     ReadUnusedBytesFromFile(file, 7);
475
476     element_info[element].use_gfx_element = getFile8Bit(file);
477     element_info[element].gfx_element =
478       checkLevelElement(getFile16BitBE(file));
479
480     element_info[element].score = getFile8Bit(file);
481     element_info[element].gem_count = getFile8Bit(file);
482
483     element_info[element].push_delay_fixed = getFile16BitBE(file);
484     element_info[element].push_delay_random = getFile16BitBE(file);
485     element_info[element].move_delay_fixed = getFile16BitBE(file);
486     element_info[element].move_delay_random = getFile16BitBE(file);
487
488     element_info[element].move_pattern = getFile16BitBE(file);
489     element_info[element].move_direction_initial = getFile8Bit(file);
490     element_info[element].move_stepsize = getFile8Bit(file);
491
492     for(y=0; y<3; y++)
493       for(x=0; x<3; x++)
494         element_info[element].content[x][y] =
495           checkLevelElement(getFile16BitBE(file));
496
497     element_info[element].change.events = getFile32BitBE(file);
498
499     element_info[element].change.target_element =
500       checkLevelElement(getFile16BitBE(file));
501
502     element_info[element].change.delay_fixed = getFile16BitBE(file);
503     element_info[element].change.delay_random = getFile16BitBE(file);
504     element_info[element].change.delay_frames = getFile16BitBE(file);
505
506     element_info[element].change.trigger_element =
507       checkLevelElement(getFile16BitBE(file));
508
509     element_info[element].change.explode = getFile8Bit(file);
510     element_info[element].change.use_content = getFile8Bit(file);
511     element_info[element].change.only_complete = getFile8Bit(file);
512     element_info[element].change.use_random_change = getFile8Bit(file);
513
514     element_info[element].change.random = getFile8Bit(file);
515     element_info[element].change.power = getFile8Bit(file);
516
517     for(y=0; y<3; y++)
518       for(x=0; x<3; x++)
519         element_info[element].change.content[x][y] =
520           checkLevelElement(getFile16BitBE(file));
521
522     /* some free bytes for future properties and padding */
523     ReadUnusedBytesFromFile(file, LEVEL_CPART_CUS3_UNUSED);
524   }
525
526   return chunk_size;
527 }
528
529 void LoadLevelFromFilename(char *filename)
530 {
531   char cookie[MAX_LINE_LEN];
532   char chunk_name[CHUNK_ID_LEN + 1];
533   int chunk_size;
534   FILE *file;
535
536   /* always start with reliable default values */
537   setLevelInfoToDefaults();
538
539   if (!(file = fopen(filename, MODE_READ)))
540   {
541     level.no_level_file = TRUE;
542
543     Error(ERR_WARN, "cannot read level '%s' - creating new level", filename);
544     return;
545   }
546
547   getFileChunkBE(file, chunk_name, NULL);
548   if (strcmp(chunk_name, "RND1") == 0)
549   {
550     getFile32BitBE(file);               /* not used */
551
552     getFileChunkBE(file, chunk_name, NULL);
553     if (strcmp(chunk_name, "CAVE") != 0)
554     {
555       Error(ERR_WARN, "unknown format of level file '%s'", filename);
556       fclose(file);
557       return;
558     }
559   }
560   else  /* check for pre-2.0 file format with cookie string */
561   {
562     strcpy(cookie, chunk_name);
563     fgets(&cookie[4], MAX_LINE_LEN - 4, file);
564     if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
565       cookie[strlen(cookie) - 1] = '\0';
566
567     if (!checkCookieString(cookie, LEVEL_COOKIE_TMPL))
568     {
569       Error(ERR_WARN, "unknown format of level file '%s'", filename);
570       fclose(file);
571       return;
572     }
573
574     if ((level.file_version = getFileVersionFromCookieString(cookie)) == -1)
575     {
576       Error(ERR_WARN, "unsupported version of level file '%s'", filename);
577       fclose(file);
578       return;
579     }
580
581     /* pre-2.0 level files have no game version, so use file version here */
582     level.game_version = level.file_version;
583   }
584
585   if (level.file_version < FILE_VERSION_1_2)
586   {
587     /* level files from versions before 1.2.0 without chunk structure */
588     LoadLevel_HEAD(file, LEVEL_HEADER_SIZE,           &level);
589     LoadLevel_BODY(file, level.fieldx * level.fieldy, &level);
590   }
591   else
592   {
593     static struct
594     {
595       char *name;
596       int size;
597       int (*loader)(FILE *, int, struct LevelInfo *);
598     }
599     chunk_info[] =
600     {
601       { "VERS", FILE_VERS_CHUNK_SIZE,   LoadLevel_VERS },
602       { "HEAD", LEVEL_HEADER_SIZE,      LoadLevel_HEAD },
603       { "AUTH", MAX_LEVEL_AUTHOR_LEN,   LoadLevel_AUTH },
604       { "BODY", -1,                     LoadLevel_BODY },
605       { "CONT", -1,                     LoadLevel_CONT },
606       { "CNT2", LEVEL_CHUNK_CNT2_SIZE,  LoadLevel_CNT2 },
607       { "CUS1", -1,                     LoadLevel_CUS1 },
608       { "CUS2", -1,                     LoadLevel_CUS2 },
609       { "CUS3", -1,                     LoadLevel_CUS3 },
610       {  NULL,  0,                      NULL }
611     };
612
613     while (getFileChunkBE(file, chunk_name, &chunk_size))
614     {
615       int i = 0;
616
617       while (chunk_info[i].name != NULL &&
618              strcmp(chunk_name, chunk_info[i].name) != 0)
619         i++;
620
621       if (chunk_info[i].name == NULL)
622       {
623         Error(ERR_WARN, "unknown chunk '%s' in level file '%s'",
624               chunk_name, filename);
625         ReadUnusedBytesFromFile(file, chunk_size);
626       }
627       else if (chunk_info[i].size != -1 &&
628                chunk_info[i].size != chunk_size)
629       {
630         Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
631               chunk_size, chunk_name, filename);
632         ReadUnusedBytesFromFile(file, chunk_size);
633       }
634       else
635       {
636         /* call function to load this level chunk */
637         int chunk_size_expected =
638           (chunk_info[i].loader)(file, chunk_size, &level);
639
640         /* the size of some chunks cannot be checked before reading other
641            chunks first (like "HEAD" and "BODY") that contain some header
642            information, so check them here */
643         if (chunk_size_expected != chunk_size)
644         {
645           Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
646                 chunk_size, chunk_name, filename);
647         }
648       }
649     }
650   }
651
652   fclose(file);
653
654   if (leveldir_current == NULL)         /* only when dumping level */
655     return;
656
657   if (IS_LEVELCLASS_CONTRIBUTION(leveldir_current) ||
658       IS_LEVELCLASS_USER(leveldir_current))
659   {
660     /* For user contributed and private levels, use the version of
661        the game engine the levels were created for.
662        Since 2.0.1, the game engine version is now directly stored
663        in the level file (chunk "VERS"), so there is no need anymore
664        to set the game version from the file version (except for old,
665        pre-2.0 levels, where the game version is still taken from the
666        file format version used to store the level -- see above). */
667
668     /* do some special adjustments to support older level versions */
669     if (level.file_version == FILE_VERSION_1_0)
670     {
671       Error(ERR_WARN, "level file '%s' has version number 1.0", filename);
672       Error(ERR_WARN, "using high speed movement for player");
673
674       /* player was faster than monsters in (pre-)1.0 levels */
675       level.double_speed = TRUE;
676     }
677
678     /* Default behaviour for EM style gems was "slippery" only in 2.0.1 */
679     if (level.game_version == VERSION_IDENT(2,0,1))
680       level.em_slippery_gems = TRUE;
681   }
682   else
683   {
684     /* Always use the latest version of the game engine for all but
685        user contributed and private levels; this allows for actual
686        corrections in the game engine to take effect for existing,
687        converted levels (from "classic" or other existing games) to
688        make the game emulation more accurate, while (hopefully) not
689        breaking existing levels created from other players. */
690
691     level.game_version = GAME_VERSION_ACTUAL;
692
693     /* Set special EM style gems behaviour: EM style gems slip down from
694        normal, steel and growing wall. As this is a more fundamental change,
695        it seems better to set the default behaviour to "off" (as it is more
696        natural) and make it configurable in the level editor (as a property
697        of gem style elements). Already existing converted levels (neither
698        private nor contributed levels) are changed to the new behaviour. */
699
700     if (level.file_version < FILE_VERSION_2_0)
701       level.em_slippery_gems = TRUE;
702   }
703
704   /* map some elements which have changed in newer versions */
705   if (level.game_version <= VERSION_IDENT(2,2,0))
706   {
707     int x, y;
708
709     /* map game font elements */
710     for(y=0; y<level.fieldy; y++)
711     {
712       for(x=0; x<level.fieldx; x++)
713       {
714         int element = Ur[x][y];
715
716         if (element == EL_CHAR('['))
717           element = EL_CHAR_AUMLAUT;
718         else if (element == EL_CHAR('\\'))
719           element = EL_CHAR_OUMLAUT;
720         else if (element == EL_CHAR(']'))
721           element = EL_CHAR_UUMLAUT;
722         else if (element == EL_CHAR('^'))
723           element = EL_CHAR_COPYRIGHT;
724
725         Feld[x][y] = Ur[x][y] = element;
726       }
727     }
728   }
729
730   /* determine border element for this level */
731   SetBorderElement();
732 }
733
734 void LoadLevel(int level_nr)
735 {
736   char *filename = getLevelFilename(level_nr);
737
738   LoadLevelFromFilename(filename);
739   InitElementPropertiesEngine(level.game_version);
740 }
741
742 static void SaveLevel_VERS(FILE *file, struct LevelInfo *level)
743 {
744   putFileVersion(file, level->file_version);
745   putFileVersion(file, level->game_version);
746 }
747
748 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
749 {
750   int i, x, y;
751
752   fputc(level->fieldx, file);
753   fputc(level->fieldy, file);
754
755   putFile16BitBE(file, level->time);
756   putFile16BitBE(file, level->gems_needed);
757
758   for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
759     fputc(level->name[i], file);
760
761   for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
762     fputc(level->score[i], file);
763
764   for(i=0; i<STD_ELEMENT_CONTENTS; i++)
765     for(y=0; y<3; y++)
766       for(x=0; x<3; x++)
767         fputc((level->encoding_16bit_yamyam ? EL_EMPTY :
768                level->yamyam_content[i][x][y]),
769               file);
770   fputc(level->amoeba_speed, file);
771   fputc(level->time_magic_wall, file);
772   fputc(level->time_wheel, file);
773   fputc((level->encoding_16bit_amoeba ? EL_EMPTY : level->amoeba_content),
774         file);
775   fputc((level->double_speed ? 1 : 0), file);
776   fputc((level->gravity ? 1 : 0), file);
777   fputc((level->encoding_16bit_field ? 1 : 0), file);
778   fputc((level->em_slippery_gems ? 1 : 0), file);
779
780   fputc((level->use_custom_template ? 1 : 0), file);
781
782   WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
783 }
784
785 static void SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
786 {
787   int i;
788
789   for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
790     fputc(level->author[i], file);
791 }
792
793 static void SaveLevel_BODY(FILE *file, struct LevelInfo *level)
794 {
795   int x, y;
796
797   for(y=0; y<level->fieldy; y++) 
798     for(x=0; x<level->fieldx; x++) 
799       if (level->encoding_16bit_field)
800         putFile16BitBE(file, Ur[x][y]);
801       else
802         fputc(Ur[x][y], file);
803 }
804
805 #if 0
806 static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
807 {
808   int i, x, y;
809
810   fputc(EL_YAMYAM, file);
811   fputc(level->num_yamyam_contents, file);
812   fputc(0, file);
813   fputc(0, file);
814
815   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
816     for(y=0; y<3; y++)
817       for(x=0; x<3; x++)
818         if (level->encoding_16bit_field)
819           putFile16BitBE(file, level->yamyam_content[i][x][y]);
820         else
821           fputc(level->yamyam_content[i][x][y], file);
822 }
823 #endif
824
825 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
826 {
827   int i, x, y;
828   int num_contents, content_xsize, content_ysize;
829   int content_array[MAX_ELEMENT_CONTENTS][3][3];
830
831   if (element == EL_YAMYAM)
832   {
833     num_contents = level->num_yamyam_contents;
834     content_xsize = 3;
835     content_ysize = 3;
836
837     for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
838       for(y=0; y<3; y++)
839         for(x=0; x<3; x++)
840           content_array[i][x][y] = level->yamyam_content[i][x][y];
841   }
842   else if (element == EL_BD_AMOEBA)
843   {
844     num_contents = 1;
845     content_xsize = 1;
846     content_ysize = 1;
847
848     for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
849       for(y=0; y<3; y++)
850         for(x=0; x<3; x++)
851           content_array[i][x][y] = EL_EMPTY;
852     content_array[0][0][0] = level->amoeba_content;
853   }
854   else
855   {
856     /* chunk header already written -- write empty chunk data */
857     WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_SIZE);
858
859     Error(ERR_WARN, "cannot save content for element '%d'", element);
860     return;
861   }
862
863   putFile16BitBE(file, element);
864   fputc(num_contents, file);
865   fputc(content_xsize, file);
866   fputc(content_ysize, file);
867
868   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED);
869
870   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
871     for(y=0; y<3; y++)
872       for(x=0; x<3; x++)
873         putFile16BitBE(file, content_array[i][x][y]);
874 }
875
876 #if 0
877 static void SaveLevel_CUS1(FILE *file, struct LevelInfo *level,
878                            int num_changed_custom_elements)
879 {
880   int i, check = 0;
881
882   putFile16BitBE(file, num_changed_custom_elements);
883
884   for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
885   {
886     int element = EL_CUSTOM_START + i;
887
888     if (Properties[element][EP_BITFIELD_BASE] != EP_BITMASK_DEFAULT)
889     {
890       if (check < num_changed_custom_elements)
891       {
892         putFile16BitBE(file, element);
893         putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
894       }
895
896       check++;
897     }
898   }
899
900   if (check != num_changed_custom_elements)     /* should not happen */
901     Error(ERR_WARN, "inconsistent number of custom element properties");
902 }
903 #endif
904
905 #if 0
906 static void SaveLevel_CUS2(FILE *file, struct LevelInfo *level,
907                            int num_changed_custom_elements)
908 {
909   int i, check = 0;
910
911   putFile16BitBE(file, num_changed_custom_elements);
912
913   for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
914   {
915     int element = EL_CUSTOM_START + i;
916
917     if (element_info[element].change.target_element != EL_EMPTY_SPACE)
918     {
919       if (check < num_changed_custom_elements)
920       {
921         putFile16BitBE(file, element);
922         putFile16BitBE(file, element_info[element].change.target_element);
923       }
924
925       check++;
926     }
927   }
928
929   if (check != num_changed_custom_elements)     /* should not happen */
930     Error(ERR_WARN, "inconsistent number of custom target elements");
931 }
932 #endif
933
934 static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
935                            int num_changed_custom_elements)
936 {
937   int i, j, x, y, check = 0;
938
939   putFile16BitBE(file, num_changed_custom_elements);
940
941   for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
942   {
943     int element = EL_CUSTOM_START + i;
944
945     if (Properties[element][EP_BITFIELD_BASE] != EP_BITMASK_DEFAULT)
946     {
947       if (check < num_changed_custom_elements)
948       {
949         putFile16BitBE(file, element);
950
951         for(j=0; j<MAX_ELEMENT_NAME_LEN; j++)
952           putFile8Bit(file, element_info[element].description[j]);
953
954         putFile32BitBE(file, Properties[element][EP_BITFIELD_BASE]);
955
956         /* some free bytes for future properties and padding */
957         WriteUnusedBytesToFile(file, 7);
958
959         putFile8Bit(file, element_info[element].use_gfx_element);
960         putFile16BitBE(file, element_info[element].gfx_element);
961
962         putFile8Bit(file, element_info[element].score);
963         putFile8Bit(file, element_info[element].gem_count);
964
965         putFile16BitBE(file, element_info[element].push_delay_fixed);
966         putFile16BitBE(file, element_info[element].push_delay_random);
967         putFile16BitBE(file, element_info[element].move_delay_fixed);
968         putFile16BitBE(file, element_info[element].move_delay_random);
969
970         putFile16BitBE(file, element_info[element].move_pattern);
971         putFile8Bit(file, element_info[element].move_direction_initial);
972         putFile8Bit(file, element_info[element].move_stepsize);
973
974         for(y=0; y<3; y++)
975           for(x=0; x<3; x++)
976             putFile16BitBE(file, element_info[element].content[x][y]);
977
978         putFile32BitBE(file, element_info[element].change.events);
979
980         putFile16BitBE(file, element_info[element].change.target_element);
981
982         putFile16BitBE(file, element_info[element].change.delay_fixed);
983         putFile16BitBE(file, element_info[element].change.delay_random);
984         putFile16BitBE(file, element_info[element].change.delay_frames);
985
986         putFile16BitBE(file, element_info[element].change.trigger_element);
987
988         putFile8Bit(file, element_info[element].change.explode);
989         putFile8Bit(file, element_info[element].change.use_content);
990         putFile8Bit(file, element_info[element].change.only_complete);
991         putFile8Bit(file, element_info[element].change.use_random_change);
992
993         putFile8Bit(file, element_info[element].change.random);
994         putFile8Bit(file, element_info[element].change.power);
995
996         for(y=0; y<3; y++)
997           for(x=0; x<3; x++)
998             putFile16BitBE(file, element_info[element].change.content[x][y]);
999
1000         /* some free bytes for future properties and padding */
1001         WriteUnusedBytesToFile(file, LEVEL_CPART_CUS3_UNUSED);
1002       }
1003
1004       check++;
1005     }
1006   }
1007
1008   if (check != num_changed_custom_elements)     /* should not happen */
1009     Error(ERR_WARN, "inconsistent number of custom element properties");
1010 }
1011
1012 void SaveLevel(int level_nr)
1013 {
1014   char *filename = getLevelFilename(level_nr);
1015   int body_chunk_size;
1016   int num_changed_custom_elements = 0;
1017   int level_chunk_CUS3_size;
1018   int i, x, y;
1019   FILE *file;
1020
1021   if (!(file = fopen(filename, MODE_WRITE)))
1022   {
1023     Error(ERR_WARN, "cannot save level file '%s'", filename);
1024     return;
1025   }
1026
1027   level.file_version = FILE_VERSION_ACTUAL;
1028   level.game_version = GAME_VERSION_ACTUAL;
1029
1030   /* check level field for 16-bit elements */
1031   level.encoding_16bit_field = FALSE;
1032   for(y=0; y<level.fieldy; y++) 
1033     for(x=0; x<level.fieldx; x++) 
1034       if (Ur[x][y] > 255)
1035         level.encoding_16bit_field = TRUE;
1036
1037   /* check yamyam content for 16-bit elements */
1038   level.encoding_16bit_yamyam = FALSE;
1039   for(i=0; i<level.num_yamyam_contents; i++)
1040     for(y=0; y<3; y++)
1041       for(x=0; x<3; x++)
1042         if (level.yamyam_content[i][x][y] > 255)
1043           level.encoding_16bit_yamyam = TRUE;
1044
1045   /* check amoeba content for 16-bit elements */
1046   level.encoding_16bit_amoeba = FALSE;
1047   if (level.amoeba_content > 255)
1048     level.encoding_16bit_amoeba = TRUE;
1049
1050   /* calculate size of "BODY" chunk */
1051   body_chunk_size =
1052     level.fieldx * level.fieldy * (level.encoding_16bit_field ? 2 : 1);
1053
1054   /* check for non-standard custom elements and calculate "CUS3" chunk size */
1055   for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
1056     if (Properties[EL_CUSTOM_START +i][EP_BITFIELD_BASE] != EP_BITMASK_DEFAULT)
1057       num_changed_custom_elements++;
1058   level_chunk_CUS3_size = LEVEL_CHUNK_CUS3_SIZE(num_changed_custom_elements);
1059
1060   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
1061   putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
1062
1063   putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
1064   SaveLevel_VERS(file, &level);
1065
1066   putFileChunkBE(file, "HEAD", LEVEL_HEADER_SIZE);
1067   SaveLevel_HEAD(file, &level);
1068
1069   putFileChunkBE(file, "AUTH", MAX_LEVEL_AUTHOR_LEN);
1070   SaveLevel_AUTH(file, &level);
1071
1072   putFileChunkBE(file, "BODY", body_chunk_size);
1073   SaveLevel_BODY(file, &level);
1074
1075   if (level.encoding_16bit_yamyam ||
1076       level.num_yamyam_contents != STD_ELEMENT_CONTENTS)
1077   {
1078     putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
1079     SaveLevel_CNT2(file, &level, EL_YAMYAM);
1080   }
1081
1082   if (level.encoding_16bit_amoeba)
1083   {
1084     putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
1085     SaveLevel_CNT2(file, &level, EL_BD_AMOEBA);
1086   }
1087
1088   if (num_changed_custom_elements > 0)
1089   {
1090     putFileChunkBE(file, "CUS3", level_chunk_CUS3_size);
1091     SaveLevel_CUS3(file, &level, num_changed_custom_elements);
1092   }
1093
1094   fclose(file);
1095
1096   SetFilePermissions(filename, PERMS_PRIVATE);
1097 }
1098
1099 void DumpLevel(struct LevelInfo *level)
1100 {
1101   printf_line("-", 79);
1102   printf("Level xxx (file version %08d, game version %08d)\n",
1103          level->file_version, level->game_version);
1104   printf_line("-", 79);
1105
1106   printf("Level Author: '%s'\n", level->author);
1107   printf("Level Title:  '%s'\n", level->name);
1108   printf("\n");
1109   printf("Playfield Size: %d x %d\n", level->fieldx, level->fieldy);
1110   printf("\n");
1111   printf("Level Time:  %d seconds\n", level->time);
1112   printf("Gems needed: %d\n", level->gems_needed);
1113   printf("\n");
1114   printf("Time for Magic Wall: %d seconds\n", level->time_magic_wall);
1115   printf("Time for Wheel:      %d seconds\n", level->time_wheel);
1116   printf("Time for Light:      %d seconds\n", level->time_light);
1117   printf("Time for Timegate:   %d seconds\n", level->time_timegate);
1118   printf("\n");
1119   printf("Amoeba Speed: %d\n", level->amoeba_speed);
1120   printf("\n");
1121   printf("Gravity:                %s\n", (level->gravity ? "yes" : "no"));
1122   printf("Double Speed Movement:  %s\n", (level->double_speed ? "yes" : "no"));
1123   printf("EM style slippery gems: %s\n", (level->em_slippery_gems ? "yes" : "no"));
1124
1125   printf_line("-", 79);
1126 }
1127
1128
1129 /* ========================================================================= */
1130 /* tape file functions                                                       */
1131 /* ========================================================================= */
1132
1133 static void setTapeInfoToDefaults()
1134 {
1135   int i;
1136
1137   /* always start with reliable default values (empty tape) */
1138   TapeErase();
1139
1140   /* default values (also for pre-1.2 tapes) with only the first player */
1141   tape.player_participates[0] = TRUE;
1142   for(i=1; i<MAX_PLAYERS; i++)
1143     tape.player_participates[i] = FALSE;
1144
1145   /* at least one (default: the first) player participates in every tape */
1146   tape.num_participating_players = 1;
1147
1148   tape.level_nr = level_nr;
1149   tape.counter = 0;
1150   tape.changed = FALSE;
1151
1152   tape.recording = FALSE;
1153   tape.playing = FALSE;
1154   tape.pausing = FALSE;
1155 }
1156
1157 static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
1158 {
1159   tape->file_version = getFileVersion(file);
1160   tape->game_version = getFileVersion(file);
1161
1162   return chunk_size;
1163 }
1164
1165 static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
1166 {
1167   int i;
1168
1169   tape->random_seed = getFile32BitBE(file);
1170   tape->date        = getFile32BitBE(file);
1171   tape->length      = getFile32BitBE(file);
1172
1173   /* read header fields that are new since version 1.2 */
1174   if (tape->file_version >= FILE_VERSION_1_2)
1175   {
1176     byte store_participating_players = fgetc(file);
1177     int engine_version;
1178
1179     /* since version 1.2, tapes store which players participate in the tape */
1180     tape->num_participating_players = 0;
1181     for(i=0; i<MAX_PLAYERS; i++)
1182     {
1183       tape->player_participates[i] = FALSE;
1184
1185       if (store_participating_players & (1 << i))
1186       {
1187         tape->player_participates[i] = TRUE;
1188         tape->num_participating_players++;
1189       }
1190     }
1191
1192     ReadUnusedBytesFromFile(file, TAPE_HEADER_UNUSED);
1193
1194     engine_version = getFileVersion(file);
1195     if (engine_version > 0)
1196       tape->engine_version = engine_version;
1197   }
1198
1199   return chunk_size;
1200 }
1201
1202 static int LoadTape_INFO(FILE *file, int chunk_size, struct TapeInfo *tape)
1203 {
1204   int level_identifier_size;
1205   int i;
1206
1207   level_identifier_size = getFile16BitBE(file);
1208
1209   tape->level_identifier =
1210     checked_realloc(tape->level_identifier, level_identifier_size);
1211
1212   for(i=0; i < level_identifier_size; i++)
1213     tape->level_identifier[i] = fgetc(file);
1214
1215   tape->level_nr = getFile16BitBE(file);
1216
1217   chunk_size = 2 + level_identifier_size + 2;
1218
1219   return chunk_size;
1220 }
1221
1222 static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
1223 {
1224   int i, j;
1225   int chunk_size_expected =
1226     (tape->num_participating_players + 1) * tape->length;
1227
1228   if (chunk_size_expected != chunk_size)
1229   {
1230     ReadUnusedBytesFromFile(file, chunk_size);
1231     return chunk_size_expected;
1232   }
1233
1234   for(i=0; i<tape->length; i++)
1235   {
1236     if (i >= MAX_TAPELEN)
1237       break;
1238
1239     for(j=0; j<MAX_PLAYERS; j++)
1240     {
1241       tape->pos[i].action[j] = MV_NO_MOVING;
1242
1243       if (tape->player_participates[j])
1244         tape->pos[i].action[j] = fgetc(file);
1245     }
1246
1247     tape->pos[i].delay = fgetc(file);
1248
1249     if (tape->file_version == FILE_VERSION_1_0)
1250     {
1251       /* eliminate possible diagonal moves in old tapes */
1252       /* this is only for backward compatibility */
1253
1254       byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
1255       byte action = tape->pos[i].action[0];
1256       int k, num_moves = 0;
1257
1258       for (k=0; k<4; k++)
1259       {
1260         if (action & joy_dir[k])
1261         {
1262           tape->pos[i + num_moves].action[0] = joy_dir[k];
1263           if (num_moves > 0)
1264             tape->pos[i + num_moves].delay = 0;
1265           num_moves++;
1266         }
1267       }
1268
1269       if (num_moves > 1)
1270       {
1271         num_moves--;
1272         i += num_moves;
1273         tape->length += num_moves;
1274       }
1275     }
1276     else if (tape->file_version < FILE_VERSION_2_0)
1277     {
1278       /* convert pre-2.0 tapes to new tape format */
1279
1280       if (tape->pos[i].delay > 1)
1281       {
1282         /* action part */
1283         tape->pos[i + 1] = tape->pos[i];
1284         tape->pos[i + 1].delay = 1;
1285
1286         /* delay part */
1287         for(j=0; j<MAX_PLAYERS; j++)
1288           tape->pos[i].action[j] = MV_NO_MOVING;
1289         tape->pos[i].delay--;
1290
1291         i++;
1292         tape->length++;
1293       }
1294     }
1295
1296     if (feof(file))
1297       break;
1298   }
1299
1300   if (i != tape->length)
1301     chunk_size = (tape->num_participating_players + 1) * i;
1302
1303   return chunk_size;
1304 }
1305
1306 void LoadTapeFromFilename(char *filename)
1307 {
1308   char cookie[MAX_LINE_LEN];
1309   char chunk_name[CHUNK_ID_LEN + 1];
1310   FILE *file;
1311   int chunk_size;
1312
1313   /* always start with reliable default values */
1314   setTapeInfoToDefaults();
1315
1316   if (!(file = fopen(filename, MODE_READ)))
1317     return;
1318
1319   getFileChunkBE(file, chunk_name, NULL);
1320   if (strcmp(chunk_name, "RND1") == 0)
1321   {
1322     getFile32BitBE(file);               /* not used */
1323
1324     getFileChunkBE(file, chunk_name, NULL);
1325     if (strcmp(chunk_name, "TAPE") != 0)
1326     {
1327       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
1328       fclose(file);
1329       return;
1330     }
1331   }
1332   else  /* check for pre-2.0 file format with cookie string */
1333   {
1334     strcpy(cookie, chunk_name);
1335     fgets(&cookie[4], MAX_LINE_LEN - 4, file);
1336     if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
1337       cookie[strlen(cookie) - 1] = '\0';
1338
1339     if (!checkCookieString(cookie, TAPE_COOKIE_TMPL))
1340     {
1341       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
1342       fclose(file);
1343       return;
1344     }
1345
1346     if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1)
1347     {
1348       Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
1349       fclose(file);
1350       return;
1351     }
1352
1353     /* pre-2.0 tape files have no game version, so use file version here */
1354     tape.game_version = tape.file_version;
1355   }
1356
1357   if (tape.file_version < FILE_VERSION_1_2)
1358   {
1359     /* tape files from versions before 1.2.0 without chunk structure */
1360     LoadTape_HEAD(file, TAPE_HEADER_SIZE, &tape);
1361     LoadTape_BODY(file, 2 * tape.length,  &tape);
1362   }
1363   else
1364   {
1365     static struct
1366     {
1367       char *name;
1368       int size;
1369       int (*loader)(FILE *, int, struct TapeInfo *);
1370     }
1371     chunk_info[] =
1372     {
1373       { "VERS", FILE_VERS_CHUNK_SIZE,   LoadTape_VERS },
1374       { "HEAD", TAPE_HEADER_SIZE,       LoadTape_HEAD },
1375       { "INFO", -1,                     LoadTape_INFO },
1376       { "BODY", -1,                     LoadTape_BODY },
1377       {  NULL,  0,                      NULL }
1378     };
1379
1380     while (getFileChunkBE(file, chunk_name, &chunk_size))
1381     {
1382       int i = 0;
1383
1384       while (chunk_info[i].name != NULL &&
1385              strcmp(chunk_name, chunk_info[i].name) != 0)
1386         i++;
1387
1388       if (chunk_info[i].name == NULL)
1389       {
1390         Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'",
1391               chunk_name, filename);
1392         ReadUnusedBytesFromFile(file, chunk_size);
1393       }
1394       else if (chunk_info[i].size != -1 &&
1395                chunk_info[i].size != chunk_size)
1396       {
1397         Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
1398               chunk_size, chunk_name, filename);
1399         ReadUnusedBytesFromFile(file, chunk_size);
1400       }
1401       else
1402       {
1403         /* call function to load this tape chunk */
1404         int chunk_size_expected =
1405           (chunk_info[i].loader)(file, chunk_size, &tape);
1406
1407         /* the size of some chunks cannot be checked before reading other
1408            chunks first (like "HEAD" and "BODY") that contain some header
1409            information, so check them here */
1410         if (chunk_size_expected != chunk_size)
1411         {
1412           Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
1413                 chunk_size, chunk_name, filename);
1414         }
1415       }
1416     }
1417   }
1418
1419   fclose(file);
1420
1421   tape.length_seconds = GetTapeLength();
1422
1423 #if 0
1424   printf("tape version: %d\n", tape.game_version);
1425 #endif
1426 }
1427
1428 void LoadTape(int level_nr)
1429 {
1430   char *filename = getTapeFilename(level_nr);
1431
1432   LoadTapeFromFilename(filename);
1433 }
1434
1435 static void SaveTape_VERS(FILE *file, struct TapeInfo *tape)
1436 {
1437   putFileVersion(file, tape->file_version);
1438   putFileVersion(file, tape->game_version);
1439 }
1440
1441 static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
1442 {
1443   int i;
1444   byte store_participating_players = 0;
1445
1446   /* set bits for participating players for compact storage */
1447   for(i=0; i<MAX_PLAYERS; i++)
1448     if (tape->player_participates[i])
1449       store_participating_players |= (1 << i);
1450
1451   putFile32BitBE(file, tape->random_seed);
1452   putFile32BitBE(file, tape->date);
1453   putFile32BitBE(file, tape->length);
1454
1455   fputc(store_participating_players, file);
1456
1457   /* unused bytes not at the end here for 4-byte alignment of engine_version */
1458   WriteUnusedBytesToFile(file, TAPE_HEADER_UNUSED);
1459
1460   putFileVersion(file, tape->engine_version);
1461 }
1462
1463 static void SaveTape_INFO(FILE *file, struct TapeInfo *tape)
1464 {
1465   int level_identifier_size = strlen(tape->level_identifier) + 1;
1466   int i;
1467
1468   putFile16BitBE(file, level_identifier_size);
1469
1470   for(i=0; i < level_identifier_size; i++)
1471     fputc(tape->level_identifier[i], file);
1472
1473   putFile16BitBE(file, tape->level_nr);
1474 }
1475
1476 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
1477 {
1478   int i, j;
1479
1480   for(i=0; i<tape->length; i++)
1481   {
1482     for(j=0; j<MAX_PLAYERS; j++)
1483       if (tape->player_participates[j])
1484         fputc(tape->pos[i].action[j], file);
1485
1486     fputc(tape->pos[i].delay, file);
1487   }
1488 }
1489
1490 void SaveTape(int level_nr)
1491 {
1492   char *filename = getTapeFilename(level_nr);
1493   FILE *file;
1494   boolean new_tape = TRUE;
1495   int num_participating_players = 0;
1496   int info_chunk_size;
1497   int body_chunk_size;
1498   int i;
1499
1500   InitTapeDirectory(leveldir_current->filename);
1501
1502   /* if a tape still exists, ask to overwrite it */
1503   if (access(filename, F_OK) == 0)
1504   {
1505     new_tape = FALSE;
1506     if (!Request("Replace old tape ?", REQ_ASK))
1507       return;
1508   }
1509
1510   if (!(file = fopen(filename, MODE_WRITE)))
1511   {
1512     Error(ERR_WARN, "cannot save level recording file '%s'", filename);
1513     return;
1514   }
1515
1516   tape.file_version = FILE_VERSION_ACTUAL;
1517   tape.game_version = GAME_VERSION_ACTUAL;
1518
1519   /* count number of participating players  */
1520   for(i=0; i<MAX_PLAYERS; i++)
1521     if (tape.player_participates[i])
1522       num_participating_players++;
1523
1524   info_chunk_size = 2 + (strlen(tape.level_identifier) + 1) + 2;
1525   body_chunk_size = (num_participating_players + 1) * tape.length;
1526
1527   putFileChunkBE(file, "RND1", CHUNK_SIZE_UNDEFINED);
1528   putFileChunkBE(file, "TAPE", CHUNK_SIZE_NONE);
1529
1530   putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
1531   SaveTape_VERS(file, &tape);
1532
1533   putFileChunkBE(file, "HEAD", TAPE_HEADER_SIZE);
1534   SaveTape_HEAD(file, &tape);
1535
1536   putFileChunkBE(file, "INFO", info_chunk_size);
1537   SaveTape_INFO(file, &tape);
1538
1539   putFileChunkBE(file, "BODY", body_chunk_size);
1540   SaveTape_BODY(file, &tape);
1541
1542   fclose(file);
1543
1544   SetFilePermissions(filename, PERMS_PRIVATE);
1545
1546   tape.changed = FALSE;
1547
1548   if (new_tape)
1549     Request("tape saved !", REQ_CONFIRM);
1550 }
1551
1552 void DumpTape(struct TapeInfo *tape)
1553 {
1554   int i, j;
1555
1556   if (TAPE_IS_EMPTY(*tape))
1557   {
1558     Error(ERR_WARN, "no tape available for level %d", tape->level_nr);
1559     return;
1560   }
1561
1562   printf_line("-", 79);
1563   printf("Tape of Level %03d (file version %08d, game version %08d)\n",
1564          tape->level_nr, tape->file_version, tape->game_version);
1565   printf("Level series identifier: '%s'\n", tape->level_identifier);
1566   printf_line("-", 79);
1567
1568   for(i=0; i<tape->length; i++)
1569   {
1570     if (i >= MAX_TAPELEN)
1571       break;
1572
1573     printf("%03d: ", i);
1574
1575     for(j=0; j<MAX_PLAYERS; j++)
1576     {
1577       if (tape->player_participates[j])
1578       {
1579         int action = tape->pos[i].action[j];
1580
1581         printf("%d:%02x ", j, action);
1582         printf("[%c%c%c%c|%c%c] - ",
1583                (action & JOY_LEFT ? '<' : ' '),
1584                (action & JOY_RIGHT ? '>' : ' '),
1585                (action & JOY_UP ? '^' : ' '),
1586                (action & JOY_DOWN ? 'v' : ' '),
1587                (action & JOY_BUTTON_1 ? '1' : ' '),
1588                (action & JOY_BUTTON_2 ? '2' : ' '));
1589       }
1590     }
1591
1592     printf("(%03d)\n", tape->pos[i].delay);
1593   }
1594
1595   printf_line("-", 79);
1596 }
1597
1598
1599 /* ========================================================================= */
1600 /* score file functions                                                      */
1601 /* ========================================================================= */
1602
1603 void LoadScore(int level_nr)
1604 {
1605   int i;
1606   char *filename = getScoreFilename(level_nr);
1607   char cookie[MAX_LINE_LEN];
1608   char line[MAX_LINE_LEN];
1609   char *line_ptr;
1610   FILE *file;
1611
1612   /* always start with reliable default values */
1613   for(i=0; i<MAX_SCORE_ENTRIES; i++)
1614   {
1615     strcpy(highscore[i].Name, EMPTY_PLAYER_NAME);
1616     highscore[i].Score = 0;
1617   }
1618
1619   if (!(file = fopen(filename, MODE_READ)))
1620     return;
1621
1622   /* check file identifier */
1623   fgets(cookie, MAX_LINE_LEN, file);
1624   if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
1625     cookie[strlen(cookie) - 1] = '\0';
1626
1627   if (!checkCookieString(cookie, SCORE_COOKIE))
1628   {
1629     Error(ERR_WARN, "unknown format of score file '%s'", filename);
1630     fclose(file);
1631     return;
1632   }
1633
1634   for(i=0; i<MAX_SCORE_ENTRIES; i++)
1635   {
1636     fscanf(file, "%d", &highscore[i].Score);
1637     fgets(line, MAX_LINE_LEN, file);
1638
1639     if (line[strlen(line) - 1] == '\n')
1640       line[strlen(line) - 1] = '\0';
1641
1642     for (line_ptr = line; *line_ptr; line_ptr++)
1643     {
1644       if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
1645       {
1646         strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN);
1647         highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0';
1648         break;
1649       }
1650     }
1651   }
1652
1653   fclose(file);
1654 }
1655
1656 void SaveScore(int level_nr)
1657 {
1658   int i;
1659   char *filename = getScoreFilename(level_nr);
1660   FILE *file;
1661
1662   InitScoreDirectory(leveldir_current->filename);
1663
1664   if (!(file = fopen(filename, MODE_WRITE)))
1665   {
1666     Error(ERR_WARN, "cannot save score for level %d", level_nr);
1667     return;
1668   }
1669
1670   fprintf(file, "%s\n\n", SCORE_COOKIE);
1671
1672   for(i=0; i<MAX_SCORE_ENTRIES; i++)
1673     fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name);
1674
1675   fclose(file);
1676
1677   SetFilePermissions(filename, PERMS_PUBLIC);
1678 }
1679
1680
1681 /* ========================================================================= */
1682 /* setup file functions                                                      */
1683 /* ========================================================================= */
1684
1685 #define TOKEN_STR_PLAYER_PREFIX                 "player_"
1686
1687 /* global setup */
1688 #define SETUP_TOKEN_PLAYER_NAME                 0
1689 #define SETUP_TOKEN_SOUND                       1
1690 #define SETUP_TOKEN_SOUND_LOOPS                 2
1691 #define SETUP_TOKEN_SOUND_MUSIC                 3
1692 #define SETUP_TOKEN_SOUND_SIMPLE                4
1693 #define SETUP_TOKEN_TOONS                       5
1694 #define SETUP_TOKEN_SCROLL_DELAY                6
1695 #define SETUP_TOKEN_SOFT_SCROLLING              7
1696 #define SETUP_TOKEN_FADING                      8
1697 #define SETUP_TOKEN_AUTORECORD                  9
1698 #define SETUP_TOKEN_QUICK_DOORS                 10
1699 #define SETUP_TOKEN_TEAM_MODE                   11
1700 #define SETUP_TOKEN_HANDICAP                    12
1701 #define SETUP_TOKEN_TIME_LIMIT                  13
1702 #define SETUP_TOKEN_FULLSCREEN                  14
1703 #define SETUP_TOKEN_ASK_ON_ESCAPE               15
1704 #define SETUP_TOKEN_GRAPHICS_SET                16
1705 #define SETUP_TOKEN_SOUNDS_SET                  17
1706 #define SETUP_TOKEN_MUSIC_SET                   18
1707 #define SETUP_TOKEN_OVERRIDE_LEVEL_GRAPHICS     19
1708 #define SETUP_TOKEN_OVERRIDE_LEVEL_SOUNDS       20
1709 #define SETUP_TOKEN_OVERRIDE_LEVEL_MUSIC        21
1710
1711 #define NUM_GLOBAL_SETUP_TOKENS                 22
1712
1713 /* editor setup */
1714 #define SETUP_TOKEN_EDITOR_EL_BOULDERDASH       0
1715 #define SETUP_TOKEN_EDITOR_EL_EMERALD_MINE      1
1716 #define SETUP_TOKEN_EDITOR_EL_MORE              2
1717 #define SETUP_TOKEN_EDITOR_EL_SOKOBAN           3
1718 #define SETUP_TOKEN_EDITOR_EL_SUPAPLEX          4
1719 #define SETUP_TOKEN_EDITOR_EL_DIAMOND_CAVES     5
1720 #define SETUP_TOKEN_EDITOR_EL_DX_BOULDERDASH    6
1721 #define SETUP_TOKEN_EDITOR_EL_CHARS             7
1722 #define SETUP_TOKEN_EDITOR_EL_CUSTOM            8
1723
1724 #define NUM_EDITOR_SETUP_TOKENS                 9
1725
1726 /* shortcut setup */
1727 #define SETUP_TOKEN_SHORTCUT_SAVE_GAME          0
1728 #define SETUP_TOKEN_SHORTCUT_LOAD_GAME          1
1729 #define SETUP_TOKEN_SHORTCUT_TOGGLE_PAUSE       2
1730
1731 #define NUM_SHORTCUT_SETUP_TOKENS               3
1732
1733 /* player setup */
1734 #define SETUP_TOKEN_PLAYER_USE_JOYSTICK         0
1735 #define SETUP_TOKEN_PLAYER_JOY_DEVICE_NAME      1
1736 #define SETUP_TOKEN_PLAYER_JOY_XLEFT            2
1737 #define SETUP_TOKEN_PLAYER_JOY_XMIDDLE          3
1738 #define SETUP_TOKEN_PLAYER_JOY_XRIGHT           4
1739 #define SETUP_TOKEN_PLAYER_JOY_YUPPER           5
1740 #define SETUP_TOKEN_PLAYER_JOY_YMIDDLE          6
1741 #define SETUP_TOKEN_PLAYER_JOY_YLOWER           7
1742 #define SETUP_TOKEN_PLAYER_JOY_SNAP             8
1743 #define SETUP_TOKEN_PLAYER_JOY_BOMB             9
1744 #define SETUP_TOKEN_PLAYER_KEY_LEFT             10
1745 #define SETUP_TOKEN_PLAYER_KEY_RIGHT            11
1746 #define SETUP_TOKEN_PLAYER_KEY_UP               12
1747 #define SETUP_TOKEN_PLAYER_KEY_DOWN             13
1748 #define SETUP_TOKEN_PLAYER_KEY_SNAP             14
1749 #define SETUP_TOKEN_PLAYER_KEY_BOMB             15
1750
1751 #define NUM_PLAYER_SETUP_TOKENS                 16
1752
1753 /* system setup */
1754 #define SETUP_TOKEN_SYSTEM_SDL_AUDIODRIVER      0
1755 #define SETUP_TOKEN_SYSTEM_AUDIO_FRAGMENT_SIZE  1
1756
1757 #define NUM_SYSTEM_SETUP_TOKENS                 2
1758
1759 /* options setup */
1760 #define SETUP_TOKEN_OPTIONS_VERBOSE             0
1761
1762 #define NUM_OPTIONS_SETUP_TOKENS                1
1763
1764
1765 static struct SetupInfo si;
1766 static struct SetupEditorInfo sei;
1767 static struct SetupShortcutInfo ssi;
1768 static struct SetupInputInfo sii;
1769 static struct SetupSystemInfo syi;
1770 static struct OptionInfo soi;
1771
1772 static struct TokenInfo global_setup_tokens[] =
1773 {
1774   { TYPE_STRING, &si.player_name,       "player_name"                   },
1775   { TYPE_SWITCH, &si.sound,             "sound"                         },
1776   { TYPE_SWITCH, &si.sound_loops,       "repeating_sound_loops"         },
1777   { TYPE_SWITCH, &si.sound_music,       "background_music"              },
1778   { TYPE_SWITCH, &si.sound_simple,      "simple_sound_effects"          },
1779   { TYPE_SWITCH, &si.toons,             "toons"                         },
1780   { TYPE_SWITCH, &si.scroll_delay,      "scroll_delay"                  },
1781   { TYPE_SWITCH, &si.soft_scrolling,    "soft_scrolling"                },
1782   { TYPE_SWITCH, &si.fading,            "screen_fading"                 },
1783   { TYPE_SWITCH, &si.autorecord,        "automatic_tape_recording"      },
1784   { TYPE_SWITCH, &si.quick_doors,       "quick_doors"                   },
1785   { TYPE_SWITCH, &si.team_mode,         "team_mode"                     },
1786   { TYPE_SWITCH, &si.handicap,          "handicap"                      },
1787   { TYPE_SWITCH, &si.time_limit,        "time_limit"                    },
1788   { TYPE_SWITCH, &si.fullscreen,        "fullscreen"                    },
1789   { TYPE_SWITCH, &si.ask_on_escape,     "ask_on_escape"                 },
1790   { TYPE_STRING, &si.graphics_set,      "graphics_set"                  },
1791   { TYPE_STRING, &si.sounds_set,        "sounds_set"                    },
1792   { TYPE_STRING, &si.music_set,         "music_set"                     },
1793   { TYPE_SWITCH, &si.override_level_graphics, "override_level_graphics" },
1794   { TYPE_SWITCH, &si.override_level_sounds,   "override_level_sounds"   },
1795   { TYPE_SWITCH, &si.override_level_music,    "override_level_music"    },
1796 };
1797
1798 static struct TokenInfo editor_setup_tokens[] =
1799 {
1800   { TYPE_SWITCH, &sei.el_boulderdash,   "editor.el_boulderdash"         },
1801   { TYPE_SWITCH, &sei.el_emerald_mine,  "editor.el_emerald_mine"        },
1802   { TYPE_SWITCH, &sei.el_more,          "editor.el_more"                },
1803   { TYPE_SWITCH, &sei.el_sokoban,       "editor.el_sokoban"             },
1804   { TYPE_SWITCH, &sei.el_supaplex,      "editor.el_supaplex"            },
1805   { TYPE_SWITCH, &sei.el_diamond_caves, "editor.el_diamond_caves"       },
1806   { TYPE_SWITCH, &sei.el_dx_boulderdash,"editor.el_dx_boulderdash"      },
1807   { TYPE_SWITCH, &sei.el_chars,         "editor.el_chars"               },
1808   { TYPE_SWITCH, &sei.el_custom,        "editor.el_custom"              },
1809 };
1810
1811 static struct TokenInfo shortcut_setup_tokens[] =
1812 {
1813   { TYPE_KEY_X11, &ssi.save_game,       "shortcut.save_game"            },
1814   { TYPE_KEY_X11, &ssi.load_game,       "shortcut.load_game"            },
1815   { TYPE_KEY_X11, &ssi.toggle_pause,    "shortcut.toggle_pause"         }
1816 };
1817
1818 static struct TokenInfo player_setup_tokens[] =
1819 {
1820   { TYPE_BOOLEAN, &sii.use_joystick,    ".use_joystick"                 },
1821   { TYPE_STRING,  &sii.joy.device_name, ".joy.device_name"              },
1822   { TYPE_INTEGER, &sii.joy.xleft,       ".joy.xleft"                    },
1823   { TYPE_INTEGER, &sii.joy.xmiddle,     ".joy.xmiddle"                  },
1824   { TYPE_INTEGER, &sii.joy.xright,      ".joy.xright"                   },
1825   { TYPE_INTEGER, &sii.joy.yupper,      ".joy.yupper"                   },
1826   { TYPE_INTEGER, &sii.joy.ymiddle,     ".joy.ymiddle"                  },
1827   { TYPE_INTEGER, &sii.joy.ylower,      ".joy.ylower"                   },
1828   { TYPE_INTEGER, &sii.joy.snap,        ".joy.snap_field"               },
1829   { TYPE_INTEGER, &sii.joy.bomb,        ".joy.place_bomb"               },
1830   { TYPE_KEY_X11, &sii.key.left,        ".key.move_left"                },
1831   { TYPE_KEY_X11, &sii.key.right,       ".key.move_right"               },
1832   { TYPE_KEY_X11, &sii.key.up,          ".key.move_up"                  },
1833   { TYPE_KEY_X11, &sii.key.down,        ".key.move_down"                },
1834   { TYPE_KEY_X11, &sii.key.snap,        ".key.snap_field"               },
1835   { TYPE_KEY_X11, &sii.key.bomb,        ".key.place_bomb"               }
1836 };
1837
1838 static struct TokenInfo system_setup_tokens[] =
1839 {
1840   { TYPE_STRING,  &syi.sdl_audiodriver, "system.sdl_audiodriver"        },
1841   { TYPE_INTEGER, &syi.audio_fragment_size,"system.audio_fragment_size" }
1842 };
1843
1844 static struct TokenInfo options_setup_tokens[] =
1845 {
1846   { TYPE_BOOLEAN, &soi.verbose,         "options.verbose"               }
1847 };
1848
1849 static char *get_corrected_login_name(char *login_name)
1850 {
1851   /* needed because player name must be a fixed length string */
1852   char *login_name_new = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
1853
1854   strncpy(login_name_new, login_name, MAX_PLAYER_NAME_LEN);
1855   login_name_new[MAX_PLAYER_NAME_LEN] = '\0';
1856
1857   if (strlen(login_name) > MAX_PLAYER_NAME_LEN)         /* name has been cut */
1858     if (strchr(login_name_new, ' '))
1859       *strchr(login_name_new, ' ') = '\0';
1860
1861   return login_name_new;
1862 }
1863
1864 static void setSetupInfoToDefaults(struct SetupInfo *si)
1865 {
1866   int i;
1867
1868   si->player_name = get_corrected_login_name(getLoginName());
1869
1870   si->sound = TRUE;
1871   si->sound_loops = TRUE;
1872   si->sound_music = TRUE;
1873   si->sound_simple = TRUE;
1874   si->toons = TRUE;
1875   si->double_buffering = TRUE;
1876   si->direct_draw = !si->double_buffering;
1877   si->scroll_delay = TRUE;
1878   si->soft_scrolling = TRUE;
1879   si->fading = FALSE;
1880   si->autorecord = TRUE;
1881   si->quick_doors = FALSE;
1882   si->team_mode = FALSE;
1883   si->handicap = TRUE;
1884   si->time_limit = TRUE;
1885   si->fullscreen = FALSE;
1886   si->ask_on_escape = TRUE;
1887
1888   si->graphics_set = getStringCopy(GRAPHICS_SUBDIR);
1889   si->sounds_set = getStringCopy(SOUNDS_SUBDIR);
1890   si->music_set = getStringCopy(MUSIC_SUBDIR);
1891   si->override_level_graphics = FALSE;
1892   si->override_level_sounds = FALSE;
1893   si->override_level_music = FALSE;
1894
1895   si->editor.el_boulderdash = TRUE;
1896   si->editor.el_emerald_mine = TRUE;
1897   si->editor.el_more = TRUE;
1898   si->editor.el_sokoban = TRUE;
1899   si->editor.el_supaplex = TRUE;
1900   si->editor.el_diamond_caves = TRUE;
1901   si->editor.el_dx_boulderdash = TRUE;
1902   si->editor.el_chars = TRUE;
1903   si->editor.el_custom = TRUE;
1904
1905   si->shortcut.save_game = DEFAULT_KEY_SAVE_GAME;
1906   si->shortcut.load_game = DEFAULT_KEY_LOAD_GAME;
1907   si->shortcut.toggle_pause = DEFAULT_KEY_TOGGLE_PAUSE;
1908
1909   for (i=0; i<MAX_PLAYERS; i++)
1910   {
1911     si->input[i].use_joystick = FALSE;
1912     si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
1913     si->input[i].joy.xleft   = JOYSTICK_XLEFT;
1914     si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
1915     si->input[i].joy.xright  = JOYSTICK_XRIGHT;
1916     si->input[i].joy.yupper  = JOYSTICK_YUPPER;
1917     si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
1918     si->input[i].joy.ylower  = JOYSTICK_YLOWER;
1919     si->input[i].joy.snap  = (i == 0 ? JOY_BUTTON_1 : 0);
1920     si->input[i].joy.bomb  = (i == 0 ? JOY_BUTTON_2 : 0);
1921     si->input[i].key.left  = (i == 0 ? DEFAULT_KEY_LEFT  : KSYM_UNDEFINED);
1922     si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
1923     si->input[i].key.up    = (i == 0 ? DEFAULT_KEY_UP    : KSYM_UNDEFINED);
1924     si->input[i].key.down  = (i == 0 ? DEFAULT_KEY_DOWN  : KSYM_UNDEFINED);
1925     si->input[i].key.snap  = (i == 0 ? DEFAULT_KEY_SNAP  : KSYM_UNDEFINED);
1926     si->input[i].key.bomb  = (i == 0 ? DEFAULT_KEY_BOMB  : KSYM_UNDEFINED);
1927   }
1928
1929   si->system.sdl_audiodriver = getStringCopy(ARG_DEFAULT);
1930   si->system.audio_fragment_size = DEFAULT_AUDIO_FRAGMENT_SIZE;
1931
1932   si->options.verbose = FALSE;
1933 }
1934
1935 static void decodeSetupFileHash(SetupFileHash *setup_file_hash)
1936 {
1937   int i, pnr;
1938
1939   if (!setup_file_hash)
1940     return;
1941
1942   /* global setup */
1943   si = setup;
1944   for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
1945     setSetupInfo(global_setup_tokens, i,
1946                  getHashEntry(setup_file_hash, global_setup_tokens[i].text));
1947   setup = si;
1948
1949   /* editor setup */
1950   sei = setup.editor;
1951   for (i=0; i<NUM_EDITOR_SETUP_TOKENS; i++)
1952     setSetupInfo(editor_setup_tokens, i,
1953                  getHashEntry(setup_file_hash,editor_setup_tokens[i].text));
1954   setup.editor = sei;
1955
1956   /* shortcut setup */
1957   ssi = setup.shortcut;
1958   for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
1959     setSetupInfo(shortcut_setup_tokens, i,
1960                  getHashEntry(setup_file_hash,shortcut_setup_tokens[i].text));
1961   setup.shortcut = ssi;
1962
1963   /* player setup */
1964   for (pnr=0; pnr<MAX_PLAYERS; pnr++)
1965   {
1966     char prefix[30];
1967
1968     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
1969
1970     sii = setup.input[pnr];
1971     for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
1972     {
1973       char full_token[100];
1974
1975       sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
1976       setSetupInfo(player_setup_tokens, i,
1977                    getHashEntry(setup_file_hash, full_token));
1978     }
1979     setup.input[pnr] = sii;
1980   }
1981
1982   /* system setup */
1983   syi = setup.system;
1984   for (i=0; i<NUM_SYSTEM_SETUP_TOKENS; i++)
1985     setSetupInfo(system_setup_tokens, i,
1986                  getHashEntry(setup_file_hash, system_setup_tokens[i].text));
1987   setup.system = syi;
1988
1989   /* options setup */
1990   soi = setup.options;
1991   for (i=0; i<NUM_OPTIONS_SETUP_TOKENS; i++)
1992     setSetupInfo(options_setup_tokens, i,
1993                  getHashEntry(setup_file_hash, options_setup_tokens[i].text));
1994   setup.options = soi;
1995 }
1996
1997 void LoadSetup()
1998 {
1999   char *filename = getSetupFilename();
2000   SetupFileHash *setup_file_hash = NULL;
2001
2002   /* always start with reliable default values */
2003   setSetupInfoToDefaults(&setup);
2004
2005   setup_file_hash = loadSetupFileHash(filename);
2006
2007   if (setup_file_hash)
2008   {
2009     char *player_name_new;
2010
2011     checkSetupFileHashIdentifier(setup_file_hash, getCookie("SETUP"));
2012     decodeSetupFileHash(setup_file_hash);
2013
2014     setup.direct_draw = !setup.double_buffering;
2015
2016     freeSetupFileHash(setup_file_hash);
2017
2018     /* needed to work around problems with fixed length strings */
2019     player_name_new = get_corrected_login_name(setup.player_name);
2020     free(setup.player_name);
2021     setup.player_name = player_name_new;
2022   }
2023   else
2024     Error(ERR_WARN, "using default setup values");
2025 }
2026
2027 void SaveSetup()
2028 {
2029   char *filename = getSetupFilename();
2030   FILE *file;
2031   int i, pnr;
2032
2033   InitUserDataDirectory();
2034
2035   if (!(file = fopen(filename, MODE_WRITE)))
2036   {
2037     Error(ERR_WARN, "cannot write setup file '%s'", filename);
2038     return;
2039   }
2040
2041   fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
2042                                                getCookie("SETUP")));
2043   fprintf(file, "\n");
2044
2045   /* global setup */
2046   si = setup;
2047   for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
2048   {
2049     /* just to make things nicer :) */
2050     if (i == SETUP_TOKEN_PLAYER_NAME + 1 ||
2051         i == SETUP_TOKEN_GRAPHICS_SET)
2052       fprintf(file, "\n");
2053
2054     fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
2055   }
2056
2057   /* editor setup */
2058   sei = setup.editor;
2059   fprintf(file, "\n");
2060   for (i=0; i<NUM_EDITOR_SETUP_TOKENS; i++)
2061     fprintf(file, "%s\n", getSetupLine(editor_setup_tokens, "", i));
2062
2063   /* shortcut setup */
2064   ssi = setup.shortcut;
2065   fprintf(file, "\n");
2066   for (i=0; i<NUM_SHORTCUT_SETUP_TOKENS; i++)
2067     fprintf(file, "%s\n", getSetupLine(shortcut_setup_tokens, "", i));
2068
2069   /* player setup */
2070   for (pnr=0; pnr<MAX_PLAYERS; pnr++)
2071   {
2072     char prefix[30];
2073
2074     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
2075     fprintf(file, "\n");
2076
2077     sii = setup.input[pnr];
2078     for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
2079       fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
2080   }
2081
2082   /* system setup */
2083   syi = setup.system;
2084   fprintf(file, "\n");
2085   for (i=0; i<NUM_SYSTEM_SETUP_TOKENS; i++)
2086     fprintf(file, "%s\n", getSetupLine(system_setup_tokens, "", i));
2087
2088   /* options setup */
2089   soi = setup.options;
2090   fprintf(file, "\n");
2091   for (i=0; i<NUM_OPTIONS_SETUP_TOKENS; i++)
2092     fprintf(file, "%s\n", getSetupLine(options_setup_tokens, "", i));
2093
2094   fclose(file);
2095
2096   SetFilePermissions(filename, PERMS_PRIVATE);
2097 }
2098
2099 void LoadCustomElementDescriptions()
2100 {
2101   char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
2102   SetupFileHash *setup_file_hash;
2103   int i;
2104
2105   for (i=0; i<NUM_FILE_ELEMENTS; i++)
2106   {
2107     if (element_info[i].custom_description != NULL)
2108     {
2109       free(element_info[i].custom_description);
2110       element_info[i].custom_description = NULL;
2111     }
2112   }
2113
2114   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
2115     return;
2116
2117   for (i=0; i<NUM_FILE_ELEMENTS; i++)
2118   {
2119     char *token = getStringCat2(element_info[i].token_name, ".name");
2120     char *value = getHashEntry(setup_file_hash, token);
2121
2122     if (value != NULL)
2123       element_info[i].custom_description = getStringCopy(value);
2124
2125     free(token);
2126   }
2127
2128   freeSetupFileHash(setup_file_hash);
2129 }
2130
2131 void LoadSpecialMenuDesignSettings()
2132 {
2133   char *filename = getCustomArtworkConfigFilename(ARTWORK_TYPE_GRAPHICS);
2134   SetupFileHash *setup_file_hash;
2135   int i, j;
2136
2137   /* always start with reliable default values from default config */
2138   for (i=0; image_config_vars[i].token != NULL; i++)
2139     for (j=0; image_config[j].token != NULL; j++)
2140       if (strcmp(image_config_vars[i].token, image_config[j].token) == 0)
2141         *image_config_vars[i].value =
2142           get_integer_from_string(image_config[j].value);
2143
2144   if ((setup_file_hash = loadSetupFileHash(filename)) == NULL)
2145     return;
2146
2147   /* special case: initialize with default values that may be overwritten */
2148   for (i=0; i < NUM_SPECIAL_GFX_ARGS; i++)
2149   {
2150     char *value_x = getHashEntry(setup_file_hash, "menu.draw_xoffset");
2151     char *value_y = getHashEntry(setup_file_hash, "menu.draw_yoffset");
2152     char *list_size = getHashEntry(setup_file_hash, "menu.list_size");
2153
2154     if (value_x != NULL)
2155       menu.draw_xoffset[i] = get_integer_from_string(value_x);
2156     if (value_y != NULL)
2157       menu.draw_yoffset[i] = get_integer_from_string(value_y);
2158     if (list_size != NULL)
2159       menu.list_size[i] = get_integer_from_string(list_size);
2160   }
2161
2162   /* read (and overwrite with) values that may be specified in config file */
2163   for (i=0; image_config_vars[i].token != NULL; i++)
2164   {
2165     char *value = getHashEntry(setup_file_hash, image_config_vars[i].token);
2166
2167     if (value != NULL)
2168       *image_config_vars[i].value = get_integer_from_string(value);
2169   }
2170
2171   freeSetupFileHash(setup_file_hash);
2172 }