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