rnd-20020324-1-src
[rocksndiamonds.git] / src / files.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2001 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 "tools.h"
21 #include "tape.h"
22
23
24 #define CHUNK_ID_LEN            4       /* IFF style chunk id length  */
25 #define CHUNK_SIZE_UNDEFINED    0       /* undefined chunk size == 0  */
26 #define CHUNK_SIZE_NONE         -1      /* do not write chunk size    */
27 #define FILE_VERS_CHUNK_SIZE    8       /* size of file version chunk */
28 #define LEVEL_HEADER_SIZE       80      /* size of level file header  */
29 #define LEVEL_HEADER_UNUSED     14      /* unused level header bytes  */
30 #define LEVEL_CHUNK_CNT2_SIZE   160     /* size of level CNT2 chunk   */
31 #define LEVEL_CHUNK_CNT2_UNUSED 11      /* unused CNT2 chunk bytes    */
32 #define TAPE_HEADER_SIZE        20      /* size of tape file header   */
33 #define TAPE_HEADER_UNUSED      7       /* unused tape header bytes   */
34
35 /* file identifier strings */
36 #define LEVEL_COOKIE_TMPL       "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x"
37 #define TAPE_COOKIE_TMPL        "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
38 #define SCORE_COOKIE            "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
39
40
41 /* ========================================================================= */
42 /* level file functions                                                      */
43 /* ========================================================================= */
44
45 static void setLevelInfoToDefaults()
46 {
47   int i, x, y;
48
49   level.file_version = FILE_VERSION_ACTUAL;
50   level.game_version = GAME_VERSION_ACTUAL;
51
52   level.encoding_16bit_field = FALSE;   /* default: only 8-bit elements */
53   level.encoding_16bit_yamyam = FALSE;  /* default: only 8-bit elements */
54   level.encoding_16bit_amoeba = FALSE;  /* default: only 8-bit elements */
55
56   lev_fieldx = level.fieldx = STD_LEV_FIELDX;
57   lev_fieldy = level.fieldy = STD_LEV_FIELDY;
58
59   for(x=0; x<MAX_LEV_FIELDX; x++)
60     for(y=0; y<MAX_LEV_FIELDY; y++)
61       Feld[x][y] = Ur[x][y] = EL_ERDREICH;
62
63   level.time = 100;
64   level.gems_needed = 0;
65   level.amoeba_speed = 10;
66   level.time_magic_wall = 10;
67   level.time_wheel = 10;
68   level.time_light = 10;
69   level.time_timegate = 10;
70   level.amoeba_content = EL_DIAMANT;
71   level.double_speed = FALSE;
72   level.gravity = FALSE;
73   level.em_slippery_gems = FALSE;
74
75   for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
76     level.name[i] = '\0';
77   for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
78     level.author[i] = '\0';
79
80   strcpy(level.name, NAMELESS_LEVEL_NAME);
81   strcpy(level.author, ANONYMOUS_NAME);
82
83   for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
84     level.score[i] = 10;
85
86   level.num_yam_contents = STD_ELEMENT_CONTENTS;
87   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
88     for(x=0; x<3; x++)
89       for(y=0; y<3; y++)
90         level.yam_content[i][x][y] =
91           (i < STD_ELEMENT_CONTENTS ? EL_FELSBROCKEN : EL_LEERRAUM);
92
93   Feld[0][0] = Ur[0][0] = EL_SPIELFIGUR;
94   Feld[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] =
95     Ur[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] = EL_AUSGANG_ZU;
96
97   BorderElement = EL_BETON;
98
99   /* try to determine better author name than 'anonymous' */
100   if (strcmp(leveldir_current->author, ANONYMOUS_NAME) != 0)
101   {
102     strncpy(level.author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN);
103     level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
104   }
105   else
106   {
107     switch (LEVELCLASS(leveldir_current))
108     {
109       case LEVELCLASS_TUTORIAL:
110         strcpy(level.author, PROGRAM_AUTHOR_STRING);
111         break;
112
113       case LEVELCLASS_CONTRIBUTION:
114         strncpy(level.author, leveldir_current->name,MAX_LEVEL_AUTHOR_LEN);
115         level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
116         break;
117
118       case LEVELCLASS_USER:
119         strncpy(level.author, getRealName(), MAX_LEVEL_AUTHOR_LEN);
120         level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
121         break;
122
123       default:
124         /* keep default value */
125         break;
126     }
127   }
128 }
129
130 static int checkLevelElement(int element)
131 {
132   if (element >= EL_FIRST_RUNTIME_EL)
133   {
134     Error(ERR_WARN, "invalid level element %d", element);
135     element = EL_CHAR_FRAGE;
136   }
137
138   return element;
139 }
140
141 static int LoadLevel_VERS(FILE *file, int chunk_size, struct LevelInfo *level)
142 {
143   ReadChunk_VERS(file, &(level->file_version), &(level->game_version));
144
145   return chunk_size;
146 }
147
148 static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
149 {
150   int i, x, y;
151
152   lev_fieldx = level->fieldx = fgetc(file);
153   lev_fieldy = level->fieldy = fgetc(file);
154
155   level->time           = getFile16BitInteger(file, BYTE_ORDER_BIG_ENDIAN);
156   level->gems_needed    = getFile16BitInteger(file, BYTE_ORDER_BIG_ENDIAN);
157
158   for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
159     level->name[i] = fgetc(file);
160   level->name[MAX_LEVEL_NAME_LEN] = 0;
161
162   for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
163     level->score[i] = fgetc(file);
164
165   level->num_yam_contents = STD_ELEMENT_CONTENTS;
166   for(i=0; i<STD_ELEMENT_CONTENTS; i++)
167     for(y=0; y<3; y++)
168       for(x=0; x<3; x++)
169         level->yam_content[i][x][y] = checkLevelElement(fgetc(file));
170
171   level->amoeba_speed           = fgetc(file);
172   level->time_magic_wall        = fgetc(file);
173   level->time_wheel             = fgetc(file);
174   level->amoeba_content         = checkLevelElement(fgetc(file));
175   level->double_speed           = (fgetc(file) == 1 ? TRUE : FALSE);
176   level->gravity                = (fgetc(file) == 1 ? TRUE : FALSE);
177   level->encoding_16bit_field   = (fgetc(file) == 1 ? TRUE : FALSE);
178   level->em_slippery_gems       = (fgetc(file) == 1 ? TRUE : FALSE);
179
180   ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED);
181
182   return chunk_size;
183 }
184
185 static int LoadLevel_AUTH(FILE *file, int chunk_size, struct LevelInfo *level)
186 {
187   int i;
188
189   for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
190     level->author[i] = fgetc(file);
191   level->author[MAX_LEVEL_NAME_LEN] = 0;
192
193   return chunk_size;
194 }
195
196 static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
197 {
198   int i, x, y;
199   int header_size = 4;
200   int content_size = MAX_ELEMENT_CONTENTS * 3 * 3;
201   int chunk_size_expected = header_size + content_size;
202
203   /* Note: "chunk_size" was wrong before version 2.0 when elements are
204      stored with 16-bit encoding (and should be twice as big then).
205      Even worse, playfield data was stored 16-bit when only yamyam content
206      contained 16-bit elements and vice versa. */
207
208   if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
209     chunk_size_expected += content_size;
210
211   if (chunk_size_expected != chunk_size)
212   {
213     ReadUnusedBytesFromFile(file, chunk_size);
214     return chunk_size_expected;
215   }
216
217   fgetc(file);
218   level->num_yam_contents = fgetc(file);
219   fgetc(file);
220   fgetc(file);
221
222   /* correct invalid number of content fields -- should never happen */
223   if (level->num_yam_contents < 1 ||
224       level->num_yam_contents > MAX_ELEMENT_CONTENTS)
225     level->num_yam_contents = STD_ELEMENT_CONTENTS;
226
227   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
228     for(y=0; y<3; y++)
229       for(x=0; x<3; x++)
230         level->yam_content[i][x][y] =
231           checkLevelElement(level->encoding_16bit_field ?
232                             getFile16BitInteger(file, BYTE_ORDER_BIG_ENDIAN) :
233                             fgetc(file));
234   return chunk_size;
235 }
236
237 static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level)
238 {
239   int x, y;
240   int chunk_size_expected = level->fieldx * level->fieldy;
241
242   /* Note: "chunk_size" was wrong before version 2.0 when elements are
243      stored with 16-bit encoding (and should be twice as big then).
244      Even worse, playfield data was stored 16-bit when only yamyam content
245      contained 16-bit elements and vice versa. */
246
247   if (level->encoding_16bit_field && level->file_version >= FILE_VERSION_2_0)
248     chunk_size_expected *= 2;
249
250   if (chunk_size_expected != chunk_size)
251   {
252     ReadUnusedBytesFromFile(file, chunk_size);
253     return chunk_size_expected;
254   }
255
256   for(y=0; y<level->fieldy; y++)
257     for(x=0; x<level->fieldx; x++)
258       Feld[x][y] = Ur[x][y] =
259         checkLevelElement(level->encoding_16bit_field ?
260                           getFile16BitInteger(file, BYTE_ORDER_BIG_ENDIAN) :
261                           fgetc(file));
262   return chunk_size;
263 }
264
265 static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
266 {
267   int i, x, y;
268   int element;
269   int num_contents, content_xsize, content_ysize;
270   int content_array[MAX_ELEMENT_CONTENTS][3][3];
271
272   element = checkLevelElement(getFile16BitInteger(file,BYTE_ORDER_BIG_ENDIAN));
273   num_contents = fgetc(file);
274   content_xsize = fgetc(file);
275   content_ysize = fgetc(file);
276   ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED);
277
278   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
279     for(y=0; y<3; y++)
280       for(x=0; x<3; x++)
281         content_array[i][x][y] =
282           checkLevelElement(getFile16BitInteger(file, BYTE_ORDER_BIG_ENDIAN));
283
284   /* correct invalid number of content fields -- should never happen */
285   if (num_contents < 1 || num_contents > MAX_ELEMENT_CONTENTS)
286     num_contents = STD_ELEMENT_CONTENTS;
287
288   if (element == EL_MAMPFER)
289   {
290     level->num_yam_contents = num_contents;
291
292     for(i=0; i<num_contents; i++)
293       for(y=0; y<3; y++)
294         for(x=0; x<3; x++)
295           level->yam_content[i][x][y] = content_array[i][x][y];
296   }
297   else if (element == EL_AMOEBE_BD)
298   {
299     level->amoeba_content = content_array[0][0][0];
300   }
301   else
302   {
303     Error(ERR_WARN, "cannot load content for element '%d'", element);
304   }
305
306   return chunk_size;
307 }
308
309 void LoadLevel(int level_nr)
310 {
311   char *filename = getLevelFilename(level_nr);
312   char cookie[MAX_LINE_LEN];
313   char chunk_name[CHUNK_ID_LEN + 1];
314   int chunk_size;
315   FILE *file;
316
317   /* always start with reliable default values */
318   setLevelInfoToDefaults();
319
320   if (!(file = fopen(filename, MODE_READ)))
321   {
322     Error(ERR_WARN, "cannot read level '%s' - creating new level", filename);
323     return;
324   }
325
326   getFileChunk(file, chunk_name, NULL, BYTE_ORDER_BIG_ENDIAN);
327   if (strcmp(chunk_name, "RND1") == 0)
328   {
329     getFile32BitInteger(file, BYTE_ORDER_BIG_ENDIAN);   /* not used */
330
331     getFileChunk(file, chunk_name, NULL, BYTE_ORDER_BIG_ENDIAN);
332     if (strcmp(chunk_name, "CAVE") != 0)
333     {
334       Error(ERR_WARN, "unknown format of level file '%s'", filename);
335       fclose(file);
336       return;
337     }
338   }
339   else  /* check for pre-2.0 file format with cookie string */
340   {
341     strcpy(cookie, chunk_name);
342     fgets(&cookie[4], MAX_LINE_LEN - 4, file);
343     if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
344       cookie[strlen(cookie) - 1] = '\0';
345
346     if (!checkCookieString(cookie, LEVEL_COOKIE_TMPL))
347     {
348       Error(ERR_WARN, "unknown format of level file '%s'", filename);
349       fclose(file);
350       return;
351     }
352
353     if ((level.file_version = getFileVersionFromCookieString(cookie)) == -1)
354     {
355       Error(ERR_WARN, "unsupported version of level file '%s'", filename);
356       fclose(file);
357       return;
358     }
359
360     /* pre-2.0 level files have no game version, so use file version here */
361     level.game_version = level.file_version;
362   }
363
364   if (level.file_version < FILE_VERSION_1_2)
365   {
366     /* level files from versions before 1.2.0 without chunk structure */
367     LoadLevel_HEAD(file, LEVEL_HEADER_SIZE,           &level);
368     LoadLevel_BODY(file, level.fieldx * level.fieldy, &level);
369   }
370   else
371   {
372     static struct
373     {
374       char *name;
375       int size;
376       int (*loader)(FILE *, int, struct LevelInfo *);
377     }
378     chunk_info[] =
379     {
380       { "VERS", FILE_VERS_CHUNK_SIZE,   LoadLevel_VERS },
381       { "HEAD", LEVEL_HEADER_SIZE,      LoadLevel_HEAD },
382       { "AUTH", MAX_LEVEL_AUTHOR_LEN,   LoadLevel_AUTH },
383       { "CONT", -1,                     LoadLevel_CONT },
384       { "BODY", -1,                     LoadLevel_BODY },
385       { "CNT2", LEVEL_CHUNK_CNT2_SIZE,  LoadLevel_CNT2 },
386       {  NULL,  0,                      NULL }
387     };
388
389     while (getFileChunk(file, chunk_name, &chunk_size, BYTE_ORDER_BIG_ENDIAN))
390     {
391       int i = 0;
392
393       while (chunk_info[i].name != NULL &&
394              strcmp(chunk_name, chunk_info[i].name) != 0)
395         i++;
396
397       if (chunk_info[i].name == NULL)
398       {
399         Error(ERR_WARN, "unknown chunk '%s' in level file '%s'",
400               chunk_name, filename);
401         ReadUnusedBytesFromFile(file, chunk_size);
402       }
403       else if (chunk_info[i].size != -1 &&
404                chunk_info[i].size != chunk_size)
405       {
406         Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
407               chunk_size, chunk_name, filename);
408         ReadUnusedBytesFromFile(file, chunk_size);
409       }
410       else
411       {
412         /* call function to load this level chunk */
413         int chunk_size_expected =
414           (chunk_info[i].loader)(file, chunk_size, &level);
415
416         /* the size of some chunks cannot be checked before reading other
417            chunks first (like "HEAD" and "BODY") that contain some header
418            information, so check them here */
419         if (chunk_size_expected != chunk_size)
420         {
421           Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
422                 chunk_size, chunk_name, filename);
423         }
424       }
425     }
426   }
427
428   fclose(file);
429
430   if (IS_LEVELCLASS_CONTRIBUTION(leveldir_current) ||
431       IS_LEVELCLASS_USER(leveldir_current))
432   {
433     /* For user contributed and private levels, use the version of
434        the game engine the levels were created for.
435        Since 2.0.1, the game engine version is now directly stored
436        in the level file (chunk "VERS"), so there is no need anymore
437        to set the game version from the file version (except for old,
438        pre-2.0 levels, where the game version is still taken from the
439        file format version used to store the level -- see above). */
440
441     /* do some special adjustments to support older level versions */
442     if (level.file_version == FILE_VERSION_1_0)
443     {
444       Error(ERR_WARN, "level file '%s' has version number 1.0", filename);
445       Error(ERR_WARN, "using high speed movement for player");
446
447       /* player was faster than monsters in (pre-)1.0 levels */
448       level.double_speed = TRUE;
449     }
450   }
451   else
452   {
453     /* Always use the latest version of the game engine for all but
454        user contributed and private levels; this allows for actual
455        corrections in the game engine to take effect for existing,
456        converted levels (from "classic" or other existing games) to
457        make the game emulation more accurate, while (hopefully) not
458        breaking existing levels created from other players. */
459
460     level.game_version = GAME_VERSION_ACTUAL;
461
462     /* Set special EM style gems behaviour: EM style gems slip down from
463        normal, steel and growing wall. As this is a more fundamental change,
464        it seems better to set the default behaviour to "off" (as it is more
465        natural) and make it configurable in the level editor (as a property
466        of gem style elements). Already existing converted levels (neither
467        private nor contributed levels) are changed to the new behaviour. */
468
469     if (level.file_version < FILE_VERSION_2_0)
470       level.em_slippery_gems = TRUE;
471   }
472
473   /* determine border element for this level */
474   SetBorderElement();
475 }
476
477 static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
478 {
479   int i, x, y;
480
481   fputc(level->fieldx, file);
482   fputc(level->fieldy, file);
483
484   putFile16BitInteger(file, level->time,        BYTE_ORDER_BIG_ENDIAN);
485   putFile16BitInteger(file, level->gems_needed, BYTE_ORDER_BIG_ENDIAN);
486
487   for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
488     fputc(level->name[i], file);
489
490   for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
491     fputc(level->score[i], file);
492
493   for(i=0; i<STD_ELEMENT_CONTENTS; i++)
494     for(y=0; y<3; y++)
495       for(x=0; x<3; x++)
496         fputc((level->encoding_16bit_yamyam ? EL_LEERRAUM :
497                level->yam_content[i][x][y]),
498               file);
499   fputc(level->amoeba_speed, file);
500   fputc(level->time_magic_wall, file);
501   fputc(level->time_wheel, file);
502   fputc((level->encoding_16bit_amoeba ? EL_LEERRAUM : level->amoeba_content),
503         file);
504   fputc((level->double_speed ? 1 : 0), file);
505   fputc((level->gravity ? 1 : 0), file);
506   fputc((level->encoding_16bit_field ? 1 : 0), file);
507   fputc((level->em_slippery_gems ? 1 : 0), file);
508
509   WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
510 }
511
512 static void SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
513 {
514   int i;
515
516   for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
517     fputc(level->author[i], file);
518 }
519
520 #if 0
521 static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
522 {
523   int i, x, y;
524
525   fputc(EL_MAMPFER, file);
526   fputc(level->num_yam_contents, file);
527   fputc(0, file);
528   fputc(0, file);
529
530   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
531     for(y=0; y<3; y++)
532       for(x=0; x<3; x++)
533         if (level->encoding_16bit_field)
534           putFile16BitInteger(file, level->yam_content[i][x][y],
535                               BYTE_ORDER_BIG_ENDIAN);
536         else
537           fputc(level->yam_content[i][x][y], file);
538 }
539 #endif
540
541 static void SaveLevel_BODY(FILE *file, struct LevelInfo *level)
542 {
543   int x, y;
544
545   for(y=0; y<level->fieldy; y++) 
546     for(x=0; x<level->fieldx; x++) 
547       if (level->encoding_16bit_field)
548         putFile16BitInteger(file, Ur[x][y], BYTE_ORDER_BIG_ENDIAN);
549       else
550         fputc(Ur[x][y], file);
551 }
552
553 static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
554 {
555   int i, x, y;
556   int num_contents, content_xsize, content_ysize;
557   int content_array[MAX_ELEMENT_CONTENTS][3][3];
558
559   if (element == EL_MAMPFER)
560   {
561     num_contents = level->num_yam_contents;
562     content_xsize = 3;
563     content_ysize = 3;
564
565     for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
566       for(y=0; y<3; y++)
567         for(x=0; x<3; x++)
568           content_array[i][x][y] = level->yam_content[i][x][y];
569   }
570   else if (element == EL_AMOEBE_BD)
571   {
572     num_contents = 1;
573     content_xsize = 1;
574     content_ysize = 1;
575
576     for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
577       for(y=0; y<3; y++)
578         for(x=0; x<3; x++)
579           content_array[i][x][y] = EL_LEERRAUM;
580     content_array[0][0][0] = level->amoeba_content;
581   }
582   else
583   {
584     /* chunk header already written -- write empty chunk data */
585     WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_SIZE);
586
587     Error(ERR_WARN, "cannot save content for element '%d'", element);
588     return;
589   }
590
591   putFile16BitInteger(file, element, BYTE_ORDER_BIG_ENDIAN);
592   fputc(num_contents, file);
593   fputc(content_xsize, file);
594   fputc(content_ysize, file);
595
596   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED);
597
598   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
599     for(y=0; y<3; y++)
600       for(x=0; x<3; x++)
601         putFile16BitInteger(file, content_array[i][x][y],
602                             BYTE_ORDER_BIG_ENDIAN);
603 }
604
605 void SaveLevel(int level_nr)
606 {
607   int i, x, y;
608   char *filename = getLevelFilename(level_nr);
609   int body_chunk_size;
610   FILE *file;
611
612   if (!(file = fopen(filename, MODE_WRITE)))
613   {
614     Error(ERR_WARN, "cannot save level file '%s'", filename);
615     return;
616   }
617
618
619   /* check level field for 16-bit elements */
620   level.encoding_16bit_field = FALSE;
621   for(y=0; y<level.fieldy; y++) 
622     for(x=0; x<level.fieldx; x++) 
623       if (Ur[x][y] > 255)
624         level.encoding_16bit_field = TRUE;
625
626   /* check yamyam content for 16-bit elements */
627   level.encoding_16bit_yamyam = FALSE;
628   for(i=0; i<level.num_yam_contents; i++)
629     for(y=0; y<3; y++)
630       for(x=0; x<3; x++)
631         if (level.yam_content[i][x][y] > 255)
632           level.encoding_16bit_yamyam = TRUE;
633
634   /* check amoeba content for 16-bit elements */
635   level.encoding_16bit_amoeba = FALSE;
636   if (level.amoeba_content > 255)
637     level.encoding_16bit_amoeba = TRUE;
638
639   body_chunk_size =
640     level.fieldx * level.fieldy * (level.encoding_16bit_field ? 2 : 1);
641
642   putFileChunk(file, "RND1", CHUNK_SIZE_UNDEFINED, BYTE_ORDER_BIG_ENDIAN);
643   putFileChunk(file, "CAVE", CHUNK_SIZE_NONE,      BYTE_ORDER_BIG_ENDIAN);
644
645   putFileChunk(file, "VERS", FILE_VERS_CHUNK_SIZE, BYTE_ORDER_BIG_ENDIAN);
646   WriteChunk_VERS(file, FILE_VERSION_ACTUAL, GAME_VERSION_ACTUAL);
647
648   putFileChunk(file, "HEAD", LEVEL_HEADER_SIZE, BYTE_ORDER_BIG_ENDIAN);
649   SaveLevel_HEAD(file, &level);
650
651   putFileChunk(file, "AUTH", MAX_LEVEL_AUTHOR_LEN, BYTE_ORDER_BIG_ENDIAN);
652   SaveLevel_AUTH(file, &level);
653
654   putFileChunk(file, "BODY", body_chunk_size, BYTE_ORDER_BIG_ENDIAN);
655   SaveLevel_BODY(file, &level);
656
657   if (level.encoding_16bit_yamyam ||
658       level.num_yam_contents != STD_ELEMENT_CONTENTS)
659   {
660     putFileChunk(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE, BYTE_ORDER_BIG_ENDIAN);
661     SaveLevel_CNT2(file, &level, EL_MAMPFER);
662   }
663
664   if (level.encoding_16bit_amoeba)
665   {
666     putFileChunk(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE, BYTE_ORDER_BIG_ENDIAN);
667     SaveLevel_CNT2(file, &level, EL_AMOEBE_BD);
668   }
669
670   fclose(file);
671
672   SetFilePermissions(filename, PERMS_PRIVATE);
673 }
674
675
676 /* ========================================================================= */
677 /* tape file functions                                                       */
678 /* ========================================================================= */
679
680 static void setTapeInfoToDefaults()
681 {
682   int i;
683
684   /* always start with reliable default values (empty tape) */
685   tape.file_version = FILE_VERSION_ACTUAL;
686   tape.game_version = GAME_VERSION_ACTUAL;
687   TapeErase();
688
689   /* default values (also for pre-1.2 tapes) with only the first player */
690   tape.player_participates[0] = TRUE;
691   for(i=1; i<MAX_PLAYERS; i++)
692     tape.player_participates[i] = FALSE;
693
694   /* at least one (default: the first) player participates in every tape */
695   tape.num_participating_players = 1;
696
697   tape.level_nr = level_nr;
698   tape.counter = 0;
699   tape.changed = FALSE;
700
701   tape.recording = FALSE;
702   tape.playing = FALSE;
703   tape.pausing = FALSE;
704 }
705
706 static int LoadTape_VERS(FILE *file, int chunk_size, struct TapeInfo *tape)
707 {
708   ReadChunk_VERS(file, &(tape->file_version), &(tape->game_version));
709
710   return chunk_size;
711 }
712
713 static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
714 {
715   int i;
716
717   tape->random_seed = getFile32BitInteger(file, BYTE_ORDER_BIG_ENDIAN);
718   tape->date        = getFile32BitInteger(file, BYTE_ORDER_BIG_ENDIAN);
719   tape->length      = getFile32BitInteger(file, BYTE_ORDER_BIG_ENDIAN);
720
721   /* read header fields that are new since version 1.2 */
722   if (tape->file_version >= FILE_VERSION_1_2)
723   {
724     byte store_participating_players = fgetc(file);
725
726     ReadUnusedBytesFromFile(file, TAPE_HEADER_UNUSED);
727
728     /* since version 1.2, tapes store which players participate in the tape */
729     tape->num_participating_players = 0;
730     for(i=0; i<MAX_PLAYERS; i++)
731     {
732       tape->player_participates[i] = FALSE;
733
734       if (store_participating_players & (1 << i))
735       {
736         tape->player_participates[i] = TRUE;
737         tape->num_participating_players++;
738       }
739     }
740   }
741
742   return chunk_size;
743 }
744
745 static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
746 {
747   int i, j;
748   int chunk_size_expected =
749     (tape->num_participating_players + 1) * tape->length;
750
751   if (chunk_size_expected != chunk_size)
752   {
753     ReadUnusedBytesFromFile(file, chunk_size);
754     return chunk_size_expected;
755   }
756
757   for(i=0; i<tape->length; i++)
758   {
759     if (i >= MAX_TAPELEN)
760       break;
761
762     for(j=0; j<MAX_PLAYERS; j++)
763     {
764       tape->pos[i].action[j] = MV_NO_MOVING;
765
766       if (tape->player_participates[j])
767         tape->pos[i].action[j] = fgetc(file);
768     }
769
770     tape->pos[i].delay = fgetc(file);
771
772     if (tape->file_version == FILE_VERSION_1_0)
773     {
774       /* eliminate possible diagonal moves in old tapes */
775       /* this is only for backward compatibility */
776
777       byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
778       byte action = tape->pos[i].action[0];
779       int k, num_moves = 0;
780
781       for (k=0; k<4; k++)
782       {
783         if (action & joy_dir[k])
784         {
785           tape->pos[i + num_moves].action[0] = joy_dir[k];
786           if (num_moves > 0)
787             tape->pos[i + num_moves].delay = 0;
788           num_moves++;
789         }
790       }
791
792       if (num_moves > 1)
793       {
794         num_moves--;
795         i += num_moves;
796         tape->length += num_moves;
797       }
798     }
799     else if (tape->file_version < FILE_VERSION_2_0)
800     {
801       if (tape->pos[i].delay > 1)
802       {
803         /* action part */
804         tape->pos[i + 1] = tape->pos[i];
805         tape->pos[i + 1].delay = 1;
806
807         /* delay part */
808         for(j=0; j<MAX_PLAYERS; j++)
809           tape->pos[i].action[j] = MV_NO_MOVING;
810         tape->pos[i].delay--;
811
812         i++;
813         tape->length++;
814       }
815     }
816
817     if (feof(file))
818       break;
819   }
820
821   if (i != tape->length)
822     chunk_size = (tape->num_participating_players + 1) * i;
823
824   return chunk_size;
825 }
826
827 void LoadTape(int level_nr)
828 {
829   char *filename = getTapeFilename(level_nr);
830   char cookie[MAX_LINE_LEN];
831   char chunk_name[CHUNK_ID_LEN + 1];
832   FILE *file;
833   int chunk_size;
834
835   /* always start with reliable default values */
836   setTapeInfoToDefaults();
837
838   if (!(file = fopen(filename, MODE_READ)))
839     return;
840
841   getFileChunk(file, chunk_name, NULL, BYTE_ORDER_BIG_ENDIAN);
842   if (strcmp(chunk_name, "RND1") == 0)
843   {
844     getFile32BitInteger(file, BYTE_ORDER_BIG_ENDIAN);   /* not used */
845
846     getFileChunk(file, chunk_name, NULL, BYTE_ORDER_BIG_ENDIAN);
847     if (strcmp(chunk_name, "TAPE") != 0)
848     {
849       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
850       fclose(file);
851       return;
852     }
853   }
854   else  /* check for pre-2.0 file format with cookie string */
855   {
856     strcpy(cookie, chunk_name);
857     fgets(&cookie[4], MAX_LINE_LEN - 4, file);
858     if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
859       cookie[strlen(cookie) - 1] = '\0';
860
861     if (!checkCookieString(cookie, TAPE_COOKIE_TMPL))
862     {
863       Error(ERR_WARN, "unknown format of tape file '%s'", filename);
864       fclose(file);
865       return;
866     }
867
868     if ((tape.file_version = getFileVersionFromCookieString(cookie)) == -1)
869     {
870       Error(ERR_WARN, "unsupported version of tape file '%s'", filename);
871       fclose(file);
872       return;
873     }
874
875     /* pre-2.0 tape files have no game version, so use file version here */
876     tape.game_version = tape.file_version;
877   }
878
879   if (tape.file_version < FILE_VERSION_1_2)
880   {
881     /* tape files from versions before 1.2.0 without chunk structure */
882     LoadTape_HEAD(file, TAPE_HEADER_SIZE, &tape);
883     LoadTape_BODY(file, 2 * tape.length,  &tape);
884   }
885   else
886   {
887     static struct
888     {
889       char *name;
890       int size;
891       int (*loader)(FILE *, int, struct TapeInfo *);
892     }
893     chunk_info[] =
894     {
895       { "VERS", FILE_VERS_CHUNK_SIZE,   LoadTape_VERS },
896       { "HEAD", TAPE_HEADER_SIZE,       LoadTape_HEAD },
897       { "BODY", -1,                     LoadTape_BODY },
898       {  NULL,  0,                      NULL }
899     };
900
901     while (getFileChunk(file, chunk_name, &chunk_size, BYTE_ORDER_BIG_ENDIAN))
902     {
903       int i = 0;
904
905       while (chunk_info[i].name != NULL &&
906              strcmp(chunk_name, chunk_info[i].name) != 0)
907         i++;
908
909       if (chunk_info[i].name == NULL)
910       {
911         Error(ERR_WARN, "unknown chunk '%s' in tape file '%s'",
912               chunk_name, filename);
913         ReadUnusedBytesFromFile(file, chunk_size);
914       }
915       else if (chunk_info[i].size != -1 &&
916                chunk_info[i].size != chunk_size)
917       {
918         Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
919               chunk_size, chunk_name, filename);
920         ReadUnusedBytesFromFile(file, chunk_size);
921       }
922       else
923       {
924         /* call function to load this tape chunk */
925         int chunk_size_expected =
926           (chunk_info[i].loader)(file, chunk_size, &tape);
927
928         /* the size of some chunks cannot be checked before reading other
929            chunks first (like "HEAD" and "BODY") that contain some header
930            information, so check them here */
931         if (chunk_size_expected != chunk_size)
932         {
933           Error(ERR_WARN, "wrong size (%d) of chunk '%s' in tape file '%s'",
934                 chunk_size, chunk_name, filename);
935         }
936       }
937     }
938   }
939
940   fclose(file);
941
942   tape.length_seconds = GetTapeLength();
943 }
944
945 static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
946 {
947   int i;
948   byte store_participating_players = 0;
949
950   /* set bits for participating players for compact storage */
951   for(i=0; i<MAX_PLAYERS; i++)
952     if (tape->player_participates[i])
953       store_participating_players |= (1 << i);
954
955   putFile32BitInteger(file, tape->random_seed, BYTE_ORDER_BIG_ENDIAN);
956   putFile32BitInteger(file, tape->date, BYTE_ORDER_BIG_ENDIAN);
957   putFile32BitInteger(file, tape->length, BYTE_ORDER_BIG_ENDIAN);
958
959   fputc(store_participating_players, file);
960
961   WriteUnusedBytesToFile(file, TAPE_HEADER_UNUSED);
962 }
963
964 static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
965 {
966   int i, j;
967
968   for(i=0; i<tape->length; i++)
969   {
970     for(j=0; j<MAX_PLAYERS; j++)
971       if (tape->player_participates[j])
972         fputc(tape->pos[i].action[j], file);
973
974     fputc(tape->pos[i].delay, file);
975   }
976 }
977
978 void SaveTape(int level_nr)
979 {
980   int i;
981   char *filename = getTapeFilename(level_nr);
982   FILE *file;
983   boolean new_tape = TRUE;
984   int num_participating_players = 0;
985   int body_chunk_size;
986
987   InitTapeDirectory(leveldir_current->filename);
988
989   /* if a tape still exists, ask to overwrite it */
990   if (access(filename, F_OK) == 0)
991   {
992     new_tape = FALSE;
993     if (!Request("Replace old tape ?", REQ_ASK))
994       return;
995   }
996
997   if (!(file = fopen(filename, MODE_WRITE)))
998   {
999     Error(ERR_WARN, "cannot save level recording file '%s'", filename);
1000     return;
1001   }
1002
1003   /* count number of participating players  */
1004   for(i=0; i<MAX_PLAYERS; i++)
1005     if (tape.player_participates[i])
1006       num_participating_players++;
1007
1008   body_chunk_size = (num_participating_players + 1) * tape.length;
1009
1010   putFileChunk(file, "RND1", CHUNK_SIZE_UNDEFINED, BYTE_ORDER_BIG_ENDIAN);
1011   putFileChunk(file, "TAPE", CHUNK_SIZE_NONE,      BYTE_ORDER_BIG_ENDIAN);
1012
1013   putFileChunk(file, "VERS", FILE_VERS_CHUNK_SIZE, BYTE_ORDER_BIG_ENDIAN);
1014   WriteChunk_VERS(file, FILE_VERSION_ACTUAL, GAME_VERSION_ACTUAL);
1015
1016   putFileChunk(file, "HEAD", TAPE_HEADER_SIZE, BYTE_ORDER_BIG_ENDIAN);
1017   SaveTape_HEAD(file, &tape);
1018
1019   putFileChunk(file, "BODY", body_chunk_size, BYTE_ORDER_BIG_ENDIAN);
1020   SaveTape_BODY(file, &tape);
1021
1022   fclose(file);
1023
1024   SetFilePermissions(filename, PERMS_PRIVATE);
1025
1026   tape.changed = FALSE;
1027
1028   if (new_tape)
1029     Request("tape saved !", REQ_CONFIRM);
1030 }
1031
1032 void DumpTape(struct TapeInfo *tape)
1033 {
1034   int i, j;
1035
1036   if (TAPE_IS_EMPTY(*tape))
1037   {
1038     Error(ERR_WARN, "no tape available for level %d", tape->level_nr);
1039     return;
1040   }
1041
1042   printf("\n");
1043   printf("-------------------------------------------------------------------------------\n");
1044   printf("Tape of Level %d (file version %06d, game version %06d\n",
1045          tape->level_nr, tape->file_version, tape->game_version);
1046   printf("-------------------------------------------------------------------------------\n");
1047
1048   for(i=0; i<tape->length; i++)
1049   {
1050     if (i >= MAX_TAPELEN)
1051       break;
1052
1053     for(j=0; j<MAX_PLAYERS; j++)
1054     {
1055       if (tape->player_participates[j])
1056       {
1057         int action = tape->pos[i].action[j];
1058
1059         printf("%d:%02x ", j, action);
1060         printf("[%c%c%c%c|%c%c] - ",
1061                (action & JOY_LEFT ? '<' : ' '),
1062                (action & JOY_RIGHT ? '>' : ' '),
1063                (action & JOY_UP ? '^' : ' '),
1064                (action & JOY_DOWN ? 'v' : ' '),
1065                (action & JOY_BUTTON_1 ? '1' : ' '),
1066                (action & JOY_BUTTON_2 ? '2' : ' '));
1067       }
1068     }
1069
1070     printf("(%03d)\n", tape->pos[i].delay);
1071   }
1072
1073   printf("-------------------------------------------------------------------------------\n");
1074 }
1075
1076
1077 /* ========================================================================= */
1078 /* score file functions                                                      */
1079 /* ========================================================================= */
1080
1081 void LoadScore(int level_nr)
1082 {
1083   int i;
1084   char *filename = getScoreFilename(level_nr);
1085   char cookie[MAX_LINE_LEN];
1086   char line[MAX_LINE_LEN];
1087   char *line_ptr;
1088   FILE *file;
1089
1090   /* always start with reliable default values */
1091   for(i=0; i<MAX_SCORE_ENTRIES; i++)
1092   {
1093     strcpy(highscore[i].Name, EMPTY_PLAYER_NAME);
1094     highscore[i].Score = 0;
1095   }
1096
1097   if (!(file = fopen(filename, MODE_READ)))
1098     return;
1099
1100   /* check file identifier */
1101   fgets(cookie, MAX_LINE_LEN, file);
1102   if (strlen(cookie) > 0 && cookie[strlen(cookie) - 1] == '\n')
1103     cookie[strlen(cookie) - 1] = '\0';
1104
1105   if (!checkCookieString(cookie, SCORE_COOKIE))
1106   {
1107     Error(ERR_WARN, "unknown format of score file '%s'", filename);
1108     fclose(file);
1109     return;
1110   }
1111
1112   for(i=0; i<MAX_SCORE_ENTRIES; i++)
1113   {
1114     fscanf(file, "%d", &highscore[i].Score);
1115     fgets(line, MAX_LINE_LEN, file);
1116
1117     if (line[strlen(line) - 1] == '\n')
1118       line[strlen(line) - 1] = '\0';
1119
1120     for (line_ptr = line; *line_ptr; line_ptr++)
1121     {
1122       if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
1123       {
1124         strncpy(highscore[i].Name, line_ptr, MAX_PLAYER_NAME_LEN);
1125         highscore[i].Name[MAX_PLAYER_NAME_LEN] = '\0';
1126         break;
1127       }
1128     }
1129   }
1130
1131   fclose(file);
1132 }
1133
1134 void SaveScore(int level_nr)
1135 {
1136   int i;
1137   char *filename = getScoreFilename(level_nr);
1138   FILE *file;
1139
1140   InitScoreDirectory(leveldir_current->filename);
1141
1142   if (!(file = fopen(filename, MODE_WRITE)))
1143   {
1144     Error(ERR_WARN, "cannot save score for level %d", level_nr);
1145     return;
1146   }
1147
1148   fprintf(file, "%s\n\n", SCORE_COOKIE);
1149
1150   for(i=0; i<MAX_SCORE_ENTRIES; i++)
1151     fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name);
1152
1153   fclose(file);
1154
1155   SetFilePermissions(filename, PERMS_PUBLIC);
1156 }
1157
1158
1159 /* ========================================================================= */
1160 /* setup file functions                                                      */
1161 /* ========================================================================= */
1162
1163 #define TOKEN_STR_PLAYER_PREFIX         "player_"
1164
1165 /* global setup */
1166 #define SETUP_TOKEN_PLAYER_NAME         0
1167 #define SETUP_TOKEN_SOUND               1
1168 #define SETUP_TOKEN_SOUND_LOOPS         2
1169 #define SETUP_TOKEN_SOUND_MUSIC         3
1170 #define SETUP_TOKEN_SOUND_SIMPLE        4
1171 #define SETUP_TOKEN_SCROLL_DELAY        5
1172 #define SETUP_TOKEN_SOFT_SCROLLING      6
1173 #define SETUP_TOKEN_FADING              7
1174 #define SETUP_TOKEN_AUTORECORD          8
1175 #define SETUP_TOKEN_QUICK_DOORS         9
1176 #define SETUP_TOKEN_TEAM_MODE           10
1177 #define SETUP_TOKEN_HANDICAP            11
1178 #define SETUP_TOKEN_TIME_LIMIT          12
1179 #define SETUP_TOKEN_FULLSCREEN          13
1180
1181 #define NUM_GLOBAL_SETUP_TOKENS         14
1182
1183 /* player setup */
1184 #define SETUP_TOKEN_USE_JOYSTICK        0
1185 #define SETUP_TOKEN_JOY_DEVICE_NAME     1
1186 #define SETUP_TOKEN_JOY_XLEFT           2
1187 #define SETUP_TOKEN_JOY_XMIDDLE         3
1188 #define SETUP_TOKEN_JOY_XRIGHT          4
1189 #define SETUP_TOKEN_JOY_YUPPER          5
1190 #define SETUP_TOKEN_JOY_YMIDDLE         6
1191 #define SETUP_TOKEN_JOY_YLOWER          7
1192 #define SETUP_TOKEN_JOY_SNAP            8
1193 #define SETUP_TOKEN_JOY_BOMB            9
1194 #define SETUP_TOKEN_KEY_LEFT            10
1195 #define SETUP_TOKEN_KEY_RIGHT           11
1196 #define SETUP_TOKEN_KEY_UP              12
1197 #define SETUP_TOKEN_KEY_DOWN            13
1198 #define SETUP_TOKEN_KEY_SNAP            14
1199 #define SETUP_TOKEN_KEY_BOMB            15
1200
1201 #define NUM_PLAYER_SETUP_TOKENS         16
1202
1203 static struct SetupInfo si;
1204 static struct SetupInputInfo sii;
1205
1206 static struct TokenInfo global_setup_tokens[] =
1207 {
1208   /* global setup */
1209   { TYPE_STRING,  &si.player_name,      "player_name"                   },
1210   { TYPE_SWITCH,  &si.sound,            "sound"                         },
1211   { TYPE_SWITCH,  &si.sound_loops,      "repeating_sound_loops"         },
1212   { TYPE_SWITCH,  &si.sound_music,      "background_music"              },
1213   { TYPE_SWITCH,  &si.sound_simple,     "simple_sound_effects"          },
1214   { TYPE_SWITCH,  &si.scroll_delay,     "scroll_delay"                  },
1215   { TYPE_SWITCH,  &si.soft_scrolling,   "soft_scrolling"                },
1216   { TYPE_SWITCH,  &si.fading,           "screen_fading"                 },
1217   { TYPE_SWITCH,  &si.autorecord,       "automatic_tape_recording"      },
1218   { TYPE_SWITCH,  &si.quick_doors,      "quick_doors"                   },
1219   { TYPE_SWITCH,  &si.team_mode,        "team_mode"                     },
1220   { TYPE_SWITCH,  &si.handicap,         "handicap"                      },
1221   { TYPE_SWITCH,  &si.time_limit,       "time_limit"                    },
1222   { TYPE_SWITCH,  &si.fullscreen,       "fullscreen"                    }
1223 };
1224
1225 static struct TokenInfo player_setup_tokens[] =
1226 {
1227   /* player setup */
1228   { TYPE_BOOLEAN, &sii.use_joystick,    ".use_joystick"                 },
1229   { TYPE_STRING,  &sii.joy.device_name, ".joy.device_name"              },
1230   { TYPE_INTEGER, &sii.joy.xleft,       ".joy.xleft"                    },
1231   { TYPE_INTEGER, &sii.joy.xmiddle,     ".joy.xmiddle"                  },
1232   { TYPE_INTEGER, &sii.joy.xright,      ".joy.xright"                   },
1233   { TYPE_INTEGER, &sii.joy.yupper,      ".joy.yupper"                   },
1234   { TYPE_INTEGER, &sii.joy.ymiddle,     ".joy.ymiddle"                  },
1235   { TYPE_INTEGER, &sii.joy.ylower,      ".joy.ylower"                   },
1236   { TYPE_INTEGER, &sii.joy.snap,        ".joy.snap_field"               },
1237   { TYPE_INTEGER, &sii.joy.bomb,        ".joy.place_bomb"               },
1238   { TYPE_KEY,     &sii.key.left,        ".key.move_left"                },
1239   { TYPE_KEY,     &sii.key.right,       ".key.move_right"               },
1240   { TYPE_KEY,     &sii.key.up,          ".key.move_up"                  },
1241   { TYPE_KEY,     &sii.key.down,        ".key.move_down"                },
1242   { TYPE_KEY,     &sii.key.snap,        ".key.snap_field"               },
1243   { TYPE_KEY,     &sii.key.bomb,        ".key.place_bomb"               }
1244 };
1245
1246 static void setSetupInfoToDefaults(struct SetupInfo *si)
1247 {
1248   int i;
1249
1250   si->player_name = getStringCopy(getLoginName());
1251
1252   si->sound = TRUE;
1253   si->sound_loops = TRUE;
1254   si->sound_music = TRUE;
1255   si->sound_simple = TRUE;
1256   si->toons = TRUE;
1257   si->double_buffering = TRUE;
1258   si->direct_draw = !si->double_buffering;
1259   si->scroll_delay = TRUE;
1260   si->soft_scrolling = TRUE;
1261   si->fading = FALSE;
1262   si->autorecord = TRUE;
1263   si->quick_doors = FALSE;
1264   si->team_mode = FALSE;
1265   si->handicap = TRUE;
1266   si->time_limit = TRUE;
1267   si->fullscreen = FALSE;
1268
1269   for (i=0; i<MAX_PLAYERS; i++)
1270   {
1271     si->input[i].use_joystick = FALSE;
1272     si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
1273     si->input[i].joy.xleft   = JOYSTICK_XLEFT;
1274     si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
1275     si->input[i].joy.xright  = JOYSTICK_XRIGHT;
1276     si->input[i].joy.yupper  = JOYSTICK_YUPPER;
1277     si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
1278     si->input[i].joy.ylower  = JOYSTICK_YLOWER;
1279     si->input[i].joy.snap  = (i == 0 ? JOY_BUTTON_1 : 0);
1280     si->input[i].joy.bomb  = (i == 0 ? JOY_BUTTON_2 : 0);
1281     si->input[i].key.left  = (i == 0 ? DEFAULT_KEY_LEFT  : KSYM_UNDEFINED);
1282     si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
1283     si->input[i].key.up    = (i == 0 ? DEFAULT_KEY_UP    : KSYM_UNDEFINED);
1284     si->input[i].key.down  = (i == 0 ? DEFAULT_KEY_DOWN  : KSYM_UNDEFINED);
1285     si->input[i].key.snap  = (i == 0 ? DEFAULT_KEY_SNAP  : KSYM_UNDEFINED);
1286     si->input[i].key.bomb  = (i == 0 ? DEFAULT_KEY_BOMB  : KSYM_UNDEFINED);
1287   }
1288 }
1289
1290 static void decodeSetupFileList(struct SetupFileList *setup_file_list)
1291 {
1292   int i, pnr;
1293
1294   if (!setup_file_list)
1295     return;
1296
1297   /* handle global setup values */
1298   si = setup;
1299   for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
1300     setSetupInfo(global_setup_tokens, i,
1301                  getTokenValue(setup_file_list, global_setup_tokens[i].text));
1302   setup = si;
1303
1304   /* handle player specific setup values */
1305   for (pnr=0; pnr<MAX_PLAYERS; pnr++)
1306   {
1307     char prefix[30];
1308
1309     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
1310
1311     sii = setup.input[pnr];
1312     for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
1313     {
1314       char full_token[100];
1315
1316       sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
1317       setSetupInfo(player_setup_tokens, i,
1318                    getTokenValue(setup_file_list, full_token));
1319     }
1320     setup.input[pnr] = sii;
1321   }
1322 }
1323
1324 void LoadSetup()
1325 {
1326   char *filename = getSetupFilename();
1327   struct SetupFileList *setup_file_list = NULL;
1328
1329   /* always start with reliable default values */
1330   setSetupInfoToDefaults(&setup);
1331
1332   setup_file_list = loadSetupFileList(filename);
1333
1334   if (setup_file_list)
1335   {
1336     checkSetupFileListIdentifier(setup_file_list, getCookie("SETUP"));
1337     decodeSetupFileList(setup_file_list);
1338
1339     setup.direct_draw = !setup.double_buffering;
1340
1341     freeSetupFileList(setup_file_list);
1342
1343     /* needed to work around problems with fixed length strings */
1344     if (strlen(setup.player_name) > MAX_PLAYER_NAME_LEN)
1345       setup.player_name[MAX_PLAYER_NAME_LEN] = '\0';
1346     else if (strlen(setup.player_name) < MAX_PLAYER_NAME_LEN)
1347     {
1348       char *new_name = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
1349
1350       strcpy(new_name, setup.player_name);
1351       free(setup.player_name);
1352       setup.player_name = new_name;
1353     }
1354   }
1355   else
1356     Error(ERR_WARN, "using default setup values");
1357 }
1358
1359 void SaveSetup()
1360 {
1361   char *filename = getSetupFilename();
1362   FILE *file;
1363   int i, pnr;
1364
1365   InitUserDataDirectory();
1366
1367   if (!(file = fopen(filename, MODE_WRITE)))
1368   {
1369     Error(ERR_WARN, "cannot write setup file '%s'", filename);
1370     return;
1371   }
1372
1373   fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
1374                                                getCookie("SETUP")));
1375   fprintf(file, "\n");
1376
1377   /* handle global setup values */
1378   si = setup;
1379   for (i=0; i<NUM_GLOBAL_SETUP_TOKENS; i++)
1380   {
1381     fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
1382
1383     /* just to make things nicer :) */
1384     if (i == SETUP_TOKEN_PLAYER_NAME)
1385       fprintf(file, "\n");
1386   }
1387
1388   /* handle player specific setup values */
1389   for (pnr=0; pnr<MAX_PLAYERS; pnr++)
1390   {
1391     char prefix[30];
1392
1393     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
1394     fprintf(file, "\n");
1395
1396     sii = setup.input[pnr];
1397     for (i=0; i<NUM_PLAYER_SETUP_TOKENS; i++)
1398       fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
1399   }
1400
1401   fclose(file);
1402
1403   SetFilePermissions(filename, PERMS_PRIVATE);
1404 }