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