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